def dry_transfer(sourcefname, targetfname): with open(sourcefname, 'rb') as f: sourcerawdata = f.read() with open(targetfname, 'rb') as f: targetrawdata = f.read() sourcegame, sourcedata = extract.parse_savedata(sourcerawdata) targetgame, targetdata = extract.parse_savedata(targetrawdata) # Get the player data from the source save sourcecfdata = extract.parse_changeforms(sourcedata['changeforms']) sourceplayer = extract.parse_player(sourcecfdata['playerdata'], sourcecfdata['playerchangeflags'], sourcegame) # Get the data from target save targetcfdata = extract.parse_changeforms(targetdata['changeforms']) targetplayer = extract.parse_player(targetcfdata['playerdata'], targetcfdata['playerchangeflags'], targetgame) # Merge players, return target player with source's face newplayer, newflags = extract.merge_player( sourceplayer, sourcecfdata['playerchangeflags'], targetplayer, targetcfdata['playerchangeflags'], sourcegame ) pp = pprint.PrettyPrinter(indent=4) pp.pprint(newplayer)
def merge_player_and_revert(self, fnames): """ Apply the source's face onto the target file and then revert. The target should be identical before and after. """ for fname1, fname2 in fnames: with open(fname1, 'rb') as f: rawsourcedata = f.read() with open(fname2, 'rb') as f: rawtargetdata = f.read() # First get the source for the face sourcegame, sourcedata = extract.parse_savedata(rawsourcedata) sourcecf = extract.parse_changeforms(sourcedata['changeforms']) rawsourceplayer = sourcecf['playerdata'] sourceplayer = extract.parse_player(rawsourceplayer, sourcecf['playerchangeflags'], sourcegame) # Then get the target data targetgame, targetdata = extract.parse_savedata(rawtargetdata) targetcf = extract.parse_changeforms(targetdata['changeforms']) rawtargetplayer = targetcf['playerdata'] targetplayer = extract.parse_player(rawtargetplayer, targetcf['playerchangeflags'], targetgame) # Merge the source and target mergedplayer, mergedflags = extract.merge_player( sourceplayer, sourcecf['playerchangeflags'], targetplayer, targetcf['playerchangeflags'], targetgame ) # Make sure the mergedplayer is valid rawmergedplayer = extract.encode_player(mergedplayer, targetgame) extract.parse_player(rawmergedplayer, mergedflags, targetgame) # Then get a new copy of the target, just to be sure target2game, target2data = extract.parse_savedata(rawtargetdata) rawtarget2cf = target2data['changeforms'] target2cf = extract.parse_changeforms(rawtarget2cf) rawtarget2player = target2cf['playerdata'] target2player = extract.parse_player(rawtarget2player, target2cf['playerchangeflags'], target2game) # Revert the face, aka put the newly read target face # onto the old target's data (which atm has source's face) revertedplayer, revertedflags = extract.merge_player( target2player, target2cf['playerchangeflags'], targetplayer, targetcf['playerchangeflags'], targetgame ) # Encode the target again and compare rawrevertedplayer = extract.encode_player(revertedplayer, targetgame) self.assertEqual(rawtargetplayer, rawrevertedplayer) # Encode the changeforms and compare targetcf['playerdata'] = rawrevertedplayer targetcf['playerchangeflags'] = revertedflags rawrevertedcf = extract.encode_changeforms(targetcf) self.assertEqual(rawtarget2cf, rawrevertedcf) # Encode the whole file and compare targetdata['changeforms'] = rawrevertedcf rawreverteddata = extract.encode_savedata(targetdata) self.assertEqual(rawtargetdata, rawreverteddata)
def transfer_face(sourcefname: str, targetfname: str): """ Copy facial data from one save file to another. This function should be the main entry point for the UI. """ with open(sourcefname, 'rb') as f: sourcerawdata = f.read() with open(targetfname, 'rb') as f: targetrawdata = f.read() sourcegame, sourcedata = extract.parse_savedata(sourcerawdata) targetgame, targetdata = extract.parse_savedata(targetrawdata) if sourcegame != targetgame: raise Exception('Saves are not from the same game!') if sourcedata['playersex'] != targetdata['playersex']: raise Exception('Characters must have the same gender!') if sourcedata['playerraceeditorid'] != targetdata['playerraceeditorid']: raise Exception('Characters must be the same race!') # Get the player data from the source save sourcecfdata = extract.parse_changeforms(sourcedata['changeforms']) sourceplayer = extract.parse_player(sourcecfdata['playerdata'], sourcecfdata['playerchangeflags'], sourcegame) # Get the data from target save targetcfdata = extract.parse_changeforms(targetdata['changeforms']) targetplayer = extract.parse_player(targetcfdata['playerdata'], targetcfdata['playerchangeflags'], targetgame) # Merge players, return target player with source's face newplayer, newflags = extract.merge_player( sourceplayer, sourcecfdata['playerchangeflags'], targetplayer, targetcfdata['playerchangeflags'], sourcegame ) # Encode and put the new face and flags in the target changeform data targetcfdata['playerdata'] = extract.encode_player(newplayer, sourcegame) targetcfdata['playerchangeflags'] = newflags # Encode the changeform data and put it in the target main data targetdata['changeforms'] = extract.encode_changeforms(targetcfdata) # Then encode the whole file newrawdata = extract.encode_savedata(targetdata) # Write to disk i = 0 while os.path.isfile(targetfname+'.facebak'+str(i)): i += 1 rename(targetfname, targetfname+'.facebak'+str(i)) with open(targetfname, 'wb') as f: f.write(newrawdata) return True
def dump_file(fname, rawplayer, npc, achr): with open(fname, 'rb') as f: rawdata = f.read() game, data = extract.parse_savedata(rawdata) cfdata = extract.parse_changeforms(data['changeforms']) if rawplayer: with open(join('savedumps', basename(fname) + '.rawsavedump'), 'w') as f: f.write('{}\n\n{}'.format(cfdata['playerchangeflags'], readable_bytes(cfdata['playerdata']))) return player = extract.parse_player(cfdata['playerdata'], cfdata['playerchangeflags'], game) if npc: out = '' if game == 'fallout4': keys = defaultdict(str) keys['fname'] = fname keys['flags'] = cfdata['playerchangeflags'] keys.update({k:(readable_bytes(v) if isinstance(v, bytes) else v) for k,v in player.items()}) out = falloutformat.format_map(keys) with open(join('savedumps', basename(fname) + '.savedump'), 'w') as f: f.write(out) if achr: cfdata2 = extract.parse_changeforms(data['changeforms'], refidnr=0x14) with open(join('savedumps', basename(fname) + '.ACHRsavedump'), 'w') as f: flags = cfdata2['playerchangeflags'] f.write('{}\n\n{}'.format(flags, readable_bytes(cfdata2['playerdata'])))
def dump_file(fname, rawplayer, npc, achr): with open(fname, 'rb') as f: rawdata = f.read() game, data = extract.parse_savedata(rawdata) cfdata = extract.parse_changeforms(data['changeforms']) if rawplayer: with open(join('savedumps', basename(fname) + '.rawsavedump'), 'w') as f: f.write('{}\n\n{}'.format(cfdata['playerchangeflags'], readable_bytes(cfdata['playerdata']))) return player = extract.parse_player(cfdata['playerdata'], cfdata['playerchangeflags'], game) if npc: out = '' if game == 'fallout4': keys = defaultdict(str) keys['fname'] = fname keys['flags'] = cfdata['playerchangeflags'] keys.update({ k: (readable_bytes(v) if isinstance(v, bytes) else v) for k, v in player.items() }) out = falloutformat.format_map(keys) with open(join('savedumps', basename(fname) + '.savedump'), 'w') as f: f.write(out) if achr: cfdata2 = extract.parse_changeforms(data['changeforms'], refidnr=0x14) with open(join('savedumps', basename(fname) + '.ACHRsavedump'), 'w') as f: flags = cfdata2['playerchangeflags'] f.write('{}\n\n{}'.format(flags, readable_bytes(cfdata2['playerdata'])))
def decode_and_encode(self, root): for path, _, fnames in os.walk(root): for fname in fnames: with open(os.path.join(path, fname), 'rb') as f: rawdata = f.read() _, data = extract.parse_savedata(rawdata) rawdata2 = extract.encode_savedata(data) self.assertEqual(rawdata, rawdata2)
def transfer_face(sourcefname: str, targetfname: str): """ Copy facial data from one save file to another. This function should be the main entry point for the UI. """ with open(sourcefname, 'rb') as f: sourcerawdata = f.read() with open(targetfname, 'rb') as f: targetrawdata = f.read() sourcegame, sourcedata = extract.parse_savedata(sourcerawdata) targetgame, targetdata = extract.parse_savedata(targetrawdata) if sourcegame != targetgame: raise Exception('Saves are not from the same game!') if sourcedata['playersex'] != targetdata['playersex']: raise Exception('Characters must have the same gender!') if sourcedata['playerraceeditorid'] != targetdata['playerraceeditorid']: raise Exception('Characters must be the same race!') # Get the player data from the source save sourcecfdata = extract.parse_changeforms(sourcedata['changeforms']) sourceplayer = extract.parse_player(sourcecfdata['playerdata'], sourcecfdata['playerchangeflags'], sourcegame) # Get the data from target save targetcfdata = extract.parse_changeforms(targetdata['changeforms']) targetplayer = extract.parse_player(targetcfdata['playerdata'], targetcfdata['playerchangeflags'], targetgame) # Merge players, return target player with source's face newplayer, newflags = extract.merge_player( sourceplayer, sourcecfdata['playerchangeflags'], targetplayer, targetcfdata['playerchangeflags'], sourcegame) # Encode and put the new face and flags in the target changeform data targetcfdata['playerdata'] = extract.encode_player(newplayer, sourcegame) targetcfdata['playerchangeflags'] = newflags # Encode the changeform data and put it in the target main data targetdata['changeforms'] = extract.encode_changeforms(targetcfdata) # Then encode the whole file newrawdata = extract.encode_savedata(targetdata) # Write to disk i = 0 while os.path.isfile(targetfname + '.facebak' + str(i)): i += 1 rename(targetfname, targetfname + '.facebak' + str(i)) with open(targetfname, 'wb') as f: f.write(newrawdata) return True
def decode_and_encode_changeforms(self, root): for path, _, fnames in os.walk(root): for fname in fnames: with open(os.path.join(path, fname), 'rb') as f: rawdata = f.read() _, data = extract.parse_savedata(rawdata) rawcf1 = data['changeforms'] cf = extract.parse_changeforms(rawcf1) rawcf2 = extract.encode_changeforms(cf) self.assertEqual(rawcf1, rawcf2)
def decode_and_encode_player(self, root): for path, _, fnames in os.walk(root): for fname in fnames: with open(os.path.join(path, fname), 'rb') as f: rawdata = f.read() game, data = extract.parse_savedata(rawdata) cf = extract.parse_changeforms(data['changeforms']) rawplayer1 = cf['playerdata'] player = extract.parse_player(rawplayer1, cf['playerchangeflags'], game) rawplayer2 = extract.encode_player(player, game) self.assertEqual(rawplayer1, rawplayer2)
def dry_transfer(sourcefname, targetfname): with open(sourcefname, 'rb') as f: sourcerawdata = f.read() with open(targetfname, 'rb') as f: targetrawdata = f.read() sourcegame, sourcedata = extract.parse_savedata(sourcerawdata) targetgame, targetdata = extract.parse_savedata(targetrawdata) # Get the player data from the source save sourcecfdata = extract.parse_changeforms(sourcedata['changeforms']) sourceplayer = extract.parse_player(sourcecfdata['playerdata'], sourcecfdata['playerchangeflags'], sourcegame) # Get the data from target save targetcfdata = extract.parse_changeforms(targetdata['changeforms']) targetplayer = extract.parse_player(targetcfdata['playerdata'], targetcfdata['playerchangeflags'], targetgame) # Merge players, return target player with source's face newplayer, newflags = extract.merge_player( sourceplayer, sourcecfdata['playerchangeflags'], targetplayer, targetcfdata['playerchangeflags'], sourcegame) pp = pprint.PrettyPrinter(indent=4) pp.pprint(newplayer)
def get_ui_data(fname): """ Return data useful for the UI to display, such as name, file info etc. """ with open(fname, 'rb') as f: rawdata = f.read() game, data = extract.parse_savedata(rawdata) out = {} out['save number'] = data['savenumber'] out['name'] = data['playername'] out['level'] = data['playerlevel'] out['location'] = data['playerlocation'] out['race'] = data['playerraceeditorid'] out['gender'] = data['playersex'] out['playing time'] = data['gamedate'] out['screenshot'] = (data['shotwidth'], data['shotheight'], data['screenshotdata']) return out, game