Skip to content

Instantly share code, notes, and snippets.

@jrivany
Last active December 23, 2019 22:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jrivany/0665e26759fd677eb52e44b8f93cc07a to your computer and use it in GitHub Desktop.
Save jrivany/0665e26759fd677eb52e44b8f93cc07a to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
import argparse, re, os
from pyffi.formats.nif import NifFormat
def process_dir(dir, is_dryrun):
file_changed = False
for stream, data in NifFormat.walkData(args.dir):
try:
# the replace call makes the doctest also pass on windows
os_path = stream.name
split = (os_path.split(os.sep))[-5:]
filename = os.path.join(*split).replace(os.sep, "/")
print("reading %s" % filename)
data.read(stream)
for block in data.blocks:
# Remove NiTexture effect blocks
if isinstance(block, NifFormat.NiTextureEffect):
print('\tremoving NiTextureEffect block')
data.replace_global_node(block, None)
file_changed = True
# Remove NiSourceTextures for bump maps
elif (isinstance(block, NifFormat.NiTexturingProperty)
and block.has_bump_map_texture):
source_block = block.bump_map_texture.source
bump_map_file = str(source_block.file_name)
print('\tremoving NiSourceTexture block with file name %s' % bump_map_file)
data.replace_global_node(source_block, None)
# Remove reference
block.has_bump_map_texture = False
file_changed = True
stream.close()
# Output
if file_changed and not is_dryrun:
print('\twriting to %s' % filename)
output = open(filename, 'wb')
data.write(output)
output.close()
except Exception as e:
print('Error reading file %s' % e)
if __name__ == '__main__':
try:
parser = argparse.ArgumentParser()
parser.add_argument('--dryrun', action='store_true',
help='Print out node deletions and then exit without replacing files')
parser.add_argument('dir', help='The root directory to scan for .nif files.')
args = parser.parse_args()
except Exception:
parser.print_help()
raise SystemExit()
process_dir(args.dir, args.dryrun)
@jrivany
Copy link
Author

jrivany commented Sep 25, 2017

Example usage inspired by http://openmw.readthedocs.io/en/openmw-0.41.0/openmw-mods/convert_bump_mapped_mods.html#converting-apel-s-various-things-sacks

./fix_nif.py --regex '.*_nm\.dds' PATH_TO_APELS_VAIOUS_THINGS_FOLDER

@jrivany
Copy link
Author

jrivany commented Jun 7, 2019

Update, regex option is no longer needed, as bump_maps can be found using the block data

@Dizzy611
Copy link

Hi, realize this is just a gist and an old one, but it's giving a screenful of "struct.error: unpack requires a buffer of 2 bytes
Error reading file unpack requires a buffer of 2 bytes" when trying to read the NiTriShapeData struct with pretty much every NIF it encounters.

I'm trying to figure out how to fix it but I've no idea what I'm doing :P

@jrivany
Copy link
Author

jrivany commented Dec 23, 2019

No worries. Check out this repo https://github.com/treymerkley/openmw-nif-cleaner I've made some fixes and this guy contributed a qt GUI as well.

Anyway since I wrote this, pyffi was updated to break proper support with morrowind nifs (I believe he opened an issue with them about it, perhaps theres a way to make it work with the newer versions)

This will only work with Pyffi 2.2.2, nothing newer, and I'd also recommend checking out the updated processing code in that repo. I can't remember what it fixed, but it works much better

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment