Update with simple status bar

This commit is contained in:
Retera 2020-11-13 23:12:39 -05:00
parent 632576323c
commit 2b3e5bdf4a
12 changed files with 2888 additions and 2673 deletions

View File

@ -130,7 +130,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
this.viewer.enableAudio(); this.viewer.enableAudio();
} }
try { try {
this.viewer.loadMap(this.warsmashIni.get("Map").getField("FilePath")); this.viewer.loadMap(this.warsmashIni.get("Map").getField("FilePath"), 0);
} }
catch (final IOException e) { catch (final IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -222,7 +222,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"), cameraRatesElement.getFieldFloatValue("FOV"), cameraRatesElement.getFieldFloatValue("Rotation"),
cameraRatesElement.getFieldFloatValue("Distance"), cameraRatesElement.getFieldFloatValue("Forward"), cameraRatesElement.getFieldFloatValue("Distance"), cameraRatesElement.getFieldFloatValue("Forward"),
cameraRatesElement.getFieldFloatValue("Strafe")); cameraRatesElement.getFieldFloatValue("Strafe"));
this.meleeUI = new MeleeUI(this.codebase, this.uiViewport, fontGenerator, this.uiScene, portraitScene, this.meleeUI = new MeleeUI(this.viewer.mapMpq, this.uiViewport, fontGenerator, this.uiScene, portraitScene,
cameraPresets, cameraRates, this.viewer, new RootFrameListener() { cameraPresets, cameraRates, this.viewer, new RootFrameListener() {
@Override @Override
public void onCreate(final GameUI rootFrame) { public void onCreate(final GameUI rootFrame) {

View File

@ -30,6 +30,7 @@ import com.etheller.warsmash.parsers.fdf.frames.AbstractUIFrame;
import com.etheller.warsmash.parsers.fdf.frames.FilterModeTextureFrame; import com.etheller.warsmash.parsers.fdf.frames.FilterModeTextureFrame;
import com.etheller.warsmash.parsers.fdf.frames.SetPoint; import com.etheller.warsmash.parsers.fdf.frames.SetPoint;
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame; import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
import com.etheller.warsmash.parsers.fdf.frames.SimpleStatusBarFrame;
import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame; import com.etheller.warsmash.parsers.fdf.frames.SpriteFrame;
import com.etheller.warsmash.parsers.fdf.frames.StringFrame; import com.etheller.warsmash.parsers.fdf.frames.StringFrame;
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame; import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
@ -104,16 +105,31 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
catch (final IOException e) { catch (final IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
// TODO eliminate duplicate read of skin TXT!!
if (dataSource.has("war3mapSkin.txt")) {
try (InputStream miscDataTxtStream = dataSource.getResourceAsStream("war3mapSkin.txt")) {
skinsTable.readTXT(miscDataTxtStream, true);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
// final Element main = skinsTable.get("Main"); // final Element main = skinsTable.get("Main");
// final String skinsField = main.getField("Skins"); // final String skinsField = main.getField("Skins");
// final String[] skins = skinsField.split(","); // final String[] skins = skinsField.split(",");
final Element defaultSkin = skinsTable.get("Default"); final Element defaultSkin = skinsTable.get("Default");
final Element userSkin = skinsTable.get(skin); final Element userSkin = skinsTable.get(skin);
final Element customSkin = skinsTable.get("CustomSkin");
for (final String key : defaultSkin.keySet()) { for (final String key : defaultSkin.keySet()) {
if (!userSkin.hasField(key)) { if (!userSkin.hasField(key)) {
userSkin.setField(key, defaultSkin.getField(key)); userSkin.setField(key, defaultSkin.getField(key));
} }
} }
if (customSkin != null) {
for (final String key : customSkin.keySet()) {
userSkin.setField(key, customSkin.getField(key));
}
}
return userSkin; return userSkin;
} }
@ -125,16 +141,31 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
catch (final IOException e) { catch (final IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
// TODO eliminate duplicate read of skin TXT!!
if (dataSource.has("war3mapSkin.txt")) {
try (InputStream miscDataTxtStream = dataSource.getResourceAsStream("war3mapSkin.txt")) {
skinsTable.readTXT(miscDataTxtStream, true);
}
catch (final IOException e) {
throw new RuntimeException(e);
}
}
final Element main = skinsTable.get("Main"); final Element main = skinsTable.get("Main");
final String skinsField = main.getField("Skins"); final String skinsField = main.getField("Skins");
final String[] skins = skinsField.split(","); final String[] skins = skinsField.split(",");
final Element defaultSkin = skinsTable.get("Default"); final Element defaultSkin = skinsTable.get("Default");
final Element userSkin = skinsTable.get(skins[skinIndex]); final Element userSkin = skinsTable.get(skins[skinIndex]);
final Element customSkin = skinsTable.get("CustomSkin");
for (final String key : defaultSkin.keySet()) { for (final String key : defaultSkin.keySet()) {
if (!userSkin.hasField(key)) { if (!userSkin.hasField(key)) {
userSkin.setField(key, defaultSkin.getField(key)); userSkin.setField(key, defaultSkin.getField(key));
} }
} }
if (customSkin != null) {
for (final String key : customSkin.keySet()) {
userSkin.setField(key, customSkin.getField(key));
}
}
return userSkin; return userSkin;
} }
@ -252,6 +283,17 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
} }
inflatedFrame = simpleFrame; inflatedFrame = simpleFrame;
} }
else if ("SIMPLESTATUSBAR".equals(frameDefinition.getFrameType())) {
final boolean decorateFileNames = frameDefinition.has("DecorateFileNames")
|| ((parentDefinitionIfAvailable != null)
&& parentDefinitionIfAvailable.has("DecorateFileNames"));
final SimpleStatusBarFrame simpleStatusBarFrame = new SimpleStatusBarFrame(frameDefinition.getName(),
parent, decorateFileNames);
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
simpleStatusBarFrame.add(inflate(childDefinition, simpleStatusBarFrame, frameDefinition));
}
inflatedFrame = simpleStatusBarFrame;
}
else if ("SPRITE".equals(frameDefinition.getFrameType())) { else if ("SPRITE".equals(frameDefinition.getFrameType())) {
final SpriteFrame spriteFrame = new SpriteFrame(frameDefinition.getName(), parent, this.uiScene, final SpriteFrame spriteFrame = new SpriteFrame(frameDefinition.getName(), parent, this.uiScene,
viewport2); viewport2);
@ -448,6 +490,10 @@ public final class GameUI extends AbstractUIFrame implements UIFrame {
} }
public Scene getUiScene() { public Scene getUiScene() {
return uiScene; return this.uiScene;
}
public FrameTemplateEnvironment getTemplates() {
return this.templates;
} }
} }

View File

@ -0,0 +1,39 @@
package com.etheller.warsmash.parsers.fdf.frames;
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
public class SimpleStatusBarFrame extends AbstractUIFrame {
private final boolean decorateFileNames;
private final TextureFrame barFrame;
private final TextureFrame borderFrame;
public SimpleStatusBarFrame(final String name, final UIFrame parent, final boolean decorateFileNames) {
super(name, parent);
this.decorateFileNames = decorateFileNames;
this.barFrame = new TextureFrame(name + "Bar", this, decorateFileNames, new Vector4Definition(0, 1, 0, 1));
this.borderFrame = new TextureFrame(name + "Border", this, decorateFileNames,
new Vector4Definition(0, 1, 0, 1));
this.borderFrame.setSetAllPoints(true);
this.barFrame.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this, FramePoint.TOPLEFT, 0, 0));
this.barFrame.addSetPoint(new SetPoint(FramePoint.BOTTOMLEFT, this, FramePoint.BOTTOMLEFT, 0, 0));
add(this.barFrame);
add(this.borderFrame);
}
public boolean isDecorateFileNames() {
return this.decorateFileNames;
}
public void setValue(final float value) {
this.barFrame.setWidth(this.renderBounds.width * value);
}
public TextureFrame getBarFrame() {
return this.barFrame;
}
public TextureFrame getBorderFrame() {
return this.borderFrame;
}
}

