VarsityPuppet

Random CSCI Adventures with VP

Recommended Posts

I believe you are right, and it is of course mainly meant to use for web applications. But it can be used elsewhere, although it might need a different build. Anyway, my main point was simply that I suppose I shouldn't find learning Perl too hard, as I have worked with PHP. Which means I might be able to understand something about your source codes...

 

Besides that, LiliArch, I can pretty much translate the source code into layman's terms for anyone whose interested. Also, if one were to explain to me the functions needed to read a file in a certain programming language, I could probably outline a version of the coding libraries I'll be using, if anyone's interested...

Share this post


Link to post
Share on other sites

Update:

 

I've gotten more of the file decoded. It can read the Struct Array and Field Array. Keep in mind reading these arrays is still quite a ways from actually putting together some working version of a GFF file, but I'm still getting there.

 

I actually ran into a bit of an issue with reading the Label Array. According to the file format PDF, they should be the next item referenced in the Header, but something tells me that it's out of order. Whenever I read the Labels, I get junk data.

 

Ah well, anyways. Continue on..

 

EDIT:

 

Ah, well nevermind that. I figured out the issues I was having with labels. Forgot to reference an actual array index, not just the variable I was incrementing. How stupid.

Share this post


Link to post
Share on other sites

Sounds a bit like my if clause, where I was comparing a value of a variable to a former value of that same variable, instead of the one it was meant to replace...

 

 

 


Besides that, LiliArch, I can pretty much translate the source code into layman's terms for anyone whose interested. Also, if one were to explain to me the functions needed to read a file in a certain programming language, I could probably outline a version of the coding libraries I'll be using, if anyone's interested...

Well, I think learning a new programming language wouldn't do any harm to me.

Share this post


Link to post
Share on other sites

Sounds worth looking in to for sure!

 

For now though, I just want to have the experience of reading/parsing files on my own. It's one thing to understand the code, but it's another to write it yourself.

 

Of course it would be much easier to use the existing code considering xml files are far easier to merge than GFF files (for which all intents and purposes of Git, may as well be binary files). Merge the xml file and then generate the GFF file from the code.

 

Might not be a bad idea to consider writing down everything as an XML and then converting to the preferred format.

 

 

Anyways, I managed to get some of the complex data types read (things like resrefs and cexostrings). Wasn't really hard, but coming back to the code after a couple of days was a little confusing. Won't be long until I can build a GFF hierarchy and then rewrite the file with new information.

Share this post


Link to post
Share on other sites

Sounds worth looking in to for sure!

 

For now though, I just want to have the experience of reading/parsing files on my own. It's one thing to understand the code, but it's another to write it yourself.

 

Of course it would be much easier to use the existing code considering xml files are far easier to merge than GFF files (for which all intents and purposes of Git, may as well be binary files). Merge the xml file and then generate the GFF file from the code.

 

Might not be a bad idea to consider writing down everything as an XML and then converting to the preferred format.

 

 

Anyways, I managed to get some of the complex data types read (things like resrefs and cexostrings). Wasn't really hard, but coming back to the code after a couple of days was a little confusing. Won't be long until I can build a GFF hierarchy and then rewrite the file with new information.

 

 

Have you considered the GFF2XML tool by Tk102? It's a commandline-utility...

 

info:

http://www.lucasforums.com/showthread.php?t=150277

 

direct file link:

starwarsknights.com/mtools/gff_xml_05.rar

Share this post


Link to post
Share on other sites

Have you considered the GFF2XML tool by Tk102? It's a commandline-utility...

 

info:

http://www.lucasforums.com/showthread.php?t=150277

 

direct file link:

starwarsknights.com/mtools/gff_xml_05.rar

 

Yeah, I thought about it, but that would sort of make all the work I just did irrelevant.... :'( Isn't hindsight great?

 

But on the plus side of things, I know how the GFF file works and I've had practice writing code that parses files! Not to mention I want to know how to work with writing files to XML format.

 

If it came down to me not being able to figure out how to read or parse anything, then that would have likely been my course of action. If I for instance, wanted to pack/unpack Rim files or compile source scripts (aka, eventual plans), then I may take that route...

