Jump to content
  • entries
    20
  • comments
    9
  • views
    6,975

synthetic slidergroups builder -- first draft


sen4mi

237 views

In my previous entry, I mentioned a bunch of goals for dealing with bodyslide under mo2.

 

I had made a small amount of progress towards them -- I implemented a script to give me a "synthetic groups", so basically a single bodyslide group which represents all bodytalk3 outfits (including the base body) and another for all fusion girl outfits (including the base body).

 

After working with this, I still need to address some of the other goals there. But, mostly, doing them manually kinda works. So... maybe I will come back to them later, or maybe not.

 

But, also, after working with this, I realized that I need another kind of synthetic group, which is the list of outfits which need manual attention. This means either conflicting outfits building the same mesh or outfits with zaps. Zaps are an interesting but poorly designed feature of bodyslide and outfit studio. (Poorly designed because the general case of changing the default values, for batch builds, is quite tedious and in some cases impossible, despite the fact the bodyslide clearly supports the underlying mechanisms.)

 

(And, a third variation here would take the "conflicting outfits" groups and reduce them manually to just the ones where I want to change something. In other words, I would take the hypothetical auto-built conflict groups and remove stuff from them that I do not care about, giving the edited groups new names.)

 

Anyways... here's my current synthetic slidergroups builder that only does the first part:

 

#!/usr/bin/perl
use Carp;
use strict;
use warnings;

if (0 == scalar @ARGV || ! -r 'modlist.txt') {
	print STDERR <<ENDUSAGE
	current directory must be an MO2 profile directory (containing modlist.txt)

Usage: $0 [presetnames]

	builds synthetic groups for the preset names listed on the command line
ENDUSAGE
}