View File

@ -9,9 +9,9 @@ public class AudioBufferSource {
} }
public void start(final int value) { public void start(final int value, final float volume, final float pitch) {
if (this.buffer != null) { if (this.buffer != null) {
this.buffer.play(1); this.buffer.play(volume, pitch, 0.0f);
} }
} }
} }

View File

@ -22,328 +22,348 @@ import com.etheller.warsmash.viewer5.Texture;
import com.etheller.warsmash.viewer5.handlers.EmitterObject; import com.etheller.warsmash.viewer5.handlers.EmitterObject;
public class EventObjectEmitterObject extends GenericObject implements EmitterObject { public class EventObjectEmitterObject extends GenericObject implements EmitterObject {
private static final class LoadGenericSoundCallback implements LoadGenericCallback { private static final class LoadGenericSoundCallback implements LoadGenericCallback {
private final String filename; private final String filename;
public LoadGenericSoundCallback(final String filename) { public LoadGenericSoundCallback(final String filename) {
this.filename = filename; this.filename = filename;
} }
@Override @Override
public Object call(final InputStream data) { public Object call(final InputStream data) {
final FileHandle temp = new FileHandle(this.filename) { final FileHandle temp = new FileHandle(this.filename) {
@Override @Override
public InputStream read() { public InputStream read() {
return data; return data;
} }
; ;
}; };
if (data != null) { if (data != null) {
return Gdx.audio.newSound(temp); return Gdx.audio.newSound(temp);
} else { }
System.err.println("Warning: missing sound file: " + this.filename); else {
return null; System.err.println("Warning: missing sound file: " + this.filename);
} return null;
} }
} }
}
private static final LoadGenericCallback mappedDataCallback = new LoadGenericCallback() { private static final LoadGenericCallback mappedDataCallback = new LoadGenericCallback() {
@Override @Override
public Object call(final InputStream data) { public Object call(final InputStream data) {
final StringBuilder stringBuilder = new StringBuilder(); final StringBuilder stringBuilder = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(data, "utf-8"))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(data, "utf-8"))) {
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
stringBuilder.append(line); stringBuilder.append(line);
stringBuilder.append("\n"); stringBuilder.append("\n");
} }
} catch (final UnsupportedEncodingException e) { }
throw new RuntimeException(e); catch (final UnsupportedEncodingException e) {
} catch (final IOException e) { throw new RuntimeException(e);
throw new RuntimeException(e); }
} catch (final IOException e) {
return new MappedData(stringBuilder.toString()); throw new RuntimeException(e);
} }
}; return new MappedData(stringBuilder.toString());
}
};
private int geometryEmitterType = -1; private int geometryEmitterType = -1;
public final String type; public final String type;
private final String id; private final String id;
public final long[] keyFrames; public final long[] keyFrames;
private long globalSequence = -1; private long globalSequence = -1;
private final long[] defval = {1}; private final long[] defval = { 1 };
public MdxModel internalModel; public MdxModel internalModel;
public Texture internalTexture; public Texture internalTexture;
public float[][] colors; public float[][] colors;
public float[] intervalTimes; public float[] intervalTimes;
public float scale; public float scale;
public int columns; public int columns;
public int rows; public int rows;
public float lifeSpan; public float lifeSpan;
public int blendSrc; public int blendSrc;
public int blendDst; public int blendDst;
public float[][] intervals; public float[][] intervals;
public float distanceCutoff; public float distanceCutoff;
private float maxDistance; private float maxDistance;
public float minDistance; public float minDistance;
private float pitch; public float pitch;
private float pitchVariance; public float pitchVariance;
private float volume; public float volume;
public List<Sound> decodedBuffers = new ArrayList<>(); public List<Sound> decodedBuffers = new ArrayList<>();
/** /**
* If this is an SPL/UBR emitter object, ok will be set to true if the tables * If this is an SPL/UBR emitter object, ok will be set to true if the tables
* are loaded. * are loaded.
* <p> * <p>
* This is because, like the other geometry emitters, it is fine to use them * This is because, like the other geometry emitters, it is fine to use them
* even if the textures don't load. * even if the textures don't load.
* <p> * <p>
* The particles will simply be black. * The particles will simply be black.
*/ */
private boolean ok = false; private boolean ok = false;
public EventObjectEmitterObject(final MdxModel model, public EventObjectEmitterObject(final MdxModel model,
final com.etheller.warsmash.parsers.mdlx.EventObject eventObject, final int index) { final com.etheller.warsmash.parsers.mdlx.EventObject eventObject, final int index) {
super(model, eventObject, index); super(model, eventObject, index);
final ModelViewer viewer = model.viewer; final ModelViewer viewer = model.viewer;
final String name = eventObject.getName(); final String name = eventObject.getName();
String type = name.substring(0, 3); String type = name.substring(0, 3);
final String id = name.substring(4); final String id = name.substring(4);
// Same thing // Same thing
if ("FPT".equals(type)) { if ("FPT".equals(type)) {
type = "SPL"; type = "SPL";
} }
if ("SPL".equals(type)) { if ("SPL".equals(type)) {
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPLAT; this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPLAT;
} else if ("UBR".equals(type)) { }
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_UBERSPLAT; else if ("UBR".equals(type)) {
} else if ("SPN".equals(type)) { this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_UBERSPLAT;
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPN; }
} else if ("SPN".equals(type)) {
this.geometryEmitterType = GeometryEmitterFuncs.EMITTER_SPN;
}
this.type = type; this.type = type;
this.id = id; this.id = id;
this.keyFrames = eventObject.getKeyFrames(); this.keyFrames = eventObject.getKeyFrames();
final int globalSequenceId = eventObject.getGlobalSequenceId(); final int globalSequenceId = eventObject.getGlobalSequenceId();
if (globalSequenceId != -1) { if (globalSequenceId != -1) {
this.globalSequence = model.getGlobalSequences().get(globalSequenceId); this.globalSequence = model.getGlobalSequences().get(globalSequenceId);
} }
final List<GenericResource> tables = new ArrayList<>(); final List<GenericResource> tables = new ArrayList<>();
final PathSolver pathSolver = model.pathSolver; final PathSolver pathSolver = model.pathSolver;
final Object solverParams = model.solverParams; final Object solverParams = model.solverParams;
if ("SPN".equals(type)) { if ("SPN".equals(type)) {
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SpawnData.slk", solverParams).finalSrc, tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SpawnData.slk", solverParams).finalSrc,
FetchDataTypeName.SLK, mappedDataCallback)); FetchDataTypeName.SLK, mappedDataCallback));
} else if ("SPL".equals(type)) { }
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SplatData.slk", solverParams).finalSrc, else if ("SPL".equals(type)) {
FetchDataTypeName.SLK, mappedDataCallback)); tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\SplatData.slk", solverParams).finalSrc,
} else if ("UBR".equals(type)) { FetchDataTypeName.SLK, mappedDataCallback));
tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\UberSplatData.slk", solverParams).finalSrc, }
FetchDataTypeName.SLK, mappedDataCallback)); else if ("UBR".equals(type)) {
} else if ("SND".equals(type)) { tables.add(viewer.loadGeneric(pathSolver.solve("Splats\\UberSplatData.slk", solverParams).finalSrc,
if (!model.reforged) { FetchDataTypeName.SLK, mappedDataCallback));
tables.add(viewer.loadGeneric(pathSolver.solve("UI\\SoundInfo\\AnimLookups.slk", solverParams).finalSrc, }
FetchDataTypeName.SLK, mappedDataCallback)); else if ("SND".equals(type)) {
} if (!model.reforged) {
tables.add(viewer.loadGeneric(pathSolver.solve("UI\\SoundInfo\\AnimSounds.slk", solverParams).finalSrc, tables.add(viewer.loadGeneric(pathSolver.solve("UI\\SoundInfo\\AnimLookups.slk", solverParams).finalSrc,
FetchDataTypeName.SLK, mappedDataCallback)); FetchDataTypeName.SLK, mappedDataCallback));
} else { }
// Units\Critters\BlackStagMale\BlackStagMale.mdx has an event object named tables.add(viewer.loadGeneric(pathSolver.solve("UI\\SoundInfo\\AnimSounds.slk", solverParams).finalSrc,
// "Point01". FetchDataTypeName.SLK, mappedDataCallback));
return; }
} else {
// Units\Critters\BlackStagMale\BlackStagMale.mdx has an event object named
// "Point01".
return;
}
// TODO I am scrapping some async stuff with promises here from the JS and // TODO I am scrapping some async stuff with promises here from the JS and
// calling load // calling load
this.load(tables); this.load(tables);
} }
private float getFloat(final MappedDataRow row, final String name) { private float getFloat(final MappedDataRow row, final String name) {
final Float x = (Float) row.get(name); final Float x = (Float) row.get(name);
if (x == null) { if (x == null) {
return Float.NaN; return Float.NaN;
} else { }
return x.floatValue(); else {
} return x.floatValue();
} }
}
private int getInt(final MappedDataRow row, final String name) { private int getInt(final MappedDataRow row, final String name) {
return getInt(row, name, Integer.MIN_VALUE); return getInt(row, name, Integer.MIN_VALUE);
} }
private int getInt(final MappedDataRow row, final String name, final int defaultValue) { private int getInt(final MappedDataRow row, final String name, final int defaultValue) {
final Number x = (Number) row.get(name); final Number x = (Number) row.get(name);
if (x == null) { if (x == null) {
return defaultValue; return defaultValue;
} else { }
return x.intValue(); else {
} return x.intValue();
} }
}
private void load(final List<GenericResource> tables) { private void load(final List<GenericResource> tables) {
final MappedData firstTable = (MappedData) tables.get(0).data; final MappedData firstTable = (MappedData) tables.get(0).data;
if (firstTable == null) { if (firstTable == null) {
return; return;
} }
final MappedDataRow row = firstTable.getRow(this.id.trim()); final MappedDataRow row = firstTable.getRow(this.id.trim());
if (row != null) { if (row != null) {
final MdxModel model = this.model; final MdxModel model = this.model;
final ModelViewer viewer = model.viewer; final ModelViewer viewer = model.viewer;
final PathSolver pathSolver = model.pathSolver; final PathSolver pathSolver = model.pathSolver;
if ("SPN".equals(this.type)) { if ("SPN".equals(this.type)) {
this.internalModel = (MdxModel) viewer.load(((String) row.get("Model")).replace(".mdl", ".mdx"), this.internalModel = (MdxModel) viewer.load(((String) row.get("Model")).replace(".mdl", ".mdx"),
pathSolver, model.solverParams); pathSolver, model.solverParams);
if (this.internalModel != null) { if (this.internalModel != null) {
// TODO javascript async code removed here // TODO javascript async code removed here
// this.internalModel.whenLoaded((model) => this.ok = model.ok) // this.internalModel.whenLoaded((model) => this.ok = model.ok)
this.ok = this.internalModel.ok; this.ok = this.internalModel.ok;
} }
} else if ("SPL".equals(this.type) || "UBR".equals(this.type)) { }
final String texturesExt = model.reforged ? ".dds" : ".blp"; else if ("SPL".equals(this.type) || "UBR".equals(this.type)) {
final String texturesExt = model.reforged ? ".dds" : ".blp";
this.internalTexture = (Texture) viewer.load( this.internalTexture = (Texture) viewer.load(
"ReplaceableTextures\\Splats\\" + row.get("file") + texturesExt, pathSolver, "ReplaceableTextures\\Splats\\" + row.get("file") + texturesExt, pathSolver,
model.solverParams); model.solverParams);
this.scale = getFloat(row, "Scale"); this.scale = getFloat(row, "Scale");
this.colors = new float[][]{ this.colors = new float[][] {
{getFloat(row, "StartR"), getFloat(row, "StartG"), getFloat(row, "StartB"), { getFloat(row, "StartR"), getFloat(row, "StartG"), getFloat(row, "StartB"),
getFloat(row, "StartA")}, getFloat(row, "StartA") },
{getFloat(row, "MiddleR"), getFloat(row, "MiddleG"), getFloat(row, "MiddleB"), { getFloat(row, "MiddleR"), getFloat(row, "MiddleG"), getFloat(row, "MiddleB"),
getFloat(row, "MiddleA")}, getFloat(row, "MiddleA") },
{getFloat(row, "EndR"), getFloat(row, "EndG"), getFloat(row, "EndB"), { getFloat(row, "EndR"), getFloat(row, "EndG"), getFloat(row, "EndB"),
getFloat(row, "EndA")}}; getFloat(row, "EndA") } };
if ("SPL".equals(this.type)) { if ("SPL".equals(this.type)) {
this.columns = getInt(row, "Columns"); this.columns = getInt(row, "Columns");
this.rows = getInt(row, "Rows"); this.rows = getInt(row, "Rows");
this.lifeSpan = getFloat(row, "Lifespan") + getFloat(row, "Decay"); this.lifeSpan = getFloat(row, "Lifespan") + getFloat(row, "Decay");
this.intervalTimes = new float[]{getFloat(row, "Lifespan"), getFloat(row, "Decay")}; this.intervalTimes = new float[] { getFloat(row, "Lifespan"), getFloat(row, "Decay") };
this.intervals = new float[][]{ this.intervals = new float[][] {
{getFloat(row, "UVLifespanStart"), getFloat(row, "UVLifespanEnd"), { getFloat(row, "UVLifespanStart"), getFloat(row, "UVLifespanEnd"),
getFloat(row, "LifespanRepeat")}, getFloat(row, "LifespanRepeat") },
{getFloat(row, "UVDecayStart"), getFloat(row, "UVDecayEnd"), { getFloat(row, "UVDecayStart"), getFloat(row, "UVDecayEnd"),
getFloat(row, "DecayRepeat")},}; getFloat(row, "DecayRepeat") }, };
} else { }
this.columns = 1; else {
this.rows = 1; this.columns = 1;
this.lifeSpan = getFloat(row, "BirthTime") + getFloat(row, "PauseTime") + getFloat(row, "Decay"); this.rows = 1;
this.intervalTimes = new float[]{getFloat(row, "BirthTime"), getFloat(row, "PauseTime"), this.lifeSpan = getFloat(row, "BirthTime") + getFloat(row, "PauseTime") + getFloat(row, "Decay");
getFloat(row, "Decay")}; this.intervalTimes = new float[] { getFloat(row, "BirthTime"), getFloat(row, "PauseTime"),
} getFloat(row, "Decay") };
}
final int[] blendModes = FilterMode final int[] blendModes = FilterMode
.emitterFilterMode(com.etheller.warsmash.parsers.mdlx.ParticleEmitter2.FilterMode .emitterFilterMode(com.etheller.warsmash.parsers.mdlx.ParticleEmitter2.FilterMode
.fromId(getInt(row, "BlendMode"))); .fromId(getInt(row, "BlendMode")));
this.blendSrc = blendModes[0]; this.blendSrc = blendModes[0];
this.blendDst = blendModes[1]; this.blendDst = blendModes[1];
this.ok = true; this.ok = true;
} else if ("SND".equals(this.type)) { }
// Only load sounds if audio is enabled. else if ("SND".equals(this.type)) {
// This is mostly to save on bandwidth and loading time, especially when loading // Only load sounds if audio is enabled.
// full maps. // This is mostly to save on bandwidth and loading time, especially when loading
if (viewer.audioEnabled) { // full maps.
final MappedData animSounds = (MappedData) tables.get(1).data; if (viewer.audioEnabled) {
final MappedData animSounds = (MappedData) tables.get(1).data;
final MappedDataRow animSoundsRow = animSounds.getRow((String) row.get("SoundLabel")); final MappedDataRow animSoundsRow = animSounds.getRow((String) row.get("SoundLabel"));
if (animSoundsRow != null) { if (animSoundsRow != null) {
this.distanceCutoff = getFloat(animSoundsRow, "DistanceCutoff"); this.distanceCutoff = getFloat(animSoundsRow, "DistanceCutoff");
this.maxDistance = getFloat(animSoundsRow, "MaxDistance"); this.maxDistance = getFloat(animSoundsRow, "MaxDistance");
this.minDistance = getFloat(animSoundsRow, "MinDistance"); this.minDistance = getFloat(animSoundsRow, "MinDistance");
this.pitch = getFloat(animSoundsRow, "Pitch"); this.pitch = getFloat(animSoundsRow, "Pitch");
this.pitchVariance = getFloat(animSoundsRow, "PitchVariance"); this.pitchVariance = getFloat(animSoundsRow, "PitchVariance");
this.volume = getFloat(animSoundsRow, "Volume"); this.volume = getFloat(animSoundsRow, "Volume") / 127f;
final String[] fileNames = ((String) animSoundsRow.get("FileNames")).split(","); final String[] fileNames = ((String) animSoundsRow.get("FileNames")).split(",");
final GenericResource[] resources = new GenericResource[fileNames.length]; final GenericResource[] resources = new GenericResource[fileNames.length];
for (int i = 0; i < fileNames.length; i++) { for (int i = 0; i < fileNames.length; i++) {
final String path = ((String) animSoundsRow.get("DirectoryBase")) + fileNames[i]; final String path = ((String) animSoundsRow.get("DirectoryBase")) + fileNames[i];
try { try {
final String pathString = pathSolver.solve(path, model.solverParams).finalSrc; final String pathString = pathSolver.solve(path, model.solverParams).finalSrc;
final GenericResource genericResource = viewer.loadGeneric(pathString, final GenericResource genericResource = viewer.loadGeneric(pathString,
FetchDataTypeName.ARRAY_BUFFER, new LoadGenericSoundCallback(pathString)); FetchDataTypeName.ARRAY_BUFFER, new LoadGenericSoundCallback(pathString));
if (genericResource == null) { if (genericResource == null) {
System.err.println("Null sound: " + fileNames[i]); System.err.println("Null sound: " + fileNames[i]);
} }
resources[i] = genericResource; resources[i] = genericResource;
} catch (final Exception exc) { }
System.err.println("Failed to load sound: " + path); catch (final Exception exc) {
exc.printStackTrace(); System.err.println("Failed to load sound: " + path);
} exc.printStackTrace();
} }
}
// TODO JS async removed // TODO JS async removed
for (final GenericResource resource : resources) { for (final GenericResource resource : resources) {
if (resource != null) { if (resource != null) {
this.decodedBuffers.add((Sound) resource.data); this.decodedBuffers.add((Sound) resource.data);
} }
} }
this.ok = true; this.ok = true;
} }
} }
} else { }
System.err.println("Unknown event object type: " + this.type + this.id); else {
} System.err.println("Unknown event object type: " + this.type + this.id);
} else { }
System.err.println("Unknown event object ID: " + this.type + this.id); }
} else {
} System.err.println("Unknown event object ID: " + this.type + this.id);
}
}
public int getValue(final long[] out, final MdxComplexInstance instance) { public int getValue(final long[] out, final MdxComplexInstance instance) {
if (this.globalSequence != -1) { if (this.globalSequence != -1) {
return this.getValueAtTime(out, instance.counter % this.globalSequence, 0, this.globalSequence); return this.getValueAtTime(out, instance.counter % this.globalSequence, 0, this.globalSequence);
} else if (instance.sequence != -1) { }
final long[] interval = this.model.getSequences().get(instance.sequence).getInterval(); else if (instance.sequence != -1) {
final long[] interval = this.model.getSequences().get(instance.sequence).getInterval();
return this.getValueAtTime(out, instance.frame, interval[0], interval[1]); return this.getValueAtTime(out, instance.frame, interval[0], interval[1]);
} else { }
out[0] = this.defval[0]; else {
out[0] = this.defval[0];
return -1; return -1;
} }
} }
public int getValueAtTime(final long[] out, final long frame, final long start, final long end) { public int getValueAtTime(final long[] out, final long frame, final long start, final long end) {
if ((frame >= start) && (frame <= end)) { if ((frame >= start) && (frame <= end)) {
for (int i = this.keyFrames.length - 1; i > -1; i--) { for (int i = this.keyFrames.length - 1; i > -1; i--) {
if (this.keyFrames[i] < start) { if (this.keyFrames[i] < start) {
out[0] = 0; out[0] = 0;
return i; return i;
} else if (this.keyFrames[i] <= frame) { }
out[0] = 1; else if (this.keyFrames[i] <= frame) {
out[0] = 1;
return i; return i;
} }
} }
} }
out[0] = 0; out[0] = 0;
return -1; return -1;
} }
@Override @Override
public boolean ok() { public boolean ok() {
return this.ok; return this.ok;
} }
@Override @Override
public int getGeometryEmitterType() { public int getGeometryEmitterType() {
return this.geometryEmitterType; return this.geometryEmitterType;
} }
} }

