GithubHelp home page GithubHelp logo

mtrop / doomstruct Goto Github PK

View Code? Open in Web Editor NEW
15.0 5.0 3.0 9.04 MB

Reads Doom Engine and Doom Engine-derivative structures.

Home Page: https://mtrop.github.io/DoomStruct/

License: GNU Lesser General Public License v2.1

Java 100.00%
doom java java-library doom-engine modding standalone-library

doomstruct's Introduction

Doom Struct

Copyright (c) 2015 - 2024 Matt Tropiano

Latest Release

NOTICE

This library is an offshoot/rewrite of Black Rook Software's Doom Struct Project, of which I have been granted rights to rewrite (the rights were granted to myself BY myself).

All deprecated classes from the origin project will not be in this one. All end users are encouraged to switch to this one, as this project will be actively maintained.

Required Libraries

NONE

Required Modules

java.desktop

Source

The master branch contains stable code (I hope). Until a release is cut, the master branch will be shifting.

Introduction

The purpose of the Doom Struct project is to provide a means to read/write data structures for the Doom Engine and similar derivatives.

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.

Implemented Features (so far)

  • 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.

In the Future...

  • Reading/converting PC Speaker effects.
  • Supporting additional BSP node types.
  • Stuff for drawing maps more easily (graphic-wise).
  • Better ENDOOM rendering options.
  • Turning this project into a Maven Repository Compatible one (currently it's Ant-compatible; it gets the job done).
  • Better Unit tests (or automatable ones).

Library

Contained in this release is a series of libraries that allow reading, writing, and extracting data in Doom Engine structures, found in the net.mtrop.doom packages.

Unless otherwise specified, assume that all methods are not thread-safe.

Examples

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 DOOM.WAD, fetch all map headers, and extract those maps' entries to separate WADs.

WadFile wad = new WadFile("doom.wad");
for (int headerIndex : MapUtils.getAllMapIndices(wad)) {
	String headerName = wad.getEntry(headerIndex).getName();
	WadBuffer.extract(wad, MapUtils.getMapEntries(wad, headerName))
			.writeToFile(new File(headerName + ".wad"));
}
wad.close();

Open DOOM2.WAD, extract MAP01 from it into a file called MAP01.WAD, and replace any wall texture that starts with TEKGREN to FIREBLU1.

WadFile wad = new WadFile("doom2.wad");
WadFile temp = WadFile.extract(new File("MAP01.WAD"), wad, MapUtils.getMapEntries(wad, "MAP01"));
temp.transformData("sidedefs", DoomSidedef.class, DoomSidedef.LENGTH, (sidedef, n) -> {
	if (sidedef.getTextureMiddle().startsWith("TEKGREN"))
		sidedef.setTextureMiddle("FIREBLU1");
});
temp.close();
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();

Open DOOM.WAD, get the first map of each episode and write it to a new WAD called OUT.wad and close both (with one statement!).

WadUtils.openWadAndExtractTo("DOOM.WAD", "OUT.wad", (wad)->
	WadUtils.withEntries(MapUtils.getMapEntries(wad, "E1M1"))
		.and(MapUtils.getMapEntries(wad, "E2M1"))
		.and(MapUtils.getMapEntries(wad, "E3M1"))
		.and(MapUtils.getMapEntries(wad, "E4M1"))
	.get()
);

Open DOOM2.WAD, create a new Wad called TEXTURES.wad and copy over only a few textures and flats (and also-close them):

try (WadFile source = new WadFile("DOOM2.WAD")) {
	try (WadFile target = WadFile.createWadFile("TEXTURES.wad")) {
		try (TextureCopier copier = TextureUtils.createTextureCopier(source, target)) {
			copier.copyFlat("FLOOR7_1");
			copier.copyFlat("CEIL5_2");
			copier.copyTexture("AASHITTY"); // first texture is "null" texture
			copier.copyTexture("SUPPORT3");
			copier.copyTexture("SUPPORT2");
			copier.copyTexture("BIGDOOR1");
			copier.copyTexture("BIGDOOR2");
			copier.copyTexture("BIGDOOR3");
			copier.copyTexture("BIGDOOR4");
			copier.copyTexture("BIGDOOR5");
		}
	}
}

Compiling with Ant

To compile this library with Apache Ant, type:

ant compile

To make Maven-compatible JARs of this library (placed in the build/jar directory), type:

ant jar

To make Javadocs (placed in the build/docs directory):

ant javadoc

To compile main and test code and run tests (if any):

ant test

To make Zip archives of everything (main src/resources, bin, javadocs, placed in the build/zip directory):

ant zip

To compile, JAR, test, and Zip up everything:

ant release

To clean up everything:

ant clean

Javadocs

Online Javadocs can be found at: https://mtrop.github.io/DoomStruct/javadoc/

Other

This program/library and the accompanying materials are made available under the terms of the GNU Lesser Public License v2.1 which accompanies this distribution, and is available at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html

A copy of the LGPL should have been included in this release (LICENSE.txt). If it was not, please contact me for a copy, or to notify me of a distribution that has not included it.

This contains code copied from Black Rook Base, under the terms of the MIT License (docs/LICENSE-BlackRookBase.txt).

Eat your heart out, OMGIFOL!

doomstruct's People

Contributors

derekmd avatar mtrop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

doomstruct's Issues

Add Maven Support and Add to Maven Central

This project should probably end up in Maven Central at some point, but I was lazy about it/didn't anticipate demand.

Stuff that needs to happen on my end:

  • Add the net.mtrop group to Sonatype/Maven Central (for this project and potentially others).
  • Convert the Ant build scripts to a POM.
  • Push to Maven as the doom artifact.

"Tall Patch" Graphics are Absolutely Broken

Most graphics in Doom editing do not always exceed 254 pixels in height. However, a lot of source ports use them, and DoomStruct unfortunately does not support this (in the form of horrible data corruption on write).

A fix will need to be made to support this.

NameUtils.java regex for valid entry names is too strict

Within NameUtils.java the lump names regex appears to be too strict. It's possible for patches to use the plus character ( + ) in their name, but doing so causes it to throw an error due to invalid characters. A live example of a WAD with this naming can be seen in Otex v1.1 (https://www.doomworld.com/idgames/graphics/otex_1_1)

I'm unsure what other characters may be missing from the regex, if any.

public static final Pattern ENTRY_NAME = Pattern.compile("[A-Z0-9\\[\\]\\-\\_\\^\\\\]{1,8}");

Support Extended DEMO Format

A new version byte was introduced a while back for extended Demo header versions and this will throw an exception in Demo.java if read.

This issue is for adding support or some other handling at some point.

Interface BinaryObject extending MapObject Makes No Sense

I don't know what I was thinking with this one. Remedying this will change object hierarchies, but since MapObject is just a constants interface, the damage would be minimal.

The planned correction would be to separate the two, and re-implement where necessary.

Legal WAD filenames are incomplete

java.lang.IllegalArgumentException: The provided entry name, "^BRICKS", is invalid. It must be up to 8 characters long; all characters must be A-Z (uppercase only), 0-9, and [ ] - _ plus the backslash \.

This is when trying to load and merge a valid WAD file in the wadmerge utility.

Map Detection is Incorrect (GL Lumps)

DoomStruct's map detection (MapUtils.isMapDataLump(String)) should also consider lumps like GL_MAP01 as part of a map, and not a separate one. It currently separates it out.

UDMF Readers Need an Incremental Iterator/Reader

Currently, the entirety of a UDMF structure is loaded into memory. This is terrible for maps that are incredibly large, and not all of the map data may be important.

In order to reduce the memory footprint, the UDMF Reader should also optionally employ a parse-and-apply method for reading and resetting a UDMF object's fields, like what can be done with the binary objects.

Palette.getColor() -> Color parameter outside of expected range

Hi, 1st I am new to Java and I hope I didn't screwed this up.
I actually want to use some sprites from doom.wad in libGDX as texture. Currently I read from Picture pixel by pixel and call Palette.getColor() which sometimes throws an error.

I tried to debug it but only got hold of java.awt.Color(int r, int g, int b) and for this index the r-component is -93.

(BTW eclipse just told me: Unable to install breakpoints in net.mtrop... due to missing line number attributes. Modify compiler options to generate line number attributes")

public class Test {
	public static void main(String[] args) {
		try {
			WadFile wad = new WadFile("doom.wad");

			final Palette pal = wad.getDataAs("playpal", Palette.class);

			var c2 = pal.getColor(67);
		} catch (Exception e) {
			System.out.println(e);
		}
	}
}

Add Capacity Control to WadBuffer

WadBuffer currently has no way for users to control how its internal buffer expands. This would create problems with large WADs and small heap allocations. FIX!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.