Share this post


Link to post
Share on other sites

So I decided to do the phonebook thing in c++. This reads a file, stores it, sorts it, and then writes it. I have my own implementation for sort, but for readability I have used the STL sort in what I'm posting here. I also need to clean up the output using iomanip, but this is fine. Searching to find a name is just implementing a custom find(), wouldn't be difficult but I didn't include it.

 

#include <iostream>
#include <vector>
#include <istream>
#include <fstream>
#include <ostream>
#include <iomanip>
#include <algorithm>

using namespace std;

class record {
public:
  record() {}

  bool  operator<(const record &)const;
  friend istream& operator>>(istream &, record &);
  friend ostream& operator<<(ostream &, const record &);  // friend declarations

private:
  string firstname;
  string lastname;
  string phonenum;
};

bool record::operator<(const record & values)const{
  if (lastname < values.lastname)
    return true;
  if(lastname == values.lastname && firstname < values.firstname)
    return true;
}

istream & operator>>(istream &in, record & values){
  in >> values.firstname >> values.lastname >> values.phonenum;
}

ostream & operator<<(ostream &out, const record & values){
  out << left << values.lastname << " " << values.firstname << " " << values.phonenum;
}

int main(int argc, char *argv[]) {
  string line, firstname, lastname, phonenum;
  record values;
  vector<record> A;

  if(argc < 2){
    cerr << "Incorrect usage, please try again at a later time. Optionally, do not try again and go directly to ja\
il. Do not pass go, do not collect 200 dollars." << endl;     // parse command-line arguments
 }

  ifstream in(argv[1]); // open file

  while(in >> values){
    A.push_back(values);
    }
  in.close();   // close file

  sort(A.begin(), A.end());    // sort data

    for(int i = 0; i < A.size(); i++){
      cout << A[i] << endl;    // write data to stdout { array index [] based }
    }

}


Share this post


Link to post
Share on other sites

WOW

 

 

So I've been coding all day. A lot of it was spent refactoring. Needless to say, my mind feels like mush.

 

 

I'm pretty damn close to having the file format laid out perfectly so I can just write a few nested loops that will build it into an xml file.

 

So close!

Share this post


Link to post
Share on other sites

WOW

 

 

So I've been coding all day. A lot of it was spent refactoring. Needless to say, my mind feels like mush.

 

 

I'm pretty damn close to having the file format laid out perfectly so I can just write a few nested loops that will build it into an xml file.

 

So close!

Way to go, VP! I tip my hat to you!

Share this post


Link to post
Share on other sites

 

So I decided to do the phonebook thing in c++. This reads a file, stores it, sorts it, and then writes it. I have my own implementation for sort, but for readability I have used the STL sort in what I'm posting here. I also need to clean up the output using iomanip, but this is fine. Searching to find a name is just implementing a custom find(), wouldn't be difficult but I didn't include it.

 

...That' a lot of code! :vava:

 

I think I might stick with Perl for a little while...

Share this post


Link to post
Share on other sites

...That' a lot of code! :vava:

 

I think I might stick with Perl for a little while...

Heh, C++ syntax is quite heavy. This program does a lot more than what the Perl/PHP scripts do, though. It could be done without using classes and just storing everything as a single strings and be less than 20 lines. In that previous one, it would read a file, store all the names and numbers, then sort them by last name. Here's one possible way(using libraries) Of course you could always use character arrays and do it, but that's more work than is needed, lol.

#include <iostream>
#include <map>

using namespace std;

int main(){
string name, number;
string namefind;
map<string, string> mymap;
cout << "ENTER YO NAME AND NUMBA CRACKA" << endl;
while(cin >> name >> number){
mymap.insert(pair<string,string>(name,number));
}

cout << "ENTER DA NAME OF DA GUY YOU BE WISHIN TO FIND" << endl;
cin >> namefind;

it=mymap.find(namefind);

cout << it->first << "'s number is" << it->second << endl;
}


Share this post


Link to post
Share on other sites

Heh, C++ syntax is quite heavy. This program does a lot more than what the Perl/PHP scripts do, though. It could be done without using classes and just storing everything as a single strings and be less than 20 lines. In that previous one, it would read a file, store all the names and numbers, then sort them by last name. Here's one possible way(using libraries) Of course you could always use character arrays and do it, but that's more work than is needed, lol.

#include <iostream>
#include <map>

using namespace std;

int main(){
string name, number;
string namefind;
map<string, string> mymap;
cout << "ENTER YO NAME AND NUMBA CRACKA" << endl;
while(cin >> name >> number){
mymap.insert(pair<string,string>(name,number));
}

cout << "ENTER DA NAME OF DA GUY YOU BE WISHIN TO FIND" << endl;
cin >> namefind;

it=mymap.find(namefind);

cout << it->first << "'s number is" << it->second << endl;
}


 

I know the code isn't actually that complicated, but I feel dumb for not actually knowing any C++...

Share this post


Link to post
Share on other sites

I know the code isn't actually that complicated, but I feel dumb for not actually knowing any C++...

It's a pretty fun language to play in.

 

Also forgot to mention if you print that map out, it'll be in alphabetical order.

 

If I knew exactly what you were doing with these files I could try helping with whatever, just let me know.

Share this post


Link to post
Share on other sites

So my XML formatting is a little weird, but should it be necessary to edit with an XML editor, I wanted it to be as easy to read as possible.

 

XML formatting is a little weird, but as long as it's able to read and merge changes in a git repo, then I should be good. Should be able to read pretty much any GFF file, although I'll have to make a few changes so it can read .dlg files. Imagine merging dlg files finally!

 

 

 

<UTI>V3.2
		<STRUCT>-1
			<TemplateResRef type="RESREF">g_w_amthsbr01
			</TemplateResRef>
        <BaseItem type="INT">129
			</BaseItem>
        <LocalizedName type="CEXOLOCSTRING">-1
				<substring>Darth Ametha's Lightsaber
				</substring>
        </LocalizedName>
        <Description type="CEXOLOCSTRING">-1
			</Description>
        <DescIdentified type="CEXOLOCSTRING">-1
				<substring>Designer: Evasto

This lightsaber belonged to a Sith Lady under the tutelage of Darth Evasto. In stark contrast to her master's lightsaber, Lady Ametha's lightsaber is of a wicked design, sporting five rows of spikes on the emitter and a single, large spike serving as the pommel, their cold silver appearance contrasting against the black metal of the hilt. 
				</substring>
        </DescIdentified>
        <Tag type="CEXOSTRING">g_w_amthsbr01
			</Tag>
        <Charges type="BYTE">0
			</Charges>
        <Cost type="DWORD">900
			</Cost>
        <Stolen type="BYTE">1
			</Stolen>
        <StackSize type="WORD">1
			</StackSize>
        <Plot type="BYTE">0
			</Plot>
        <AddCost type="DWORD">900
			</AddCost>
        <Identified type="BYTE">0
			</Identified>
        <ModelVariation type="BYTE">1
			</ModelVariation>
        <PropertiesList type="LIST">29
				<STRUCT>0
					<PropertyName type="WORD">43
					</PropertyName>
                <Subtype type="WORD">2
					</Subtype>
                <CostTable type="BYTE">0
					</CostTable>
                <CostValue type="WORD">0
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">1
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">9
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">22
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">8
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">1
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">4
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">3
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">1
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">11
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">12
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">55
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">1
					</CostTable>
                <CostValue type="WORD">5
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">6
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">23
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">6
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">22
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">5
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">3
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">11
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">8
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">12
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">1
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">7
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">1
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">12
					</PropertyName>
                <Subtype type="WORD">3
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">8
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">6
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">13
					</PropertyName>
                <Subtype type="WORD">5
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">10
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">12
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">9
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">13
					</PropertyName>
                <Subtype type="WORD">5
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">12
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">8
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">13
					</PropertyName>
                <Subtype type="WORD">5
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">23
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">5
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">2
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">5
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">1
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">0
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">28
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">0
					</CostTable>
                <CostValue type="WORD">0
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">4
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">49
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">10
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">5
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">32
					</PropertyName>
                <Subtype type="WORD">1
					</Subtype>
                <CostTable type="BYTE">25
					</CostTable>
                <CostValue type="WORD">0
					</CostValue>
                <Param1 type="BYTE">1
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">10
					</UpgradeType>
            </STRUCT>
        </PropertiesList>
        <PaletteID type="BYTE">7
			</PaletteID>
        <Comment type="CEXOSTRING">Blue
			</Comment>
        <UpgradeLevel type="BYTE">3
			</UpgradeLevel>
    </STRUCT>
</UTI>

 

Share this post


Link to post
Share on other sites

So my XML formatting is a little weird, but should it be necessary to edit with an XML editor, I wanted it to be as easy to read as possible.

 

XML formatting is a little weird, but as long as it's able to read and merge changes in a git repo, then I should be good. Should be able to read pretty much any GFF file, although I'll have to make a few changes so it can read .dlg files. Imagine merging dlg files finally!

 

 

 

<UTI>V3.2
		<STRUCT>-1
			<TemplateResRef type="RESREF">g_w_amthsbr01
			</TemplateResRef>
        <BaseItem type="INT">129
			</BaseItem>
        <LocalizedName type="CEXOLOCSTRING">-1
				<substring>Darth Ametha's Lightsaber
				</substring>
        </LocalizedName>
        <Description type="CEXOLOCSTRING">-1
			</Description>
        <DescIdentified type="CEXOLOCSTRING">-1
				<substring>Designer: Evasto

This lightsaber belonged to a Sith Lady under the tutelage of Darth Evasto. In stark contrast to her master's lightsaber, Lady Ametha's lightsaber is of a wicked design, sporting five rows of spikes on the emitter and a single, large spike serving as the pommel, their cold silver appearance contrasting against the black metal of the hilt. 
				</substring>
        </DescIdentified>
        <Tag type="CEXOSTRING">g_w_amthsbr01
			</Tag>
        <Charges type="BYTE">0
			</Charges>
        <Cost type="DWORD">900
			</Cost>
        <Stolen type="BYTE">1
			</Stolen>
        <StackSize type="WORD">1
			</StackSize>
        <Plot type="BYTE">0
			</Plot>
        <AddCost type="DWORD">900
			</AddCost>
        <Identified type="BYTE">0
			</Identified>
        <ModelVariation type="BYTE">1
			</ModelVariation>
        <PropertiesList type="LIST">29
				<STRUCT>0
					<PropertyName type="WORD">43
					</PropertyName>
                <Subtype type="WORD">2
					</Subtype>
                <CostTable type="BYTE">0
					</CostTable>
                <CostValue type="WORD">0
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">1
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">9
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">22
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">8
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">1
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">4
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">3
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">1
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">11
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">38
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">12
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">55
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">1
					</CostTable>
                <CostValue type="WORD">5
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">6
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">23
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">6
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">22
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">5
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">3
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">11
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">12
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">8
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">12
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">1
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">7
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">11
					</PropertyName>
                <Subtype type="WORD">1
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">3
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">12
					</PropertyName>
                <Subtype type="WORD">3
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">8
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">6
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">24
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">13
					</PropertyName>
                <Subtype type="WORD">5
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">10
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">12
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">9
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">13
					</PropertyName>
                <Subtype type="WORD">5
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">12
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">8
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">13
					</PropertyName>
                <Subtype type="WORD">5
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">7
					</CostValue>
                <Param1 type="BYTE">0
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">23
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">5
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">2
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">2
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">5
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">2
					</CostTable>
                <CostValue type="WORD">1
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">0
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">28
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">0
					</CostTable>
                <CostValue type="WORD">0
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">4
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">49
					</PropertyName>
                <Subtype type="WORD">0
					</Subtype>
                <CostTable type="BYTE">4
					</CostTable>
                <CostValue type="WORD">10
					</CostValue>
                <Param1 type="BYTE">255
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">5
					</UpgradeType>
            </STRUCT>
            <STRUCT>0
					<PropertyName type="WORD">32
					</PropertyName>
                <Subtype type="WORD">1
					</Subtype>
                <CostTable type="BYTE">25
					</CostTable>
                <CostValue type="WORD">0
					</CostValue>
                <Param1 type="BYTE">1
					</Param1>
                <Param1Value type="BYTE">0
					</Param1Value>
                <ChanceAppear type="BYTE">100
					</ChanceAppear>
                <UpgradeType type="BYTE">10
					</UpgradeType>
            </STRUCT>
        </PropertiesList>
        <PaletteID type="BYTE">7
			</PaletteID>
        <Comment type="CEXOSTRING">Blue
			</Comment>
        <UpgradeLevel type="BYTE">3
			</UpgradeLevel>
    </STRUCT>
