[WIP] ArzBaller - the CLI for packing dbrs

I need to establish that templateName -> Class is a true 1:1 relationship, but each template has defaultValue field for the Class variable. But as far as I can tell, it can be an empty string “”…

Anyone know anything about this aspect? Maybe from TQ days?

I suspect if all your records have Class set to a valid Class, then arzBaller might work. Records (dbrs) that do not have this information, are currently unsupported.

Ill try it later, but I dont think this is it, the npc “mod” alone isnt working either and:

templateName,database/templates/monster.tpl,
ActorName,,
Class,Monster,
FileDescription,,
stunResistanceInc,0.0,
ambientSound,,
ambientPeriodMin,0.0,
ambientPeriodMax,0.0,

I tested 091 and it actually breaks the file when extracting… removing the template field :slight_smile: I assume it does the same when packing.

I can upload the test mod for you, but its really just a new map with that NPC placed, nothing else.

EDIT:
tried something else with the folders, it might just be a path thing - which is still annoying but copying records out of database into another folder worked.

EDIT2:
doing this for dga isnt working, GD gets stuck in the loading screen, Ill do some more testing later and see what file is causing it.

EDIT3:
the Caravan alone is working with 0.9

EDIT4:
copied over the dga NPCs and they show up… but I cant click on them :smiley:

Ok, this time I swear it will work ™

v0.9.2 Source:


Binary

on dga…at least, as for everything else, well, who knows.

I went back to the templates, and tried my best to handle inheritance to get the top level Class name for each templateName. So for dga, I am actually injecting the Class for each record that needs it, there are still some blank class fields, but they are like that in Crate’s arz/dbr files as well. (Thanks to Stormcaller for independent verification of that - this project is driving me insane)

Seriously, I would not have reposted it without a test, I felt a couple of hangs while loading and talking to NPCs, but it at least functions. File size is crazy big but one step at a time.

Imagine Smilies everywhere they should be please.

Current R script for template parsing:


setwd( "c:/users/jiaco/documents/templateWork" );
t.path = "templates";
t.suffix = "*.tpl";
lsd = list.files( t.path, t.suffix, recursive = TRUE );

file.path = sprintf( "%s/%s", t.path, lsd );
file.path = file.path[ grep( "[Cc]opy", file.path, invert=TRUE ) ];

known.empty = c( "templates/menu/menuwindow.tpl" );

file.path = file.path[ !( file.path %in% known.empty ) ];

parseTpl = function( path )
{
	not.used = c( "list", "system" );
	rv = list();
	lines = readLines( path );
	lines = gsub( "	", "", lines );
	lines = gsub( "\"", "", lines );
	toks = strsplit( lines, " = " );
	oi = 1;
	inVar = FALSE;
	t.name = "";
	t.class = "";
	t.type = "";
	t.default = "";
	for( i in 1:length(toks) ) {
		nTok = length( toks[[ i ]] );
		if( nTok == 1 ) {
			if( toks[[ i ]][ 1 ] == "Variable" ) {
				inVar = TRUE;
			} else if( toks[[ i ]][ 1 ] == "}" ) {
				if( t.name != "" ) {
					rv[[ oi ]] = c( t.name, t.class,
				 	 t.type, t.default );
					oi = oi + 1;
				}
				t.name = "";
				t.class = "";
				t.type = "";
				t.default = "";
			}
		} else if( nTok == 2 ) {
			t1 = toks[[i]][1];
			t2 = toks[[i]][2];
			if( t1 == "name" ) {
				t.name = t2;
			} else if( t1 == "class" ) {
				t.class = t2;
			} else if( t1 == "type" ) {
				t.type = t2;
			} else if( t1 == "defaultValue" ) {
				t.default = t2;
			}
		}
	}
	rv = do.call( rbind, rv );
	rv = cbind( path, rv );
	colnames( rv ) = c( "templateName",
	 "fieldName", "fieldClass", "fieldType", "defaultValue" );
	return( rv[ !( rv[,"fieldType"] %in% not.used ), ] );
}
names( file.path ) = file.path;
result = lapply( file.path, parseTpl );

## only 1 now with 1 line:
## templates/ingameui/simplerollover.tpl and it is a string variable
## that points to another dbr called defaultTextStyle
##


