diff --git a/.travis.yml b/.travis.yml index 3ee61e3578..bf1cb132ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,8 @@ env: # Run single test targets - TARGET=":jsettlers.logic:unitTest" - TARGET=":jsettlers.common:test" - - TARGET=":jsettlers.network:test --info" + - TARGET=":jsettlers.graphics:test" + - TARGET=":jsettlers.network:test" - TARGET=":jsettlers.logic:aiDifficultiesIT" - TARGET=":jsettlers.logic:autoReplayIT" - TARGET=":jsettlers.logic:replayValidationIT" diff --git a/build.gradle b/build.gradle index 7585e7b56a..1bb4446442 100644 --- a/build.gradle +++ b/build.gradle @@ -78,6 +78,7 @@ subprojects { tasks.withType(Test) { testLogging { exceptionFormat = 'full' + events "PASSED", "FAILED", "SKIPPED" } } diff --git a/jsettlers.graphics/build.gradle b/jsettlers.graphics/build.gradle index c4981313e8..914d1f192e 100644 --- a/jsettlers.graphics/build.gradle +++ b/jsettlers.graphics/build.gradle @@ -19,6 +19,11 @@ dependencies { implementation project(':jsettlers.common') implementation project(':go.graphics') implementation 'com.google.code.gson:gson:2.8.2' + + testImplementation 'org.mockito:mockito-core:2.18.3' + testImplementation 'org.hamcrest:hamcrest-library:1.3' + + } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SelectionRow.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SelectionRow.java index a00f3c6a28..616ddb3181 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SelectionRow.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SelectionRow.java @@ -24,47 +24,47 @@ import jsettlers.common.movable.EMovableType; import jsettlers.graphics.image.Image; import jsettlers.graphics.localization.Labels; +import jsettlers.graphics.map.draw.settlerimages.SettlerImageFlavor; import jsettlers.graphics.map.draw.settlerimages.SettlerImageMap; import jsettlers.graphics.ui.UIPanel; public class SelectionRow extends UIPanel { - private final EMovableType type; + private final Image movableImage; + private String localizedLabelName; private final int count; /** - * Creates a new row in the selection view - * - * @param type - * The type of the movables - * @param count - * How many of them are selected. + * Creates a new row in the selection view. + * + * @param movableImage + * @param localizedLabelName + * @param selectionCount how many are selected. */ - public SelectionRow(EMovableType type, int count) { - this.type = type; - this.count = count; + public SelectionRow(Image movableImage, String localizedLabelName, int selectionCount) { + this.count = selectionCount; + this.movableImage = movableImage; + this.localizedLabelName = localizedLabelName; + } + + static SelectionRow createFromMovableType(EMovableType type, int count) { + SettlerImageFlavor flavor = new SettlerImageFlavor(type, EMovableAction.NO_ACTION, EMaterialType.NO_MATERIAL, EDirection.SOUTH_EAST); + return new SelectionRow(SettlerImageMap.getInstance().getImageForSettler(flavor, 0.0f), Labels.getName(type), count); } @Override public void drawAt(GLDrawContext gl) { float width = getPosition().getWidth(); - Image image = - SettlerImageMap.getInstance().getImageForSettler(type, - EMovableAction.NO_ACTION, EMaterialType.NO_MATERIAL, - EDirection.SOUTH_EAST, 0); Color color = getColor(); - float bottomy = getPosition() - .getMinY() + getPosition().getHeight() / 4; + float bottomY = getPosition().getMinY() + getPosition().getHeight() / 4; float left = getPosition().getMinX(); - float imagex = left + width / 20; - image.drawAt(gl, imagex, bottomy, color); + float imageX = left + width / 20; + movableImage.drawAt(gl, imageX, bottomY, color); TextDrawer drawer = gl.getTextDrawer(EFontSize.NORMAL); - drawer.drawString(left + width / 5, getPosition().getMinY() + getPosition().getHeight() * .75f, "" + count); - drawer.drawString(left + width / 5, bottomy, Labels.getName(type)); - + drawer.drawString(left + width / 5, bottomY, localizedLabelName); } private Color getColor() { diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/ShipSelectionContent.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/ShipSelectionContent.java index 3a7cd66761..9cea363d59 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/ShipSelectionContent.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/ShipSelectionContent.java @@ -57,7 +57,7 @@ public static void addRowsToPanel(UIPanel panel, ISelectionSet selection, EMovab int count = selection.getMovableCount(type); if (count > 0) { - SelectionRow row = new SelectionRow(type, count); + SelectionRow row = SelectionRow.createFromMovableType(type, count); panel.addChild(row, 0.1f, rowHeight * (rowi - 1), .9f, rowHeight * (rowi)); rowi--; diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SoilderSelectionContent.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SoilderSelectionContent.java index 37157d71df..bd1518c9d1 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SoilderSelectionContent.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/controls/original/panel/selection/SoilderSelectionContent.java @@ -65,7 +65,7 @@ public static void addRowsToPanel(UIPanel panel, ISelectionSet selection, int count = selection.getMovableCount(type); if (count > 0) { - SelectionRow row = new SelectionRow(type, count); + SelectionRow row = SelectionRow.createFromMovableType(type, count); panel.addChild(row, 0.1f, rowHeight * (rowi - 1), .9f, rowHeight * (rowi)); rowi--; diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImagePreloadTask.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImagePreloadTask.java index 3173d737c6..8568a4fbbb 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImagePreloadTask.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImagePreloadTask.java @@ -17,9 +17,16 @@ import jsettlers.graphics.map.draw.settlerimages.SettlerImageMap; public class ImagePreloadTask implements Runnable { + + private final SettlerImageMap settlerImageMap; + + public ImagePreloadTask(SettlerImageMap settlerImageMap) { + this.settlerImageMap = settlerImageMap; + } + @Override public void run() { - SettlerImageMap.getInstance(); + settlerImageMap.loadFromMovablesTextFile(); Background.preloadTexture(); diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImageProvider.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImageProvider.java index bef6e864b8..caf0c68472 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImageProvider.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/ImageProvider.java @@ -35,6 +35,8 @@ import jsettlers.graphics.image.reader.versions.SettlersVersionMapping; import jsettlers.graphics.image.sequence.ArraySequence; import jsettlers.graphics.image.sequence.Sequence; +import jsettlers.graphics.map.draw.settlerimages.SettlerImageMap; +import jsettlers.graphics.map.draw.settlerimages.SettlerImageMapItem; import java.io.File; import java.util.Arrays; @@ -51,7 +53,7 @@ * * @author michael */ -public final class ImageProvider { +public class ImageProvider { private static final String FILE_PREFIX = "siedler3_"; private static final int LAST_SEQUENCE_NUMBER = 2; private static final List HIGHRES_IMAGE_FILE_NUMBERS = Arrays.asList(3, 14); @@ -73,7 +75,7 @@ public final class ImageProvider { private Thread preloadingThread; private ImageIndexFile indexFile = null; - private ImageProvider() { + public ImageProvider() { } /** @@ -305,7 +307,7 @@ private DatFileReader createFileReader(int fileIndex) { */ public void startPreloading() { if (lookupPath != null && preloadingThread == null) { - preloadingThread = new Thread(new ImagePreloadTask(), "image preloader"); + preloadingThread = new Thread(new ImagePreloadTask(SettlerImageMap.getInstance()), "image preloader"); preloadingThread.start(); } } @@ -327,4 +329,9 @@ public void waitForPreloadingFinish() { public void addPreloadTask(GLPreloadTask task) { tasks.add(task); } + + public Image getImageSafe(SettlerImageMapItem item, float progress) { + return getSettlerSequence(item.getFile(), item.getSequenceIndex()) + .getImageSafe(item.imageIndex(progress)); + } } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java index 02352a1a3c..b65612992e 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/MapObjectDrawer.java @@ -50,6 +50,7 @@ import jsettlers.graphics.image.SingleImage; import jsettlers.graphics.image.sequence.Sequence; import jsettlers.graphics.map.MapDrawContext; +import jsettlers.graphics.map.draw.settlerimages.SettlerImageFlavor; import jsettlers.graphics.map.draw.settlerimages.SettlerImageMap; import jsettlers.graphics.map.geometry.MapCoordinateConverter; import jsettlers.graphics.sound.SoundManager; @@ -375,8 +376,8 @@ private void drawShip(IMovable ship, int x, int y) { if (yShift >= 0) { float xShift = PASSENGER_POSITION_TO_FRONT[j] * xShiftForward + PASSENGER_POSITION_TO_RIGHT[j] * xShiftRight; IMovable passenger = passengerList.get(j); - Image image = this.imageMap.getImageForSettler(passenger.getMovableType(), EMovableAction.NO_ACTION, - EMaterialType.NO_MATERIAL, getPassengerDirection(direction, shipPosition, i), 0 + Image image = this.imageMap.getImageForSettler( + new SettlerImageFlavor(passenger.getMovableType(), EMovableAction.NO_ACTION, EMaterialType.NO_MATERIAL, getPassengerDirection(direction, shipPosition, i)), 0 ); image.drawAt(glDrawContext, drawBuffer, viewX + xShift, viewY + yShift + PASSENGER_DECK_HEIGHT, color, shade); } @@ -408,8 +409,8 @@ EMaterialType.NO_MATERIAL, getPassengerDirection(direction, shipPosition, i), 0 if (yShift < 0) { float xShift = PASSENGER_POSITION_TO_FRONT[j] * xShiftForward + PASSENGER_POSITION_TO_RIGHT[j] * xShiftRight; IMovable passenger = passengerList.get(j); - Image image = this.imageMap.getImageForSettler(passenger.getMovableType(), EMovableAction.NO_ACTION, - EMaterialType.NO_MATERIAL, getPassengerDirection(direction, shipPosition, i), 0 + Image image = this.imageMap.getImageForSettler( + new SettlerImageFlavor(passenger.getMovableType(), EMovableAction.NO_ACTION, EMaterialType.NO_MATERIAL, getPassengerDirection(direction, shipPosition, i)), 0 ); image.drawAt(glDrawContext, drawBuffer, viewX + xShift, viewY + yShift + PASSENGER_DECK_HEIGHT, color, shade); } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageFlavor.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageFlavor.java new file mode 100644 index 0000000000..2be7dfeacd --- /dev/null +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageFlavor.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2015 - 2018 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *******************************************************************************/ +package jsettlers.graphics.map.draw.settlerimages; + +import jsettlers.common.material.EMaterialType; +import jsettlers.common.movable.EDirection; +import jsettlers.common.movable.EMovableAction; +import jsettlers.common.movable.EMovableType; +import jsettlers.common.movable.IMovable; + +import java.util.Objects; + +public final class SettlerImageFlavor { + + public static final SettlerImageFlavor NONE = new SettlerImageFlavor(null, null, null, null); + private final EMovableType type; + private final EMovableAction action; + private final EMaterialType material; + private final EDirection direction; + + public SettlerImageFlavor(EMovableType type, EMovableAction action, EMaterialType material, EDirection direction) { + this.type = type; + this.action = action; + this.material = material; + this.direction = direction; + } + + static SettlerImageFlavor createFromMovable(IMovable movable) { + return new SettlerImageFlavor(movable.getMovableType(), movable.getAction(), movable.getMaterial(), movable.getDirection()); + } + + public EMovableType getType() { + return type; + } + + public EMovableAction getAction() { + return action; + } + + public EMaterialType getMaterial() { + return material; + } + + public EDirection getDirection() { + return direction; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SettlerImageFlavor that = (SettlerImageFlavor) o; + + if (type != that.type) return false; + if (action != that.action) return false; + if (material != that.material) return false; + return direction == that.direction; + } + + @Override + public int hashCode() { + int result = type != null ? type.hashCode() : 0; + result = 31 * result + (action != null ? action.hashCode() : 0); + result = 31 * result + (material != null ? material.hashCode() : 0); + result = 31 * result + (direction != null ? direction.hashCode() : 0); + return result; + } + + int calculatePriority() { + int priority = 1;// more than 0. + if (getType() != null) { + priority += 10; + } + if (getAction() != null) { + priority += 100; + } + if (getMaterial() != null) { + priority += 1000; + } + if (getDirection() != null) { + priority += 10000; + } + return priority; + } +} diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMap.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMap.java index c62eb53a3a..e1a82a201f 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMap.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMap.java @@ -14,10 +14,8 @@ *******************************************************************************/ package jsettlers.graphics.map.draw.settlerimages; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; +import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -38,69 +36,44 @@ */ public final class SettlerImageMap { - private static final SettlerImageMapItem DEFAULT_ITEM = new SettlerImageMapItem(10, 0, 0, 1); + static final SettlerImageMapItem DEFAULT_ITEM = new SettlerImageMapItem(10, 0, 0, 1); private static SettlerImageMap instance; - private final ImageProvider imageProvider = ImageProvider.getInstance(); + private final ImageProvider imageProvider; - private final SettlerImageMapItem[][][][] map; + final HashMap map = new HashMap<>(); private final Pattern linePattern = Pattern.compile("\\s*([\\w\\*]+)\\s*," + "\\s*([\\w\\*]+)\\s*," + "\\s*([\\w\\*]+)\\s*," + "\\s*([\\w\\*]+)\\s*" + "=\\s*(\\d+)\\s*," + "\\s*(\\d+)\\s*," + "\\s*(\\d+)\\s*," + "\\s*(-?\\d+)\\s*"); - private final int types; - - private final int actions; - - private final int materials; - - private final int directions; - - /** - * Creates a new settler image map. - */ private SettlerImageMap() { - this.types = EMovableType.NUMBER_OF_MOVABLETYPES; - this.actions = EMovableAction.values().length; - this.materials = EMaterialType.NUMBER_OF_MATERIALS; - this.directions = EDirection.VALUES.length; - this.map = new SettlerImageMapItem[this.types][this.actions][this.materials][this.directions]; + imageProvider = ImageProvider.getInstance(); + } + SettlerImageMap(ImageProvider imageProvider){ + this.imageProvider = imageProvider; + } + + public void loadFromMovablesTextFile() { try { InputStream file = getClass().getResourceAsStream("movables.txt"); - readFromFile(file); + readFromReader(new BufferedReader(new InputStreamReader(file))); } catch (IOException e) { System.err.println("Error reading image file. " + "Settler images might not work."); } } - /** - * Reads the map from the given file. - * - * @param file - * The file to read from. - */ - private void readFromFile(InputStream file) throws IOException { - int[][][][] priorities = new int[this.types][this.actions][this.materials][this.directions]; - - // add pseudo entry. - addEntryToMap(priorities, null, null, null, null, DEFAULT_ITEM, -1); - - readFromFile(file, priorities); - } - - private void readFromFile(InputStream file, int[][][][] priorities) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(file)); - + private void readFromReader(BufferedReader reader) throws IOException { + HashMap priorities = new HashMap<>(); String line = reader.readLine(); while (line != null) { if (!line.isEmpty() && !line.startsWith("#")) { try { - addByLine(priorities, line); + addByLine(line, priorities); } catch (IllegalArgumentException e) { e.printStackTrace(); } @@ -113,14 +86,13 @@ private void readFromFile(InputStream file, int[][][][] priorities) throws IOExc /** * Adds a line to the map * - * @param priorities - * The priority table to use. * @param line * The line. + * @param priorities * @throws IllegalArgumentException * if the line is not correct. */ - private void addByLine(int[][][][] priorities, String line) { + private void addByLine(String line, HashMap priorities) { final Matcher matcher = parseLine(line); final String typeString = matcher.group(1); final String actionString = matcher.group(2); @@ -132,14 +104,18 @@ private void addByLine(int[][][][] priorities, String line) { EMaterialType material = parseMaterial(materialString); EDirection direction = parseDirection(directionString); - int priority = calculatePriority(type, action, material, direction); - final int fileIndex = Integer.parseInt(matcher.group(5)); final int sequence = Integer.parseInt(matcher.group(6)); final int start = Integer.parseInt(matcher.group(7)); final int duration = Integer.parseInt(matcher.group(8)); - addEntryToMap(priorities, type, action, material, direction, new SettlerImageMapItem(fileIndex, sequence, start, duration), priority); + SettlerImageFlavor flavor = new SettlerImageFlavor(type, action, material, direction); + int priority = flavor.calculatePriority(); + Integer cachedPriority = priorities.get(flavor); + if(cachedPriority == null || cachedPriority < priority) { + map.put(flavor, new SettlerImageMapItem(fileIndex, sequence, start, duration)); + priorities.put(flavor, priority); + } } private EMovableType parseType(final String typeString) { @@ -182,23 +158,6 @@ private EDirection parseDirection(final String directionString) { return direction; } - private int calculatePriority(EMovableType type, EMovableAction action, EMaterialType material, EDirection direction) { - int priority = 1;// more than 0. - if (type != null) { - priority += 10; - } - if (action != null) { - priority += 100; - } - if (material != null) { - priority += 1000; - } - if (direction != null) { - priority += 10000; - } - return priority; - } - /** * Parses a line. * @@ -217,76 +176,13 @@ private Matcher parseLine(String line) { return matcher; } - /** - * Adds an entry to the map. Overrides cells with lower priorities. - * - * @param priorities - * The priority table to use. - * @param type - * @param action - * @param material - * @param direction - * @param item - * @param priority - */ - private void addEntryToMap(int[][][][] priorities, EMovableType type, EMovableAction action, EMaterialType material, EDirection direction, SettlerImageMapItem item, int priority) { - int minType, maxType; - if (type == null) { - minType = 0; - maxType = this.types; - } else { - minType = type.ordinal(); - maxType = minType + 1; - } - - int minAction, maxAction; - if (action == null) { - minAction = 0; - maxAction = this.actions; - } else { - minAction = action.ordinal(); - maxAction = minAction + 1; - } - - int minMaterial, maxMaterial; - if (material == null) { - minMaterial = 0; - maxMaterial = this.materials; - } else { - minMaterial = material.ordinal(); - maxMaterial = minMaterial + 1; - } - - int minDirection, maxDirection; - if (direction == null) { - minDirection = 0; - maxDirection = this.directions; - } else { - minDirection = direction.ordinal(); - maxDirection = minDirection + 1; - } - - for (int typeIndex = minType; typeIndex < maxType; typeIndex++) { - for (int actionIndex = minAction; actionIndex < maxAction; actionIndex++) { - for (int materialIndex = minMaterial; materialIndex < maxMaterial; materialIndex++) { - for (int direcitonIndex = minDirection; direcitonIndex < maxDirection; direcitonIndex++) { - if (priorities[typeIndex][actionIndex][materialIndex][direcitonIndex] < priority) { - this.map[typeIndex][actionIndex][materialIndex][direcitonIndex] = item; - priorities[typeIndex][actionIndex][materialIndex][direcitonIndex] = priority; - } - } - } - } - } - } - /** * Gets an image for a given settler. * * @param movable * The settler to get the image for - * @return The image or an null-image. - * @see SettlerImageMap#getImageForSettler(EMovableType, EMovableAction, EMaterialType, EDirection, float) + * @return The image or a null-image. + * @see SettlerImageMap#getImageForSettler(SettlerImageFlavor, float) */ public Image getImageForSettler(IMovable movable, float progress) { if (movable.getAction() == EMovableAction.WALKING) { @@ -295,51 +191,31 @@ public Image getImageForSettler(IMovable movable, float progress) { progress += .5f; } } - return getImageForSettler(movable.getMovableType(), - movable.getAction(), movable.getMaterial(), - movable.getDirection(), progress); + return getImageForSettler(SettlerImageFlavor.createFromMovable(movable), progress); } /** * Gets an image for a given settler. * - * @param movableType - * The type of the settler. - * @param action - * The action the settler is doing. - * @param material - * The material that is assigned to the settler. - * @param direction - * Its direction. + * + * @param settlerImageFlavor * @param progress * The progress. * @return The image. */ - public Image getImageForSettler(EMovableType movableType, EMovableAction action, EMaterialType material, EDirection direction, float progress) { - SettlerImageMapItem item = getMapItem(movableType, action, material, direction); - - int duration = item.getDuration(); - int imageIndex; - if (duration >= 0) { - imageIndex = item.getStart() + Math.min((int) (progress * duration), duration - 1); - } else { - imageIndex = item.getStart() + Math.max((int) (progress * duration), duration + 1); - } - return this.imageProvider.getSettlerSequence(item.getFile(), item.getSequenceIndex()).getImageSafe(imageIndex); + public Image getImageForSettler(SettlerImageFlavor settlerImageFlavor, float progress) { + SettlerImageMapItem item = getMapItem(settlerImageFlavor); + return imageProvider.getImageSafe(item, progress); } /** * Gets a map item. * - * @param movableType - * @param action - * @param material - * @param direction - * @param progress - * @return The item of the map at the given position. Is not null. + * + * @param settlerImageFlavor@return The item of the map at the given position. Is not null. */ - private SettlerImageMapItem getMapItem(EMovableType movableType, EMovableAction action, EMaterialType material, EDirection direction) { - SettlerImageMapItem item = this.map[movableType.ordinal()][action.ordinal()][material.ordinal][direction.ordinal]; + private SettlerImageMapItem getMapItem(SettlerImageFlavor settlerImageFlavor) { + SettlerImageMapItem item = map.get(settlerImageFlavor); if (item == null) { return DEFAULT_ITEM; } else { @@ -353,4 +229,8 @@ public static SettlerImageMap getInstance() { } return instance; } + + void loadFromMovablesText(String text) throws IOException { + readFromReader(new BufferedReader(new StringReader(text))); + } } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMapItem.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMapItem.java index ae5df2309c..33cebad2ba 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMapItem.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMapItem.java @@ -14,19 +14,19 @@ *******************************************************************************/ package jsettlers.graphics.map.draw.settlerimages; +import java.util.Objects; + /** * This is a map item of settler images. * * @author michael * */ -public class SettlerImageMapItem { - private final int file; +public final class SettlerImageMapItem { + private final int file; private final int sequenceIndex; - private final int start; - private final int duration; public SettlerImageMapItem(int file, int sequenceIndex, int start, @@ -52,4 +52,37 @@ public int getStart() { public int getDuration() { return this.duration; } + + public int imageIndex(float progress) { + int duration = getDuration(); + int imageIndex; + if (duration >= 0) { + imageIndex = getStart() + Math.min((int) (progress * duration), duration - 1); + } else { + imageIndex = getStart() + Math.max((int) (progress * duration), duration + 1); + } + return imageIndex; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SettlerImageMapItem that = (SettlerImageMapItem) o; + + if (file != that.file) return false; + if (sequenceIndex != that.sequenceIndex) return false; + if (start != that.start) return false; + return duration == that.duration; + } + + @Override + public int hashCode() { + int result = file; + result = 31 * result + sequenceIndex; + result = 31 * result + start; + result = 31 * result + duration; + return result; + } } diff --git a/jsettlers.graphics/src/main/java/jsettlers/graphics/ui/UIPanel.java b/jsettlers.graphics/src/main/java/jsettlers/graphics/ui/UIPanel.java index a18c4a0f03..6634339eb2 100644 --- a/jsettlers.graphics/src/main/java/jsettlers/graphics/ui/UIPanel.java +++ b/jsettlers.graphics/src/main/java/jsettlers/graphics/ui/UIPanel.java @@ -42,10 +42,7 @@ public class UIPanel implements UIElement { private boolean attached = false; /** - * Sets the background. file=-1 means no background - * - * @param file - * @param settlerSeqIndex + * Sets the background. file=-1 means no background. */ public void setBackground(ImageLink imageLink) { this.background = imageLink; diff --git a/jsettlers.graphics/src/test/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMapTest.java b/jsettlers.graphics/src/test/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMapTest.java new file mode 100644 index 0000000000..80dfe0719b --- /dev/null +++ b/jsettlers.graphics/src/test/java/jsettlers/graphics/map/draw/settlerimages/SettlerImageMapTest.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2015 - 2018 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + *******************************************************************************/ +package jsettlers.graphics.map.draw.settlerimages; + +import jsettlers.common.material.EMaterialType; +import jsettlers.common.movable.EDirection; +import jsettlers.common.movable.EMovableAction; +import jsettlers.common.movable.EMovableType; +import jsettlers.graphics.image.Image; +import jsettlers.graphics.map.draw.ImageProvider; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +import static org.hamcrest.collection.IsMapContaining.hasEntry; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class SettlerImageMapTest { + + private static final SettlerImageFlavor TEST_IMAGE_FLAVOR = new SettlerImageFlavor(EMovableType.BEARER, EMovableAction.WALKING, EMaterialType.NO_MATERIAL, EDirection.SOUTH_WEST); + private SettlerImageMap settlerImages; + private Image dummyImage; + + @Before + public void setUp(){ + dummyImage = mock(Image.class); + ImageProvider imageProvider = mock(ImageProvider.class); + when(imageProvider.getImageSafe(any(SettlerImageMapItem.class), anyFloat())).thenReturn(dummyImage); + + settlerImages = new SettlerImageMap(imageProvider); + } + + @Test + public void givenTextWithCommentWhenLoadThenContainsNoEntry() throws IOException { + String text = "# some comment"; + settlerImages.loadFromMovablesText(text); + assertTrue(settlerImages.map.isEmpty()); + } + + @Test + public void givenTextWithDefaultEntryWhenLoadThenContainsDefaultEntry() throws IOException { + String text = "*,*,*,*=10, 0, 0, 1"; + settlerImages.loadFromMovablesText(text); + assertEquals(1, settlerImages.map.size()); + assertThat(settlerImages.map, hasEntry(SettlerImageFlavor.NONE, SettlerImageMap.DEFAULT_ITEM)); + } + + @Test + public void givenTextWithTestEntryWhenLoadthenContainsTestEntry() throws IOException { + String text = "BEARER, WALKING, NO_MATERIAL, SOUTH_WEST = 10, 0, 0, 12"; + settlerImages.loadFromMovablesText(text); + assertOneEntryInMap(); + } + + private void assertOneEntryInMap() { + assertEquals(1, settlerImages.map.size()); + assertThat(settlerImages.map, hasEntry(TEST_IMAGE_FLAVOR, new SettlerImageMapItem(10, 0, 0, 12))); + } + + @Test + public void givenTextWithDuplicateEntryWhenLoadThenContainsOnlyOneEntry() throws IOException { + String text = "BEARER, WALKING, NO_MATERIAL, SOUTH_WEST = 10, 0, 0, 12\nBEARER, WALKING, NO_MATERIAL, SOUTH_WEST = 10, 0, 0, 12"; + settlerImages.loadFromMovablesText(text); + assertOneEntryInMap(); + } +} \ No newline at end of file