Writing a Pakrat replacement

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
:closedeyes: If you behave yourself and it's OK with your mother.

Perhaps you could instead suggest use-cases beyond "A GUI is an absolute necessity... That does... stuff..."
 
Last edited:

Nineaxis

Quack Doctor
aa
May 19, 2008
1,767
2,820
Perhaps you could instead suggest use-cases beyond "A GUI is an absolute necessity... That does... stuff..."

A GUI is necessary for...
USABILITY.

If it's command line, people won't want to use it, because GUI was the progression from command-line interfaces because it is easier to use. And if you have a program that works better than Pakrat, but isn't user friendly, then you might as well have nothing, because people aren't going to use it.
 

RavenStryker

Former Alias: †Blade†/Xi.Cynx
aa
Nov 25, 2008
782
845
A GUI is necessary for...
USABILITY.

If it's command line, people won't want to use it, because GUI was the progression from command-line interfaces because it is easier to use. And if you have a program that works better than Pakrat, but isn't user friendly, then you might as well have nothing, because people aren't going to use it.

Very well put my friend.. couldn't have said it better myself. =)
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
Edit: Post shortened for to-the-pointness.

Usability: Yeeees, I took a few required and elective classes specifically about Usability/HCI in order to graduate, so I am grudgingly familiar with the field... :mellow:

____

I was considering a text-based interface simply because it seems like most of the "correct" actions for packing are straightforward and can be automated. As I've been saying, if there are non-straightforward use-cases you've found yourself in, tell me what they are, please.

Specific examples would be far more constructive than "no gui wtf".* Ex. How often would automatic checking flag a VMT/VMF that you don't want to embed? Why would that happen? How often would it miss something you do want, and what could cause that?

*Yes, it has a "File" menu in the corner already. It's a GUI. Call of your attack spiders, they're tickling my brain and I need to sleep.
 
Last edited:

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
aloooone.jpg

:D
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
Here's how I see the basic workflow.

  • File chooser popup: User is prompted to choose a BSP file. (foo_a3.bsp)
  • User chooses "mod profile" (autodetected from BSP location)
  • Alert: "scripts/soundscapes_foo_a2.txt found, but none for "a3". Create copy for A3? Y/N"
  • Alert: "maps/foo_a2_particles.txt found, but none for "a3". Create copy for A3? Y/N"
  • Alert: "Include/Exclude profile found for a2. Import settings?
  • "Packing options" screen. User ticks/unticks/enters the data for:
    • Pack soundscapes
    • Pack particles
    • Pack textures
    • Pack models
    • Use Include/Exclude profile
    • Pack briefing materials
    • Edit: Pack custom skyboxes
    • Edit: Pack custom detail sprites
    • Edit: Pack .WAVs
  • User clicks OK. Magical stuff happens, looking at various GCFs and the BSP and determining what should/can/can't be packed.
  • User has final screen showing table of things already embedded in the BSP, and what is planned to be embedded. They can make changes by (un-)ticking "Pack" on items, editing, or adding new items.
  • Another tickbox column, "Remember", tells the program to remember this row's choice inside the Include/Exclude profile for next time.
  • User clicks "Save", chooses "Replace" or "New Location".

Right now I'm not sure there's any way for me to automatically determine what .wav are needed by ambient_generic, or what particle-systems are in use. I may just ignore the first case (solved by the mapper entering the wav to the the include/exclude profile) and let the second be whatever the mapper PCFs the mapper puts in the particle manifest.

Quick mockup:
packbspmockup.png

(Please pretend "Embed" is greyed out for the "status" columns (On-disk/gcf, in-bsp) and also unavailable for the files found in GCFs.)
 
Last edited:

Altaco

L420: High Member
Jul 3, 2008
484
120
If you haven't already, make it detect custom skybox textures, I don't think pakrat does that.
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
Hrm. That may be tricky.

HlExtract probably won't do it, because the skybox isn't already embedded. Vbspinfo may not show it's usage, because it's not a "world texture" being used.

To accomplish that, the best option might be to require the original .VMF file and parse that... And a VMF parser would be big enough to be a separate project. (If still a more straightforward task than a BSP parser.) I'll keep it in mind, though.

_______________

Edit: OK, I may have been too pessimistic. It seems that in the .bsp it may be possible to extract just the entity data, which would include "worldspawn" like so:
Code:
{
"world_maxs" "256 6488 976"
"world_mins" "-3296 -2400 64"
"skyname" "sky_tf2_04"
"maxpropscreenwidth" "-1"
"detailvbsp" "detail_trainyard.vbsp"
"detailmaterial" "detail/detailsprites_trainyard"
"classname" "worldspawn"
"mapversion" "344"
"hammerid" "1"
}