</UTI>

 

Yay!

 

I've just got to figure out how to store blank bytes and how the TLK format uses floats. After that, I should be able to programmatically add entries...

Share this post


Link to post
Share on other sites

Yay!

 

I've just got to figure out how to store blank bytes and how the TLK format uses floats. After that, I should be able to programmatically add entries...

Hmmm... care to share the knowledge and/or code when you're done? I could use something along the lines of a .tlk strref retrieval.

 

It's going to be in Perl isn't it?

 

 

I fixed the reader so that it reads dlg files (turns out I made a silly mistake when I read the structs from a List). I'm working on rebuilding the files back into GFF/Binary. So far I've just outputting test information like the number of structs, fields, etc. Writing an XML and writing back to a GFF should result in a net change of 0 in the overall size of the file. I'm.... uh... basically not there yet.

Share this post


Link to post
Share on other sites

Hmmm... care to share the knowledge and/or code when you're done? I could use something along the lines of a .tlk strref retrieval.

 

It's going to be in Perl isn't it?

 

Not necessarily. If you can PM me just some example code of reading "X" amount of bytes from a file after opening it in binary, how to go to a certain position in the file(for example, the 20th byte from the beginning of the file) and how to declare variables in whatever language you're using, I can whip up something that will help you out.

 

As it is, the StrRef retrieval thing was the extent of the work Tk102 did on the TLK in his programming libraries. He already had that done because he needed it for his most of his other libraries.

 

...Or I can post the code and add lots of comments to explain it?

Share this post


Link to post
Share on other sites

Maybe just post the code and explain the crap out of it lol.

 

Alternatively, if you want to just post the file structure, that'd be cool.

 

 

Or, I think you should join me in my quest and learn C# and we can work off of eachother. It's very similar to java in terms of syntax.

Share this post


Link to post
Share on other sites

Maybe just post the code and explain the crap out of it lol.

 

Alternatively, if you want to just post the file structure, that'd be cool.

 

 

Or, I think you should join me in my quest and learn C# and we can work off of eachother. It's very similar to java in terms of syntax.

 

I'm sorry that I wasn't on earlier; my charger for my laptop is being stingy about when it's working, and my laptop's battery won't hold a charge...

 

Anyways, here's the code and  the file structure, as I currently see it:

 

 

//A note before we begin: the # is the comment symbol. When you see # and then text, it was already in the source code. When it's ##, I've added it for this explanation.

#
#  NOTES ~~ Fair Strides, not Tk102
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#	1. Seek starts from the beginning of the file every time...
#       2. There is no ending to the file, except the last StrRef.
#       3. You have the header, then two tables: String data, and String.
#       4. To access the string data, you need to count 20 + (StrRef*40) from the beginning of the file.
#       5. The string data for any given StrRef is 40 bytes.

## Declare the Library
# Define package name
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package Bioware::TLK; #~~~~~~~~~~~~~~~
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//Not a comment in the file, but I'm cutting out some library-specific code that isn't important to the explanation...

