| 12-27-2006, 11:30 PM | #1 | |
After taking a look at file specs for various Wc3 files, I decided to try messing with the war3map.doo file. After awhile of messing around, I finally made a program that is meant to open a .doo file, read the header and then the destructable data, and then change that into a series of CreateDestructableZ calls. (puts the code in a separate .j file). The code works for the first destructable in the file, up to the ID of the destructable (last field described in Pitzer Mike's sticky thread). I get a very large number which I'm not entirely sure of. And on the second line and lines thereafter, the outputted strings become even more and more messed-up. Here's the outputted text of the first few lines: Code:
call CreateDestructableZ('LTlt',-9088.00,-4160.00,292.63,270.00,1.,4)
call CreateDestructableZ('lt',0.00,0.00,-30050048.00,-1821037410910208.00,1.,0)
call CreateDestructableZ('',-4160.00,304.25,4.71,48.52,1.,-972292096)
call CreateDestructableZ('',159411300868160510000000000000.00,-30050102.00,-0.00,-0.00,1.,50700)
call CreateDestructableZ('',299.38,4.71,1.02,58.51,1.,-981336064)
call CreateDestructableZ('ÀÅ',-30050078.00,-33272618564671244000000000000000000000.00,-33271840227202704000000000000000000000.00,-1.#J,1.,-1073691258)
call CreateDestructableZ('',4.71,1.00,1.00,57.01,1.,1134419968)
call CreateDestructableZ('‚Å',-0.00,-0.00,-0.00,550648208909562900000000.00,1.,-874167408)
call CreateDestructableZ('',1.01,1.01,1.01,0.00,1.,1083624421)
call CreateDestructableZ('ƒCåË',-2.69,-2.69,9610575770217395300000.00,0.00,1.,-1070841706)And now here's my code:
Also, the file that was opened was a ROC war3map.doo file if that helps too. I guess I could also attach the program, as it is only 6kb. It's a command-line program, it takes 1 argument which should be the file to open. |
| 12-28-2006, 01:15 AM | #2 |
I would say that int in your compiler is not 4 bytes. Try outputting sizeof(int) or something like that, if it is 2 bytes use long int . -- I wonder though what's the benefit for using this tool? |
| 12-28-2006, 02:14 AM | #3 |
Your compiler is aligning the structure members to boundaries of their size. The int after the char sits two bytes too far. Read the documentation to figure out how to pack the members in. For gcc, it will look something like Code:
byte x __attribute__ ((packed)); The large numbers are what happens when you stuff a big number like 'a' into the exponent of a floating point number. I think you're also not inlining the structures properly. The data is all linear/consecutive as you read it in. The item table int is not a pointer-the item table actually sits in there N times. Although this is trees, so it's likely I'm misreading. Someone was asking the other day getting the height of a destructable, I assume recovering that and other information is the intent. You could also easily measure things like how much trees are slowing down your start up time. |
| 12-28-2006, 03:17 AM | #4 | |
Quote:
I checked all the sizes of int/byte/etc. and they're all the right sizes. With this tool, I'm really just trying to get some practice with binary file I/O (I've never done it before). Also, I want to find out just how much the trees slow loading time (however, doing it this way would increase the overall file size, oh well). I'm using Dev C++ which I believe uses the gcc compiler. Now, which members of the struct do I need to pack in? EDIT: With packing all the variables in the struct it worked... for about 80% of the file, then I get the same random stuff as before. (ROC format still). Also, here's the outputted file with the new packed version. |
| 12-28-2006, 03:59 AM | #5 |
Create a file that has just the bad tree, and figure out why the tree is bad. The output doesn't have the info I want to check, but it's clear that your reader is still ignorant in the tree-structure-isn't-fixed-size department. So check if all of the numbers that your reader depends on being zero really are zero. |
| 12-28-2006, 12:12 PM | #6 |
I actually never tried reading an struct directly from a file, and always used a wrapper for it. That's actually a necessary evil for some of the wc3 formats that are not that fixed |
| 12-28-2006, 01:35 PM | #7 |
I've found that the reader even bugs on a map full of only 1 type of tree. It will read a majority of them, but after awhile it will fail. I made a function to check the rawcodes of the trees to make sure that they are valid, and that part is working fine. I get that the tree structures aren't all the same size, but how do I find a way around this? Also, I'm currently cycling through the .doo file to see exactly when the reader messes up, I'll post my results when I'm finished. EDIT: The file works fine until after the 26th tree. The tree after the 26th is read in fine, until I found that the unique ID of the tree was 0. All the trees have an ID starting at 0 and counting up. After that 26th tree (ID = 25) the next ID was 0, and I'm guessing that was what threw off the rest of the file. Hopefully this information can help. Btw, if you're reading this PizterMike, I found a 4th flag that trees get. If the flag is 3, then the tree is outside camera bounds (from what I can tell). I'm still reading at the 'fixed size', because I'm not sure how I would do that differently. Here's a file of the information gathered into each Tree struct (RoC format) if it helps at all. Also, unless I read something wrong, the RoC format for trees is 42 bytes, unlike the TFT ones which I'll mess with later. |
| 12-28-2006, 04:04 PM | #8 |
Here is how I read .doo files in my map editor: Code:
Stream.Load(MapHandle, 'war3map.doo');
Stream.Position := 12;
Stream.Read(Count, 4);
TriggerData.Doodads.Capacity := Count;
for i := 0 to Count - 1 do
begin
New(D);
Stream.Read(D^, 38);
if MapData.IsExpansion then
begin
Stream.Read(D.ItemTable, 4);
Stream.Read(c, 4);
if c > 0 then
begin
D.ItemSets := TList.Create;
D.ItemSets.Capacity := c;
Dec(c);
for x := 0 to c do
begin
New(ItemSet);
D.ItemSets.Add(ItemSet);
ItemSet.Read(Stream);
end;
end;
end;
Stream.Read(D.IntID, 4);
New(D.Ext);
D.Ext.VariableType := 'desctructable';
D.Ext.Data := D;
D.Ext.UTF8Name := D.Id+' ('+IntToStr(D.IntID)+')';
D.Ext.IsArray := False;
D.Ext.Refers := 0;
D.Ext.JassName := 'gg_dest_'+D.Id+'_'+StringToIntEx(D.IntID);
TriggerData.Doodads.Add(D.Ext);
PlacedObjects.lstDebug.Items.Add(D.Ext.JassName);
end;
Stream.Free;
Dispose(Stream);and the records: Code:
PDoodad = ^TDoodad;
TDoodad = record
Id: array [0..3] of Char;
Variation: Integer;
X,Y,Z, Angle, sX, sY, sZ: Single;
Flags, Life:Byte;
ItemTable,IntID: Integer;
ItemSets: TList;
Ext:PVariable;
end;
PPObject = ^TPObject;
TPObject = record
Id:array [0..3] of Char;
ChanceToDropOrIndex:Integer;
end;
PItemSet = ^TItemSet;
TItemSet = record
Items: TList;
procedure Read(Stream: TReadFile);
end;
procedure TItemSet.Read(Stream: TReadFile);
var ItemSet:PPObject;
Count, i: Integer;
begin
Items := TList.Create;
Stream.Read(Count, 4);
Items.Capacity := Count;
Dec(Count);
for i := 0 to Count do
begin
New(ItemSet);
Items.Add(ItemSet);
Stream.Read(ItemSet.Id, 4);
Stream.Read(ItemSet.ChanceToDropOrIndex, 4);
end;
end; |
| 12-28-2006, 06:44 PM | #9 |
good luck converting that to C |
| 12-28-2006, 08:30 PM | #10 |
Could you comment your code so I can get an idea on what does what? I have a slight understanding, but I don't know what Delphi functions do what (and I'm a bit confused with some of the syntax). EDIT: Finally figured out what Zoxc's code did (scanned the file little by little, tree by tree), and it worked for me (RoC). Now I just need to finish the code up and this should be a working tool. |
| 12-29-2006, 01:03 PM | #11 |
Delphi ~= English so :D |
| 12-29-2006, 09:08 PM | #12 |
My program is working fine now, but according to a post inside Pitzer Mike's sticky thread, the .doo file contains both destructables and doodads. My program is meant to find any data that can be removed and created in the map script. However, doodads cannot be created in JASS (correct me if I'm wrong), so I need some way to tell if the data is a doodad or destructable. So basically, how would I go about doing this? |
| 12-31-2006, 11:07 AM | #13 |
Copy all destructable ids from Units\DestructableData.slk into a hashtable or binary search tree. When parsing the doo file just look it up. Custom ids for destructable start with B, so the first custom destructable is 'B000' whereas doodads start at 'D000'. So when you can't find the id in your lookup table and the id doesn't start with a B it's a doodad. Here's a list of exceptions, namely doodads that start with a B: BPtw BPca BObo BOct BOth BOtt BRcr BRfs BRrk BRrp BRrs BRsp BRgs BSar BSra BSr1 BSrc BSrv BSrw |
| 12-31-2006, 02:21 PM | #14 |
Okay, I've got all the IDs from the DestructableData.slk in a file. So as you're saying, all I need to do for custom ones is check if it starts with a B and isn't one of those IDs? |
| 12-31-2006, 03:52 PM | #15 |
Exactly. You just check if it starts with a B and is not in the list that i posted above. |
