I Wanted Orange (The machine would not make a mistake.)


Intitial FGD library available

I finally managed to tear myself away from the Google AI Challenge and packaged up some stuff for FGDs. Check the Hl2Parse project page for more.

Quick code example:

File src = new File("test.fgd");
FgdSpec spec = new FgdSpec();
// If test.fgd uses an @include statement to 
// get another FGD, the DefaultLoader 
// will automatically handle it.
// Now you can pull information from spec
for(String name : spec.getEntClassNames()){
    FgdEntClass eclass = spec.getEntClass(name);
    System.out.println("Class "+name+" found of type "+eclass.getType());

This should give you output like:

Class base_prop_thing found of type BaseClass
Class prop_thingy found of type PointClass
Tagged as: , Comments Off

Hl2parse & FGDs

Recently someone asked if they could use my FGD-parsing code, so I'm working on re-organizing the Hl2Parse code-base.

What I'd like to do is release it as a series of connected Maven modules to avoid burdening anybody with unnecessary dependencies. For example, someone who "just" wants to parse an MDL file doesn't need to pull in all the dependencies (like ANTLR) that would be involved in FGD parsing.

So the modules would probably be something like:

  • Text-parsers (VDF/FGD)
  • Data representation (VDF/FGD classes, used by all other modules)
  • Model binary parsing (MDL, PHY)
  • Map binary parsing (BSP)
  • ClientRegistry.blob binary parsing
  • Higher-level utilities for soundscapes, materials, and comparing FGDs against map-entity data.

The emphasis, however, is just on the FGD stuff for now.

Tagged as: , Comments Off

Takin’ New Ground in PackBSP

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".


PackBSP: Just the GUI now

Well, I'm happy with PackBSP right now. It does everything I want it to... as long as you're willing to hardcode the answers to things like "Which game do you want to package for". Sometime in the next month I hope to get around to making a GUI that'll put it into Beta status, but right now there's a lot of stuff at work that's taking priority when it comes to creative energies. Off-kilter mind-bending Javascript rich application asynchrony.

Back in terms of PackBSP... in the words of William Stafford, the solution to writer's block is "Lower your standards and keep writing." I may have to go ahead and take that route and deliberately give up the seductive vision of a GUI done the "right way". Use some of that fancy hokery-pokery "Agile" methodology the kids are all talkin' about these days.

Dang, I'm losing ground!

It turns out that Valve has recently added some new stuff with their "Steam for Mac" business phase. There are new sections to the FGD files (see wiki) and it seems that instead of Episode 1 and Orange Box engines, they are now showing three, with new labels:

  • "Source 2006" (ep1)
  • "Source 2007" (source2007)
  • "Source 2009" (orangebox)

I'm guessing they created the source2007 category specifically to hold games (such as HL2:Ep2) which are not being moved forward onto their new cross-platform-buildable engine. The engine differences should be a really fast fix. Since I rewrote everything to read the Source SDK data files, all I have to do is change the "SdkEngine" enum.  The FGD stuff might take a little bit longer, especially if the new sections have any inheritance/override rules when multiple FGDs are layered together.

Tagged as: , Comments Off

FGD API example

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 : "" =
TeamNum(choices) : "Team" : 0 : "Team" =
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."
Tagged as: , , Comments Off

PackBSP status

The FGD-parsing code is pretty well integrated now. Given an FGD and a BSP, it's easy to find all the places that models/sounds/materials etc. are being used in the map entity data.  There are some wrinkles for relationships not part of the FGD,  such as skyboxes on the "worldspawn" entity.

Right now I'm experimenting with rewriting the GUI as a backward/forward style interface (similar to an installer) and using the JSR-296 project along with property listeners. The older GUI code didn't need any of this since it basically functioned as a convenient way to launch a command-line program. However, I'm ditching command-line support until end-users seems to want it.

Tagged as: , Comments Off

Valve’s handling of FGD files

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.

Tagged as: , , Continue reading

The Formal Grammar you never learned in School

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.