View File

@ -47,7 +47,9 @@ public class EventObjectSnd extends EmittedObject<MdxComplexInstance, EventObjec
source.connect(panner); source.connect(panner);
// Make a sound. // Make a sound.
source.start(0); source.start(0, emitterObject.volume,
(emitterObject.pitch + ((float) Math.random() * emitterObject.pitchVariance * 2))
- emitterObject.pitchVariance);
} }
} }

View File

@ -22,15 +22,15 @@ public final class UnitAckSound {
private final List<Sound> sounds = new ArrayList<>(); private final List<Sound> sounds = new ArrayList<>();
private final float volume; private final float volume;
private final float pitch; private final float pitch;
private final float pitchVariation; private final float pitchVariance;
private final float minDistance; private final float minDistance;
private final float maxDistance; private final float maxDistance;
private final float distanceCutoff; private final float distanceCutoff;
private Sound lastPlayedSound; private Sound lastPlayedSound;
public static UnitAckSound create(final DataSource dataSource, final DataTable unitAckSounds, final String soundName, public static UnitAckSound create(final DataSource dataSource, final DataTable unitAckSounds,
final String soundType) { final String soundName, final String soundType) {
final Element row = unitAckSounds.get(soundName + soundType); final Element row = unitAckSounds.get(soundName + soundType);
if (row == null) { if (row == null) {
return SILENT; return SILENT;
@ -40,13 +40,17 @@ public final class UnitAckSound {
if ((directoryBase.length() > 1) && !directoryBase.endsWith("\\")) { if ((directoryBase.length() > 1) && !directoryBase.endsWith("\\")) {
directoryBase += "\\"; directoryBase += "\\";
} }
final float volume = row.getFieldFloatValue("Volume"); final float volume = row.getFieldFloatValue("Volume") / 127f;
final float pitch = row.getFieldFloatValue("Pitch"); final float pitch = row.getFieldFloatValue("Pitch");
final float pitchVariation = row.getFieldFloatValue("PitchVariance"); float pitchVariance = row.getFieldFloatValue("PitchVariance");
if (pitchVariance == 1.0f) {
pitchVariance = 0.0f;
}
final float minDistance = row.getFieldFloatValue("MinDistance"); final float minDistance = row.getFieldFloatValue("MinDistance");
final float maxDistance = row.getFieldFloatValue("MaxDistance"); final float maxDistance = row.getFieldFloatValue("MaxDistance");
final float distanceCutoff = row.getFieldFloatValue("DistanceCutoff"); final float distanceCutoff = row.getFieldFloatValue("DistanceCutoff");
final UnitAckSound sound = new UnitAckSound(volume, pitch, pitchVariation, minDistance, maxDistance, distanceCutoff); final UnitAckSound sound = new UnitAckSound(volume, pitch, pitchVariance, minDistance, maxDistance,
distanceCutoff);
for (final String fileName : fileNames.split(",")) { for (final String fileName : fileNames.split(",")) {
String filePath = directoryBase + fileName; String filePath = directoryBase + fileName;
if (!filePath.toLowerCase().endsWith(".wav")) { if (!filePath.toLowerCase().endsWith(".wav")) {
@ -63,7 +67,7 @@ public final class UnitAckSound {
final float maxDistance, final float distanceCutoff) { final float maxDistance, final float distanceCutoff) {
this.volume = volume; this.volume = volume;
this.pitch = pitch; this.pitch = pitch;
this.pitchVariation = pitchVariation; this.pitchVariance = pitchVariation;
this.minDistance = minDistance; this.minDistance = minDistance;
this.maxDistance = maxDistance; this.maxDistance = maxDistance;
this.distanceCutoff = distanceCutoff; this.distanceCutoff = distanceCutoff;
@ -96,7 +100,8 @@ public final class UnitAckSound {
source.connect(panner); source.connect(panner);
// Make a sound. // Make a sound.
source.start(0); source.start(0, this.volume,
(this.pitch + ((float) Math.random() * this.pitchVariance * 2)) - this.pitchVariance);
this.lastPlayedSound = source.buffer; this.lastPlayedSound = source.buffer;
final float duration = Extensions.soundLengthExtension.getDuration(this.lastPlayedSound); final float duration = Extensions.soundLengthExtension.getDuration(this.lastPlayedSound);
unit.lastUnitResponseEndTimeMillis = millisTime + (long) (1000 * duration); unit.lastUnitResponseEndTimeMillis = millisTime + (long) (1000 * duration);

View File

@ -22,7 +22,7 @@ public final class UnitSound {
private final List<Sound> sounds = new ArrayList<>(); private final List<Sound> sounds = new ArrayList<>();
private final float volume; private final float volume;
private final float pitch; private final float pitch;
private final float pitchVariation; private final float pitchVariance;
private final float minDistance; private final float minDistance;
private final float maxDistance; private final float maxDistance;
private final float distanceCutoff; private final float distanceCutoff;
@ -40,13 +40,16 @@ public final class UnitSound {
if ((directoryBase.length() > 1) && !directoryBase.endsWith("\\")) { if ((directoryBase.length() > 1) && !directoryBase.endsWith("\\")) {
directoryBase += "\\"; directoryBase += "\\";
} }
final float volume = row.getFieldFloatValue("Volume"); final float volume = row.getFieldFloatValue("Volume") / 127f;
final float pitch = row.getFieldFloatValue("Pitch"); final float pitch = row.getFieldFloatValue("Pitch");
final float pitchVariation = row.getFieldFloatValue("PitchVariance"); float pitchVariance = row.getFieldFloatValue("PitchVariance");
if (pitchVariance == 1.0f) {
pitchVariance = 0.0f;
}
final float minDistance = row.getFieldFloatValue("MinDistance"); final float minDistance = row.getFieldFloatValue("MinDistance");
final float maxDistance = row.getFieldFloatValue("MaxDistance"); final float maxDistance = row.getFieldFloatValue("MaxDistance");
final float distanceCutoff = row.getFieldFloatValue("DistanceCutoff"); final float distanceCutoff = row.getFieldFloatValue("DistanceCutoff");
final UnitSound sound = new UnitSound(volume, pitch, pitchVariation, minDistance, maxDistance, distanceCutoff); final UnitSound sound = new UnitSound(volume, pitch, pitchVariance, minDistance, maxDistance, distanceCutoff);
for (final String fileName : fileNames.split(",")) { for (final String fileName : fileNames.split(",")) {
String filePath = directoryBase + fileName; String filePath = directoryBase + fileName;
if (!filePath.toLowerCase().endsWith(".wav")) { if (!filePath.toLowerCase().endsWith(".wav")) {
@ -63,7 +66,7 @@ public final class UnitSound {
final float maxDistance, final float distanceCutoff) { final float maxDistance, final float distanceCutoff) {
this.volume = volume; this.volume = volume;
this.pitch = pitch; this.pitch = pitch;
this.pitchVariation = pitchVariation; this.pitchVariance = pitchVariation;
this.minDistance = minDistance; this.minDistance = minDistance;
this.maxDistance = maxDistance; this.maxDistance = maxDistance;
this.distanceCutoff = distanceCutoff; this.distanceCutoff = distanceCutoff;
@ -112,7 +115,8 @@ public final class UnitSound {
source.connect(panner); source.connect(panner);
// Make a sound. // Make a sound.
source.start(0); source.start(0, this.volume,
(this.pitch + ((float) Math.random() * this.pitchVariance * 2)) - this.pitchVariance);
this.lastPlayedSound = source.buffer; this.lastPlayedSound = source.buffer;
return true; return true;
} }

View File

@ -12,10 +12,13 @@ import com.etheller.warsmash.util.RenderMathUtils;
import com.etheller.warsmash.util.War3ID; import com.etheller.warsmash.util.War3ID;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance; import com.etheller.warsmash.viewer5.handlers.mdx.MdxComplexInstance;
import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel; import com.etheller.warsmash.viewer5.handlers.mdx.MdxModel;
import com.etheller.warsmash.viewer5.handlers.w3x.*; import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag; import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag; import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover; import com.etheller.warsmash.viewer5.handlers.w3x.SplatModel.SplatMover;
import com.etheller.warsmash.viewer5.handlers.w3x.UnitSoundset;
import com.etheller.warsmash.viewer5.handlers.w3x.War3MapViewer;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid; import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid;
import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType; import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid.MovementType;
import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI; import com.etheller.warsmash.viewer5.handlers.w3x.rendersim.ability.AbilityDataUI;
@ -64,7 +67,6 @@ public class RenderUnit {
private boolean corpse; private boolean corpse;
private boolean boneCorpse; private boolean boneCorpse;
private final RenderUnitTypeData typeData; private final RenderUnitTypeData typeData;
public UnitSound buildSound;
public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row, final float x, public RenderUnit(final War3MapViewer map, final MdxModel model, final MutableGameObject row, final float x,
final float y, final float z, final int playerIndex, final UnitSoundset soundset, final float y, final float z, final int playerIndex, final UnitSoundset soundset,
@ -127,7 +129,6 @@ public class RenderUnit {
final float blendTime = row.getFieldAsFloat(BLEND_TIME, 0); final float blendTime = row.getFieldAsFloat(BLEND_TIME, 0);
instance.setBlendTime(blendTime * 1000.0f); instance.setBlendTime(blendTime * 1000.0f);
buildSound = map.getUiSounds().getSound(row.getFieldAsString(BUILD_SOUND_LABEL, 0));
} }
this.instance = instance; this.instance = instance;
@ -350,8 +351,9 @@ public class RenderUnit {
this.selectionCircle.move(dx, dy, map.terrain.centerOffset); this.selectionCircle.move(dx, dy, map.terrain.centerOffset);
} }
this.unitAnimationListenerImpl.update(); this.unitAnimationListenerImpl.update();
if(!dead && simulationUnit.isConstructing()) { if (!dead && this.simulationUnit.isConstructing()) {
instance.setFrameByRatio(simulationUnit.getConstructionProgress() / simulationUnit.getUnitType().getBuildTime()); this.instance.setFrameByRatio(
this.simulationUnit.getConstructionProgress() / this.simulationUnit.getUnitType().getBuildTime());
} }
} }

View File

@ -50,6 +50,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
this.activeHighlightFrame.setVisible(false); this.activeHighlightFrame.setVisible(false);
this.cooldownFrame.setVisible(false); this.cooldownFrame.setVisible(false);
this.autocastFrame.setVisible(false); this.autocastFrame.setVisible(false);
setVisible(false);
} }
else { else {
if (commandButton.isEnabled()) { if (commandButton.isEnabled()) {
@ -74,6 +75,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
public void setCommandButtonData(final Texture texture, final int abilityHandleId, final int orderId, public void setCommandButtonData(final Texture texture, final int abilityHandleId, final int orderId,
final int autoCastOrderId, final boolean active, final boolean autoCastActive, final boolean menuButton) { final int autoCastOrderId, final boolean active, final boolean autoCastActive, final boolean menuButton) {
this.menuButton = menuButton; this.menuButton = menuButton;
setVisible(true);
this.iconFrame.setVisible(true); this.iconFrame.setVisible(true);
this.activeHighlightFrame.setVisible(active); this.activeHighlightFrame.setVisible(active);
this.cooldownFrame.setVisible(false); this.cooldownFrame.setVisible(false);
@ -113,7 +115,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
@Override @Override
public UIFrame touchDown(final float screenX, final float screenY, final int button) { public UIFrame touchDown(final float screenX, final float screenY, final int button) {
if (this.renderBounds.contains(screenX, screenY)) { if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
return this; return this;
} }
return super.touchDown(screenX, screenY, button); return super.touchDown(screenX, screenY, button);
@ -121,7 +123,7 @@ public class CommandCardIcon extends AbstractRenderableFrame {
@Override @Override
public UIFrame touchUp(final float screenX, final float screenY, final int button) { public UIFrame touchUp(final float screenX, final float screenY, final int button) {
if (this.renderBounds.contains(screenX, screenY)) { if (isVisible() && this.renderBounds.contains(screenX, screenY)) {
return this; return this;
} }
return super.touchUp(screenX, screenY, button); return super.touchUp(screenX, screenY, button);