|
Post by fufu508 on Feb 9, 2019 23:29:34 GMT -5
Ok so I have a mostly working search. insert code hereimport io import struct
import sims4.resources import sims4.commands
def get_clip_name(resource: io.BytesIO) -> str: resource.seek(0x38, io.SEEK_SET) name_length: int = struct.unpack('i', resource.read(4))[0] return resource.read(name_length).decode('ascii')
@sims4.commands.Command('clips', command_type=sims4.commands.CommandType.Live) def clips(keyword:str="fufu508", _connection=None): output = sims4.commands.CheatOutput(_connection) clip_count = 0 clip_limit = 20 badkeys = 0 output('Gathering list of clips...') key = 0 keys = sims4.resources.list(type=sims4.resources.Types.CLIP_HEADER) output(f'{len(keys)} clips found.') output(f'Searching for {keyword} in clip names...') while (clip_count < clip_limit) and (key < len(keys)): try: resource_loader = sims4.resources.ResourceLoader(keys[key], sims4.resources.Types.CLIP_HEADER) resource: io.BytesIO = resource_loader.load() clip_name: str = get_clip_name(resource) if keyword in clip_name: output(f'key {key}: {clip_name}') clip_count = clip_count + 1 except: badkeys = badkeys + 1 key = key + 1 output(f'Limit reached. {clip_limit} clip(s) listed. Last key read: {key}') output(f'Number of clips with keys that failed to read: {badkeys}')
But after finding the number of clips I specified, the game eventually closes (crashes). 
|
|
|
Post by andrew on Feb 10, 2019 0:45:57 GMT -5
fufu508 In your post about writing to a file, the example you posted looks like it just lacks from io import open As far as the crashing, it could be because my lazy example is not closing the resource stream. You could try auto-closing it with a "with" statement. ... resource_loader = sims4.resources.ResourceLoader(keys[key], sims4.resources.Types.CLIP_HEADER) with resource_loader.load() as resource: clip_name: str = get_clip_name(resource) ...
As far as skipping non-cc clips, that could be tricky. The quick ways are like you tried (filter by creator name), filter by ':' or 'PosePack' if you want to show all clips created by pose packs. If you only need clips that were created as a pose pack, you could also read through the pose pack snippet tunings to find them all like the pose player does and skip the steps of reading from the clip headers. The get_clip_name function is just one I quickly wrote to simply get the name with as few lines as possible. You could get more information about the clip from there (as much as you see in the warehouse of Studio) with more complete parsing code, but things like the location of the package or whether it is CC are not available there. Also the sims4.resources.Type can be found in the decompiled scripts (sims4/resources).
|
|
|
Post by fufu508 on Feb 10, 2019 1:19:31 GMT -5
Thanks Andrew for the quick response! I'll dig into the details after I get some sleep... :sunny I think the name search will be adequate for now.
|
|
|
Post by fufu508 on Feb 10, 2019 10:31:35 GMT -5
My ts4script still doesn't generate a file after explicitly importing open. I'm currently searching the EA decompiled content for evidence of how EA may be writing files.
I confirmed that open is built in. No need to import, at least not in the pyCharm environment.
scratch.py
f = open("scratchy.txt", "w+") for a in range(1, 10): f.write(f'line {a}\n') f.close() Output of scratchy.txt
line 1 line 2 line 3 line 4 line 5 line 6 line 7 line 8 line 9
|
|
|
Post by fufu508 on Feb 10, 2019 11:19:45 GMT -5
 After messing with my scratch.py in the previous post, I realized I made a very noob mistake!
I used Windows path separator (\) instead of the forward slash (/). This worked as expected in game. Now to grab the animations... import sims4.commands
@sims4.commands.Command('proto', command_type=sims4.commands.CommandType.Live) def proto(_connection=None): output = sims4.commands.CheatOutput(_connection) output("This is my first script mod - presented by Fufu508!!!") output("Made using PyCharm.") foo = 0 f = open("c:/tmp/proto-out.txt", "w+") for num in range(1,10): output(f'{num} is the number.') f.write(f"writing line {foo}\n") foo = foo + 1 if foo > 5: output(f"foo is {foo}. We're done.") break f.close()
|
|
|
Post by fufu508 on Feb 10, 2019 11:42:04 GMT -5
Hi andrew , unfortunately the "with" statement didn't seem to address the crash. I changed this: resource: io.BytesIO = resource_loader.load()
To this:
with resource_loader.load() as resource: The console outputs the same as before, and shortly after that the game suddenly closes.
I'm wondering if there's something in the content of one or more of the keys that doesn't like to be read by the means we are using.
Now that I can write stuff to file, perhaps there are debugging statements I could add?
In the meantime, I will see if I can get the whole list of clips written to file before the game crashes. Crude but it will allow me to work with the list in my next steps.
|
|
|
Post by fufu508 on Feb 10, 2019 12:31:43 GMT -5
I now have the list of clips! Unfortunately it comes at the cost of crashing the game, until the cause can be found.
|
|
|
Post by fufu508 on Feb 10, 2019 13:33:26 GMT -5
In the spoiler is the current content of clips2file.py import io import struct
import sims4.resources import sims4.commands
def get_clip_name(resource: io.BytesIO) -> str: resource.seek(0x38, io.SEEK_SET) name_length: int = struct.unpack('i', resource.read(4))[0] return resource.read(name_length).decode('ascii')
@sims4.commands.Command('clips2file', command_type=sims4.commands.CommandType.Live) def clips2file(_connection=None): output = sims4.commands.CheatOutput(_connection) badkeys = 0 key = 0 clip_names_file = 'c:/tmp/ts4-anim-clips.txt' clip_names :str = [] output('Gathering list of clips...') keys = sims4.resources.list(type=sims4.resources.Types.CLIP_HEADER) output(f'{len(keys)} clips found.') for key in range(len(keys)): try: resource_loader = sims4.resources.ResourceLoader(keys[key], sims4.resources.Types.CLIP_HEADER) with resource_loader.load() as resource: clip_names.append(get_clip_name(resource)) except: badkeys = badkeys + 1 output(f'Number of clips with keys that failed to read: {badkeys}') output(f'Sorting the {len(clip_names)} clip names.') clip_names.sort() output(f'Writing the clip names to {clip_names_file}') f = open(clip_names_file, 'w+') for i in range (len(clip_names)): f.write(f'{"{:5d}".format(i)} {clip_names[i]}\n') f.close() output(f'Done writing {clip_names_file}')
In case the script is consuming info from the game that it shouldn't, here's the current output with some custom clips in it.
|
|