• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Java] Attempt to create a generic MDX Chunk class.

Status
Not open for further replies.
Level 2
Joined
Aug 24, 2015
Messages
19
Hi !

I'm planning to add MDX support to my newborn lib and I would like to define a Chunk class that avoids code redundancy. My goal is abstraction and ease of use&reading, not performances (but when there is no big trade-off they are of course always welcome).
The Chunk must be able to parse any number of primitives or Marshalable objects. Marshalable is an interface with 2 read&write methods, I took it from Dr Super Good's WC3Utilities.
My implementation seems to work, but it looks a bit verbose and not very elegant. Any ideas to improve it ?

Chunk class :
https://github.com/Koward/jM2lib/blob/master/src/jm2lib/blizzard/common/types/Chunk.java

Example with MDX Version chunk :
https://github.com/Koward/jM2lib/blob/master/src/jm2lib/blizzard/wc3/mdx/VersionChunk.java

Here's another example using a nested class to define chunk's content :
Note : this one is a WoW chunk but the principle is the same
https://github.com/Koward/jM2lib/blob/master/src/jm2lib/blizzard/wow/legion/AFID.java

EDIT : I changed my classes a lot since I created this post and I don't think it's that verbose anymore, but help would always be good.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,191
MDX files are kind of tricky to deal with.

They are themselves one big object, the mdx object, which contains many smaller objects, the MDX chunks. Each chunk needs special I/O methods because it contains marshaled data which has to be unmarshaled (you cannot pass it around as a buffer of bytes as you cannot extract meaning from it then).

I would imagine an implementation would use two tiers of readers and writes. The first is the ObjectInput/Output which deals with the high level MDX object. Another type of ObjectInput/Output, a ChunkInput/Output is then used to unmarshal/marshal the chunks by the MDX I/O method.

Each chunk is technically an object. All the chunks are written in a stream. Hence it makes sense for them to be read and written using ObjectInput/Output. Since each chunk has a standardized header, it should be dealt with by the same piece of code. Additionally each chunk has a well defined size which it is important to respect. As such the chunk headers should be parsed by the ChunkStreams, which then wrap the actual stream in a way that when unmarshalling/marshalling the chunk objects you cannot violate the chunk size, and any attempt to do so (or if bytes are left over) flags up as a corrupted chunk.

This disconnect could be done by reading the chunk content into an array, and wrapping that array into a DataInputStream which is then used during the unmarshalling of the chunks. Attempts to read passed the end of file or if the end of file is not reached before unmarshalling ends throws an exception. This is not needed when marshalling chunks since one should be able to assume your marshalling implementation is correct (anything else is a bug) so corrupt or invalid chunks should never be produced.
 
Level 2
Joined
Aug 24, 2015
Messages
19
Well, since I created this post a lot in the code has changed, and I'm now pretty satisfied with my implementation : https://github.com/Koward/jM2lib/blob/master/src/jm2lib/blizzard/common/types/Chunk.java

For example, to make the bones chunk, you just create a class to define what a bone is and declare a Chunk<Bone> wherever you want. Easy.
The <T> can be a Marshallable (like a Bone class) or a primitive type and it will be read accordingly.
It works pretty well and chunk caracteristics cannot be violated.
The global MDX reading is :
Reading: read magic => switch case => unmarshall the identified chunk => repeat
Writing: write all non-null chunks
 
Status
Not open for further replies.
Top