FLFacHash Tool
-
Hi all,
Some of you may remember me from the very old TLR forums. I’ve recently returned to Freelancer, after noticing that there are quite a few interesting mods out there. Anyway, enough introduction – onto the reason for this post.
As some of you know, FLHash is a very basic program that produces hash codes for any given Freelancer ID. Unfortunately, it doesn’t seem to work for faction IDs – a different hash algorithm is used for that, and as far as I know, short of hooking directly into Content.dll no one really knows the exact method. Several years ago, I’ve searched the forums of several different Freelancer sites but came up empty.
So, I decided to get to work myself, and took about a day to solve the problem with my own little code, which I’ve been using ever since. I figured that since then, someone would have solved the problem, but apparently not. Once again, I searched for it, but came up empty.
So permit me to introduce FLFacHash, a tool that will generate a hashcode for any given Freelancer faction ID. FLFacHash is a standalone C executable, and in case anyone is worried, I’ve included the cleaned up C source code. It should be in the Files section shortly, assuming the mods approve of it. While the executable itself may be of little interest, maybe the source code may be of more use.
Cheers,
– The Haen.
-
For the curious who wanted to see the source code right away, here it is:
/* Name: FLFacHash Author: Haenlomal Date: October 2006 Purpose: Returns hashcodes for Freelancer Faction ID strings This is free software. Permission to copy, store and use granted as long as this copyright note remains intact. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define _VERSION_STAMP 1.00.10 // The hash table used is the standard CRC-16-CCITT Lookup table using the standard big-endian // polynomial of 0x1021. #define POLYNOMIAL 0x1021 #define NUM_BITS 8 #define HASH_TABLE_SIZE (1 << NUM_BITS) unsigned short FactionIDHashTable[HASH_TABLE_SIZE]; void usage( const char* prog ) { fprintf( stderr, "Usage: %s faction_id [faction_id [faction_id [faction_id]]] ...\r\n", prog ); fprintf( stderr, "The faction hash code(s) will be returned in unsigned, signed, and hexadecimal\r\n" ); fprintf( stderr, "formats. The unsigned format is suitable for most purposes.\r\n" ); fprintf( stderr, "\r\n" ); fprintf( stderr, "Examples:\r\n" ); fprintf( stderr, "\r\n" ); fprintf( stderr, "\"%s fc_c_grp\"\r\n", prog ); fprintf( stderr, "This will return the faction hash code for faction fc_c_grp.\r\n" ); fprintf( stderr, "\r\n" ); fprintf( stderr, "\"%s li_p_grp ku_p_grp gd_bh_grp\"\r\n", prog ); fprintf( stderr, "This will return the faction hash codes for li_p_grp, ku_p_grp, and gd_bh_grp.\r\n" ); } void InitializeHashTable() { int i, j; unsigned short x; for ( i = 0 ; i < HASH_TABLE_SIZE ; i++ ) { x = i << ( 16 - NUM_BITS ); for ( j = 0; j < NUM_BITS ; j++) { x = ( x & 0x8000 ) ? ( x << 1 ) ^ POLYNOMIAL : ( x << 1 ); } FactionIDHashTable[i] = x; } } unsigned short MakeID( char* id, int l ) { unsigned short hash, x; int i; hash = 0xFFFF; for ( i = 0 ; i < l ; i++ ) { x = ( hash & 0xFF00 ) >> 8; hash = x ^ ( FactionIDHashTable[( hash & 0x00FF ) ^ tolower( id[i] )] ); } return hash; } int main( int argc, char* argv[] ) { int i; char* p; unsigned short x; if ( argc < 2 ) { fprintf( stderr, "Error: wrong number of arguments.\r\n" ); usage( argv[0] ); exit( 1 ); } InitializeHashTable(); for ( i = 1 ; i < argc ; i++ ) { p = argv[i]; x = MakeID( p, strlen ( p ) ); fprintf( stdout, "\"%s\", %u, %d, 0x%.4X\r\n", p, x, x, x ); } return ( 0 ); } Edit: Updated with latest version of the source code[/i][/i]</errno.h></string.h></stdlib.h></stdio.h>
-
Hi Haen, and welcome! Good to see another old timer!
And even if you hadn’t introduced yourself I would have guessed you’re an old’un from your code!! Not many of us use small variable names any more! lol)
Good work, new tools are always welcome.
Apart from universe.ini in [Base] entries (W02Fxx) I haven’t needed a hashcode for factions until now, where are they given/used?
-
StarTrader wrote:
Apart from universe.ini in [Base] entries (W02Fxx) I haven’t needed a hashcode for factions until now, where are they given/used?As far as I know, faction hash codes are used exclusively in the save game files.
If you decode any of the save game files, you’ll notice right away that there’s a massive section of the file in this format: “visit = (some very big number here), (much smaller number here)”. Most of the bigger numbers are in the 2 - 3 billion range – these would be the hash codes for most Freelancer entities.
However, near the beginning of the visit section, you’ll also notice a bunch of visit lines in which the big number is much smaller – smaller than 65536, in fact. These are the faction ID hash codes. If a faction’s hash code is present in the save file indicates then that faction should show up in the player’s reputation list. Otherwise, it won’t.
How is this useful? Well, for example, in the vanilla game the Order faction will never show up in your faction reputation list thanks to some stuff hard-coded into the Freelancer main executable. If you’re not into exe hacking, one way you can get it to show up is to generate the Faction hash code for the Order (fc_or_grp => 3775), and stuff the line “visit=3775, 65” at the appropriate place in the save file.
Cannon wrote:
Wonderful, I’ve been wondering about the algorithm for ages but never found the time, motivation or talent to figure it out. Very nice.I know. Actually, that’s how I found out that no algorithm for hashing faction IDs was out there in the first place. I downloaded your Discovery Account Manager (very nice tool, btw) and browsed through the source code, and saw your comments about how hashing faction IDs was still unknown. Seeing that I had solved that nearly 3 years ago and was rather selfishly not sharing, I decided to do the right thing, extract the snippet of code needed, re-compile a new executable in the grand ol’ tradition of command-line based FLHash.exe, and make it public. Probably should’ve done it back then – just surprised that no one else had bothered to decode the algorithm since that time.
Anyway, I hope this would be of use to you in your Discovery Account Manager.
Cheers,
– The Haen.
-
Excellent work and thanks a lot for sharing, this sure will prove useful
Welcome to The Starport!
-
Thanks all of you guys!!
By the way, something I’ve often needed but not found, is a way to use the hash generator for a list of nicknames, and get the list back in an output with the original nickname and its hashcode after it. Maybe with an = between as a delimiter, I can easily remove it if needed.
Like this:-
ge_s_battery_01 = 2596081674
ge_s_repair_01 = 2911012559
…And preferably I would like to be able to specify the list’s filename in an input window (not CMD please! :pint: ), so I don’t have to use the same filename each time, this way I can prepare several list files and run them one by one.
Is this something one of you guys here can turn out during a coffee break? :oops:
I’ve been using excel to do it line by line until now, and it’s a pain.
:-?
-
The FL Player Cleaner does something similar, it puts 1 line with the nickname then the next line with the hash…
-
Why avoid CMD if you can do it all in practically 1 line using DOS’s “for” command?
Suppose you have FLFacHash and your input file with a list of IDs to be hashed (say, Input.txt) in the same directory. Then just open up the command prompt and enter the following commands:
echo off for /F %i in (Input.txt) do FLFacHash %i >> Output.txt echo on
Open up Output.txt and you should have the information you need in almost the format you wanted. If you are hashing normal hashes, then you can use FLHash instead of FLFacHash.
– The Haen.
-
If you like this
ge_s_battery_01_loot
F:\PRIVAT\FL\DATA\EQUIPMENT\misc_equip.ini
0xe3d9bbbf 2667548365
ge_s_battery_01
F:\PRIVAT\FL\DATA\EQUIPMENT\misc_equip.ini
0x179c884a 2596081674check the ‘CRC Tool’.
It creates a text file besides the database. -
FLDev also creates a similar file in its CRC tab (has both CRCs and Hashes), but I thought this wasn’t what you were after, from what I gathered.
-
StarTrader wrote:
I’ve been using excel to do it line by line until now, and it’s a pain.
If you actually want to use it in Excel, CreateID’s output is tab-delimited (with an option for CSV), so you should be able to import that and just swap the columns around. Or I could just modify CreateID to put the nickname first…
-
Wow, good responses guys!
Now you gave me another problem, I’ll have to try out and assess each of your suggestions! :?
But I ain’t got enough time! Haven’t you lot seen my avatar for goodness’ sakes!!??
Haen - now I KNOW you’re an old bugger like me!!
Actually your suggestion is very helpful, I think I can work my way around the FOR command and make a cmd/bat file to give it the input & output filenames and tailor the output results the way I want too.
Many thanks, guys.
-
Haen - now I KNOW you’re an old bugger like me!!
I’m not THAT old. In fact, believe or not, I’m not even an programmer – I’m a business major!
A quick question for Jason: I just noticed you mentioned “location hashes” for your createid program. Are you referring to the hash number after the “location =” entry in the save game files? If yes, do you know if they are used anywhere else?
Cheers,
– The Haen.
-
downloaded the tool to try it out, double clicked the exe file and i get a black box appear for a nano second and then nothing.
-
It’s a command-line program! Try running it through the command host (cmd)
-
adoxa wrote:
That’s right. I don’t believe so.Ah, I see. Thanks for your answer.
I always thought of location hashes as FLHash being applied twice over. I didn’t know that Freelancer actually called a different routine just for location hashes. Though on further reflection, I guess I should have anticipated that.
At any rate, now that I’ve got these three hashes, that gives me an idea with which I can play around…
– The Haen.
-
Having decoded the faction hash algorithm, I would’ve thought you’d know how it generates the location hash, too. It takes the hex of the base hash, appends an underscore and the name of the room, then hashes that. For example, Manhattan’s bar is: Manhattan = li01_01_base = A7303E0D, so hash “A7303E0D_bar” = 2729128783. Of course, if you’re importing from common.dll, just do MakeLocationID( CreateID( “li01_01_base” ), “bar” ). My version of FlCodec is capable of converting the hashes back to nicknames (Li01_01_Base/Bar) or names (Planet Manhattan Bar), using the database made by CreateID.