sub slurp {
	my ($fname)= @_;
	open(my $fref, '<', $fname) or croak "cannot open $fname: $!";
	return map {s/[\r\n]//gr} <$fref>;
}

my @mods= map {s/^[+]//r} grep {/^[+]/} slurp('modlist.txt');


sub getname {
	my ($element)= @_;
	$element=~ s{.*name="}{};
	$element=~ s{".*}{};
	return $element;
}

sub gettext {
	my ($element)= @_;
	$element=~ s{</.*}{};
	$element=~ s{.*>}{};
	return $element;
}

print STDERR "Checking presets\n";
my %havepreset= ();
for my $mod (@mods) {
	for my $presetdefs (glob qq{"../../mods/$mod/Tools/BodySlide/SliderPresets/*.xml"}) {
		my @defs= slurp $presetdefs;
		for my $preset (@ARGV) {
			if (grep {/<Preset name="$preset"/} @defs) {
				if (grep {/<Group name="z Preset - $preset"/} @defs) {
					$havepreset{$preset}++;
					print STDERR "Preset $preset looks ok\n"
				} elsif (!$havepreset{$preset}) {
					print STDERR <<ENDCAUTION
CAUTION: $presetdefs defines preset $preset
That preset should be manually edited, adding:
	<Group name="z Preset - $preset"/>
ENDCAUTION
				}
			}
		}
	}
}
print STDERR "Have @{[scalar keys %havepreset]} target preset(s)\n";

print STDERR "Studying SliderSets\n";
my %outfitnifs= ();
my %outfitnif_files= ();
for my $mod (@mods) {
	for my $file (glob qq{"../../mods/$mod/tools/bodyslide/slidersets/*.osp"}) {
		my ($outfit, $outputpath, $outputfile);
		for my $element (grep {/<SliderSet name=|<Output(Path|File)/} slurp $file) {
			if ($element=~/<SliderSet /) {
				$outfit= getname $element;
			} elsif ($element=~/<OutputPath/) {
				$outputpath= gettext $element;
			} elsif ($element=~/<OutputFile/) {
				$outputfile= gettext $element;
				$outfitnifs{$outfit}= lc "$outputpath\\$outputfile";
				$outfitnif_files{$outfit}= $file;
			}
		}
	}
}
print STDERR "Have @{[scalar keys %outfitnifs]} bodyslide outfits\n";

print STDERR "\nstudying SliderPresets...\n";
my %grouppresets= ();
my %grouppreset_files= ();
for my $mod (@mods) {
	for my $file (glob qq{"../../mods/$mod/Tools/BodySlide/SliderPresets/*.xml"}) {
		my $presetname;
		for my $element (grep {/<(Preset|Group) name=/} slurp $file) {
			if ($element=~/<Preset /) {
				$presetname= getname $element;
				$presetname= '' if !exists $havepreset{$presetname};
			} elsif ('' ne $presetname && $element=~/<Group /) {
				my $groupname= getname $element;
				if (exists $grouppresets{$groupname}) {
					if ($presetname ne $grouppresets{$groupname}) {
						print STDERR "Warning: group '$groupname' declared as supporting presets '$presetname' and '$grouppresets{$groupname}', so '$presetname' will be ignored for '$groupname' ($grouppreset_files{$groupname} overriding $file).\n";
					}
				} else {
					$grouppresets{$groupname}= $presetname;
					$grouppreset_files{$groupname}= $file;
				}
			}
		}
	}
}
print STDERR "Have @{[scalar keys %grouppresets]} relevant groups\n";

print STDERR "Studying SliderGroups\n";
my %outfitgroups= ();
my %outfitgroup_files= ();
my %nifpresets= ();
my %nifpreset_files= ();
my %outfitgroup_warnings= ();
for my $mod (@mods) {
	for my $file (glob  qq{"../../mods/$mod/tools/bodyslide/slidergroups/*.xml"}) {
		my $groupname;
		for my $element (grep {/<(Group|Member) name=/} slurp $file) {
			if ($element=~/<Group /) {
				$groupname= getname $element;
				if (!exists $grouppresets{$groupname}) {
					$groupname= '';
				}
				if ($groupname=~/z Preset -/) {
					print STDERR "Ignoring synthetic group '$groupname'\n";
					$groupname= '';
				}
			} elsif ('' ne $groupname && $element=~/<Member /) {
				my $outfit= getname $element; # $outfit will be the name of a SliderSet
				if (!exists $outfitnifs{$outfit}) {
					print STDERR "Warning: ignoring mod ${mod}'s missing outfit '$outfit' mentioned in group '$groupname' (from $file)\n"
				       		unless 'BodyTalk' eq $mod; # BodyTalk is on Patreon, and I am not going to pay money for the right to report problems with the mod
				} else {
					# outfits can be in many groups, but here we're typically focusing on distinguishing male and female outfits
					if (exists $outfitgroups{$outfit} && $groupname ne $outfitgroups{$outfit}) {
						my $nif= $outfitnifs{$outfit};
						my $gpreset= ''; $gpreset= $grouppresets{$groupname} if exists $grouppresets{$groupname};
						my $npreset= ''; $npreset= $nifpresets{$nif} if exists $nifpresets{$nif};
						if ('' ne $gpreset) {
							if ('' ne $npreset && $gpreset ne $npreset) {
								print STDERR "Warning: ignoring conflicting group $groupname for outfit $outfit and preset $npreset which is in already in group $outfitgroups{$outfit} for preset $gpreset ($outfitgroup_files{$outfit} overriding $file)\n";
								next;
							}
						}
					} 
					$outfitgroups{$outfit}= $groupname;
					$outfitgroup_files{$outfit}= $file;
					my $nif= $outfitnifs{$outfit};
					if (exists $grouppresets{$groupname}) {
						my $preset= $grouppresets{$groupname};
						if (exists $nifpresets{$nif}) {
							if ($preset ne $nifpresets{$nif}) {
								print STDERR "Warning: outfit $outfit is in group $preset but its nif $nif was alrady in group $nifpresets{$nif}, so ignoring $preset here ($nifpreset_files{$nif} overriding $file)\n";
							}
						} else {
							$nifpresets{$nif}= $preset;
							$nifpreset_files{$nif}= $file;
						}
					}
				}
			}
		}
	}
}
print STDERR "Have @{[scalar keys %outfitgroups]} relevant source outfits and @{[scalar keys %nifpresets]} relevant outfit targets\n";

print STDERR "Propagating presets for slidersets without groups\n";
my %outfitpresets= ();
my %outfitpreset_files= ();
for my $outfit (keys %outfitnifs) {
	my $nif= $outfitnifs{$outfit};
	if (exists $nifpresets{$nif}) {
		if (exists $outfitpresets{$outfit}) {
			if ($outfitpresets{$outfit} ne $nifpresets{$nif}) {
				print STDERR "Warning: $outfit was assigned to preset $outfitpresets{$outfit} so ignoring preset $nifpresets{$nif} which should never happen (conflict between $outfitpreset_files{$outfit} and $nifpreset_files{$nif})\n";
			}
		} else {
			$outfitpresets{$outfit}= $nifpresets{$nif};
			$outfitpreset_files{$outfit}= $nifpreset_files{$nif};
		}
	} else {
	}
}
print STDERR "Confirm @{[scalar keys %outfitpresets]} categorized outfits\n";

print STDERR "Loading prechosen outfits\n";
my %outputchoice= ();
my %choiceoutput= ();
for my $element (grep {/<OutputChoice/} slurp '../../mods/BodySlide and Outfit Studio/Tools/BodySlide/BuildSelection.xml') {
	my @fields= split /"/, $element;
	my $path= lc$fields[1];
	my $choice= $fields[3];
	if (exists $outputchoice{$path}) {
		if ($choice ne $outputchoice{$path}) {
			print STDERR "Warning: outfit $choice was specified for nif $path but $outputchoice{$path} had already been selected. Ignoring $choice\n";
		}
	} else {
		$outputchoice{$path}= $choice;
		$choiceoutput{$choice}= $path;
	}
}
print STDERR "Have @{[scalar keys %outputchoice]} pre-chosen target outfits\n";

# Now we generate the synthetic groups
# When we've chosen an outfit for a nif, we only include that outfit in the new group,
# ignoring the other outfits which could create that nif
# Otherwise, we include all the possibilities
my %fragments;
for my $preset (@ARGV) {
	$fragments{$preset}= '';
}
for my $outfit (sort keys %outfitpresets) {
	my $nif= $outfitnifs{$outfit};
	if (!exists $outputchoice{$nif} || $outfit eq $outputchoice{$nif}) {
		$fragments{$outfitpresets{$outfit}}.= "        <Member name=\"$outfit\"/>\n";
	}
}

mkdir '../../overwrite/Tools';
mkdir '../../overwrite/Tools/BodySlide';
mkdir '../../overwrite/Tools/BodySlide/SliderGroups';
my $target= '../../overwrite/Tools/BodySlide/SliderGroups/LocalSynthetic.xml';
open my $xmlfile, '>', $target or die "can't write to $target: $!";

print $xmlfile <<ENDPREFIX;
<?xml version="1.0" encoding="UTF-8"?>
<SliderGroups>
ENDPREFIX

for my $preset (sort keys %fragments) {
	print $xmlfile qq{    <Group name="z Preset - $preset">\n};
	print $xmlfile $fragments{$preset};
	print $xmlfile qq{    </Group>\n};
}
print $xmlfile "</SliderGroups>\n";

print STDERR "\nBuilt $target\n";

 

Edited by sen4mi

0 Comments


Recommended Comments

There are no comments to display.

×
×
  • Create New...