-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from inwc3/HeaderSupport
Add map header support
- Loading branch information
Showing
5 changed files
with
348 additions
and
37 deletions.
There are no files selected for viewing
41 changes: 41 additions & 0 deletions
41
src/main/java/net/moonlightflower/wc3libs/bin/app/MapFlag.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package net.moonlightflower.wc3libs.bin.app; | ||
|
||
import net.moonlightflower.wc3libs.dataTypes.app.FlagsInt; | ||
|
||
import javax.annotation.Nonnull; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class MapFlag extends FlagsInt.Flag { | ||
private final static List<MapFlag> _all = new ArrayList<>(); | ||
|
||
public final static MapFlag HIDE_MINIMAP = new MapFlag(0, "hideMinimap"); | ||
public final static MapFlag MODIFY_ALLY_PRIORITIES = new MapFlag(1, "modifyAllyPriorities"); | ||
public final static MapFlag MELEE_MAP = new MapFlag(2, "meleeMap"); | ||
public final static MapFlag INITIAL_MAP_SIZE_LARGE_NEVER_MODIFIED = new MapFlag(3, "initialMapSizeLargeNeverModified"); | ||
public final static MapFlag MASKED_AREAS_PARTIALLY_VISIBLE = new MapFlag(4, "maskedAreasPartiallyVisible"); | ||
public final static MapFlag FIXED_PLAYER_FORCE_SETTING = new MapFlag(5, "fixedPlayerForceSetting"); | ||
public final static MapFlag USE_CUSTOM_FORCES = new MapFlag(6, "useCustomForces"); | ||
public final static MapFlag USE_CUSTOM_TECHS = new MapFlag(7, "useCustomTechs"); | ||
public final static MapFlag USE_CUSTOM_ABILS = new MapFlag(8, "useCustomAbils"); | ||
public final static MapFlag USE_CUSTOM_UPGRADES = new MapFlag(9, "useCustomUpgrades"); | ||
public final static MapFlag MAP_PROPERTIES_WINDOW_OPENED_BEFORE = new MapFlag(10, "mapPrioritiesWindowOpenedBefore"); | ||
public final static MapFlag SHOW_WATER_WAVES_ON_CLIFF_SHORES = new MapFlag(11, "showWaterWavesOnCliffShores"); | ||
public final static MapFlag SHOW_WATER_WAVES_ON_ROLLING_SHORES = new MapFlag(12, "showWaterWavesOnRollingShores"); | ||
public final static MapFlag UNKNOWN = new MapFlag(13, "unknown"); | ||
public final static MapFlag UNKNOWN_B = new MapFlag(14, "unknownB"); | ||
public final static MapFlag UNKNOWN_C = new MapFlag(15, "unknownC"); | ||
|
||
@Nonnull | ||
public static MapFlag[] values() { | ||
MapFlag[] flags = new MapFlag[_all.size()]; | ||
|
||
return _all.toArray(flags); | ||
} | ||
|
||
private MapFlag(int pos, @Nonnull String label) { | ||
super(pos, label); | ||
|
||
_all.add(this); | ||
} | ||
} |
263 changes: 263 additions & 0 deletions
263
src/main/java/net/moonlightflower/wc3libs/bin/app/MapHeader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
package net.moonlightflower.wc3libs.bin.app; | ||
|
||
import net.moonlightflower.wc3libs.bin.*; | ||
import net.moonlightflower.wc3libs.misc.Id; | ||
|
||
import javax.annotation.Nonnull; | ||
import javax.annotation.Nullable; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
import java.nio.charset.StandardCharsets; | ||
|
||
public class MapHeader { | ||
public final static Id START_TOKEN = Id.valueOf("HM3W"); | ||
public final static long HEADER_BYTES_SIZE = 512; | ||
|
||
private int _unknown; | ||
|
||
public int getUnknown() { | ||
return _unknown; | ||
} | ||
|
||
public void setUnknown(int unknown) { | ||
_unknown = unknown; | ||
} | ||
|
||
private String _mapName; | ||
|
||
@Nullable | ||
private String getMapName() { | ||
return _mapName; | ||
} | ||
|
||
public void setMapName(@Nullable String mapName) { | ||
_mapName = mapName; | ||
} | ||
|
||
private int _flags; | ||
|
||
public int getFlags() { | ||
return _flags; | ||
} | ||
|
||
private int _maxPlayersCount; | ||
|
||
public int getMaxPlayersCount() { | ||
return _maxPlayersCount; | ||
} | ||
|
||
public void setMaxPlayersCount(int val) { | ||
_maxPlayersCount = val; | ||
} | ||
|
||
public void setFlags(int flags) { | ||
_flags = flags; | ||
} | ||
|
||
public static class EncodingFormat extends Format<EncodingFormat.Enum> { | ||
public enum Enum { | ||
AUTO, | ||
MAP_HEADER_0x0, | ||
} | ||
|
||
public final static EncodingFormat AUTO = new EncodingFormat(Enum.AUTO, null); | ||
public final static EncodingFormat MAP_HEADER_0x0 = new EncodingFormat(Enum.MAP_HEADER_0x0, 0xB); | ||
|
||
@Nullable | ||
public static EncodingFormat valueOf(@Nonnull Integer version) { | ||
return get(EncodingFormat.class, version); | ||
} | ||
|
||
private EncodingFormat(@Nonnull Enum enumVal, @Nullable Integer version) { | ||
super(enumVal, version); | ||
} | ||
} | ||
|
||
public static class Writer extends net.moonlightflower.wc3libs.bin.Writer<EncodingFormat> { | ||
@Override | ||
public EncodingFormat getAutoFormat() { | ||
return EncodingFormat.AUTO; | ||
} | ||
|
||
private MapHeader _mapHeader; | ||
|
||
private void write_0x0(@Nonnull Wc3BinOutputStream stream) throws BinStream.StreamException { | ||
long startPos = stream.getPos(); | ||
|
||
stream.writeId(START_TOKEN); | ||
|
||
stream.writeInt32(_mapHeader._unknown); | ||
|
||
stream.writeString(_mapHeader._mapName); | ||
|
||
stream.writeInt32(_mapHeader._flags); | ||
|
||
stream.writeInt32(_mapHeader._maxPlayersCount); | ||
|
||
long fillBytesSize = HEADER_BYTES_SIZE - stream.getPos() - startPos; | ||
|
||
if (fillBytesSize > 0) { | ||
do { | ||
int fillBytesSizeI = (int) fillBytesSize; | ||
|
||
stream.writeBytes(new byte[fillBytesSizeI]); | ||
|
||
fillBytesSize -= fillBytesSizeI; | ||
} while (fillBytesSize > 0); | ||
} | ||
} | ||
|
||
public void exec(@Nonnull MapHeader mapHeader) throws BinStream.StreamException { | ||
_mapHeader = mapHeader; | ||
|
||
switch (getFormat().toEnum()) { | ||
case AUTO: | ||
case MAP_HEADER_0x0: { | ||
write_0x0(getStream()); | ||
|
||
break; | ||
} | ||
} | ||
} | ||
|
||
public Writer(@Nonnull Wc3BinOutputStream stream) { | ||
super(stream); | ||
} | ||
} | ||
|
||
public static class Reader extends net.moonlightflower.wc3libs.bin.Reader<EncodingFormat> { | ||
public Reader(@Nonnull Wc3BinInputStream stream) { | ||
super(stream); | ||
} | ||
|
||
@Override | ||
public EncodingFormat getAutoFormat() { | ||
return EncodingFormat.AUTO; | ||
} | ||
|
||
@Nonnull | ||
public MapHeader exec() throws IOException { | ||
return exec(new MapHeader()); | ||
} | ||
|
||
private MapHeader _mapHeader; | ||
|
||
private MapHeader exec(@Nonnull MapHeader mapHeader) throws IOException { | ||
_mapHeader = mapHeader; | ||
|
||
read(getFormat()); | ||
|
||
return _mapHeader; | ||
} | ||
|
||
@Nonnull | ||
private MapHeader read(@Nonnull EncodingFormat format) throws IOException { | ||
switch (format.toEnum()) { | ||
case AUTO: { | ||
return read_auto(); | ||
} | ||
case MAP_HEADER_0x0: { | ||
return read_0x0(); | ||
} | ||
default: | ||
throw new EncodingFormat.InvalidFormatException(format); | ||
} | ||
} | ||
|
||
@Nonnull | ||
private MapHeader read_0x0() throws BinInputStream.StreamException { | ||
Wc3BinInputStream stream = getStream(); | ||
|
||
Id startToken = stream.readId("startToken"); | ||
|
||
_mapHeader._unknown = stream.readInt32("unknown"); | ||
_mapHeader._mapName = stream.readString("mapName"); | ||
_mapHeader._flags = stream.readInt32("flags"); | ||
_mapHeader._maxPlayersCount = stream.readInt32("maxPlayersCount"); | ||
|
||
return _mapHeader; | ||
} | ||
|
||
@Nonnull | ||
private MapHeader read_auto() throws IOException { | ||
return read_0x0(); | ||
} | ||
} | ||
|
||
public void writeToMapFile(@Nonnull File file) throws IOException { | ||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); | ||
|
||
Wc3BinOutputStream stream = new Wc3BinOutputStream(byteStream); | ||
|
||
Writer writer = new Writer(stream); | ||
|
||
writer.exec(this); | ||
|
||
stream.close(); | ||
|
||
byte[] bytes = byteStream.toByteArray(); | ||
|
||
RandomAccessFile fp = new RandomAccessFile(file, "r"); | ||
|
||
byte[] startTokenBytes = new byte[4]; | ||
|
||
fp.read(startTokenBytes, 0, startTokenBytes.length); | ||
|
||
fp.close(); | ||
|
||
Id startToken = Id.valueOf(new String(startTokenBytes, StandardCharsets.US_ASCII)); | ||
|
||
if (!startToken.equals(START_TOKEN)) { | ||
//start token is missing, assume that header must be missing, prepend new one | ||
fp = new RandomAccessFile(file, "rw"); | ||
|
||
long length = fp.length(); | ||
|
||
long endPos = length - 1; | ||
|
||
int maxChunkSize = Integer.MAX_VALUE / 2; | ||
|
||
int chunkSize = (int) Math.min(length, maxChunkSize); | ||
|
||
long startPos = endPos - chunkSize + 1; | ||
|
||
while (chunkSize > 0) { | ||
fp.seek(startPos); | ||
|
||
byte[] chunkBytes = new byte[chunkSize]; | ||
|
||
fp.read(chunkBytes, 0, chunkBytes.length); | ||
|
||
fp.write(chunkBytes); | ||
|
||
length = startPos; | ||
|
||
chunkSize = (int) Math.min(length, maxChunkSize); | ||
|
||
endPos = startPos - 1; | ||
|
||
startPos = endPos - chunkSize + 1; | ||
} | ||
} else { | ||
fp = new RandomAccessFile(file, "rw"); | ||
} | ||
|
||
fp.write(bytes); | ||
|
||
fp.close(); | ||
} | ||
|
||
public static MapHeader ofFile(@Nonnull File file) throws IOException { | ||
Wc3BinInputStream stream = new Wc3BinInputStream(file); | ||
|
||
Reader reader = new Reader(stream); | ||
|
||
MapHeader mapHeader = reader.exec(); | ||
|
||
stream.close(); | ||
|
||
return mapHeader; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.