## Declaring and defining a method/function
sub string_from_resref($$;$) {
    my $tlk_path=shift;   ## the path to the .tlk file's directory. Tk102 used a variable set to the Win32 Registry's Path value
    my $resrefnum=shift; ## the StrRef
    my $breadcrumb=shift; ## Generally, the file that the StrRef lookup was launched for. Example, a Name StrRef from spells.2da would make $breadcrumb = spells.2da
    
    return '' if $resrefnum<0;
    
    ## Self-explanatory; opens the file in read-only mode
    (open TLK, "<", "$tlk_path\\dialog.tlk") || (return);

    ## Seek traverses the bytes in a file. The first argument is a FileHandle(FH), set by the open command(notice the TLK in open above). The next argument is the number of bytes to traverse, and the third argument tells where to start from; it's a 0, 1, or 2, and suffice to say for this explanation that the 0 in the third argument means to seek from the beginning of the file...
    seek TLK,0,0;
   ## read from the FH, where the first argument is the FH, the second the variable to read the bytes into, and the third is the number of bytes to read. Read works from the current position, which is where seek comes in handy.
    read TLK,(my $tlkversion),8;

// Here I've cut out a big chunk of an if-statement that only applied if $tlkversion = TLK V4.0, which is the version for Jade Empire

    seek TLK,12,0;
   ## Read the number of strings in the TLK
    read TLK,(my $string_count_packed),4;
   ## Translate the 4 bytes into Human
    my $string_count=unpack('V',$string_count_packed);
   ## If the StrRef you're looking up is beyond the range of the TLK's string count, you've got a problem...
    if ($resrefnum>=$string_count) {
      $msgbox->Call(0,"Attempted to read past end of end of dialog.tlk \n"
      ."(tried to read string $resrefnum but dialog.tlk only goes up to entry number " . ($string_count-1) .")"."\n\n$breadcrumb",
      "Dialog.tlk error",0);

#      die "Dialog.tlk error: Attempted to read past end of end of dialog.tlk \n"
#        ."(tried to read string $resrefnum but dialog.tlk only goes up to entry number " . ($string_count-1) .")"."\n$breadcrumb"
    }
   ## Read the offset from the start of the file
    read TLK,(my $offset_packed),4;
    my $offset=unpack('V',$offset_packed);
   ## Tell me the offset
    print "\$offset is $offset\n";
   ## This is a bit of beauty. It seeks from the start of the file 20 bytes(the header, which is what we've read so far) plus 40 times the StrRef(since the StrRef entry's data is 40 bytes) plus an additional 28 bytes to skip the StrRef's Flags, SoundResRef, Pitch Variance, and Volume variance. After that, you are at the offset to the string.
    seek TLK, 20+(40*$resrefnum)+28,0;
   ## Read the Offset from the first offset read from the header to the StrRef's text. Also reads the number of bytes that are in the string, starting from the second offset.
    read TLK,(my $info_packed),8;
    my ($offset2,$size)=unpack('V2',$info_packed);
   ## Go to the StrRef's text
    seek TLK,$offset+$offset2,0;
   ## Read the entire StrRef
    read TLK,(my $string),$size;
   ## Spit it back at ya
    return $string;
}

 

 

 

Now the file format layout, as I currently know it, is as follows:

 

 

The TLK file has three sections, in order of placement in the file:
-Header
--String Data Table(sound resref, soundlength, .etc)
--String Entry Table(the text for each StrRef, seems to have no boundary between entries...)

In the TLK format, the WORD, DWORD, and FLOAT are as follows:
WORD ~~ 2-byte unsigned integer, little endian order
DWORD ~~ 4-byte unsigned integer, little endian order
FLOAT ~~ 4-byte floating point value in IEEE Std 754-1985 format

The first 20 bytes are the header:
0-8 ~~ A piece of plain text. For KotOR and TSL, this is "TLK V3.0" WITHOUT the quotes and WITH the spaces.
9-12 ~~DWORD, the language ID*.
13-16 ~~ DWORD, number of strings
17-20 ~~ DWORD, offset from the start of the file to the beginning of the string entry table

