Skip to content

Commit

Permalink
Merge pull request #5 from inwc3/HeaderSupport
Browse files Browse the repository at this point in the history
Add map header support
  • Loading branch information
WaterKnight authored Mar 3, 2018
2 parents d0a470d + 1a715f3 commit 76eb357
Show file tree
Hide file tree
Showing 5 changed files with 348 additions and 37 deletions.
41 changes: 41 additions & 0 deletions src/main/java/net/moonlightflower/wc3libs/bin/app/MapFlag.java
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 src/main/java/net/moonlightflower/wc3libs/bin/app/MapHeader.java
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;
}
}
41 changes: 4 additions & 37 deletions src/main/java/net/moonlightflower/wc3libs/bin/app/W3I.java
Original file line number Diff line number Diff line change
Expand Up @@ -182,47 +182,14 @@ public Object toTXTVal() {
return null;
}

public static class Flag extends FlagsInt.Flag {
private final static List<Flag> _all = new ArrayList<>();

public final static Flag HIDE_MINIMAP = new Flag(0, "hideMinimap");
public final static Flag MODIFY_ALLY_PRIORITIES = new Flag(1, "modifyAllyPriorities");
public final static Flag MELEE_MAP = new Flag(2, "meleeMap");
public final static Flag INITIAL_MAP_SIZE_LARGE_NEVER_MODIFIED = new Flag(3, "initialMapSizeLargeNeverModified");
public final static Flag MASKED_AREAS_PARTIALLY_VISIBLE = new Flag(4, "maskedAreasPartiallyVisible");
public final static Flag FIXED_PLAYER_FORCE_SETTING = new Flag(5, "fixedPlayerForceSetting");
public final static Flag USE_CUSTOM_FORCES = new Flag(6, "useCustomForces");
public final static Flag USE_CUSTOM_TECHS = new Flag(7, "useCustomTechs");
public final static Flag USE_CUSTOM_ABILS = new Flag(8, "useCustomAbils");
public final static Flag USE_CUSTOM_UPGRADES = new Flag(9, "useCustomUpgrades");
public final static Flag MAP_PROPERTIES_WINDOW_OPENED_BEFORE = new Flag(10, "mapPrioritiesWindowOpenedBefore");
public final static Flag SHOW_WATER_WAVES_ON_CLIFF_SHORES = new Flag(11, "showWaterWavesOnCliffShores");
public final static Flag SHOW_WATER_WAVES_ON_ROLLING_SHORES = new Flag(12, "showWaterWavesOnRollingShores");
public final static Flag UNKNOWN = new Flag(13, "unknown");
public final static Flag UNKNOWN_B = new Flag(14, "unknownB");
public final static Flag UNKNOWN_C = new Flag(15, "unknownC");

public static Flag[] values() {
Flag[] flags = new Flag[_all.size()];

return _all.toArray(flags);
}

private Flag(int pos, String label) {
super(pos, label);

_all.add(this);
}
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder("");

Flag[] flags = Flag.values();
MapFlag[] flags = MapFlag.values();

if (flags.length > 0) {
for (Flag flag : flags) {
for (MapFlag flag : flags) {
if (sb.length() > 0) {
sb.append(" ");
}
Expand Down Expand Up @@ -253,11 +220,11 @@ public void setFlags(Flags val) {
_flags = val;
}

public boolean getFlag(Flags.Flag flag) {
public boolean getFlag(MapFlag flag) {
return _flags.containsFlag(flag);
}

public void setFlag(Flags.Flag flag, boolean val) {
public void setFlag(MapFlag flag, boolean val) {
_flags.setFlag(flag, val);
}

Expand Down
Loading

0 comments on commit 76eb357

Please sign in to comment.