MTrop Posted June 17, 2019 (edited) https://github.com/MTrop/DoomStruct Releases: https://github.com/MTrop/DoomStruct/releases Javadoc: https://mtrop.github.io/DoomStruct/javadoc/ What up, y'all? I made a Java library for reading/editing Doom stuff (again, again, again). What the heck is this? After quite a few false starts over the years at making this thing, my Java Library for parsing Doom Engine related stuff is finally at a place I don't hate. Here it is, ready to use for all 3 of the people out there in the Doom Community that write stuff in Java: https://github.com/MTrop/DoomStruct Why? There are several libraries out there for reading data from Doom in many different programming languages, but there isn't a decent one for Java. And by decent, I mean: Useful Documented Performant Efficient The goal with this library is to get end-users up-and-running quickly with little boilerplate code, and to ensure clarity within documentation and with written code, and future-proofing to a reasonable extent. What kind of features are there? You want features? I got ya features: Reads/edits WAD files. Reads PK3 files (zips). Full UDMF parsing/writing support. Reads/edits all Doom data structures in Doom, Hexen/ZDoom, or Strife formats. This includes textures, patches, lines, vertices, things, sectors, nodes, palettes, colormaps, text, PNG data, music data, sound data, flats, blockmaps, reject, and even ENDOOM-type VGA lumps. Supports PNGs with offset data (grAb). Reads/edits Boom-engine data lumps like ANIMATED and SWITCHES. Contains a utility class for converting Doom graphics to standard Java graphics structures, and vice-versa. Contains a utility class for converting Doom DMX sound data to other formats via the Java SPI, and vice-versa. Contains a utility class for managing texture sets without needing to care too much about Doom's nightmarish texture data setup. You Got Examples? Of course I do! Look at how easy this shit is! Open a WAD file (and close it): WadFile wad = new WadFile("doom2.wad"); wad.close(); Open DOOM2.WAD and read MAP01 into a Doom Map. WadFile wad = new WadFile("doom2.wad"); DoomMap map = MapUtils.createDoomMap(wad, "map01"); wad.close(); Open DOOM2.WAD and fetch all sectors in MAP29 with the BLOOD1 floor texture. WadFile wad = new WadFile("doom2.wad"); Set<DoomSector> set = wad.getDataAsList("sectors", "map29", DoomSector.class, DoomSector.LENGTH).stream() .filter((sector) -> sector.getFloorTexture().equals("BLOOD1")) .collect(Collectors.toSet()); wad.close(); Open DOOM.WAD and fetch all things in E1M1 that appear in multiplayer. WadFile wad = new WadFile("doom.wad"); Set<DoomThing> set = wad.getDataAsList("things", "e1m1", DoomThing.class, DoomThing.LENGTH).stream() .filter((thing) -> thing.isFlagSet(DoomThingFlags.NOT_SINGLEPLAYER)) .collect(Collectors.toSet()); wad.close(); Open HEXEN.WAD and fetch all things in MAP01 that have a special. WadFile wad = new WadFile("hexen.wad"); Set<HexenThing> set = wad.getDataAsList("things", "map01", HexenThing.class, HexenThing.LENGTH).stream() .filter((thing) -> thing.getSpecial() > 0) .collect(Collectors.toSet()); wad.close(); Open DOOM.WAD and fetch all maps that have less than 1000 linedefs. final WadFile wad = new WadFile("doom.wad"); Set<String> set = Arrays.asList(MapUtils.getAllMapHeaders(wad)).stream() .filter((header) -> wad.getEntry("linedefs", header).getSize() / DoomLinedef.LENGTH < 1000) .collect(Collectors.toSet()); wad.close(); Open SQUARE1.PK3, fetch maps/E1A1.WAD and read it into a UDMF Map. DoomPK3 pk3 = new DoomPK3("square1.pk3"); WadBuffer wad = pk3.getDataAsWadBuffer("maps/e1a1.wad"); UDMFMap map = wad.getTextDataAs("textmap", Charset.forName("UTF-8"), UDMFMap.class); pk3.close(); Open DOOM2.WAD, read DEMO2 and figure out how many tics that player 1 was pushing "fire". WadFile wad = new WadFile("doom2.wad"); Demo demo = wad.getDataAs("demo2", Demo.class); int tics = 0; for (int i = 0; i < demo.getTicCount(); i++) { tics += (demo.getTic(i).getAction() & Demo.Tic.ACTION_FIRE) != 0 ? 1 : 0; } wad.close(); Open DOOM.WAD and get MD5 hashes of each entry. WadFile wad = new WadFile("doom.wad"); byte[][] hashes = new byte[wad.getEntryCount()][]; int i = 0; for (WadEntry entry : wad) hashes[i++] = MessageDigest.getInstance("MD5").digest(wad.getData(entry)); wad.close(); Open DOOM2.WAD, fetch all TROO* (graphic) entries and export them as PNGs. WadFile wad = new WadFile("doom2.wad"); final Palette pal = wad.getDataAs("playpal", Palette.class); for (WadEntry entry : wad) { if (entry.getName().startsWith("TROO")) { Picture p = wad.getDataAs(entry, Picture.class); ImageIO.write(GraphicUtils.createImage(p, pal), "PNG", new File(entry.getName()+".png")); } } wad.close(); Open DOOM.WAD, fetch all DS* (audio) entries, upsample them to 22kHz (cosine interpolation), and export them as WAVs. WadFile wad = new WadFile("doom.wad"); for (WadEntry entry : wad) { if (entry.getName().startsWith("DS")) { DMXSound sound = wad.getDataAs(entry, DMXSound.class) .resample(InterpolationType.COSINE, DMXSound.SAMPLERATE_22KHZ); SoundUtils.writeSoundToFile(sound, AudioFileFormat.Type.WAVE, new File(entry.getName() + ".wav")); } } wad.close(); Open DOOM2.WAD, assemble a TextureSet, remove every texture that begins with R, and write it to a new WAD. WadFile wad = new WadFile("doom2.wad"); TextureSet textureSet = new TextureSet( wad.getDataAs("pnames", PatchNames.class), wad.getDataAs("texture1", DoomTextureList.class) ); wad.close(); Iterator<TextureSet.Texture> it = textureSet.iterator(); while (it.hasNext()) { TextureSet.Texture t = it.next(); if (t.getName().startsWith("R")) it.remove(); } PatchNames pout = new PatchNames(); DoomTextureList tout = new DoomTextureList(); textureSet.export(pout, tout); WadFile newwad = WadFile.createWadFile("new.wad"); newwad.addData("PNAMES", pout.toBytes()); newwad.addData("TEXTURE1", tout.toBytes()); newwad.close(); All that and more! LGPL licensed! No dependencies! Everything documented! Have fun! Eat your heart out, OMGIFOL! Edited January 7, 2020 by MTrop 23 Quote Share this post Link to post
regevamoj Posted December 31, 2019 Hello, MTrop! Congratulations! I think your library is very useful! I love it! Is it possible to use it to load and render a doom level? Just to try to make a game on my own using this library. Thanks in advance, Joe 1 Quote Share this post Link to post
MTrop Posted January 6, 2020 On 12/31/2019 at 7:12 AM, regevamoj said: Congratulations! I think your library is very useful! I love it! Is it possible to use it to load and render a doom level? Just to try to make a game on my own using this library. Load a level? Yes! Render a level? Unfortunately, no. This library does not contain anything out-of-the-box for rendering, but you can still read the data. 1 Quote Share this post Link to post
Tango Posted January 7, 2020 well shit, this is an amazing effort mate! 2 Quote Share this post Link to post
Xymph Posted May 7, 2021 (edited) I'm interested to try this, but know next to nothing about Java. I'm on (perhaps too old) Linux and have 'java' and 'ant' commands. Running "ant compile" and "ant jar" in the extracted .tgz directory errors out: BUILD FAILED .../DoomStruct/build-import.xml:133: Class not found: javac1.8 How would I go about running some of the above examples? Edited May 8, 2021 by Xymph 0 Quote Share this post Link to post
MTrop Posted May 14, 2021 Your version of Apache Ant is out of date. You'll need at least Java 8 and a version of Ant that is also compatible with it, like version 1.9.0 or better. 0 Quote Share this post Link to post
Xymph Posted June 4, 2021 (edited) On 5/14/2021 at 9:57 AM, MTrop said: Your version of Apache Ant is out of date. You'll need at least Java 8 and a version of Ant that is also compatible with it, like version 1.9.0 or better. That's what I suspected, but only now I got around to booting a modern distro (finishing the transition to which got stuck in something of a migration hell a while ago). With OpenJDK 11 and Ant 1.10, the ant commands in README.md work fine and I have a .jar file in build/jar/doomstruct-2021.06.04.160511817.jar But being a Java noob, I'm unsure how to try out any of the examples. I suspect one would need to put, e.g., the MD5 hashes example in a .java file and import the appropriate net.mtrop.doom package(s), perhaps compile it with javac while invoking the .jar, but it's all too unfamiliar to me. I realize this is beyond the scope of a library README, but some more guidance and a complete practical example would be helpful, and make this library more accessible to interested Java noobs such as myself. :) Edited June 4, 2021 by Xymph 0 Quote Share this post Link to post
MTrop Posted June 6, 2021 You'll have to add the JAR to your classpath somehow when you compile and/or run Java programs. You can write them using the help of an IDE like VSCode or Eclipse or IntelliJ (and add the JAR to your project classpath), or from the command line using the -cp switch when you use both javac and java or javaw. All of them can do that differently, but the idea and result is the same. 1 Quote Share this post Link to post
Nevander Posted June 6, 2021 Holy shit it's like SQL for Doom WADs. Pretty cool stuff. 0 Quote Share this post Link to post
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.