Post reply

Warning: this topic has not been posted in for at least 120 days.
Unless you're sure you want to reply, please consider starting a new topic.
Name:
Email:
Subject:
Message icon:

Verification:
Type the letters shown in the picture
Listen to the letters / Request another image

Type the letters shown in the picture:
What color is grass?:
What is the seventh word in this sentence?:
What is five minus two (use the full word)?:

shortcuts: hit alt+s to submit/post or alt+p to preview


Topic Summary

Posted by: devSin
« on: May 24, 2005, 01:04:52 AM »

Quote
If this academia thing doesn't work out I would appear to have a promising career in remote debugging.
Omniscient QA Technician does sound quite nice. :-) I'll always be hoping for professor, though (you can give out WeiDU assignments for extra credit :-D).

Quote
I wouldn't have bothered to convert to it, but once you've converted I wouldn't bother to convert back (except for the first line in a block until I post the update, I guess). Minor syntax changes don't really make parsing/lexing any faster. They just make writing new code faster.
It was a simple grep find/replace that took all of 10 seconds, and I prefer consistency over convenience (if the .= operators had been in WeiDU since day one, I'd have been using them; since they're here now, I'll be using them, so might as well use them everywhere). I was actually editing the wrong copy of the TP2 (the installation TP2 in the BG2 directory), so I did still have the old x=x+y and didn't have to change everything back (or add SET STRING PLUS_EQUALS blah blah to the source).

The new timings with the STRING_SET block and separate TRB:
Code: [Select]
WeiDU Timings
MKDIR                            0.000
PATCH_PRINT                      0.000
AT_*                             0.000
load TLK                         0.000
process copy_trans               0.000
APPEND_COL                       0.000
postprocess .D actions           0.000
parsing .log files               0.000
preprocess APPEND_EARLY          0.000
ADD_PROJECTILE                   0.017
process .D files                 0.017
<<<<<<<<                         0.033
unmarshal compressed BIFF        0.033
process .D actions               0.033
resolve labels                   0.050
resolve strings                  0.083
preprocess .D actions            0.100
unmarshal BIFF                   0.100
parsing .ids files               0.133
APPEND                           0.217
parsing .trb files               0.250
push_copy_trans                  0.267
BUT_ONLY                         0.267
unmarshal KEY                    0.550
find local string                0.667
marshal and save TLK             0.750
marshal DLG                      0.933
unmarshal TLK                    1.200
unmarshal DLG                    1.250
parsing .d files                 1.600
READ_*                           2.067
eval_pe                          3.850
STRING_SET                       4.467
COPY                             5.333
parsing .baf files               6.317
loading files                    8.233
process_patch2                   8.650
COMPILE                         16.967
saving files                    22.283
parsing .tp2 files              25.617
TOTAL                          112.333
Very substantial. Once the initial TP2 parse is out of the way, it's now smooth sailing all the way through. Thanks for your attention to this today, it's very much appreciated (under 2 minute install times!) Down from 625.733 in v178 to 243.600 in v179 to 183.317 in v180+, and finally to 112.333 (shaving off an additional 70/80 seconds in a day is not bad at all).

Quote
push_copy_trans                  0.267
COMPILE                         16.967
These numbers gravitate upward when the script strings are moved to a separate file and COMPILE ~list~ USING ~tra~. The current values I have are 0.333 / 17.550, which is a little much for normal variation (although still possible, these are pretty much the only times on a "clean" run that differ from the original install). I imagine I'm grabbing the overhead of loading the new scripts TRB for the COMPILE commands for all of 19 strings (this would probably be especially true if the TRB is loaded for each file in a multi-file COMPILE action), or something (hopefully not having WeiDU snatch out the @s in the scripts). I think I'll convert the runtime messages to just generic string constants (cutting the TRB out for all the PRINTs), which should reduce the number of strings by ~80, and just let the COMPILE actions use the global TRB.
Posted by: weimer
« on: May 24, 2005, 12:04:09 AM »

Quote
Once I convert all my "+="-type operators back to the old "x = x + y"-type statements,

I wouldn't have bothered to convert to it, but once you've converted I wouldn't bother to convert back (except for the first line in a block until I post the update, I guess). Minor syntax changes don't really make parsing/lexing any faster. They just make writing new code faster.

Quote
Would COMPILE ~~ USING reduces the push/copy even further (my current thinking is that WeiDU also loads the "global" TRA, even were I to be using USING, but maybe USING brings only the specified TRA "in-scope"?).

When you do COMPILE source USING loca.tra, this happens: we do a push_copy_trans on global.tra, making a copy of it. We load local.tra, and it gets the chance to override the definitions in global.tra and/or provide new definitions for translation strings. Then we compile the source file. Then we throw away (pop) the translation strings (which effectively throws away information in local.tra and leaves us with only the stuff in global.tra).

If you put your script strings in a tra file and do a COMPILE/USING with those and put your string-set strings in a separate tra file and do a STRING_SET/USING with those and have only a few things in your global tra file, your push_copy_trans time should approach 0.

Quote
Is there a way to further break apart the TRA to speed things up a little more?

Nothing springs to mind.

Quote
8 scripts that I compile and use REPLACE for the new strings,

COMPILE can take USING. Scripts (.d and .baf) can take @123 right in their text (e.g., DisplayStringHead(Myself,@345)). No need to use REPLACE in most cases.

Quote
46 strings used with REPLACE on 2DA files, and 149 used only for SAY actions in patching CREs, SPLs, etc.

Those would all have to be in the global scope, as it stands.
Posted by: devSin
« on: May 23, 2005, 11:51:39 PM »

Quote
Is is related to .TRA (or .TRB) files. Essentially, every time you do a COMPILE we make a copy of all of the translation strings "in scope" (just in case the copy gets changed by new local TRA files providing new definitions for translations or whatnot) and then restore from the copy at the end.
Ah. Push-copy trans(lations). I understand now.

Quote
Then huge.tra will be loaded once, all of the STRING_SETs will be processed in one swell foop, and you won't pay for your huge.tra whenever you do a COMPILE. If your current TRA file has some bit for STRING_SETs and some other bit, separate it manually so as to keep the "always in scope" portion as small as possible (COMPILE/USING may help here).
Without the default dialog.tlk strings, the TRA would go from 91K lines down to about 400 (it's very organized, so won't take more than a couple seconds to break into chunks). Would COMPILE ~~ USING reduces the push/copy even further (my current thinking is that WeiDU also loads the "global" TRA, even were I to be using USING, but maybe USING brings only the specified TRA "in-scope"?).

Is there a way to further break apart the TRA to speed things up a little more? I have about 50 ~+ this is what I'm doing now~ feedback messages that are only used for PRINT in the TP2 (which should technically be the only always "in-scope" strings), 8 scripts that I compile and use REPLACE for the new strings, 46 strings used with REPLACE on 2DA files, and 149 used only for SAY actions in patching CREs, SPLs, etc.

Quote
I hope your text editor has line-bounded (or column-bounded) search-and-replace or somesuch.
Won't be a problem.

Quote
Attaching dparser.mly and tp.ml -- if you throw those over your current versions STRING_SET will take a list as described above and you can try it out for yourself.
Thanks, I'll bash on it for a bit. Once I convert all my "+="-type operators back to the old "x = x + y"-type statements, that is -- one of these days, I'll let somebody else test the new features first. ;-)
Posted by: weimer
« on: May 23, 2005, 11:19:13 PM »

