As I mentioned earlier, Valve’s been updating some of the SDK stuff, which means I have to play catch-up supporting these new things before I can really get my momentum back for PackBSP 2. In addition to the @MaterialExclusion and @AutoVisGroup sections, it seems that @FilterClass is a new part of the FGD lexicon, to support some TF2 features.
So I’ve managed to rewrite the FGD parsing code in such a way that it should be a lot more friendly for a hypothetical future where Valve adds a new @ArbitraryPurposeClass, as long as it fulfills the same expectations that the other class declaration sections do.
With that out of the way I can get back to putting in a GUI for a beta release. Except for the interface for customizing which files you want to pack, the user generally just has to choose things and click ‘next”.
Just a sample from the FGD code I wrote for the
Hl2Parse library. This snippet loads the TF2 FGD file and then re-outputs the FGD format to show it has parsed everything. It also prints the “default” version and then the “combined” version which collapses all the inheritance.
final String fgdPath = "...";
FgdSpec spec = new FgdSpec();
spec.loadFrom(new File(fgd));
final String entName = "func_respawnroom";
FgdEntClass spawnroom = spec.getEntClass(entName); // Get normal version
System.out.println(spawnroom.toText(entName)); // Print sparse form
FgdEntClass combined = spawnroom.getInherited(spec); // Do inheritance
System.out.println(combined.toText(entName)); // Print comnined form
The first print statement replicates the set-up in the original file, using the base(…) modifier to do inheritance.
@SolidClass base(Targetname,TeamNum,EnableDisable,Toggle) = func_respawnroom :
"Designates a respawn room for a team." [
]
The second prints statement shows how it looks after the inheritance rules have been applied.
@SolidClass = func_respawnroom :
"Designates a respawn room for a team." [
targetname(target_source) : "Name" : "" : "The name that other entities refer to this entity by."
StartDisabled(choices) : "Start Disabled" : 0 : "" =
[
0:"No"
1:"Yes"
]
TeamNum(choices) : "Team" : 0 : "Team" =
[
0:"Any"
2:"Red"
3:"Blue"
]
input KillHierarchy(void) : "Removes this entity and all its children from the world."
input Enable(void) : "Enable this entity."
input Disable(void) : "Disable this entity."
input SetTeam(integer) : "Changes the entity's team."
input Kill(void) : "Removes this entity from the world."
input FireUser4(void) : "Causes this entity's OnUser4 output to be fired."
input FireUser3(void) : "Causes this entity's OnUser3 output to be fired."
input FireUser2(void) : "Causes this entity's OnUser2 output to be fired."
input AddOutput(string) : "Adds an entity I/O connection to this entity. Format: <output name> <targetname>:<inputname>:<parameter>:<delay>:<max times to fire (-1 == infinite)>. Very dangerous, use with care."
input FireUser1(void) : "Causes this entity's OnUser1 output to be fired."
input Toggle(void) : "Toggle the enabled/disabled status of this entity."
output OnUser1(void) : "Fired in response to FireUser1 input."
output OnUser4(void) : "Fired in response to FireUser4 input."
output OnUser2(void) : "Fired in response to FireUser2 input."
output OnUser3(void) : "Fired in response to FireUser3 input."
]
One of the issues in PackBSP I want to improve is that it doesn’t “know” about dependencies (like a model used in a prop_static entity) stored in the entity data of a map. At least, not for other mods: PackBSP is currently hardcoded to the set that TF2 supports. The solution seems to be interpreting the FGD files that Hammer uses to determine all the places a user might insert a model or a texture while mapping. These definition files should be created by mod-makers for just about any “serious” Source Engine mod, so it seems safe to piggyback on their information. I’ve had a parser for the FGD files for a while now, but just parsing the file isn’t enough: You have to resolve and assemble all the dependencies into a final state.
Read more…
An update to my earlier post, here’s a set of examples where ANTLR’s inheritance-system fails in an unexpected way. In this example, we parse a sequence of words or integers, printing out what we get as we go.
Code below the fold.
Read more…
I’m a little bit frustrated with ANTLR’s “composite” or “delegate” grammar support now.
The pitch is that you can define a bunch of rules in one file, and then selectively override them in another file. In practice, some painful warts get in the way.
For one thing, my “base” parser cannot have a @header{} block at the same time the children do, which is used for–among other things–setting imports and packages in Java. So I either have to manually edit everything on every build, eliminating the benefits of code-generation… Or I’ll have one AbstractBaseParser.java class always sitting around which is chock-full of errors since it’s missing imports and a package declaration. (And to fix that, I’d still have to do manual changes after each build.) It’s a complicated program, yes, but I’d have hoped these kinds of things would work by now given that bugs about them have been filed about a year ago.
In a sense this is emblematic of my experiences with ANTLR: Incredibly powerfuland convenient, as long as you don’t try to do anything too fancy. Once you do, things begin to explode or get hung up on tiny details that make you roll-back your work, while strange error messages appear which lead to absolutely nothing when searching Google.
I’d post some examples, but I’m still trying to find the right mix of plugins to display the code snippets the way I want.
Worked on PackBsp a bit today. Indirectly.
I’m rewriting my ANTLR grammars for Valve‘s data formats, since I’m now trying to parse some new file types. Valve’s own SDK framework has a bunch of configuration data that I’d like to be able to get at. Namely, information in the SDK’s GameConfig files and inside the FGD files. Using those together, I can begin to create my own tool-launcher which is able to automatically know a lot more about the SDK environment.
The end-goal, of course, is for PackBsp to automatically gather all the entity information for maps. (Such as custom sounds which play when you enter a certain area.) If someone creates a new mod, PackBsp will automatically support it once it’s been wired up to the SDK. More up-front work, less maintenance later.
One other belated announcement: I’ve been relying on HlLib in order to access Steam’s compressed archive files. Of course, this is a Windows DLL, and I’m programming in Java, but it’s not entirely a Shakespearean tragedy. Through the magic of JNA you can bridge the two. Since it’s been a while since I’ve needed to change it, I’ve gone ahead and released JHlLib on the off-chance that somebody else has a similar need in the future.