Still more work, but something far simpler than a full blown VMF lexer/parser. (Which would need to apply visgroup settings to know what entities were truly "there".)
Bonus: I could pull ambient_generic wav data and custom detail sprite files :D

It certainly won't make the first version, but I'll keep it on the roadmap. In the medium-term this will be a TF2 specific tool, and then I may go and put in some special logic so that things like particle manifests are only enabled when the tool is in "tf2 mode".
 
Last edited:

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
I've coded in a bunch of languages, but never really got into C/C++. (Yeah, I know, I have good excuses.)

Anyway, today I started playing with the Java JNA library as a way to interface with HLLib (DLL) so I can do things much faster and more stably than parsing HLExtract output.

Basic hello-world-esque integration, at least, is working: I can get the library to tell me what I already know--the type of an archive file based on it's extension.

Although if there's a C/C++ DLL guru in the crowd, able to pierce the veil of totally-uncommented code... :p
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
It seems this is becoming a bit of a soapbox/dev-blog, and if that bothers anybody I can stop.

But I have successfully opened and listed files from first GCF with the Java/C++ bridging stuff mentioned earlier. Yes, it's what I do on Saturdays. I'm all tingly.
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
No need to stop. I'm gleaning info from this thread for when I eventually make my own tool >.>
And what might that be? <tears off a fresh sheet from his "Indus-pionage"-brand paper pad>


My plan is to provide the HlLib-interacting packages (mainly interfaces, enums) as a separate JAR at some point.
 

A Boojum Snark

Toraipoddodezain Mazahabado
aa
Nov 2, 2007
4,775
7,670
It would do everything short of creating the VMF. and do them the way I want cause nothing I've ran into ever does it that way. (don't ask me to explain, they are all rather vague and ethereal ideas and wants at the moment)
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
If you're looking into reading/writing the VMF itself I'd point you towards a Parser-Generator like Antlr (or the venerable LEX/YACC) which allows you to generate code that makes an efficient/reliable parser for complex data, like source code.

In some ways those types of programs are easy, in other ways they get incredibly arcane...
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
Busy with other stuff this weekend, but managed to pack in some more library-interfacing improvements: While the C++ stuff is passing Bytes/Chars around for boolean values, the Java interface side can be much cleaner with a little work.

Here's some code from Java for the curious.

Code:
        File gcf = new File("test.gcf");
        assert (gcf.exists());

        PackageType pt = hllib.hlGetPackageTypeFromName(gcf.getAbsolutePath());
        assert(pt.equals(PackageType.GCF));

        IntByReference id = new IntByReference();
        boolean r_create = hllib.hlCreatePackage(pt, id);

        boolean r_bind = hllib.hlBindPackage(id.getValue());

        FileMode fm = new FileMode();
        fm.set(FileMode.INDEX_MODE_READ,true);
        boolean r_open = hllib.hlPackageOpenFile(gcf.getAbsolutePath(), fm);

        hllib.hlSetBoolean(HlOption.OVERWRITE_FILES, false);

And here's how some of the same method signatures are defined in the header files, with some of the typedefs cleaned up.
Code:
HLPackageType hlGetPackageTypeFromName(const char *lpName);
unsigned char hlCreatePackage(HLPackageType ePackageType, unsigned int *uiPackage);
unsigned char hlBindPackage(unsigned int uiPackage);
unsigned char hlPackageOpenFile(const char *lpFileName, unsigned int uiMode);
unsigned char hlGetBoolean(HLOption eOption);
void hlSetBoolean(HLOption eOption, unsigned char bValue);

I realize it's not as sexy as the GUI bits, but this is the part that could cause the majority of any mysterious crashing and corruption if I don't get it right...
 
Last edited:

psihomir

L4: Comfortable Member
Mar 17, 2008
192
32
I already have my own script which generates an include list to use with bspzip - so I just need to run the script, which then runs a batch file which uses the generated list, and that's it - but I guess a GUI can always come in handy.
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
I already have my own script which generates an include list to use with bspzip
Ah, but will it detect custom skyboxes and dispense cuddly kittens on demand?

Ahah! I thought not! :p

But seriously: How are you getting information out of the BSP about world brush textures? vbspinfo?
 
Last edited:

psihomir

L4: Comfortable Member
Mar 17, 2008
192
32
Oh no, it's nothing fancy like that. Just takes a directory(ies) as a parameter, and goes through them in materials/ to make the list. If yours works by getting them directly out of the BSP, I'd definitely use it over mine :)
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
Ah, so everything in /materials/cp_control/, etc.

(Oh god, that sounds awful. I propose a pre-emptive boycott of all maps named ctf_capturetheflag or cp_controlpoint.)