Quote
As you suspected, the push_copy_trans

If this academia thing doesn't work out I would appear to have a promising career in remote debugging.

Quote
If push_copy_trans is related to .D files

Is is related to .TRA (or .TRB) files. Essentially, every time you do a COMPILE we make a copy of all of the translation strings "in scope" (just in case the copy gets changed by new local TRA files providing new definitions for translations or whatnot) and then restore from the copy at the end.

For you, with your 8 megabytes of translation strings, even COMPILE-ing a blank file requires an 8 MB memcpy.

This is one of those "conceptual simplicity" things -- making a copy every time prevents me from having to spend time bookkeeping what has been changed and whatnot, so it makes development easier.

You mentioned earlier that 99% of your translation strings fed directly into STRING_SETs (I hate STRING_SET, but so it goes). As you note, the USING clause of STRING_SET is currently unusable. With the next version, you will want to change your mod from:

Code: [Select]
LANGUAGE ~huge.tra~

STRING_SET 1a 1b
STRING_SET 2a 2b
STRING_SET 3a 3b

Into:

Code: [Select]
// no LANGUAGE-loaded huge.tra

STRING_SET 1a 1b
                   2a 2b
                   3a 3b
USING ~huge.tra~

Then huge.tra will be loaded once, all of the STRING_SETs will be processed in one swell foop, and you won't pay for your huge.tra whenever you do a COMPILE. If your current TRA file has some bit for STRING_SETs and some other bit, separate it manually so as to keep the "always in scope" portion as small as possible (COMPILE/USING may help here). I hope your text editor has line-bounded (or column-bounded) search-and-replace or somesuch.

