Это старая версия скрипта, позволяющая выдирать игровые ячейки в ниф файлы.
При этом, со всем их содержимым, в т.ч. с мелкими объектами.
Выдираются, как интерьеры, так и экстерьеры.
Создать текстовый файл, вставить текст, сохранить с расширением .PY
Выполнить посредством консоли и установленных в системе
Pyffi утилит.
(С) Greatness7
#!python2
import os
from math import cos, sin
from subprocess import Popen, PIPE
from tempfile import NamedTemporaryFile
from pyffi.formats.nif import NifFormat
path = "C:\\Users\\Jad\\Games\\Morrowind\\Data Files\\"
perl = \
"""
my $cell = "Balmora (-3, -2)";
my %scan = map{$_, 1} (
"ACTI",
"ALCH",
"APPA",
"ARMO",
"BODY",
"BOOK",
"CLOT",
"CONT",
"DOOR",
"INGR",
"LOCK",
"MISC",
"PROB",
"REPA",
"STAT",
"WEAP",
# "LIGH",
);
# extract x/y coords
my($x, $y) = $cell =~ /\((-?\d+), (-?\d+)\)$/;
# scan load order
my(%refs, %mesh, %done);
for my $plugin (reverse $T3->load_order) {
my $input = open_for_input($plugin);
# scan plugin records
while (my $record = TES3::Record->new_from_input($input, undef, $plugin)) {
my $type = $record->rectype;
# make id/mesh dictionary
if (exists $scan{$type}) {
my $id = $record->decode->id;
my $model = $record->get('MODL', 'model');
$mesh{$id} = lc $model if defined $model;
}
# find specified cell
next if $type ne 'CELL';
next if $cell eq 'DONE';
my $id = $record->decode->id;
# filter unwanted cells
if (defined $x and defined $y) {
next if $record->is_interior;
next if $id !~ /\($x, $y\)$/;
} else {
next if $id !~ lc $cell;
}
# loop through cell references
for (map {@$_} $record->split_groups) {
my %sub = map {substr(ref $_, 6), $_} @$_;
next unless exists $sub{FRMR};
my $key = $sub{FRMR}{objidx};
# skip deleted refs
if (exists $sub{DELE}) {
$refs{$key} = undef;
}
# skip removed indices
next if exists $refs{$key};
# center exterior coords
unless ($record->is_interior) {
$sub{DATA}{x} -= ($x * 2 + 1) * 4096;
$sub{DATA}{y} -= ($y * 2 + 1) * 4096;
}
# save reference data
$refs{$key} = [lc
$sub{NAME}{name},
$sub{XSCL}{scale} // 1,
$sub{DATA}{x},
$sub{DATA}{y},
$sub{DATA}{z},
$sub{DATA}{x_angle},
$sub{DATA}{y_angle},
$sub{DATA}{z_angle},
]
}
$cell = 'DONE';
}
}
undef %done;
local $" = ',';
# scan references
while (my($key, $data) = each %refs) {
next unless $data;
# skip no-model refs
my $name = shift @$data;
my $model = $mesh{$name};
next unless defined $model;
# replace backslashes
$model =~ s/\\\/\\//g;
# create model ref-array
$done{$model} = [] unless exists $done{$model};
# append ref data as python tuple
push @{ $done{$model} },
qq/("$name", @$data[0], [@$data[1..3]], [@$data[4..6]])/;
# AKA name, scale, translation, rotation
}
# send to python as dictionary
print "{";
while (my($mesh, $data) = each %done) {
print qq/"$mesh":[@$data],/
}
print "}";
exit
"""
try:
os.chdir(path)
f = NamedTemporaryFile(dir=path, suffix=".pl", delete=False)
f.write(str.encode(perl))
f.close()
args = ["tes3cmd.exe", "modify", "-program", f.name]
pipe = Popen(args, stdin=PIPE, stdout=PIPE)
nifs = eval(pipe.communicate()[0])
except Exception as e:
quit("ERROR! %s" % e)
finally:
os.remove(f.name)
vec = NifFormat.Vector3()
mat = NifFormat.Matrix33()
parent = NifFormat.NiNode()
for file, refs in nifs.items():
mesh = os.path.normpath(
os.path.join(path, "meshes", file)
)
try: # read mesh data
with open(mesh, 'rb') as stream:
print "Reading Mesh:", file
roots = []
for i in range(len(refs)):
data = NifFormat.Data()
data.read(stream)
stream.seek(0)
root = data.roots[0]
root.translation = vec
root.rotation = mat
root.scale = 1
roots.append(root)
except FileNotFoundError:
print "Missing Mesh:", file
continue
for root, ref in zip(roots, refs):
name, sca, loc, rot = ref
node = NifFormat.NiNode()
node.add_child(root)
node.name = name
node.scale = sca
(node.translation.x,
node.translation.y,
node.translation.z) = loc
for i, r in enumerate(rot):
cr, sr = cos(r), sin(r)
r = rot[i] = NifFormat.Matrix33()
r.m_11 = ( 1, cr, cr ) [i]
r.m_12 = ( 0, 0, -sr ) [i]
r.m_13 = ( 0, -sr, 0 ) [i]
r.m_21 = ( 0, 0, sr ) [i]
r.m_22 = ( cr, 1, cr ) [i]
r.m_23 = ( sr, 0, 0 ) [i]
r.m_31 = ( 0, -sr, 0 ) [i]
r.m_32 = ( sr, 0, 0 ) [i]
r.m_33 = ( cr, cr, 1 ) [i]
node.rotation = rot[0] * rot[1] * rot[2]
parent.add_child(node)
if parent.children:
out = os.path.join(path, "CELL.nif")
print "Writing Mesh:", out
with open(out, 'wb') as stream:
data = NifFormat.Data()
data.roots = [parent]
data.write(stream)