From: Kimmo R. <ki...@us...> - 2011-10-03 15:42:53
|
Update of /cvsroot/arianne/stendhal/src/games/stendhal/client In directory vz-cvs-4.sog:/tmp/cvs-serv28200/src/games/stendhal/client Modified Files: GameScreen.java StaticGameLayers.java StendhalClient.java TileStore.java Added Files: Zone.java Log Message: Split single zone data from StaticGameLayers. Cope with data layer being read after the tileset layer (happens when the tileset layer is cached, but data not) --- NEW FILE: Zone.java --- /*************************************************************************** * (C) Copyright 2003-2011 - Stendhal * *************************************************************************** *************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ package games.stendhal.client; import games.stendhal.client.gui.j2d.Blend; import games.stendhal.common.CollisionDetection; import games.stendhal.common.MathHelper; import games.stendhal.tools.tiled.LayerDefinition; import java.awt.Graphics; import java.awt.geom.Rectangle2D; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import marauroa.common.game.RPObject; import marauroa.common.net.InputSerializer; /** * Layer data of a zone. */ public class Zone { /** Name of the zone. */ private final String name; /** Renderers for normal layers. */ private final Map<String, LayerRenderer> layers = new HashMap<String, LayerRenderer>(); /** Global current zone information. */ private final ZoneInfo zoneInfo = ZoneInfo.get(); /** Collision layer. */ private CollisionDetection collision; /** Protection layer. */ private CollisionDetection protection; /** Tilesets. */ private TileStore tileset; /** * <code>true</code>, if the zone has been succesfully validated since the * last change, <code>false</code> otherwise. */ private boolean isValid; /** * If <code>true</code>, the zone needs a data layer added before it can be * validated. */ private boolean requireData; /** * Create a new zone. * * @param name zone name */ Zone(String name) { this.name = name; } /** * Call, if the zone requires a data layer. Calling this must happen * <b>before</b> the said data layer is added. */ void requireDataLayer() { requireData = true; } /** * Add a layer. * * @param layer layer name * @param in Stream for reading the layer data * * @throws IOException * @throws ClassNotFoundException */ void addLayer(String layer, InputStream in) throws IOException, ClassNotFoundException { if (layer.equals("collision")) { /* * Add a collision layer. */ collision = new CollisionDetection(); collision.setCollisionData(LayerDefinition.decode(in)); } else if (layer.equals("protection")) { /* * Add protection */ protection = new CollisionDetection(); protection.setCollisionData(LayerDefinition.decode(in)); } else if (layer.equals("tilesets")) { /* * Add tileset */ TileStore store = new TileStore(); store = new TileStore(); store.addTilesets(new InputSerializer(in)); tileset = store; } else if (layer.equals("data_map")) { // Zone attributes RPObject obj = new RPObject(); obj.readObject(new InputSerializer(in)); String colorMode = obj.get("color_method"); if ("multiply".equals(colorMode)) { zoneInfo.setColorMethod(Blend.Multiply); } else if ("screen".equals(colorMode)) { zoneInfo.setColorMethod(Blend.Screen); } String color = obj.get("color"); if (color != null) { // Keep working, but use an obviously broken color if parsing // the value fails. zoneInfo.setZoneColor(MathHelper.parseIntDefault(color, 0x00ff00)); } // OK to try validating after this requireData = false; } else { /* * It is a tile layer. */ TileRenderer content = new TileRenderer(); content.setMapData(in); layers.put(layer, content); } isValid = false; } /** * Get the name of the zone. * * @return zone name */ String getName() { return name; } /** * Get the zone width. * * @return zone width, or 0 if the zone is not ready enough to return the * real width */ double getWidth() { if (!validate()) { return 0.0; } return collision.getWidth(); } /** * Get the zone height. * * @return zone height, or 0 if the zone is not ready enough to return the * real height */ double getHeight() { if (!validate()) { return 0.0; } return collision.getHeight(); } /** * Check if a shape collides within the zone. * * @param shape * @return <code>true</code>, if the shape overlaps the static zone * collision, <code>false</code> otherwise */ boolean collides(final Rectangle2D shape) { if (collision != null) { return collision.collides(shape); } return false; } /** * Draw a layer. * * @param g graphics * @param layer layer name * @param x * @param y * @param width * @param height */ void draw(Graphics g, final String layer, final int x, final int y, final int width, final int height) { if (!validate()) { return; } final LayerRenderer lr = layers.get(layer); if (lr != null) { lr.draw(g, x, y, width, height); } } /** * Get the collision map. * * @return collision */ CollisionDetection getCollision() { return collision; } /** * Get the protection map. * * @return protection. */ CollisionDetection getProtection() { return protection; } /** * Get a composite representation of multiple tile layers. * * @param compositeName name to be used for the composite for caching * @param layerNames names of the layers making up the composite starting * from the bottom * @return layer corresponding to all sub layers or <code>null</code> if * they can not be merged */ LayerRenderer getMerged(String compositeName, String ... layerNames) { LayerRenderer r = layers.get(compositeName); if (r == null) { List<TileRenderer> subLayers = new ArrayList<TileRenderer>(layerNames.length); for (int i = 0; i < layerNames.length; i++) { LayerRenderer subLayer = layers.get(layerNames[i]); if (subLayer instanceof TileRenderer) { subLayers.add((TileRenderer) subLayer); } else { // Can't merge return null; } } // Make sure the sub layers have their tiles defined before passing // them to CompositeLayerRenderer if (!validate()) { return null; } r = new CompositeLayerRenderer(subLayers); layers.put(compositeName, r); } return r; } /** * Try validating the zone. * * @return <code>true</code>, if the zone has been successfully validated, * <code>false</code> otherwise. */ boolean validate() { if (isValid) { return true; } // Tilesets are always required. Also fail validation until required // data_map has been added if (tileset == null || requireData) { return false; } // Collision is always required if (collision == null) { return false; } if (!tileset.validate(zoneInfo.getZoneColor(), zoneInfo.getColorMethod())) { return false; } for (final LayerRenderer lr : layers.values()) { lr.setTileset(tileset); } isValid = true; return true; } } Index: StaticGameLayers.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/client/StaticGameLayers.java,v retrieving revision 1.105 retrieving revision 1.106 diff -C2 -d -r1.105 -r1.106 *** StaticGameLayers.java 2 Oct 2011 21:21:08 -0000 1.105 --- StaticGameLayers.java 3 Oct 2011 15:42:50 -0000 1.106 *************** *** 13,33 **** package games.stendhal.client; - import games.stendhal.client.gui.j2d.Blend; import games.stendhal.common.CollisionDetection; - import games.stendhal.common.MathHelper; - import games.stendhal.tools.tiled.LayerDefinition; import java.awt.Graphics; import java.awt.geom.Rectangle2D; - import java.io.IOException; - import java.io.InputStream; - import java.net.URL; - import java.util.ArrayList; - import java.util.HashMap; - import java.util.List; - import java.util.Map; - - import marauroa.common.game.RPObject; - import marauroa.common.net.InputSerializer; import org.apache.log4j.Logger; --- 13,20 ---- *************** *** 36,83 **** public class StaticGameLayers { - - /** the logger instance. */ private static final Logger logger = Logger.getLogger(StaticGameLayers.class); - - /** - * Area collision maps. - */ - private final Map<String, CollisionDetection> collisions; - - /** - * Area protection maps. - */ - private final Map<String, CollisionDetection> protections; - - /** - * The current collision map. - */ - private CollisionDetection collision; - /** - * The current protection map. - */ - private CollisionDetection protection; - - /** - * Named layers. - */ - private final Map<String, LayerRenderer> layers; - - /** - * Area tilesets. - */ - private final Map<String, TileStore> tilesets; - - /** - * The current area height. - */ - private double height; - - /** - * The current area width. - */ - private double width; - /** Name of the layers set that we are rendering right now. */ private String area; --- 23,28 ---- *************** *** 86,233 **** private boolean areaChanged; ! /** ! * Whether the internal state is valid. ! */ ! private boolean isValid; ! /** Global current zone information */ private final ZoneInfo zoneInfo = ZoneInfo.get(); public StaticGameLayers() { - collisions = new HashMap<String, CollisionDetection>(); - protections = new HashMap<String, CollisionDetection>(); - layers = new HashMap<String, LayerRenderer>(); - tilesets = new HashMap<String, TileStore>(); - - height = 0.0; - width = 0.0; area = null; areaChanged = true; - isValid = true; } /** @return width in world units. */ public double getWidth() { ! validate(); ! ! return width; } /** @return the height in world units */ public double getHeight() { ! validate(); ! ! return height; } ! /** ! * Add a new Layer to the set. ! * @param area ! * @param layer ! * @param in ! * @throws IOException * ! * @throws ClassNotFoundException */ ! public void addLayer(final String area, final String layer, final InputStream in) ! throws IOException, ClassNotFoundException { ! final String name = getLayerKey(area, layer); ! ! logger.debug("Layer name: " + name); ! ! if (layer.equals("collision")) { ! /* ! * Add a collision layer. ! */ ! if (collisions.containsKey(area)) { ! // Repeated layers should be ignored. ! return; ! } ! ! final CollisionDetection collisionTemp = new CollisionDetection(); ! collisionTemp.setCollisionData(LayerDefinition.decode(in)); ! ! collisions.put(area, collisionTemp); ! } else if (layer.equals("protection")) { ! /* ! * Add protection ! */ ! if (protections.containsKey(area)) { ! // Repeated layers should be ignored. ! return; ! } ! ! final CollisionDetection protectionTemp = new CollisionDetection(); ! protectionTemp.setCollisionData(LayerDefinition.decode(in)); ! ! protections.put(area, protectionTemp); ! } else if (layer.equals("tilesets")) { ! /* ! * Add tileset ! */ ! final TileStore tileset = new TileStore(); ! tileset.addTilesets(new InputSerializer(in), ! zoneInfo.getZoneColor(), zoneInfo.getColorMethod()); ! ! tilesets.put(area, tileset); ! } else if (layer.equals("data_map")) { ! // Zone attributes ! RPObject obj = new RPObject(); ! obj.readObject(new InputSerializer(in)); ! ! String colorMode = obj.get("color_method"); ! if ("multiply".equals(colorMode)) { ! zoneInfo.setColorMethod(Blend.Multiply); ! } ! String color = obj.get("color"); ! if (color != null) { ! // Keep working, but use an obviously broken color if parsing ! // the value fails ! zoneInfo.setZoneColor(MathHelper.parseIntDefault(color, 0x00ff00)); ! } ! } else { ! /* ! * It is a tile layer. ! */ ! if (layers.containsKey(name)) { ! // Repeated layers should be ignored. ! return; ! } ! ! LayerRenderer content = null; ! ! final URL url = getClass().getClassLoader().getResource( ! "data/layers/" + area + "/" + layer + ".jpg"); ! ! if (url != null) { ! content = new ImageRenderer(url); ! } ! ! if (content == null) { ! content = new TileRenderer(); ! ((TileRenderer) content).setMapData(in); ! } ! ! layers.put(name, content); ! } ! ! invalidate(); } public boolean collides(final Rectangle2D shape) { ! validate(); ! ! if (collision != null) { ! return collision.collides(shape); } - return false; } ! /** Removes all layers. */ public void clear() { - layers.clear(); - tilesets.clear(); - collision = null; - protection = null; area = null; zoneInfo.zoneChanged(); --- 31,87 ---- private boolean areaChanged; ! /** Global current zone information. */ private final ZoneInfo zoneInfo = ZoneInfo.get(); + /** The current zone. */ + private Zone currentZone; public StaticGameLayers() { area = null; areaChanged = true; } /** @return width in world units. */ public double getWidth() { ! if (currentZone != null) { ! return currentZone.getWidth(); ! } ! return 0.0; } /** @return the height in world units */ public double getHeight() { ! if (currentZone != null) { ! return currentZone.getHeight(); ! } ! return 0.0; } ! /** ! * Set the current zone. * ! * @param zone */ ! public void setZone(Zone zone) { ! currentZone = zone; ! setAreaName(zone.getName()); ! markAreaChanged(); } + /** + * Check if a shape collides within the current zone. + * + * @param shape + * @return <code>true</code>, if the shape overlaps the static zone + * collision, <code>false</code> otherwise + */ public boolean collides(final Rectangle2D shape) { ! if (currentZone != null) { ! return currentZone.collides(shape); } return false; } ! /** Prepare for zone change. */ public void clear() { area = null; zoneInfo.zoneChanged(); *************** *** 238,310 **** * @param area the areas name */ ! public void setAreaName(final String area) { this.area = area; - this.areaChanged = true; - invalidate(); } /** ! * Invalidate any cached settings. */ - public void invalidate() { - isValid = false; - } - - protected void validate() { - if (isValid) { - return; - } - - if (area == null) { - height = 0.0; - width = 0.0; - collision = null; - protection = null; - isValid = true; - return; - } - - /* - * Set collision map - */ - collision = collisions.get(area); - - /* - * Set protection map - */ - protection = protections.get(area); - - /* - * Get maximum layer size. Assign tileset to layers. - */ - final TileStore tileset = tilesets.get(area); - height = 0.0; - width = 0.0; - - final String prefix = area + "."; - - for (final Map.Entry<String, LayerRenderer> entry : layers.entrySet()) { - if (entry.getKey().startsWith(prefix)) { - final LayerRenderer lr = entry.getValue(); - - lr.setTileset(tileset); - height = Math.max(height, lr.getHeight()); - width = Math.max(width, lr.getWidth()); - } - } - - isValid = true; - } - public String getAreaName() { return area; } public void draw(Graphics g, final String area, final String layer, final int x, final int y, final int width, final int height) { ! validate(); ! ! final LayerRenderer lr = getLayer(area, layer); ! if (lr != null) { lr.draw(g, x, y, width, height); --- 92,146 ---- * @param area the areas name */ ! private void setAreaName(final String area) { this.area = area; } /** ! * Get the area name. ! * ! * @return area name */ public String getAreaName() { return area; } + /** + * Draw a layer. + * + * @param g graphics + * @param area zone name + * @param layer layer name + * @param x + * @param y + * @param width + * @param height + */ public void draw(Graphics g, final String area, final String layer, final int x, final int y, final int width, final int height) { ! if (currentZone != null) { ! if (currentZone.getName().equals(area)) { ! currentZone.draw(g, layer, x, y, width, height); ! } else { ! logger.warn("Trying to draw zone: " + area + ", but the current zone is: " + currentZone.getName()); ! } ! } ! } ! ! /** ! * Draw a set of layers. ! * ! * @param g Graphics ! * @param area Zone name ! * @param compositeName A bundle name for the set of layers. It is used to ! * cache the layer set ! * @param x ! * @param y ! * @param width ! * @param height ! * @param layers names of the layer set, starting from the bottom ! */ ! public void drawLayers(Graphics g, final String area, final String compositeName, final int x, ! final int y, final int width, final int height, String ... layers) { ! LayerRenderer lr = getMerged(area, compositeName, layers); if (lr != null) { lr.draw(g, x, y, width, height); *************** *** 322,346 **** * they can not be merged */ ! public LayerRenderer getMerged(String area, String compositeName, String ... layers) { ! LayerRenderer r = getLayer(area, compositeName); ! if (r == null) { ! List<TileRenderer> subLayers = new ArrayList<TileRenderer>(layers.length); ! for (int i = 0; i < layers.length; i++) { ! LayerRenderer subLayer = getLayer(area, layers[i]); ! if (subLayer instanceof TileRenderer) { ! subLayers.add((TileRenderer) subLayer); ! } else { ! // Can't merge ! return null; ! } } - // Make sure the sub layers have their tiles defined before passing - // them to CompositeLayerRenderer - validate(); - - r = new CompositeLayerRenderer(subLayers); - this.layers.put(getLayerKey(area, compositeName), r); } ! return r; } --- 158,170 ---- * they can not be merged */ ! private LayerRenderer getMerged(String area, String compositeName, String ... layers) { ! if (currentZone != null) { ! if (currentZone.getName().equals(area)) { ! return currentZone.getMerged(compositeName, layers); ! } else { ! logger.warn("Trying to draw zone: " + area + ", but the current zone is: " + currentZone.getName()); } } ! return null; } *************** *** 351,357 **** */ public CollisionDetection getCollisionDetection() { ! validate(); ! ! return collision; } --- 175,182 ---- */ public CollisionDetection getCollisionDetection() { ! if (currentZone != null) { ! return currentZone.getCollision(); ! } ! return null; } *************** *** 362,368 **** */ public CollisionDetection getProtectionDetection() { ! validate(); ! ! return protection; } --- 187,194 ---- */ public CollisionDetection getProtectionDetection() { ! if (currentZone != null) { ! return currentZone.getProtection(); ! } ! return null; } *************** *** 377,404 **** /** - * Get a layer renderer. - * @param area the areas name - * @param layer the layer to be rendered - * - * @return A layer renderer, or <code>null</code>, - */ - public LayerRenderer getLayer(final String area, final String layer) { - return layers.get(getLayerKey(area, layer)); - } - - /** - * Make a map "key" from an area/layer name. - * - * @param area - * the areas name - * @param layer - * the layer to be rendered - * @return the combined key - */ - protected String getLayerKey(final String area, final String layer) { - return area + "." + layer; - } - - /** * @return true if the area has changed since the last */ --- 203,206 ---- *************** *** 410,414 **** * marks the area as changed */ ! public void markAreaChanged() { this.areaChanged = true; } --- 212,216 ---- * marks the area as changed */ ! private void markAreaChanged() { this.areaChanged = true; } Index: TileStore.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/client/TileStore.java,v retrieving revision 1.58 retrieving revision 1.59 diff -C2 -d -r1.58 -r1.59 *** TileStore.java 2 Oct 2011 12:53:07 -0000 1.58 --- TileStore.java 3 Oct 2011 15:42:50 -0000 1.59 *************** *** 27,30 **** --- 27,31 ---- import java.net.URL; import java.util.ArrayList; + import java.util.List; import marauroa.common.net.InputSerializer; *************** *** 61,64 **** --- 62,72 ---- */ private ArrayList<Sprite> tiles; + /** Tilesets waiting to be added to the store. */ + private final List<TileSetDefinition> tilesets = new ArrayList<TileSetDefinition>(); + /** + * <code>true</code>, if the store has been successfully validated, + * otherwise <code>false</code>. + */ + private boolean validated; /** *************** *** 75,79 **** * A sprite store. */ ! public TileStore(final SpriteStore store) { this.store = store; --- 83,87 ---- * A sprite store. */ ! private TileStore(final SpriteStore store) { this.store = store; *************** *** 161,170 **** /** ! * Add tilesets. * * @param in ! * The object stream. ! * @param color Color for adjusting the tileset, or <code>null</code> ! * @param blend blend mode for applying the adjustment color, or * <code>null</code> * --- 169,176 ---- /** ! * Add tilesets. The store will require validating afterwards. * * @param in ! * The object stream. * <code>null</code> * *************** *** 172,177 **** * @throws ClassNotFoundException */ ! public void addTilesets(final InputSerializer in, final Color color, ! final Composite blend) throws IOException, ClassNotFoundException { final int amount = in.readInt(); --- 178,182 ---- * @throws ClassNotFoundException */ ! public void addTilesets(final InputSerializer in) throws IOException, ClassNotFoundException { final int amount = in.readInt(); *************** *** 180,185 **** final TileSetDefinition tileset = (TileSetDefinition) in.readObject(new TileSetDefinition( null, -1)); ! add(tileset, color, blend); } } --- 185,213 ---- final TileSetDefinition tileset = (TileSetDefinition) in.readObject(new TileSetDefinition( null, -1)); ! tilesets.add(tileset); ! } ! } ! /** ! * Try finishing the tile store withan adjustment color and blend mode for ! * the tilesets. ! * ! * @param color Color for adjusting the tileset, or <code>null</code> ! * @param blend blend mode for applying the adjustment color, or ! * @return <code>true</code> if the store has been validated successfully, ! * <code>false</code> otherwise ! */ ! boolean validate(final Color color, final Composite blend) { ! if (!validated) { ! if (!tilesets.isEmpty()) { ! for (TileSetDefinition def : tilesets) { ! add(def, color, blend); ! } ! tilesets.clear(); ! validated = true; ! return true; ! } ! return false; } + return true; } Index: GameScreen.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/client/GameScreen.java,v retrieving revision 1.198 retrieving revision 1.199 diff -C2 -d -r1.198 -r1.199 *** GameScreen.java 26 Sep 2011 21:36:17 -0000 1.198 --- GameScreen.java 3 Oct 2011 15:42:50 -0000 1.199 *************** *** 571,584 **** layerHeight = Math.min(layerHeight, clip.height / IGameScreen.SIZE_UNIT_PIXELS) + 2; ! LayerRenderer r = gameLayers.getMerged(set, "floor_bundle", "0_floor", "1_terrain", "2_object"); ! if (r != null) { ! r.draw(graphics, startTileX, startTileY, layerWidth, layerHeight); ! } else { ! // Fall back to individual layers in case the layers can't be ! // merged. (Is that even possible?) ! gameLayers.draw(graphics, set, "0_floor", startTileX, startTileY, layerWidth, layerHeight); ! gameLayers.draw(graphics, set, "1_terrain", startTileX, startTileY, layerWidth, layerHeight); ! gameLayers.draw(graphics, set, "2_object", startTileX, startTileY, layerWidth, layerHeight); ! } drawEntities(graphics); --- 571,577 ---- layerHeight = Math.min(layerHeight, clip.height / IGameScreen.SIZE_UNIT_PIXELS) + 2; ! gameLayers.drawLayers(graphics, set, "floor_bundle", startTileX, ! startTileY, layerWidth, layerHeight, "0_floor", "1_terrain", ! "2_object"); drawEntities(graphics); *************** *** 758,761 **** --- 751,755 ---- */ boolean found = true; + int tries = 0; while (found) { *************** *** 772,775 **** --- 766,775 ---- } } + + tries++; + // give up, if no location found in a reasonable amount of tries + if (tries > 20) { + break; + } } Index: StendhalClient.java =================================================================== RCS file: /cvsroot/arianne/stendhal/src/games/stendhal/client/StendhalClient.java,v retrieving revision 1.240 retrieving revision 1.241 diff -C2 -d -r1.240 -r1.241 *** StendhalClient.java 2 Oct 2011 21:16:46 -0000 1.240 --- StendhalClient.java 3 Oct 2011 15:42:50 -0000 1.241 *************** *** 97,100 **** --- 97,102 ---- private final StendhalPerceptionListener stendhalPerceptionListener; + /** The zone currently under loading. */ + private Zone currentZone; public static StendhalClient get() { *************** *** 242,248 **** inBatchUpdate = true; logger.debug("Batch update started"); ! ! /** We clean the game object container */ ! logger.debug("CLEANING static object list"); staticLayers.clear(); --- 244,248 ---- inBatchUpdate = true; logger.debug("Batch update started"); ! logger.debug("Preparing for zone change"); staticLayers.clear(); *************** *** 260,264 **** } ! staticLayers.setAreaName(name.substring(0, i)); } --- 260,264 ---- } ! currentZone = new Zone(name.substring(0, i)); } *************** *** 270,273 **** --- 270,278 ---- for (final TransferContent item : items) { + if ("data_map".equals(item.name)) { + // Tell the zone to be invalid until the data layer has been + // added + currentZone.requireDataLayer(); + } final InputStream is = cache.getItem(item); *************** *** 295,298 **** --- 300,308 ---- } } + + // Don't change the zone until it's ready + if (currentZone.validate()) { + staticLayers.setZone(currentZone); + } return items; *************** *** 326,333 **** } - final String area = name.substring(0, i); final String layer = name.substring(i + 1); ! staticLayers.addLayer(area, layer, in); } --- 336,342 ---- } final String layer = name.substring(i + 1); ! currentZone.addLayer(layer, in); } *************** *** 344,348 **** } } ! staticLayers.markAreaChanged(); contentToLoad -= items.size(); --- 353,359 ---- } } ! // Prefer preparing the zone outside the EDT, if possible ! currentZone.validate(); ! staticLayers.setZone(currentZone); contentToLoad -= items.size(); |