Assuming that I am correctly remembering that you mostly have the TRA file for STRING_SETs, this should reduce the push_copy_trans time to 0-ish. If my clairvoyant powers do not extend to guessing your TP2 file, it won't be as helpful.

Attaching dparser.mly and tp.ml -- if you throw those over your current versions STRING_SET will take a list as described above and you can try it out for yourself.
Posted by: devSin
« on: May 23, 2005, 09:19:05 PM »

OK, here are the results from a "clean" run on a (more-or-less) "clean" installation:
Code: [Select]
WeiDU Timings
MKDIR                            0.000
PATCH_PRINT                      0.000
AT_*                             0.000
load TLK                         0.000
process copy_trans               0.000
APPEND_COL                       0.000
postprocess .D actions           0.000
parsing .log files               0.000
ADD_PROJECTILE                   0.000
preprocess APPEND_EARLY          0.000
process .D files                 0.000
strings to add                   0.017
unmarshal BIFF                   0.033
resolve labels                   0.033
process .D actions               0.050
<<<<<<                           0.050
unmarshal compressed BIFF        0.050
preprocess .D actions            0.067
resolve strings                  0.100
APPEND                           0.133
parsing .ids files               0.150
BUT_ONLY                         0.167
parsing .trb files               0.517
unmarshal KEY                    0.550
add strings to TLK               0.767
marshal and save TLK             0.800
marshal DLG                      0.917
unmarshal DLG                    0.983
find local string                1.067
unmarshal TLK                    1.217
parsing .d files                 1.567
READ_*                           1.950
STRING_SET                       4.017
eval_pe                          4.167
COPY                             4.250
parsing .baf files               6.067
process_patch2                   9.033
loading files                    9.417
COMPILE                         17.033
saving files                    24.433
parsing .tp2 files              26.383
push_copy_trans                 67.333
TOTAL                          183.317
As you suspected, the push_copy_trans is responsible for more than 2/3 of the compile time. Also, the incredible TRB drop (from 1/2 minute down to 1/2 second!) is very real (enough so that I certainly won't be living without it; I'm a true-believer, now). The TRA parse disappeared once I removed the TRA from the mod language directory (strangely, I do specify AUTO_TRA ~FIXPACK/%s~, even though it's not used for anything, ever). Other than the TP2 parse and the push_copy_trans, everything comes in below disk throughput (for a 6,000+ file-patching mod, at least).

If push_copy_trans is related to .D files, here's a little blurb about my .D needs: in the mod, there's a single inlined .D file that contains patches to about 500 dialogues. There are about 3 APPEND .D actions, one or two BEGIN .D actions, and the rest is comprised entirely of REPLACE .D actions (with some of my favorite SET_WEIGHTs tacked on at the end). As I'm not actually creating new content, everything is simply a literal patch (changing the triggers or actions, or the transition, etc.). Nowhere in the entire .D is a string literal used (translated or otherwise); everything is specified as an absolute string reference, and the state labels are all specified numerically (although I convert to the .D actions to "short-hand" format, everything is pretty much identical to what WeiDU would normally output when given a BioWare-supplied dialogue file). I don't use any other feature of the .D format (no COPY_TRANS, I_C_T, EXTEND_, CHAIN, INTERJECT, DO_THIS_OR_THAT, etc.).

On a somewhat-related note, the timings from a simple --uninstall when the mod isn't even installed are as thus:
Code: [Select]
WeiDU Timings
unmarshal BIFF                   0.000
load TLK                         0.000
parsing .log files               0.000
eval_pe                          0.433
parsing .trb files               0.467
unmarshal KEY                    0.550
marshal and save TLK             0.767
loading files                    0.850
unmarshal TLK                    1.200
tp2 uninstall                    4.650
parsing .tp2 files              44.750
TOTAL                           53.667
I've noticed this on all installations, and was wondering if there was a particular reason the TP2 parse always takes twice as long uninstalling than it does installing? (At first, I thought it was the re-parse for every component for the .log file, but I'm pretty sure it does this on install, too.)
Posted by: devSin
« on: May 23, 2005, 08:40:30 PM »