## a template can include a template that includes a template
## sounds like recursion

save_result = result;

fixInclude = function( path )
{
	rv = tolower( path );
	rv = gsub( "\\", "/", rv, fixed = TRUE );
	rv = gsub( "*database/", "", rv );
	rv = sub( ".*[%]", "", rv );
	return( rv );
}
hasInclude = function( tab )
{
	if( is.null( dim( tab ) ) || ( n = dim( tab )[1] ) == 1 ) {
		return( -1 );
	}
	for( i in 1:n ) {
		if( tab[ i, "fieldType" ] == "include" ) {
			return( i );
		}
	}
	return( -1 );
}
getClass = function( tab )
{
	if( is.null( dim( tab ) ) ) {
		rv = tab[5];
	} else {
		rv = tab[ tab[,2] == "Class", 5 ];
	}
	if( length( rv ) == 0 ) {
		rv = "";
	}
	return( rv );
}

result = save_result;
t2c = vector( mode = "character", length = length( result ) )
names( t2c ) = names( result );
for( tplname in names( result ) ) {
	#pc = getClass( result[[ tplname ]] );
	t2c[ tplname ] = getClass( result[[ tplname ]] );
	while( ( i = hasInclude( result[[ tplname ]] ) ) > 0 ) {
		incname = result[[ tplname ]][ i, "defaultValue" ];
		incname = fixInclude( incname );
		nres = result[[ tplname ]];
		nres = nres[ -i, ];
		inc = result[[ incname ]];
		if( nchar( t2c[ tplname ] ) == 0 ) {
			t2c[ tplname ] = getClass( result[[ incname ]] );
		}
		inc[,1] = tplname;
		result[[ tplname ]] = rbind( nres, inc );
	}
}

res = do.call( rbind, result );
res[,1] = sub( "[.]tpl$", "", sub( ".*[/]", "", res[,1] ) );

ores = res[, c(1,2,4) ];
ores = ores[ order( ores[,1], ores[,2], ores[,3] ), ];
## ugh, some commas in fieldType
sres = apply( ores, 1, paste, collapse=";" );
sres = unique( sres );

write.table( sres, "Templates.csv", quote=FALSE, row.names=FALSE,
col.names=FALSE );

t2ctab = cbind( names( t2c ), t2c );
t2ctab[,1] = sub( "[.]tpl$", "", sub( ".*[/]", "", t2ctab[,1] ) );
st2c = apply( t2ctab, 1, paste, collapse=";" );
write.table( st2c, "TemplateNameToClass.csv", quote=FALSE, row.names = FALSE);

#ores = unique( res );

##ugh, the full path here, but not in Qt so trim here
#write.csv( res, "Templates.csv", quote=FALSE, row.names=FALSE );


Yeah I was just verifying if all dbr’s contained the same class for the same template, running from the output of arzballer(not parsing templates)
so yes, in the end if a dbr has the template x, it will be always have the class y
here is a json file that matches template paths to classes, and outputs the file lists if the template had no class specified.
https://paste.ee/p/vv9Xb

sadly this probably wasn’t really useful because I confirmed it only after you did, but in either case if anyone needs to parse dbrs for whatever purpose heres a php script

<?php
/*.
require_module 'standard';
require_module 'json';
.*/

// assuming there is a records/ folder in the same dir as this script

/**
 * @param string $path
 * @param string $ext
 * @return string[]
 */
function getFilesRecursive($path, $ext = '.dbr') {
    /*.string[].*/$files = [];
    $Directory           = new RecursiveDirectoryIterator($path);
    $Iterator            = new RecursiveIteratorIterator($Directory);
    $Regex               = new RegexIterator($Iterator, '/^.+\\' . $ext . '$/i', RecursiveRegexIterator::GET_MATCH);

    foreach ($Regex as $file) {
        $files[] = $file[0];
    }

    return $files;
}


$dbrFiles = getFilesRecursive(__DIR__ . '/records/');

/*array[mixed]*/$templates = [];

