/// <see cref="IMapLoader.NewMap"/> public IMapAccess NewMap(string mapName, ITileSet tileset, string defaultTerrain, RCIntVector size) { if (!this.initThreadStarted) { throw new InvalidOperationException("Component has not yet been started!"); } this.initThread.Join(); if (mapName == null) { throw new ArgumentNullException("mapName"); } if (tileset == null) { throw new ArgumentNullException("tileset"); } if (defaultTerrain == null) { throw new ArgumentNullException("defaultTerrain"); } if (size == RCIntVector.Undefined) { throw new ArgumentNullException("size"); } MapAccess retObj = new MapAccess(mapName, this.mapStructure); this.mapStructure.BeginOpen(tileset, size, defaultTerrain); this.mapStructure.EndOpen(); return(retObj); }
/// <see cref="IMapEditor.RemoveTerrainObject"/> public void RemoveTerrainObject(IMapAccess targetMap, ITerrainObject terrainObject) { if (targetMap == null) { throw new ArgumentNullException("targetMap"); } if (terrainObject == null) { throw new ArgumentNullException("terrainObject"); } if (targetMap != terrainObject.ParentMap) { throw new InvalidOperationException("The map of the terrain object must equal with the target map!"); } /// TODO: Avoid this downcast! MapAccess targetMapObj = targetMap as MapAccess; if (targetMapObj == null) { throw new ArgumentException("The given map cannot be handled by the MapEditor!", "targetMap"); } /// Undo the cell data changesets of the removed terrain object. foreach (ICellDataChangeSet changeset in terrainObject.Type.CellDataChangesets) { changeset.Undo(terrainObject); } targetMapObj.DetachTerrainObject(terrainObject); }
/// <summary> /// Initializes the terrain objects of the map. /// </summary> /// <param name="terrainObjListPackage">The package that contains the terrain object informations.</param> /// <param name="map">Reference to the map.</param> private void LoadTerrainObjects(RCPackage terrainObjListPackage, IMapAccess map) { /// TODO: Avoid this downcast! MapAccess mapObj = map as MapAccess; if (mapObj == null) { throw new ArgumentException("The given map cannot be handled by the MapEditor!", "map"); } string[] terrainObjIndexTable = terrainObjListPackage.ReadStringArray(0); byte[] terrainObjInfoBytes = terrainObjListPackage.ReadByteArray(1); int offset = 0; while (offset < terrainObjInfoBytes.Length) { int parsedBytes; RCPackage package = RCPackage.Parse(terrainObjInfoBytes, offset, terrainObjInfoBytes.Length - offset, out parsedBytes); if (package == null || !package.IsCommitted) { throw new MapException("Syntax error!"); } offset += parsedBytes; if (package.PackageFormat.ID == MapFileFormat.TERRAINOBJ) { RCIntVector quadCoords = new RCIntVector(package.ReadShort(0), package.ReadShort(1)); ITerrainObjectType terrainObjType = this.mapStructure.Tileset.GetTerrainObjectType(terrainObjIndexTable[package.ReadByte(2)]); /// TODO: Might be better to create the TerrainObject with a factory? ITerrainObject newObj = new TerrainObject(map, terrainObjType, quadCoords); foreach (ICellDataChangeSet changeset in newObj.Type.CellDataChangesets) { changeset.Apply(newObj); } mapObj.AttachTerrainObject(newObj); } } /// Check the constraints of the terrain objects. List <ITerrainObject> terrainObjects = new List <ITerrainObject>(map.TerrainObjects); foreach (ITerrainObject terrainObj in terrainObjects) { mapObj.DetachTerrainObject(terrainObj); if (terrainObj.Type.CheckConstraints(map, terrainObj.MapCoords).Count != 0) { throw new MapException(string.Format("Terrain object at {0} is voilating the tileset constraints!", terrainObj.MapCoords)); } if (terrainObj.Type.CheckTerrainObjectIntersections(map, terrainObj.MapCoords).Count != 0) { throw new MapException(string.Format("Terrain object at {0} intersects other terrain objects!", terrainObj.MapCoords)); } mapObj.AttachTerrainObject(terrainObj); } }
/// <see cref="IMapEditor.PlaceTerrainObject"/> public ITerrainObject PlaceTerrainObject(IMapAccess targetMap, IQuadTile targetTile, ITerrainObjectType type) { if (targetMap == null) { throw new ArgumentNullException("targetMap"); } if (targetTile == null) { throw new ArgumentNullException("targetTile"); } if (type == null) { throw new ArgumentNullException("type"); } if (targetMap.Tileset != type.Tileset) { throw new InvalidOperationException("The tileset of the terrain object type must be the same as the tileset of the map!"); } /// TODO: Avoid this downcast! MapAccess targetMapObj = targetMap as MapAccess; if (targetMapObj == null) { throw new ArgumentException("The given map cannot be handled by the MapEditor!", "targetMap"); } if (type.CheckConstraints(targetMap, targetTile.MapCoords).Count != 0) { return(null); } if (type.CheckTerrainObjectIntersections(targetMap, targetTile.MapCoords).Count != 0) { return(null); } /// TODO: Might be better to create the TerrainObject with a factory? ITerrainObject newObj = new TerrainObject(targetMap, type, targetTile.MapCoords); foreach (ICellDataChangeSet changeset in newObj.Type.CellDataChangesets) { changeset.Apply(newObj); } targetMapObj.AttachTerrainObject(newObj); return(newObj); }
/// <see cref="IMapLoader.LoadMap"/> public IMapAccess LoadMap(ITileSet tileset, byte[] data) { if (!this.initThreadStarted) { throw new InvalidOperationException("Component has not yet been started!"); } this.initThread.Join(); if (tileset == null) { throw new ArgumentNullException("tileset"); } if (data == null) { throw new ArgumentNullException("data"); } /// Load the packages from the byte array. RCPackage mapHeaderPackage = null; RCPackage isotileListPackage = null; RCPackage terrainObjListPackage = null; int offset = 0; while (offset < data.Length) { int parsedBytes; RCPackage package = RCPackage.Parse(data, offset, data.Length - offset, out parsedBytes); if (package == null || !package.IsCommitted) { throw new MapException("Syntax error!"); } offset += parsedBytes; if (package.PackageFormat.ID == MapFileFormat.MAP_HEADER) { mapHeaderPackage = package; } else if (package.PackageFormat.ID == MapFileFormat.ISOTILE_LIST) { isotileListPackage = package; } else if (package.PackageFormat.ID == MapFileFormat.TERRAINOBJ_LIST) { terrainObjListPackage = package; } } /// Validate the packages. if (mapHeaderPackage == null) { throw new MapException("Syntax error: map header is missing!"); } if (isotileListPackage == null) { throw new MapException("Syntax error: isometric-tile-list is missing!"); } if (terrainObjListPackage == null) { throw new MapException("Syntax error: terrain-object-list is missing!"); } /// Validate the map header. MapHeader mapHeader = MapHeader.FromPackage(mapHeaderPackage); if (mapHeader.AppVersion > new Version(ConstantsTable.Get <string>("RC.App.Version"))) { throw new MapException(string.Format("Incompatible map version: {0}!", mapHeader.AppVersion)); } if (mapHeader.TilesetName != tileset.Name) { throw new ArgumentException(string.Format("The given tileset '{0}' has to equal with the map tileset '{1}'!", tileset.Name, mapHeader.TilesetName), "tileset"); } if (mapHeader.MapSize.X > MapStructure.MAX_MAPSIZE || mapHeader.MapSize.Y > MapStructure.MAX_MAPSIZE) { throw new MapException(string.Format("Map size exceeds the limits: {0}x{0}!", MapStructure.MAX_MAPSIZE)); } MapAccess retObj = new MapAccess(mapHeader.MapName, this.mapStructure); this.mapStructure.BeginOpen(tileset, mapHeader.MapSize); this.LoadIsoTiles(isotileListPackage); this.mapStructure.EndOpen(); this.LoadTerrainObjects(terrainObjListPackage, retObj); // TODO: validate MapHeader.MaxPlayers! // TODO: validate the MapHeader checksums! return(retObj); }