Quote
You didn't convert all of your TRAs over, so it's hard to tell. Are those other TRAs for that mod or some other mod?
I have both the TRA and the TRB in the languages folder, but I only have the TRB referenced from the TP2 (I think, I can't think of anywhere I would specify it other than language -- maybe the AUTO_TRA parse is looking for something on compile?). I'll try going solo with the TRB (just deleting the TRA) and see if the TRA parse drops of the map.
Posted by: devSin
« on: May 23, 2005, 08:37:51 PM »

Quote
Why not put one _NOW at the end of the each action where you do > 0 _LATERs?
I currently do (and am fine with this). I was just thinking about the way PatchLater works, and about exploiting the fact that WeiDU retains all the data indefinitely (either the first PatchNow ~patchLaterList~ or WeiDU just finishes installing). It was really just a consequence of having to re-examine all the ancient 2DA code in the TP2 here, and thinking about how I could streamline it by changing everything to requiredColumnCount 1 and then just shoving all the data out in one universal push at the end.

Like I said, it's not terribly practical, nor very safe to rely on user-controlled data floating around in the ether. I was just wondering if variable substitution was done, and if the suggested approach would be possible if it was, not that I think it's something anybody should or would ever actually do.

Quote
The COMPILE time may actually be for processing translation strings, marshaling BCS files, ... ah, I have a theory. The cost is probably from push_copy_trans. Do you load a huge generic/universal TRA file at the beginning of your TP2? I'm guessing that you do!
The TRA you downloaded is the single TRA for the mod. I load it (via the LANGUAGE command at the head of TP2). It's only actually required for the STRING_SETs, some textual REPLACE in 2DA files, a slew of SAY patches, and about 5-10 scripts (and then using REPLACE, not any AUTO_TRA or anything). I simply don't know how to defer loading all 5M of a TRA (I was hoping STRING_SET x USING would help, but it turned out to be egregiously slow (since it reloads for each action)), when it's only needed for the STRING_SETs, a couple hundred simple patches, and 10 scripts (using AUTO_TRA would be dumb, as I'd have a single TRA for patching all of one string in a script).

Quote
You could check fairly easily (well, five minutes later) by changing the definition of push_copy_trans on line 94
I'm back home so I'll do this now.
Posted by: weimer
« on: May 23, 2005, 08:33:02 PM »

You could check fairly easily (well, five minutes later) by changing the definition of push_copy_trans on line 94 of src/dc.ml to:

Code: [Select]
let push_copy_trans () =
  Stats.time "push_copy_trans" (fun () ->
  let now = match !trans_strings with
    hd :: tl -> hd
  | [] -> Hashtbl.create 511
  in 
  trans_strings := (Hashtbl.copy now) :: !trans_strings
  ) ()

... and then checking the timing. If my guess is write, most of the time from COMPILE will go to pct.
Posted by: weimer
« on: May 23, 2005, 08:23:54 PM »

Quote
Given the following TP2 code:

That code won't work (as you note). I'm not sure why you want to defer the _LATER for so long and then do them all at once, but I can see where having variables in the _NOW/_LATER variable name would help with that.

Quote
and then using PatchNow in a single copy action

Why not put one _NOW at the end of the each action where you do > 0 _LATERs?

Quote
I had other things going on the installation machine, so the timings aren't really optimal, but should be close enough. Under 4 minutes now, at least. The ball is still up in the air for binary TRAs (I want to do a "clean" run here with only WeiDU running), but cutting the parse time in half isn't giving a bad initial impression.

You didn't convert all of your TRAs over, so it's hard to tell. Are those other TRAs for that mod or some other mod?

The COMPILE time may actually be for processing translation strings, marshaling BCS files, ... ah, I have a theory. The cost is probably from push_copy_trans. Do you load a huge generic/universal TRA file at the beginning of your TP2? I'm guessing that you do!
Posted by: devSin
« on: May 23, 2005, 08:00:16 PM »