Immediately after, you have the String Entry Table, full of 40-Byte entries for each StrRef, which are laid out like so:
0-4 ~~ DWORD, Flags**
5-20 ~~ plain text, the name of the sound file that goes with the StrRef
21-24 ~~ DWORD, Volume variance(not used)
25-28 ~~ DWORD, Pitch variance(not used)
29-32 ~~ DWORD, String offset, from the header offset
33-36 ~~ DWORD, String size, in bytes
37-40 ~~ FLOAT,  Duration of the sound file, in seconds(0.0, 4.9. .etc)

After the 40-byte sections for each StrRef, you have the text for each one thrown together; when one ends, the next one begins.

* The language IDs:
English 0
French 1
German 2
Italian 3
Spanish 4
Polish 5
Korean 128
Chinese Traditional 129
Chinese Simplified 130
Japanese 131

**:The flags are a part I don't understand programming-wise yet. I throw them into the file, but the TLKEd doesn't recognize them, so I'm not doing them right...

They seem to be bits possessing the following values:

TEXT_PRESENT 0x0001 If flag is set, there is text specified in the file for this
StrRef. Use the OffsetToString and StringSize to
determine what the text is.
If flag is unset, then this StrRef has no text. Return an
empty string.
SND_PRESENT 0x0002 If flag is set, read the SoundResRef from the file.
If flag is unset, SoundResRef is an empty string.
SNDLENGTH_PRESENT 0x0004 If flag is set, read the SoundLength from the file.
If flag is unset, SoundLength is 0.0 seconds.

 

 

 

P.S: Tell me how to remove the color-coding and I will gladly do so...

 

EDIT: SUCCESS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

 

As of 8:46pm, February 16, 2014, FS added a freakin' entry that was accepted by TLKED!

 

The mistake was rather stupid of me. Through a series of test messages to the console, I discovered that the function wasn't actually receiving my hash(I guess an array in C#, from what I understand of Disturbed's code snippet). I was passing the hash directly, when I apparently needed to pass it as a reference to the hash itself...

 

A stupid, but easy, mistake. However, I have officially added an entry programmatically into a tlk file, which I also made programmatically from scratch. However, it should be easy now add entries to an existing one...

Share this post


Link to post
Share on other sites

I know it's been a couple of days, but I'll take a look at your TLK write up in a bit.

 

In the meantime, I've managed to code up the read/write to XML/write to GFF code for GFF files!

 

It works with the 3 I've tested so far :/, although, it's not incredibly fast with larger files...

 

... but it works! It's cool though, I have some ideas for optimizing all that.

 

Like probably not using Lists to build up byte arrays lol. But it was fun and convenient to use at the time.

Share this post


Link to post
Share on other sites

I know it's been a couple of days, but I'll take a look at your TLK write up in a bit.

 

In the meantime, I've managed to code up the read/write to XML/write to GFF code for GFF files!

 

It works with the 3 I've tested so far :/, although, it's not incredibly fast with larger files...

 

... but it works! It's cool though, I have some ideas for optimizing all that.

 

Like probably not using Lists to build up byte arrays lol. But it was fun and convenient to use at the time.

 

I can imagine. :D

 

In Perl, I'd probably just use a hash and convert the info into the necessary bytes as I wrote it.

 

An example from the code I wrote to add a new TLK entry to a blank TLK file;

 

 