foreach ($dbrFiles as $dbrFile) {
    $dbrContents = file_get_contents($dbrFile);
    $dbrContents = (string) str_replace("
", '', $dbrContents);
    $dbrContents = (string) str_replace("
", '', $dbrContents);

    $dbrArr = explode(',', $dbrContents);

    array_pop($dbrArr); // since .dbr files end with ',', the last element will be just ''(nothing)

    $dbrAssoc = [];

    for ($i = -1, $len = count($dbrArr); $i < $len;) {
        $dbrAssoc[$dbrArr[++$i]] = $dbrArr[++$i];
    }
    // $dbrAssoc is an assocative array of dbr values now, e.g.
    // array =>
    // ["templateName"]=>
    //  string(50) "database/templates/controllerstationarymonster.tpl"
    // ["AllyAttackedAnger"]=>
    //  string(8) "8.000000"
    // ...

    if (isset($dbrAssoc['Class'])) {
        // skip duplicate classes
        if (isset($templates[$dbrAssoc['templateName']]) && in_array($dbrAssoc['Class'], $templates[$dbrAssoc['templateName']])) {
            continue;
        }
        $templates[(string) $dbrAssoc['templateName']][] = $dbrAssoc['Class'];
    } else {
        $templates[(string) $dbrAssoc['templateName']][] = 'file:' . $dbrFile;

    }
}
unset($dbrFile);

file_put_contents('out', json_encode($templates, JSON_PRETTY_PRINT));


I tried it again and still the same issues I had before. The entire mod in mod/database/records doesnt work and moving it into a new folder (newmod/records/) crashes GD.
splitting it up with just stasher and my npcs works except I cant interact with my NPCs and I think they dont even move :smiley:

Anyways, I have to get back to my mod and other projects, Ill test it when there is a new version, but I wont test every possibility and check files etc.

Thanks WareBare

Not sure what is going on, but my vacations are over and this project is well on the back burner now as I have moved on to a bigger project and for this, we are just using AssetManager to build for now. When this new project gets released, I will start working on this again to automate the last step, but for now, I prefer to use the dev’s tools as there are enough bugs to hunt in the mod that I do not need to combine that with bugs introduced by arzBaller.

Anyway, this project remains open source. If somebody jumps on board to help debug/code, I might regain interest.

Here is the template changes for the new crucible. I am still on the v0.4, btw. Please take a look when you return to the project.

MISSING FIELD TYPE INFORMATION FOR marketNumScrollDuplicates from template market records/creatures/npcs/merchants/merchanttbl_s01.dbr
INPUT 41 has marketNumScrollDuplicates,3,
MISSING FIELD TYPE INFORMATION FOR marketNumScrollDuplicates from template market records/creatures/npcs/merchants/merchanttbl_s02.dbr
INPUT 43 has marketNumScrollDuplicates,3,
MISSING FIELD TYPE INFORMATION FOR marketNumScrollDuplicates from template market records/creatures/npcs/merchants/merchanttbl_s03.dbr
INPUT 43 has marketNumScrollDuplicates,3,
MISSING FIELD TYPE INFORMATION FOR defensiveReflect from template gameadjustment records/game/balancingadjustment_survivalmode_enemies01.dbr
INPUT 115 has defensiveReflect,-70.000000,
MISSING FIELD TYPE INFORMATION FOR defensiveReflect from template gameadjustment records/game/balancingadjustment_survivalmode_enemies02.dbr
INPUT 115 has defensiveReflect,-70.000000,
MISSING FIELD TYPE INFORMATION FOR defensiveReflect from template gameadjustment records/game/balancingadjustment_survivalmode_enemies03.dbr
INPUT 115 has defensiveReflect,-70.000000,
MISSING FIELD TYPE INFORMATION FOR bonusLifePercent from template oneshot_food records/items/misc/potions/potion_constitutionc01.dbr
INPUT 13 has bonusLifePercent,10.000000,
MISSING FIELD TYPE INFORMATION FOR defensiveBleedingDuration from template petbonus records/skills/powerups/blessingulo_petbonus.dbr

Thanks. I will update the template system then soon as I will need it for other things as well.

Here is v0.9.3 compatible with the latest version (at least I just unpacked and repacked crucible, so should work for what Stormcaller needs)

Source

Binary

Ty <3
I will report back if I come across any issues