Quote
I reallly can't understand what you're talking about or what you're trying to do.
Given the following TP2 code:
Code: [Select]
COPY_EXISTING ~foo.2da~ ~override~
  FOR ( i=10; i>0; i-=1 ) BEGIN
    SET_2DA_ENTRY_LATER ~theStuff~ ~%i%~ 1 ~%i%HeyNow~
  END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING ~bar.2da~ ~override~
  FOR ( i=8; i>2; i-=1 ) BEGIN
    SET_2DA_ENTRY_LATER ~theStuff~ 2 ~%i%~ ~whatever~
  END
BUT_ONLY_IF_IT_CHANGES

COPY_EXISTING ~foo.2da~ ~override~
~bar.2da~ ~override~
  SET_2DA_ENTRIES_NOW ~theStuff~ 2
BUT_ONLY_IF_IT_CHANGES
If PatchLater doesn't associate the list entries with the file being patched, how is it going to know which patches were for foo and which were for bar? And, if PatchNow chucks the list after execution, how's there going to be anything left for bar? Basically, I was thinking of having all the PatchLaters use ~%SOURCE_RES%~, and then using PatchNow in a single copy action afterward (since %SOURCE_RES% will be unique to each file, and contain the changes for only that file). [EDIT: I modified the original example to clarify what the code would look like in this situation.]

I couldn't have been more wrong about compile vs. actual process action times (COMPILE doesn't take up 1/3 of it, it takes up *all* of it)
Code: [Select]
WeiDU Timings
MKDIR                            0.000 // lots of these, but WeiDU doesn't actually have to do anything
PATCH_PRINT                      0.000 // not too many of these
AT_*                             0.000 // 2 of these
load TLK                         0.000 // only 1 (no localized F) with default strings
process copy_trans               0.000 // none
APPEND_COL                       0.000 // 2 of these
process .D files                 0.000 // a huge inlined .D file (~ 500 dialogues)
parsing .log files               0.000 // no mods installed
ADD_PROJECTILE                   0.000 // 2 of these
preprocess APPEND_EARLY          0.000 // none
postprocess .D actions           0.017 // from the giant .D
unmarshal compressed BIFF        0.033 // default BIFFs only
resolve labels                   0.033 // I'm guessing more .D stuff
process .D actions               0.033 // from the giant .D
unmarshal BIFF                   0.050 // the Understudy
<<<<<<                           0.050 // at least a thousand of these
preprocess .D actions            0.083 // from the giant .D
resolve strings                  0.083 // from whatever
parsing .ids files               0.117 // n/a
APPEND                           0.167 // dialogue or Tp2? (100 or so TP_Append)
BUT_ONLY                         0.217 // for every single Tp2 action!
parsing .trb files               0.500 // Why do we have to parse TRA files, too, then?
unmarshal KEY                    0.550 // yeah
find local string                0.667 // huh?
marshal and save TLK             0.783 // yeah
marshal DLG                      0.933 // from the giant .D file, I guess
unmarshal DLG                    1.033 // from .D
unmarshal TLK                    1.200 // whatever
parsing .d files                 1.650 // from the 500+ dialogue updates
READ_*                           2.150 // lots of these
eval_pe                          3.800 // tons of expressions
STRING_SET                       4.617 // every single string
COPY                             4.950 // about 6,000 files
parsing .baf files               5.850 // about 1,000 of these
loading files                    9.167 // yeah
parsing .tra files               9.583 // Where did this come from?
process_patch2                  13.233 // actually doing some important stuff here
saving files                    19.883 // go disk go
parsing .tp2 files              26.617 // yeah
COMPILE                         86.600 // ouch! I know what to comment out for normal dev runs, now
TOTAL                          194.650
I had other things going on the installation machine, so the timings aren't really optimal, but should be close enough. Under 4 minutes now, at least. The ball is still up in the air for binary TRAs (I want to do a "clean" run here with only WeiDU running), but cutting the parse time in half isn't giving a bad initial impression.
Posted by: weimer
« on: May 23, 2005, 07:46:27 PM »

Quote
Will this patch the same entry 10 times (just as using a series of SET_2DA_ENTRY actions would), or does it start overwriting the same variable

... neither or both. It will continue to add entries to the list of deferred updates, but since the time taken by _NOW is "11" and not "2N", it won't take any more time. Last _LATER update to (x,y,) wins.

Quote
So if I deferred PatchNow, opting to have some special action to do it all at once, it would fail after the first patch, right?