sub add_new_entry
{
    my $tlk_path = shift; ## the path to the directory, used for testing by the KSE's source code
    my $entry = shift; ## a reference to the hash holding the entry's info

## Open the dummy tlk file, in this case, creating it since it doesn't exist
    open(TLK, ">", "$tlk_path\\funny.tlk");

## Converting the reference into the actual hash
    my %entry1 = %{$entry};

## A cheap way of getting the bytes, since I have the code set to use bytes instead of characters for counting purposes...
## The length function does exactly what it does in KOTOR's scripting, finds the length of the string.
## In this case, I'm setting the size of the string in the hash to the number of bytes the string is long.
    $entry1{StringSize} = length($entry1{String});

## Begin writing Header info
    syswrite TLK, "TLK V3.0";
    syswrite TLK, pack('V', 0); ## For test purposes, the language id is 0
    syswrite TLK, pack('V', 1); ## For test purposes, there's only one string
    syswrite TLK, pack('V', 60); ## For test purposes, only one string(20 bytes in the header + 40 bytes of entry info = a 60-byte offset to the actual string

## The below loop is purely for testing purposes; it's how I found out that the function wasn't actually getting the hash...Whoops!:)
foreach my $key (sort keys %entry1)
{
     print "\$key is $key\n";
     print "The entry is: $entry1{$key}\n";
}

## Start writing the entry's info into the file, in order
    syswrite TLK, pack('V', $entry1{Flags});
    print "Flags are: " . $entry1{Flags} . ".\n"; ## test message to the console, making sure I had the right info
    syswrite TLK, $entry1{SoundRR};  ## Plain text for the sound file, appears unused/unnecessary because of the usage in .dlg files, but... 
    syswrite TLK, pack('V', "0"); ## Reportedly unused, so 0 is always safe
    syswrite TLK, pack('V', "0"); ## Reportedly unused, so 0 is always safe
    syswrite TLK, pack('V', 0);#$entry1{OffsetToString}); ## The offset to the string, as explained in my previous post
    syswrite TLK, pack('V', $entry1{StringSize}); ## From my cheap trick above.:)
    syswrite TLK, pack('V', "0"); ## Appears to be 0 for all entries in the TSL TLK, not sure about K1. Seems unused, just like the other sound properties...

    seek TLK, 60, 0; ## Go to the offset; not needed, but it's added security
#    syswrite TLK, pack('V', "Carth's a moron!"); ## A test case...:)
    syswrite TLK, $entry1{String}; ## Throw the entry in there!

    close TLK; ## Tidy up the kitchen before we leave
}

 

 

 

I used the hash and had each entry in the hash correspond to a single element in a TLK entry(sound resref, length, content,.etc). If I were to do so in a GFF, I'd use one hash, and populate it with smaller hashes for each "branch" one would see if using K-GFF. In Perl, one can have a hash of hashes or an array of arrays...

 

Even if you don't wish to learn Perl, or at least not yet, I encourage you to read these two links, or at least skim through to get what I'm saying about references and hashes of hashes...

 

https://docs.google.com/viewer?url=http://blob.perl.org/books/beginning-perl/3145_Chap07.pdf

 

https://docs.google.com/viewer?url=http://blob.perl.org/books/beginning-perl/3145_Chap03.pdf

Share this post


Link to post
Share on other sites

Update: Well, after implementing what I thought would be a faster alternative to Lists, I found out that the main cause of the terrible performance was with one particular chunk of terrible code. After fixing that, performance was pretty damn fast.

 

From my console output:

 

651 ms to read GFF

288 ms to write XML

190 ms to write GFF

 

I'll have to try a bigger file later.

Share this post


Link to post
Share on other sites

By the way, does anyone have any deeper understanding of .mdl format? I thought I had figured the important parts out, but obviously not, as the modified file crashes the game... (I opened the model in MDLOps and tried to hex insert a node, based on the values I saw there. Decompiled ascii file is perfectly identical to one that I made with... well, editing ascii file, that would work if it would compile properly, but alas, it does not.)

 

Sorry, enough of my ramblings. I'm just frustrated.

Share this post


Link to post
Share on other sites

By the way, does anyone have any deeper understanding of .mdl format? I thought I had figured the important parts out, but obviously not, as the modified file crashes the game... (I opened the model in MDLOps and tried to hex insert a node, based on the values I saw there. Decompiled ascii file is perfectly identical to one that I made with... well, editing ascii file, that would work if it would compile properly, but alas, it does not.)

 

Sorry, enough of my ramblings. I'm just frustrated.

 

Well, the most current info, while I buy myself time to dig into the guts of MDLOps' source code(it is Perl, so I'm on my own here),

 

The two sources of info on it I've found are by the maker of MDLOps himself:

http://cchargin.home.comcast.net/~cchargin/kotor/mdl_info.html

 

and some guy I don't know named Torlack(from 2002, so it's for NWN. You'll need to copy it and make an html document on your computer and then paste the info in there...):

https://github.com/xoreos/xoreos-tools/blob/master/docs/specs/torlack/binmdl.html

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.