mirror of
https://bitbucket.org/seefoe/dockerized-swg.git
synced 2026-01-16 23:04:17 -05:00
1373 lines
38 KiB
Perl
Executable File
1373 lines
38 KiB
Perl
Executable File
# =====================================================================
|
|
# fixupClientBakedWearableData.pl
|
|
# Copyright 2003, Sony Online Entertainment, Inc.
|
|
# All rights reserved.
|
|
# =====================================================================
|
|
|
|
# =====================================================================
|
|
|
|
# This program is based on buildAssetCustomizationManagerData.pl. It
|
|
# is intended to be a one-shot program used to convert the
|
|
# client-baked wearable data in the client data files to not specify
|
|
# full variable declaration information. The program does the
|
|
# following:
|
|
|
|
# Accept a list of directories to recursively scan for CDF mif files.
|
|
|
|
# For each mif source file, do the following:
|
|
|
|
# Remove any UsePaletteCustomization or UseRangedIntCustomization
|
|
# declaration, taking not of the variable name and default value
|
|
# given.
|
|
|
|
# For the variable name, lookup if the variable is provided by any of
|
|
# the MeshGenerator assets specified in the wearable, and if so, find
|
|
# the art asset's default value.
|
|
|
|
# If the variable is not used by the LMG or any dependencies, nothing
|
|
# replaces the Use* declaration. It was bogus and any intended
|
|
# default is pointless to preserve since it can't affect anything.
|
|
|
|
# If the variable is used and the value specified as the default in the
|
|
# Use* declaration matches the default provided by the artist, nothing
|
|
# replaces the use declaration since the object will get the default
|
|
# without specifying anything.
|
|
|
|
# If the variable is used and the value specified within the Use*
|
|
# declaration specifies an out-of-range value, nothing replaces the
|
|
# use declaration since the intent of the value can't be determined
|
|
# and we might as well do the thing that reduced data size in its
|
|
# place.
|
|
|
|
# If the variable is used and the value specified within the Use*
|
|
# declaration is within range but is different than the artist
|
|
# default, emit a WearableCustomizationSetInt(variableName, intValue).
|
|
# This declaration will override the default value of the
|
|
# customization variable.
|
|
|
|
# =====================================================================
|
|
|
|
use strict;
|
|
|
|
use Crc;
|
|
use Cwd;
|
|
use File::Find;
|
|
use File::Spec;
|
|
use File::Temp;
|
|
use TreeFile;
|
|
|
|
# =====================================================================
|
|
|
|
my $debug = 0;
|
|
my $debugLinesPerOutputTick = 100;
|
|
my $examineProcessedData = 0;
|
|
|
|
my $assetLinkLineCount = 0;
|
|
my $basicRangedIntVariableLineCount = 0;
|
|
my $paletteColorVariableLineCount = 0;
|
|
|
|
my @directoriesToScan;
|
|
my $rawInputFileName;
|
|
my $treeFileLookupFileName;
|
|
|
|
my %assetIdByNameMap;
|
|
my %assetNameByCrcMap;
|
|
my %defaultIdByValueMap;
|
|
my %intRangeByIntRangeIdMap;
|
|
my %rangeIdByKeyMap;
|
|
my %rangeTypeByIdMap;
|
|
my %usedAssetIdByUserMap;
|
|
my %variableIdByNameMap;
|
|
my %variableUsageIdByAssetIdMap;
|
|
my %variableUsageIdByKeyMap;
|
|
|
|
my $maxAssignedAssetId = 0;
|
|
my $maxAssignedDefaultId = 0;
|
|
my $maxAssignedIntRangeId = 0;
|
|
my $maxAssignedPaletteId = 0;
|
|
my $maxAssignedRangeId = 0;
|
|
my $maxAssignedVariableId = 0;
|
|
my $maxAssignedVariableUsageId = 0;
|
|
|
|
# Data used specifically for CDF fixup process.
|
|
my $cdfDecreasedByteCount = 0;
|
|
my $cdfTotalByteCount = 0;
|
|
my $checkedCdfCount = 0;
|
|
my $fixedCdfCount = 0;
|
|
|
|
my $ignoreMissingPalettes = 0;
|
|
my $p4EditRetryCount = 10;
|
|
|
|
my %assetNameByIdMap;
|
|
my %defaultValueByIdMap;
|
|
my %paletteEntryCountByName;
|
|
my %rangeKeyByIdMap;
|
|
my %variableNameByIdMap;
|
|
my %variableUsageKeyByIdMap;
|
|
|
|
my $currentCdfFileName;
|
|
|
|
# =====================================================================
|
|
|
|
sub printUsage
|
|
{
|
|
print "Usage: \n";
|
|
print " perl fixupClientBakedWearableData.pl [-h]\n";
|
|
print " perl fixupClientBakedWearableData.pl [-d] -i <rawInfoFile.dat> \n";
|
|
print " [-e] -t <treefile-xlat-file.dat> directory [directory ...]\n";
|
|
print "\n";
|
|
print "Options:\n";
|
|
print " -d: enable verbose debugging information\n";
|
|
print " -e: examine (dump) processed data on STDOUT\n";
|
|
print " -h: print this help\n";
|
|
print " -i: the raw data output file from collectAssetCustomizationData.pl\n";
|
|
print " -p: ignore missing palettes\n";
|
|
print " -t: the treefile lookup data file\n";
|
|
print "\n";
|
|
print " Directories given will be scanned recursively for client data files\n";
|
|
print " ending in the extension .mif. CDF source files will be p4 edited,\n";
|
|
print " cleaned up and compiled if any modifications are needed.\n";
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub processCommandLine
|
|
{
|
|
# Process command line options.
|
|
my $requestHelp = 0;
|
|
my $printHelp = 0;
|
|
|
|
for (; (@_ > 0) && ($_[0] =~ m/^-(.*)$/); shift)
|
|
{
|
|
if ($1 eq 'd')
|
|
{
|
|
$debug = 1;
|
|
}
|
|
elsif ($1 eq 'e')
|
|
{
|
|
$examineProcessedData = 1;
|
|
print "examineProcessedData=$examineProcessedData\n" if $debug;
|
|
}
|
|
elsif ($1 eq 'i')
|
|
{
|
|
shift;
|
|
$rawInputFileName = $_[0];
|
|
print "rawInputFileName=$rawInputFileName\n" if $debug;
|
|
}
|
|
elsif ($1 eq 'h')
|
|
{
|
|
$requestHelp = 1;
|
|
$printHelp = 1;
|
|
}
|
|
elsif ($1 eq 'p')
|
|
{
|
|
$ignoreMissingPalettes = 1;
|
|
print "ignoreMissingPalettes=1\n" if $debug;
|
|
}
|
|
elsif ($1 eq 't')
|
|
{
|
|
shift;
|
|
$treeFileLookupFileName = $_[0];
|
|
print "treeFileLookupFileName=$treeFileLookupFileName\n" if $debug;
|
|
}
|
|
}
|
|
|
|
# Take remainder as directories to scan.
|
|
foreach (@_)
|
|
{
|
|
# Record directory's absolute path.
|
|
push @directoriesToScan, Cwd::abs_path($_);
|
|
}
|
|
|
|
if (!$requestHelp)
|
|
{
|
|
#-- Validate required parameters.
|
|
|
|
# Make sure we have a raw input file specified.
|
|
if (!defined($rawInputFileName) || (length($rawInputFileName) < 1))
|
|
{
|
|
print "No raw input filename specified, specify with -i switch.\n";
|
|
$printHelp = 1;
|
|
}
|
|
|
|
if (!defined($treeFileLookupFileName) || (length($treeFileLookupFileName) < 1))
|
|
{
|
|
print "No tree file lookup filename specified, specify with -t switch.\n";
|
|
$printHelp = 1;
|
|
}
|
|
|
|
|
|
# Make sure we have at least one directory.
|
|
if (@directoriesToScan < 1)
|
|
{
|
|
print "No directories specified for scanning, printing help.\n";
|
|
$printHelp = 1;
|
|
}
|
|
}
|
|
|
|
if ($printHelp)
|
|
{
|
|
printUsage();
|
|
exit -1;
|
|
}
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getNewAssetId
|
|
{
|
|
# For now assign next higher unused number. Once we figure out how
|
|
# many bits we really want to use, I'll want to come back and look
|
|
# for holes in id space and fill those up. Maybe find holes at
|
|
# startup and add to an 'asset id holes' list that we pull from.
|
|
my $newAssetId = $maxAssignedAssetId + 1;
|
|
++$maxAssignedAssetId;
|
|
|
|
return $newAssetId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getNewVariableId
|
|
{
|
|
my $newVariableId = $maxAssignedVariableId + 1;
|
|
++$maxAssignedVariableId;
|
|
|
|
return $newVariableId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getNewVariableUsageId
|
|
{
|
|
my $newVariableUsageId = $maxAssignedVariableUsageId + 1;
|
|
++$maxAssignedVariableUsageId;
|
|
|
|
return $newVariableUsageId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getNewDefaultId
|
|
{
|
|
my $newDefaultId = $maxAssignedDefaultId + 1;
|
|
++$maxAssignedDefaultId;
|
|
|
|
return $newDefaultId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getNewRangeId
|
|
{
|
|
my $newRangeId = $maxAssignedRangeId + 1;
|
|
++$maxAssignedRangeId;
|
|
|
|
return $newRangeId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getAssetId
|
|
{
|
|
# Process args.
|
|
my $assetName = shift;
|
|
die "Bad asset name arg" if !defined($assetName);
|
|
|
|
# Check if an asset id already has been assigned to this name.
|
|
my $assetId = $assetIdByNameMap{$assetName};
|
|
if (!defined($assetId))
|
|
{
|
|
# Check for a Crc dupe. We'll have a table mapping crc to internal asset it.
|
|
my $crc = Crc::calculate($assetName);
|
|
my $clashingAssetName = $assetNameByCrcMap{$crc};
|
|
die "asset crc clash: same crc=$crc for asset name $assetName and $clashingAssetName" if defined($clashingAssetName);
|
|
|
|
# Add crc entry.
|
|
$assetNameByCrcMap{$crc} = $assetName;
|
|
|
|
# Assign a new id.
|
|
$assetId = getNewAssetId();
|
|
$assetIdByNameMap{$assetName} = $assetId;
|
|
}
|
|
|
|
return $assetId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getVariableId
|
|
{
|
|
# Process args.
|
|
my $variableName = shift;
|
|
die "Bad variable name arg" if !defined($variableName);
|
|
|
|
# Check if a variable id already has been assigned to this name.
|
|
my $variableId = $variableIdByNameMap{$variableName};
|
|
if (!defined($variableId))
|
|
{
|
|
# Assign a new id.
|
|
$variableId = getNewVariableId();
|
|
$variableIdByNameMap{$variableName} = $variableId;
|
|
}
|
|
|
|
return $variableId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getDefaultId
|
|
{
|
|
# Process args.
|
|
my $defaultValue = shift;
|
|
die "Bad default value arg" if !defined($defaultValue);
|
|
|
|
# Check if a default id already has been assigned to this name.
|
|
my $defaultId = $defaultIdByValueMap{$defaultValue};
|
|
if (!defined($defaultId))
|
|
{
|
|
# Assign a new id.
|
|
$defaultId = getNewDefaultId();
|
|
$defaultIdByValueMap{$defaultValue} = $defaultId;
|
|
}
|
|
|
|
return $defaultId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getBasicRangedIntRangeId
|
|
{
|
|
die "Bad number of args" if (@_ != 2);
|
|
my $rangeKey = join(':', @_);
|
|
|
|
# Both types of ranges operate off of the same rangeIdByKeyMap.
|
|
my $rangeId = $rangeIdByKeyMap{$rangeKey};
|
|
if (!defined($rangeId))
|
|
{
|
|
# Assign a new id.
|
|
$rangeId = getNewRangeId();
|
|
$rangeIdByKeyMap{$rangeKey} = $rangeId;
|
|
}
|
|
|
|
return $rangeId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getPaletteRangeId
|
|
{
|
|
die "Bad number of args" if (@_ != 1);
|
|
my $rangeKey = shift;
|
|
|
|
# Both types of ranges operate off of the same rangeIdByKeyMap.
|
|
my $rangeId = $rangeIdByKeyMap{$rangeKey};
|
|
if (!defined($rangeId))
|
|
{
|
|
# Assign a new id.
|
|
$rangeId = getNewRangeId();
|
|
$rangeIdByKeyMap{$rangeKey} = $rangeId;
|
|
}
|
|
|
|
return $rangeId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub getVariableUsageId
|
|
{
|
|
die "Bad number of args" if (@_ != 3);
|
|
my $key = join(':', @_);
|
|
|
|
my $variableUsageId = $variableUsageIdByKeyMap{$key};
|
|
if (!defined($variableUsageId))
|
|
{
|
|
# Assign a new id.
|
|
$variableUsageId = getNewVariableUsageId();
|
|
$variableUsageIdByKeyMap{$key} = $variableUsageId;
|
|
}
|
|
|
|
return $variableUsageId;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub processAssetLink
|
|
{
|
|
# Validate arg count.
|
|
die("Wrong argument count: ", join(':', @_)) if (@_ != 2);
|
|
|
|
# Convert asset names to asset ids.
|
|
my $userAssetId = getAssetId(shift);
|
|
my $usedAssetId = getAssetId(shift);
|
|
|
|
# Save asset usage info.
|
|
if (exists $usedAssetIdByUserMap{$userAssetId})
|
|
{
|
|
# Add to ':'-separated list of used asset ids.
|
|
$usedAssetIdByUserMap{$userAssetId} .= ':' . $usedAssetId;
|
|
}
|
|
else
|
|
{
|
|
# Initialize used asset id.
|
|
$usedAssetIdByUserMap{$userAssetId} = $usedAssetId;
|
|
}
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub processBasicRangedIntVariable
|
|
{
|
|
# Validate arg count.
|
|
die("Wrong argument count: ", join(':', @_)) if (@_ != 5);
|
|
|
|
# Get args.
|
|
my $assetId = getAssetId(shift);
|
|
my $variableId = getVariableId(shift);
|
|
my $minValueInclusive = shift;
|
|
my $maxValueExclusive = shift;
|
|
my $defaultId = getDefaultId(shift);
|
|
|
|
my $rangeId = getBasicRangedIntRangeId($minValueInclusive, $maxValueExclusive);
|
|
|
|
# Add variableUsageId to the usage map for the asset.
|
|
my $variableUsageId = getVariableUsageId($variableId, $rangeId, $defaultId);
|
|
if (exists $variableUsageIdByAssetIdMap{$assetId})
|
|
{
|
|
# Append variable usage id to the map.
|
|
$variableUsageIdByAssetIdMap{$assetId} .= ':' . $variableUsageId;
|
|
}
|
|
else
|
|
{
|
|
# Add new entry.
|
|
$variableUsageIdByAssetIdMap{$assetId} = $variableUsageId;
|
|
}
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub processPaletteColorVariable
|
|
{
|
|
# Validate arg count.
|
|
die("Wrong argument count: ", join(':', @_)) if (@_ != 4);
|
|
|
|
# Get args.
|
|
my $assetId = getAssetId(shift);
|
|
my $variableId = getVariableId(shift);
|
|
my $rangeId = getPaletteRangeId(shift);
|
|
my $defaultId = getDefaultId(shift);
|
|
|
|
# Add variableUsageId to the usage map for the asset.
|
|
my $variableUsageId = getVariableUsageId($variableId, $rangeId, $defaultId);
|
|
if (exists $variableUsageIdByAssetIdMap{$assetId})
|
|
{
|
|
# Append variable usage id to the map.
|
|
$variableUsageIdByAssetIdMap{$assetId} .= ':' . $variableUsageId;
|
|
}
|
|
else
|
|
{
|
|
# Add new entry.
|
|
$variableUsageIdByAssetIdMap{$assetId} = $variableUsageId;
|
|
}
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub processRawInputData
|
|
{
|
|
die "No raw input file specified, specify with -i switch" if !defined($rawInputFileName) || (length($rawInputFileName) < 1);
|
|
|
|
print "Processing raw input file [$rawInputFileName].\n";
|
|
|
|
my $skippedLineCount = 0;
|
|
my $debugTickLineCount = 0;
|
|
|
|
my $inputFile;
|
|
open($inputFile, "< " . $rawInputFileName) or die "Failed to open raw input file for reading: $!";
|
|
|
|
while (<$inputFile>)
|
|
{
|
|
my $originalLine = $_;
|
|
|
|
chomp();
|
|
if (s/^L\s+//)
|
|
{
|
|
# Process asset linkage information. Args are the user (main) asset and the used (subordinate,dependency) asset.
|
|
processAssetLink(split /:/);
|
|
++$assetLinkLineCount;
|
|
|
|
}
|
|
elsif (s/^I\s+//)
|
|
{
|
|
# Process a use case of a basic ranged int variable.
|
|
processBasicRangedIntVariable(split /:/);
|
|
++$basicRangedIntVariableLineCount;
|
|
}
|
|
elsif (s/^P\s+//)
|
|
{
|
|
# Process a use case of a palette color variable.
|
|
processPaletteColorVariable(split /:/);
|
|
++$paletteColorVariableLineCount;
|
|
}
|
|
else
|
|
{
|
|
++$skippedLineCount;
|
|
}
|
|
|
|
++$debugTickLineCount;
|
|
if ($debug && ($debugTickLineCount >= $debugLinesPerOutputTick))
|
|
{
|
|
print STDERR ". ";
|
|
$debugTickLineCount = 0;
|
|
}
|
|
}
|
|
|
|
close($inputFile) or die "Failed to close raw input file: $!";
|
|
|
|
# Print statistics.
|
|
if ($debug)
|
|
{
|
|
print "\n";
|
|
print "Input file processing statistics:\n";
|
|
print "\tasset links: $assetLinkLineCount\n";
|
|
print "\tbasic ranged int variables: $basicRangedIntVariableLineCount\n";
|
|
print "\tpalette color variables: $paletteColorVariableLineCount\n";
|
|
print "\tskipped lines: $skippedLineCount\n";
|
|
}
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub examineProcessedData
|
|
{
|
|
print "max assigned variable counts:\n";
|
|
print "maxAssignedAssetId=$maxAssignedAssetId\n";
|
|
print "maxAssignedDefaultId=$maxAssignedDefaultId\n";
|
|
print "maxAssignedRangeId=$maxAssignedRangeId\n";
|
|
print "maxAssignedVariableId=$maxAssignedVariableId\n";
|
|
print "maxAssignedVariableUsageId=$maxAssignedVariableUsageId\n";
|
|
print "\n";
|
|
|
|
print "assetIdByNameMap:\n";
|
|
foreach my $key (sort keys %assetIdByNameMap)
|
|
{
|
|
print "\t$key=[$assetIdByNameMap{$key}]\n";
|
|
}
|
|
print "\n";
|
|
|
|
print "assetNameByCrcMap:\n";
|
|
foreach my $key (sort compare_uint32 keys %assetNameByCrcMap)
|
|
{
|
|
printf "\t%u=[$assetNameByCrcMap{$key}]\n", $key;
|
|
}
|
|
print "\n";
|
|
|
|
print "defaultIdByValueMap:\n";
|
|
foreach my $key (sort compare_uint32 keys %defaultIdByValueMap)
|
|
{
|
|
print "\t$key=[$defaultIdByValueMap{$key}]\n";
|
|
}
|
|
print "\n";
|
|
|
|
print "rangeIdByKeyMap:\n";
|
|
foreach my $key (sort keys %rangeIdByKeyMap)
|
|
{
|
|
print "\t$key=[$rangeIdByKeyMap{$key}]\n";
|
|
}
|
|
print "\n";
|
|
|
|
print "usedAssetIdByUserMap:\n";
|
|
foreach my $key (sort compare_uint32 keys %usedAssetIdByUserMap)
|
|
{
|
|
print "\t$key=[$usedAssetIdByUserMap{$key}]\n";
|
|
}
|
|
print "\n";
|
|
|
|
print "variableIdByNameMap:\n";
|
|
foreach my $key (sort keys %variableIdByNameMap)
|
|
{
|
|
print "\t$key=[$variableIdByNameMap{$key}]\n";
|
|
}
|
|
print "\n";
|
|
|
|
print "variableUsageIdByAssetIdMap:\n";
|
|
foreach my $key (sort compare_uint32 keys %variableUsageIdByAssetIdMap)
|
|
{
|
|
print "\t$key=[$variableUsageIdByAssetIdMap{$key}]\n";
|
|
}
|
|
print "\n";
|
|
|
|
print "variableUsageIdByKeyMap:\n";
|
|
foreach my $key (sort keys %variableUsageIdByKeyMap)
|
|
{
|
|
print "\t$key=[$variableUsageIdByKeyMap{$key}]\n";
|
|
}
|
|
print "\n";
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub findFirstVariableUsage
|
|
{
|
|
my $assetId = shift;
|
|
my $variableId = shift;
|
|
|
|
print "checking asset [$assetNameByIdMap{$assetId}] for variable [$variableNameByIdMap{$variableId}]\n" if $debug;
|
|
|
|
# Check specified asset id for usage of specified variable.
|
|
my $variableUsageIdsString = $variableUsageIdByAssetIdMap{$assetId};
|
|
if (defined $variableUsageIdsString)
|
|
{
|
|
my @variableUsageIdArray = split /:/, $variableUsageIdsString;
|
|
foreach my $variableUsageId (@variableUsageIdArray)
|
|
{
|
|
my $variableUsageKey = $variableUsageKeyByIdMap{$variableUsageId};
|
|
my @variableUsageData = split /:/, $variableUsageKey;
|
|
die "Bad variable usage data format, expecting 3 parts" if (@variableUsageData != 3);
|
|
|
|
if ($variableUsageData[0] == $variableId)
|
|
{
|
|
print "found [$variableNameByIdMap{$variableId}] on [$assetNameByIdMap{$assetId}]\n" if $debug;
|
|
return \@variableUsageData;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Check linked assets of specified variable
|
|
my $linkedAssetIdsString = $usedAssetIdByUserMap{$assetId};
|
|
return undef if !defined($linkedAssetIdsString);
|
|
|
|
my @linkedAssetIdArray = split /:/, $linkedAssetIdsString;
|
|
foreach my $linkedAssetId (@linkedAssetIdArray)
|
|
{
|
|
my $result = findFirstVariableUsage($linkedAssetId, $variableId);
|
|
return $result if defined($result);
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub clamp
|
|
{
|
|
my $min = shift;
|
|
my $value = shift;
|
|
my $max = shift;
|
|
|
|
$value = $max if ($value > $max);
|
|
$value = $min if ($value < $min);
|
|
|
|
return $value;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub getPaletteVariableInfo
|
|
{
|
|
# Get args.
|
|
my $meshAssetIdArrayRef = shift;
|
|
my $variableName = shift;
|
|
my $palettePathName = shift; # this optionally can be undef() in which case palette name match validation doesn't occur.
|
|
my $defaultIndex = shift;
|
|
|
|
# Variables for return state.
|
|
my $definesVariable = 0;
|
|
my $samePalette = 0;
|
|
my $sameDefault = 0;
|
|
my $defaultWithinRange = 0;
|
|
my $clampedDefault = 0;
|
|
|
|
# Lookup variable id for variable name.
|
|
my $variableId = $variableIdByNameMap{$variableName};
|
|
if (defined($variableId))
|
|
{
|
|
# Find the first asset in the list that defines the variable.
|
|
for (my $i = 0; ($i < @$meshAssetIdArrayRef) && !$definesVariable; ++$i)
|
|
{
|
|
# Check if this asset id defines the variable.
|
|
my $assetId = $$meshAssetIdArrayRef[$i];
|
|
my $variableUsageArrayRef = findFirstVariableUsage($assetId, $variableId);
|
|
$definesVariable = 1 if defined($variableUsageArrayRef);
|
|
|
|
if ($definesVariable)
|
|
{
|
|
# Get range info.
|
|
my $rangeId = $$variableUsageArrayRef[1];
|
|
my $rangeKey = $rangeKeyByIdMap{$rangeId};
|
|
|
|
# Check if range is a palette.
|
|
if ($rangeKey =~ m/:/)
|
|
{
|
|
# This isn't a palcolor variable: it probably is a basic ranged int variable.
|
|
$definesVariable = 0;
|
|
}
|
|
else
|
|
{
|
|
# The range indicates this variable is a palette color variable.
|
|
# Palette range keys are the palette pathname.
|
|
my $matchPaletteVariable;
|
|
|
|
if (!defined($palettePathName))
|
|
{
|
|
# Unknown if the caller-asserted palette name and the real palette name match.
|
|
$samePalette = '?';
|
|
|
|
# Use this palette color variable since the type is right and the variable name matches.
|
|
$matchPaletteVariable = 1;
|
|
print "CBW uses <unspecified palette>, variable uses [$rangeKey]\n" if $debug;
|
|
}
|
|
else
|
|
{
|
|
# Caller did assert the palette path name. Check if they match.
|
|
$samePalette = ($rangeKey eq $palettePathName) ? 1 : 0;
|
|
$matchPaletteVariable = $samePalette;
|
|
print "CBW uses palette [$palettePathName], variable uses [$rangeKey]\n" if $debug;
|
|
}
|
|
|
|
if ($matchPaletteVariable)
|
|
{
|
|
# Check the default info.
|
|
my $defaultId = $$variableUsageArrayRef[2];
|
|
$sameDefault = 1 if ($defaultValueByIdMap{$defaultId} == $defaultIndex);
|
|
|
|
# Check if default is within range.
|
|
my $paletteEntryCount = $paletteEntryCountByName{$rangeKey};
|
|
if (!defined($paletteEntryCount))
|
|
{
|
|
emitCdfWarning("art data error: variable [$variableName] references an invalid palette [$rangeKey], can't validate palette range.");
|
|
$defaultWithinRange = 0;
|
|
}
|
|
else
|
|
{
|
|
$defaultWithinRange = 1 if (defined($paletteEntryCount) && ($defaultIndex < $paletteEntryCount) && ($defaultIndex >= 0));
|
|
emitCdfWarning(sprintf("user specified new variable override for pal color [$variableName] but value $defaultIndex is outside the valid range of [0 .. %d]", $paletteEntryCount - 1)) if !$defaultWithinRange;
|
|
$clampedDefault = clamp(0, $defaultIndex, $paletteEntryCount - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ($definesVariable, $samePalette, $sameDefault, $defaultWithinRange, $clampedDefault);
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub getRangedIntVariableInfo
|
|
{
|
|
my $meshAssetIdArrayRef = shift;
|
|
my $variableName = shift;
|
|
my $minRangeInclusive = shift;
|
|
my $defaultValue = shift;
|
|
my $maxRangeExclusive = shift;
|
|
|
|
# Variables for return state.
|
|
my $definesVariable = 0;
|
|
my $sameRange = 0;
|
|
my $sameDefault = 0;
|
|
my $defaultWithinRange = 0;
|
|
my $clampedDefault = 0;
|
|
|
|
my $callerSpecifiedRange = defined($minRangeInclusive) && defined($maxRangeExclusive);
|
|
|
|
# Lookup variable id for variable name.
|
|
my $variableId = $variableIdByNameMap{$variableName};
|
|
if (defined($variableId))
|
|
{
|
|
# Find the first asset in the list that defines the variable.
|
|
for (my $i = 0; ($i < @$meshAssetIdArrayRef) && !$definesVariable; ++$i)
|
|
{
|
|
# Check if this asset id defines the variable.
|
|
my $assetId = $$meshAssetIdArrayRef[$i];
|
|
my $variableUsageArrayRef = findFirstVariableUsage($assetId, $variableId);
|
|
$definesVariable = 1 if defined($variableUsageArrayRef);
|
|
|
|
if ($definesVariable)
|
|
{
|
|
# Check the range info.
|
|
my $rangeId = $$variableUsageArrayRef[1];
|
|
my $rangeKey = $rangeKeyByIdMap{$rangeId};
|
|
if (!($rangeKey =~ m/:/))
|
|
{
|
|
# This is not a basic ranged int variable. It probably is a palcolor variable.
|
|
$definesVariable = 0;
|
|
}
|
|
else
|
|
{
|
|
my ($rangeMin, $rangeMax) = split /:/, $rangeKey;
|
|
|
|
if ($callerSpecifiedRange)
|
|
{
|
|
$sameRange = 1 if (($minRangeInclusive == $rangeMin) && ($maxRangeExclusive == $rangeMax));
|
|
}
|
|
else
|
|
{
|
|
$sameRange = '?';
|
|
}
|
|
|
|
# Check the default info.
|
|
my $defaultId = $$variableUsageArrayRef[2];
|
|
$sameDefault = 1 if ($defaultValueByIdMap{$defaultId} == $defaultValue);
|
|
|
|
# Check if default is within range.
|
|
$defaultWithinRange = 1 if (($defaultValue >= $rangeMin) && ($defaultValue < $rangeMax));
|
|
emitCdfWarning(sprintf("user specified new variable override for ranged int [$variableName] but value $defaultValue is outside the valid range of [$rangeMin .. %d]",$rangeMax - 1)) if !$defaultWithinRange;
|
|
|
|
$clampedDefault = clamp($rangeMin, $defaultValue, $rangeMax);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ($definesVariable, $sameRange, $sameDefault, $defaultWithinRange, $clampedDefault);
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub emitCdfWarning
|
|
{
|
|
my $warning = shift;
|
|
print STDERR "CDF WARNING($currentCdfFileName): $warning\n";
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub trimString
|
|
{
|
|
# Get args.
|
|
my $string = shift;
|
|
|
|
# Remove leading and trailing whitespace.
|
|
$string =~ s/^\s*//;
|
|
$string =~ s/\s*$//;
|
|
|
|
# Return to caller.
|
|
return $string;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub processWearableLines
|
|
{
|
|
my $lineArrayRef = shift;
|
|
my $emitWarnings = shift;
|
|
|
|
# Pull out mesh asset ids.
|
|
my @meshAssetIds = ();
|
|
foreach (@$lineArrayRef)
|
|
{
|
|
if ( m/UseMeshGenerator\s*\(\s*\"([^\"]+)\"\s*\)/ )
|
|
{
|
|
# Get asset id for the mesh generator.
|
|
my $meshName = $1;
|
|
my $assetId = $assetIdByNameMap{$meshName};
|
|
|
|
# If the mesh doesn't exist in the map, it may just mean that it provides no customizations. I can't warn here
|
|
# with the data I have. I could warn if I incorporated the tree file data.
|
|
if (defined($assetId))
|
|
{
|
|
push(@meshAssetIds, $assetId) if defined($assetId);
|
|
print "CBW uses customizable asset: assetId=[$assetId],name=[$meshName]\n" if $debug;
|
|
}
|
|
else
|
|
{
|
|
print "CBW uses non-customizable asset name=[$meshName]\n" if $debug;
|
|
}
|
|
}
|
|
}
|
|
|
|
my $modificationCount = 0;
|
|
for (my $i = 0; $i < @$lineArrayRef; )
|
|
{
|
|
my $keepLine = 1;
|
|
my $line = $$lineArrayRef[$i];
|
|
|
|
if ($line =~ m/^(\s*).*UsePaletteCustomization\s*\(([^\)]+)\)/)
|
|
{
|
|
# Any way we slice it, we're definitely modifying this line.
|
|
++$modificationCount;
|
|
|
|
# Handle old-style palette declaration.
|
|
my $leadingWhitespace = $1;
|
|
my @args = split /,/, $2; # "varname", palettePathName, paletteIndex
|
|
if (@args != 3)
|
|
{
|
|
# Trim the reported line.
|
|
my $reportedLine = trimString($line);
|
|
emitCdfWarning("removing invalid declaration due to wrong number of args, should be 3: [$reportedLine]") if $emitWarnings;
|
|
$keepLine = 0;
|
|
}
|
|
else
|
|
{
|
|
# Strip quotes from variable name.
|
|
$args[0] =~ s/[\"\s]//g;
|
|
$args[1] =~ s/[\"\s]//g;
|
|
|
|
my ($definesVariable, $samePalette, $sameDefault, $defaultWithinRange) = getPaletteVariableInfo(\@meshAssetIds, @args);
|
|
|
|
# Only emit a WearableCustomizationSetInt declaration if the variable is defined
|
|
# by one of the meshes, the variable makes use of the same palette, the default
|
|
# is within the valid range but the variable has a different default.
|
|
if ($definesVariable && $samePalette && $defaultWithinRange && !$sameDefault)
|
|
{
|
|
# Change line to WearableCustomizationSetInt directive.
|
|
$$lineArrayRef[$i] = $leadingWhitespace . "WearableCustomizationSetInt(\"$args[0]\",$args[2])";
|
|
print "keeping [$args[0]] due to ($definesVariable, $samePalette, $sameDefault, $defaultWithinRange)\n" if $debug;
|
|
}
|
|
else
|
|
{
|
|
# Remove the line.
|
|
$keepLine = 0;
|
|
print "stripping [$args[0]] due to ($definesVariable, $samePalette, $sameDefault, $defaultWithinRange)\n" if $debug;
|
|
}
|
|
}
|
|
}
|
|
elsif ($line =~ m/^(\s*).*UseRangedIntCustomization\s*\(([^\)]+)\)/)
|
|
{
|
|
# Any way we slice it, we're definitely modifying this line.
|
|
++$modificationCount;
|
|
|
|
# Handle old-style ranged-int declaration.
|
|
my $leadingWhitespace = $1;
|
|
my @args = split /,/, $2; # "varname", minInclusive, value, maxExclusive
|
|
if (@args != 4)
|
|
{
|
|
my $reportedLine = trimString($line);
|
|
emitCdfWarning("removing invalid line due to wrong number of args, should be 4: [$reportedLine]") if $emitWarnings;
|
|
$keepLine = 0;
|
|
}
|
|
else
|
|
{
|
|
# Strip quotes from variable name.
|
|
$args[0] =~ s/\"//g;
|
|
|
|
my ($definesVariable, $sameRange, $sameDefault, $defaultWithinRange) = getRangedIntVariableInfo(\@meshAssetIds, @args);
|
|
|
|
# Only emit a WearableCustomizationSetInt declaration if the variable is defined
|
|
# by one of the meshes, the variable makes use of the same range, the default
|
|
# is within the valid range but the variable has a different default.
|
|
if ($definesVariable && $sameRange && $defaultWithinRange && !$sameDefault)
|
|
{
|
|
# Change line to WearableCustomizationSetInt directive.
|
|
$$lineArrayRef[$i] = $leadingWhitespace . "WearableCustomizationSetInt(\"$args[0]\",$args[2])";
|
|
print "keeping [$args[0]] due to ($definesVariable, $sameRange, $sameDefault, $defaultWithinRange)\n" if $debug;
|
|
}
|
|
else
|
|
{
|
|
# Remove the line.
|
|
$keepLine = 0;
|
|
print "stripping [$args[0]] due to ($definesVariable, $sameRange, $sameDefault, $defaultWithinRange)\n" if $debug;
|
|
}
|
|
}
|
|
}
|
|
elsif ($line =~ m/WearableCustomizationSetInt\s*\(([^\)]*)\)/)
|
|
{
|
|
# Grab the args of the function call.
|
|
my @args = split /\s*,\s*/, $1;
|
|
|
|
# Validate arg count.
|
|
if (@args != 2)
|
|
{
|
|
my $reportedLine = trimString($line);
|
|
emitCdfWarning("WearableCusotmizationSetInt requires two args, bad line [$reportedLine]");
|
|
|
|
# Throw out the line.
|
|
$keepLine = 0;
|
|
++$modificationCount;
|
|
}
|
|
else
|
|
{
|
|
# Strip quotes from variable name.
|
|
$args[0] =~ s/\"//g;
|
|
|
|
# Check if variable is a palette color variable.
|
|
my ($definesVariable, $samePalette, $sameDefault, $defaultWithinRange, $clampedDefault) = getPaletteVariableInfo(\@meshAssetIds, $args[0], undef(), $args[1]);
|
|
if ($definesVariable)
|
|
{
|
|
if (!$defaultWithinRange)
|
|
{
|
|
# Warn about default.
|
|
my $reportedLine = trimString($line);
|
|
emitCdfWarning("index value $args[1] out of valid range, clamping to $clampedDefault");
|
|
|
|
# Replace the line with clamped value.
|
|
$$lineArrayRef[$i] = "\t\t\t\tWearableCustomizationSetInt(\"$args[0]\", $clampedDefault)";
|
|
++$modificationCount;
|
|
}
|
|
|
|
if ($sameDefault && $defaultWithinRange)
|
|
{
|
|
# No need to write this one, it's the same as the artist default.
|
|
++$modificationCount;
|
|
$keepLine = 0;
|
|
}
|
|
else
|
|
{
|
|
# Keep the line.
|
|
$keepLine = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# Check if variable is some other kind of ranged int variable.
|
|
my ($definesVariable2, $sameRange2, $sameDefault2, $defaultWithinRange2, $clampedValue2) = getRangedIntVariableInfo(\@meshAssetIds, $args[0], undef(), $args[1], undef());
|
|
if ($definesVariable2)
|
|
{
|
|
if (!$defaultWithinRange2)
|
|
{
|
|
# Warn about default.
|
|
my $reportedLine = trimString($line);
|
|
emitCdfWarning("index value $args[1] out of valid range, clamping to $clampedValue2");
|
|
|
|
# Replace the line with clamped value.
|
|
$$lineArrayRef[$i] = "\t\t\tWearableCustomizationSetInt(\"$args[0]\", $clampedValue2)";
|
|
++$modificationCount;
|
|
}
|
|
|
|
if ($sameDefault2 && $defaultWithinRange2)
|
|
{
|
|
# No need to write this one, it's the same as the artist default.
|
|
++$modificationCount;
|
|
$keepLine = 0;
|
|
}
|
|
else
|
|
{
|
|
# Keep the line.
|
|
$keepLine = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# This variable isn't even defined by any of the assets.
|
|
my $reportedLine = trimString($line);
|
|
emitCdfWarning("WearableCustomizationSetInt specified for variable not provided by asset, removing [$reportedLine]");
|
|
$keepLine = 0;
|
|
++$modificationCount;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
elsif (!($line =~ m/(Begin|End)Wearable/) && !($line =~ m/UseMeshGenerator/) && !($line =~ m/^\s+$/))
|
|
{
|
|
# @todo convert this to a warning once code is working.
|
|
print STDERR "Unsupported client-baked wearable line [$line], ignoring.\n";
|
|
}
|
|
|
|
# Determine what to do based on $keepLine status.
|
|
if ($keepLine)
|
|
{
|
|
# Move on to next line, keep this one.
|
|
++$i;
|
|
}
|
|
else
|
|
{
|
|
# Move on to next line, delete current line.
|
|
splice @$lineArrayRef, $i, 1;
|
|
}
|
|
}
|
|
|
|
return $modificationCount;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub updateCdfContents
|
|
{
|
|
# Get args.
|
|
my $inputFileName = shift;
|
|
my $outputFile = (@_ > 0) ? shift : undef;
|
|
|
|
# Determine if we're writing modified.
|
|
my $writeOutput = ref($outputFile);
|
|
|
|
# Open input file.
|
|
my $inputFile;
|
|
open($inputFile, '< ' . $inputFileName) or die "Failed to open [$inputFile] for reading: $!";
|
|
|
|
my $modificationCount = 0;
|
|
my $inWearable = 0;
|
|
my @wearableLines;
|
|
|
|
while (<$inputFile>)
|
|
{
|
|
chomp();
|
|
|
|
# Determine if we're in a wearable declaration.
|
|
if (!$inWearable)
|
|
{
|
|
$inWearable = m/BeginWearable/;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
|
|
# Process the line.
|
|
if (!$inWearable)
|
|
{
|
|
# We're not processing a wearable, just write the line.
|
|
print $outputFile "$_\n" if $writeOutput;
|
|
}
|
|
else
|
|
{
|
|
# Track the wearable line.
|
|
push @wearableLines, $_;
|
|
|
|
if (m/EndWearable/)
|
|
{
|
|
# Process the wearable lines data. Returns the fixed up
|
|
# set of lines in @wearableLines.
|
|
$modificationCount += processWearableLines(\@wearableLines, !$writeOutput);
|
|
|
|
# Write fixed up wearable block.
|
|
if ($writeOutput)
|
|
{
|
|
foreach my $line (@wearableLines)
|
|
{
|
|
print $outputFile $line, "\n";
|
|
}
|
|
}
|
|
|
|
# We're no longer in a wearable.
|
|
$inWearable = 0;
|
|
@wearableLines = ();
|
|
}
|
|
}
|
|
}
|
|
|
|
# Return the number of modifications that were/would be made.
|
|
return $modificationCount;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub getCdfFileName
|
|
{
|
|
my $iffFileName = shift;
|
|
$iffFileName =~ s!/dsrc/!/data/!;
|
|
$iffFileName =~ s!\.mif$!.cdf!;
|
|
|
|
return $iffFileName;
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub p4EditFile
|
|
{
|
|
my $fileName = shift;
|
|
my $attemptCount = 0;
|
|
|
|
# Do a p4 edit on the file.
|
|
do
|
|
{
|
|
++$attemptCount;
|
|
my $commandResult = `p4 edit $fileName`;
|
|
print "p4 edit $fileName: $commandResult\n" if $debug;
|
|
} while (($? != 0) && ($attemptCount < $p4EditRetryCount));
|
|
|
|
die "Failed to run p4 edit on $fileName, tried $attemptCount times: [$?]" if ($? != 0);
|
|
}
|
|
|
|
# ----------------------------------------------------------------------
|
|
|
|
sub runMiff
|
|
{
|
|
my $inputFileName = shift;
|
|
my $outputFileName = shift;
|
|
|
|
my $output = `miff -i $inputFileName -o $outputFileName 2>&1`;
|
|
die "failed to run miff -i $inputFileName -o $outputFileName: $output" if ($? != 0);
|
|
print "miff -i $inputFileName -o $outputFileName: $output\n" if $debug;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub fixCdf
|
|
{
|
|
# Get args.
|
|
my $inputFileName = shift;
|
|
|
|
# Open the MIF and CDF for editing.
|
|
my $cdfFileName = getCdfFileName($inputFileName);
|
|
my @oldCdfStats = stat $cdfFileName;
|
|
|
|
p4EditFile($inputFileName);
|
|
p4EditFile($cdfFileName);
|
|
|
|
# Create temp file for modification output. Temp file is created in
|
|
# same directory as the input file it will replace. This guarantees
|
|
# we will be able to rename the temp file when finished processing.
|
|
my ($inputFileVolume, $inputFileDir, $unused) = File::Spec->splitpath($inputFileName);
|
|
my $tempFileDir = File::Spec->catpath($inputFileVolume, $inputFileDir, "");
|
|
my ($outputFile, $outputFileName) = File::Temp::tempfile(DIR => $tempFileDir);
|
|
|
|
# Process the file contents, writing new version to $outputFile.
|
|
updateCdfContents($inputFileName, $outputFile);
|
|
|
|
# Close the temp output file.
|
|
close ($outputFile) or die "Failed to close newly-written CDF mif file [$outputFileName]: $!";
|
|
|
|
# Replace the CDF mif input file with the newly written version.
|
|
rename($outputFileName, $inputFileName) or die "Failed to replace [$inputFileName] with $[outputFileName]: $!";
|
|
|
|
# Mif the file.
|
|
runMiff($inputFileName, $cdfFileName);
|
|
|
|
# Collect stats.
|
|
my @newCdfStats = stat $cdfFileName;
|
|
|
|
# Track # bytes we shrank the files by and # bytes total for modified files.
|
|
if ((@oldCdfStats >= 7) && (@newCdfStats >= 7))
|
|
{
|
|
my $cdfDecreasedByteCount += ($oldCdfStats[7] - $newCdfStats[7]);
|
|
my $cdfTotalByteCount += $newCdfStats[7];
|
|
}
|
|
else
|
|
{
|
|
print STDERR "failed to process filesizes for [$cdfFileName], probably doesn't exist on client.\n";
|
|
}
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub doesCdfRequireFixing
|
|
{
|
|
# Just run the CDF update process in the mode that does not write output.
|
|
my $filename = shift;
|
|
my $modificationCount = updateCdfContents($filename);
|
|
|
|
# We need to update the cdf file if one or more modifications would
|
|
# be made.
|
|
return ($modificationCount > 0);
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub fixCdfFindFileHandler
|
|
{
|
|
# Ensure target is a normal file and is readable.
|
|
if (-f && -r && m/\.mif$/i)
|
|
{
|
|
# Keep track of the file we're processing.
|
|
$currentCdfFileName = $File::Find::name;
|
|
|
|
print "Processing file [$_]\n" if $debug;
|
|
++$checkedCdfCount;
|
|
|
|
if (doesCdfRequireFixing($File::Find::name))
|
|
{
|
|
fixCdf($File::Find::name);
|
|
++$fixedCdfCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub collectPaletteEntryCounts
|
|
{
|
|
my $missingPaletteCount = 0;
|
|
|
|
foreach my $paletteName (keys %rangeIdByKeyMap)
|
|
{
|
|
# Skip ranged int range data.
|
|
next if $paletteName =~ m/:/;
|
|
|
|
# Get the full pathname for the palette.
|
|
my $fullPathName = TreeFile::getFullPathName($paletteName);
|
|
if (!defined ($fullPathName))
|
|
{
|
|
print "Failed to find on-disk location of TreeFile-relative palette name [$paletteName]\n";
|
|
++$missingPaletteCount;
|
|
next;
|
|
}
|
|
|
|
# Open the file.
|
|
my $inputFile;
|
|
open($inputFile, '< ' . $fullPathName) or die "Failed to open palette file [$fullPathName] for reading: $!";
|
|
binmode($inputFile) or die "Failed to set file [$fullPathName] to binary mode: $!";
|
|
|
|
# Skip the first 22 bytes.
|
|
seek($inputFile, 22, 0) or die "Failed to seek to palette entry count position within [$fullPathName], bad palette file: $!";
|
|
|
|
# Collect the entry count (2 bytes starting 22 bytes in).
|
|
my $byteAsChar;
|
|
|
|
read($inputFile, $byteAsChar, 1) or die "Failed to read entry count byte from [$fullPathName]: $!";
|
|
my $entryCount = ord($byteAsChar);
|
|
|
|
read($inputFile, $byteAsChar, 1) or die "Failed to read entry count byte from [$fullPathName]: $!";
|
|
$entryCount += (ord($byteAsChar) << 8);
|
|
|
|
# Close the file.
|
|
close($inputFile) or die "Failed to close palette file [$fullPathName]: $!";
|
|
|
|
# Enter palette entry count into map.
|
|
$paletteEntryCountByName{$paletteName} = $entryCount;
|
|
printf("palette entries: %5d; name=[%s]\n", $entryCount, $paletteName) if $debug;
|
|
}
|
|
|
|
if ($missingPaletteCount > 0)
|
|
{
|
|
print "There are $missingPaletteCount missing palettes.\n";
|
|
die "Missing palettes must be added before processing can continue." if !$ignoreMissingPalettes;
|
|
}
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub fixDirectories
|
|
{
|
|
# Setup data needed by process.
|
|
%assetNameByIdMap = reverse %assetIdByNameMap;
|
|
%defaultValueByIdMap = reverse %defaultIdByValueMap;
|
|
%rangeKeyByIdMap = reverse %rangeIdByKeyMap;
|
|
%variableNameByIdMap = reverse %variableIdByNameMap;
|
|
%variableUsageKeyByIdMap = reverse %variableUsageIdByKeyMap;
|
|
|
|
# Call our find file handler on each file in the specified directories.
|
|
&File::Find::find(\&fixCdfFindFileHandler, @directoriesToScan);
|
|
|
|
# Print processing info.
|
|
print "Client Data File processing statistics:\n";
|
|
print "\tchecked file count: $checkedCdfCount\n";
|
|
print "\tfixed file count: $fixedCdfCount\n";
|
|
printf "\tmodified cdf size: %.2f KB\n", $cdfTotalByteCount / 1024;
|
|
printf "\tshrank cdfs by this: %.2f KB\n", $cdfDecreasedByteCount / 1024;
|
|
}
|
|
|
|
# ---------------------------------------------------------------------
|
|
|
|
sub initializeTreeFile
|
|
{
|
|
my $treeFile;
|
|
open($treeFile, '< ' . $treeFileLookupFileName) or die "Failed to open treefile xlat data [$treeFileLookupFileName]: $!";
|
|
TreeFile::loadFileLookupTable($treeFile);
|
|
close($treeFile) or die "Failed to close treefile xlat data [$treeFileLookupFileName]: $!";
|
|
}
|
|
|
|
# =====================================================================
|
|
# Main Program
|
|
# =====================================================================
|
|
|
|
# Handle the command line options.
|
|
processCommandLine(@ARGV);
|
|
|
|
# Initialize TreeFile.
|
|
initializeTreeFile();
|
|
|
|
# Process the raw input data.
|
|
processRawInputData();
|
|
|
|
# Collect palette entry count data.
|
|
collectPaletteEntryCounts();
|
|
|
|
# Write out the output data.
|
|
fixDirectories();
|
|
|
|
# Done, success.
|
|
exit 0;
|
|
|
|
# =====================================================================
|