Not necessarily. I reallly can't understand what you're talking about or what you're trying to do. _LATER ~myvar~ appends an update to a linked list called ~myvar~. _NOW ~myvar~ applies all of the updates in the list ~myvar~ to the current file and then sets ~myvar~ to NULL. You should be able to derive all of the behavior from that.



Posted by: devSin
« on: May 23, 2005, 07:31:23 PM »

I finally got a minute to check this. I haven't done any concrete tests yet, but here's the stats for a simple parse/load/do nothing:
Code: [Select]
WeiDU Timings
unmarshal BIFF                   0.000
load TLK                         0.000
parsing .log files               0.000
loading files                    0.050
eval_pe                          0.417
parsing .trb files               0.550
unmarshal KEY                    0.567
unmarshal TLK                    1.217
parsing .tp2 files              27.433
TOTAL                           30.233
More to come when I get a chance to do a full run.
Posted by: devSin
« on: May 23, 2005, 07:19:13 PM »

So if I deferred PatchNow, opting to have some special action to do it all at once, it would fail after the first patch, right?
Code: [Select]
COPY_EXISTING ~HPMONK.2DA~ ~OVERRIDE~
... (every other file where I stored up PatchLater actions in ~modifier~
  SET_2DA_ENTRIES_NOW ~modifier~ n
  // after patching HPMONK, ~modifier~ doesn't point to any items = no patches = fail or just do nothing to everything else in file list?
BUT_ONLY_IF_IT_CHANGES
I probably should have taken out the PatchNows in the "what if" example to better illustrate that the magic trick was just to actually patch the files all at once later (since there's no deallocation until the PatchNow). Anyway, "it doesn't work" is good enough for me.

An actual question I had is what the expected behavior is for patches to the same entry from the same list:
Code: [Select]
COPY_EXISTING ~some.2DA~ ~somewhere~
  FOR ( i=10; i>0; i-=1 ) BEGIN
    SET_2DA_ENTRY_LATER ~foo~ 0 1 ~%i%~
  END
  SET_2DA_ENTRIES_NOW ~foo~ 2
Will this patch the same entry 10 times (just as using a series of SET_2DA_ENTRY actions would), or does it start overwriting the same variable (the list index isn't updated, I guess)? I imagine the former, but I wanted to check (to help out some subset of { thebigg : CamDawg } in writing documentation, or something :-D).
Posted by: weimer
« on: May 23, 2005, 06:47:34 PM »

Quote
Does your ominous note mean that TRB is dead at birth (i.e., if it breaks, well, sorry, you shouldn't have been using it anyway), or that if something under-the-hood changes, the TRB file (either how it is read in or written) will change and all your TRB files created with earlier versions of WeiDU are bust?

Both, I guess. I wouldn't ship one unless you're on the ball and warn your users that they may have to come back to you for a mod update if things go wrong. I saw it more as a way to keep the develop-test cycle cheap on your local machine.

If you and others discover that you can't live your life without shipping this feature I can include some sort of support for shipping both the TRA and the TRB (compressed?) and parsing the TRB first if possible. But that would take five or ten minutes, and until you try it out on your machine and see whether it makes a difference or not there's no reason to do that.

Quote
Even across multiple TP2 actions? Wouldn't there be conflicts (since it's storing up everything in ~modifier~, wouldn't it try to make all the modifications to each file)?

No: PATCH_NOW clears ~myvar~ every time.
Posted by: devSin
« on: May 23, 2005, 06:42:03 PM »

Quote
We now have the "TRA binary" format
Nice.

Quote
your mod will stop working and weidu auto-update won't fix it
I assume this means that if I have a mod X that includes a binary TRA, and the Setup-MyMod executable is automatically updated for Windows users, and your string code or their marshal code changed, then the mod with the existing TRB will fail? So, on Mac OS X, I first have to update OCaml, update and/or re-compile WeiDU, and ship it with the old TRB to break anything?

Does your ominous note mean that TRB is dead at birth (i.e., if it breaks, well, sorry, you shouldn't have been using it anyway), or that if something under-the-hood changes, the TRB file (either how it is read in or written) will change and all your TRB files created with earlier versions of WeiDU are bust?

Quote
In your example you can just use ~modifier~ every time and the behavior is the same.
Even across multiple TP2 actions? Wouldn't there be conflicts (since it's storing up everything in ~modifier~, wouldn't it try to make all the modifications to each file)?