/// <see cref="IScenarioLoader.LoadScenario"/> public Scenario LoadScenario(IMapAccess map, byte[] data) { if (map == null) { throw new ArgumentNullException("map"); } if (data == null) { throw new ArgumentNullException("data"); } /// Load the packages from the byte array. int offset = 0; Scenario scenario = new Scenario(map); while (offset < data.Length) { int parsedBytes; RCPackage package = RCPackage.Parse(data, offset, data.Length - offset, out parsedBytes); if (package == null || !package.IsCommitted) { throw new SimulatorException("Syntax error!"); } offset += parsedBytes; if (package.PackageFormat.ID == ScenarioFileFormat.MINERAL_FIELD) { IQuadTile quadTile = map.GetQuadTile(new RCIntVector(package.ReadShort(0), package.ReadShort(1))); MineralField mineralField = new MineralField(); mineralField.ResourceAmount.Write(package.ReadInt(2)); scenario.AddElementToScenario(mineralField); mineralField.AttachToMap(quadTile); } else if (package.PackageFormat.ID == ScenarioFileFormat.VESPENE_GEYSER) { IQuadTile quadTile = map.GetQuadTile(new RCIntVector(package.ReadShort(0), package.ReadShort(1))); VespeneGeyser vespeneGeyser = new VespeneGeyser(); vespeneGeyser.ResourceAmount.Write(package.ReadInt(2)); scenario.AddElementToScenario(vespeneGeyser); vespeneGeyser.AttachToMap(quadTile); } else if (package.PackageFormat.ID == ScenarioFileFormat.START_LOCATION) { IQuadTile quadTile = map.GetQuadTile(new RCIntVector(package.ReadShort(0), package.ReadShort(1))); StartLocation startLocation = new StartLocation(package.ReadByte(2)); scenario.AddElementToScenario(startLocation); startLocation.AttachToMap(quadTile); } } /// Check the constraints of the visible entities. foreach (Entity entity in scenario.GetElementsOnMap <Entity>(MapObjectLayerEnum.GroundObjects, MapObjectLayerEnum.AirObjects)) { if (entity.CheckPlacementConstraints(entity.MapObject.QuadraticPosition.Location, new RCSet <Entity>()).Count != 0) { throw new MapException(string.Format("Entity at {0} is voilating its placement constraints!", entity.MapObject.QuadraticPosition.Location)); } } return(scenario); }
/// <summary> /// Initializes the isometric tiles of the map structure. /// </summary> /// <param name="isotileListPackage">The package that contains the isometric tile informations.</param> private void LoadIsoTiles(RCPackage isotileListPackage) { string[] terrainIndexTable = isotileListPackage.ReadStringArray(0); byte[] isotileInfoBytes = isotileListPackage.ReadByteArray(1); int offset = 0; while (offset < isotileInfoBytes.Length) { int parsedBytes; RCPackage package = RCPackage.Parse(isotileInfoBytes, offset, isotileInfoBytes.Length - offset, out parsedBytes); if (package == null || !package.IsCommitted) { throw new MapException("Syntax error!"); } offset += parsedBytes; if (package.PackageFormat.ID == MapFileFormat.ISOTILE) { RCIntVector quadCoords = new RCIntVector(package.ReadShort(0), package.ReadShort(1)); TerrainCombination terrainCombo = (TerrainCombination)package.ReadByte(4); string terrainA = terrainIndexTable[package.ReadByte(2)]; string terrainB = terrainCombo != TerrainCombination.Simple ? terrainIndexTable[package.ReadByte(3)] : null; int variantIdx = package.ReadByte(5); this.mapStructure.InitIsoTile(quadCoords, terrainCombo == TerrainCombination.Simple ? this.mapStructure.Tileset.GetIsoTileType(terrainA) : this.mapStructure.Tileset.GetIsoTileType(terrainA, terrainB, terrainCombo), variantIdx); } } }
/// <summary> /// Creates a MapHeader structure from the given RCPackage. /// </summary> /// <param name="package">The RCPackage that contains the map header informations.</param> /// <returns>The created MapHeader structure.</returns> public static MapHeader FromPackage(RCPackage package) { if (package == null) { throw new ArgumentNullException("package"); } if (!package.IsCommitted) { throw new ArgumentException("The header package is not committed!", "package"); } if (package.PackageType != RCPackageType.CUSTOM_DATA_PACKAGE) { throw new ArgumentException("Invalid package type!", "package"); } if (package.PackageFormat.ID != MapFileFormat.MAP_HEADER) { throw new ArgumentException("Invalid package format!", "package"); } MapHeader header = new MapHeader(); header.appVersion = new Version(package.ReadInt(0), package.ReadInt(1), package.ReadInt(2), package.ReadInt(3)); header.mapName = package.ReadString(4); header.tilesetName = package.ReadString(5); header.mapSize = new RCIntVector(package.ReadShort(6), package.ReadShort(7)); header.maxPlayers = package.ReadByte(8); header.checksumList = new List <int>(package.ReadIntArray(9)); if (header.mapName == null) { throw new MapException("Map name information is missing!"); } if (header.tilesetName == null) { throw new MapException("Tileset name information is missing!"); } if (header.mapSize.X <= 0 || header.mapSize.Y <= 0) { throw new MapException("Map size cannot be negative or 0!"); } if (header.maxPlayers <= 0) { throw new MapException("Maximum number of players cannot be negative or 0!"); } return(header); }
/// <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); } }
/// <summary> /// Registers the given commit arrived from the given operator. /// </summary> /// <param name="commit">The arrived commit package.</param> /// <param name="senderID">The sender operator.</param> /// <returns>True in case of success, false otherwise.</returns> public bool RegisterCommit(RCPackage commit, int senderID) { if (!this.initialized) { throw new DssException("DssSimulationMgr is uninitialized!"); } /// If we are currently finishing the simulation --> do nothing if (this.hostLeft) { return(true); } if (commit == null || !commit.IsCommitted) { throw new ArgumentException("commit"); } if (senderID == this.root.IdOfThisPeer) { throw new DssException("Unexpected commit sender!"); } if (senderID < 0 || senderID >= this.root.OpCount) { throw new ArgumentException("senderID"); } if (commit.PackageFormat.ID != DssRoot.DSS_COMMIT) { /// Package format error. return(false); } short senderAFT = commit.ReadShort(0); short senderAPT = commit.ReadShort(1); int roundIdx = commit.ReadInt(2); int ticket = commit.ReadInt(3); byte[] stateHash = commit.ReadByteArray(4); if (senderAFT < 0) { return(false); } if (senderAPT < 0) { return(false); } if (stateHash == null) { return(false); } bool success = false; if (roundIdx == this.nextRound.RoundIndex) { success = this.nextRound.Commit(senderID, senderAFT, senderAPT, stateHash); if (this.waitingForCommit && this.nextRound.IsCommitted) { TraceManager.WriteAllTrace("WAITING FOR COMMIT END", DssTraceFilters.SIMULATION_INFO); /// The missing commit has arrived, so we can continue the simulation this.waitingForCommit = false; /// Compute the scheduled time for the next frame int nextFrameStartTime = this.currentRound.BaseTime + (this.currentRound.CurrentFrameIndex + 1) * this.currentRound.TargetFrameTime; SendCommit(); SwapRounds(); /// Schedule the next frame. SetNextFrameExecutionTime(Math.Max(nextFrameStartTime, DssRoot.Time)); } } else if (roundIdx == this.nextNextRound.RoundIndex) { success = this.nextNextRound.Commit(senderID, senderAFT, senderAPT, stateHash); } else { TraceManager.WriteAllTrace(string.Format("RoundIdx mismatch! RoundIdx: {0}", roundIdx), DssTraceFilters.SIMULATION_ERROR); } if (success) { /// Create the answer for the commit and send it back to the sender. RCPackage commitAw = RCPackage.CreateNetworkCustomPackage(DssRoot.DSS_COMMIT_ANSWER); commitAw.WriteInt(0, ticket); this.root.LobbyIface.SendPackage(commitAw, new int[1] { senderID }); } return(success); }
/// <summary> /// Continues the connection procedure to the server. /// </summary> /// <returns> /// In case of error this function automatically shuts down the connection, notifies the listener and /// returns false. Otherwise it returns true. If the line state report arrives from the server, this /// function automatically notifies the listener. /// </returns> private bool ContinueConnectToTheServer() { RCPackage lineStateReport = null; if (this.connection.ContinueConnectToTheServer(out lineStateReport)) { if (lineStateReport != null) { short clientID = lineStateReport.ReadShort(0); byte[] lineStateBytes = lineStateReport.ReadByteArray(1); LobbyLineState[] lineStates = new LobbyLineState[lineStateBytes.Length]; bool lineStatesOK = true; for (int i = 0; i < lineStateBytes.Length; i++) { if (lineStateBytes[i] == (byte)LobbyLineState.Closed || lineStateBytes[i] == (byte)LobbyLineState.Engaged || lineStateBytes[i] == (byte)LobbyLineState.Opened) { lineStates[i] = (LobbyLineState)lineStateBytes[i]; } else { lineStatesOK = false; } } lineStatesOK = lineStatesOK && clientID > 0 && clientID < lineStateBytes.Length; if (!lineStatesOK) { /// Line state report error --> shutdown. this.connection.Shutdown(); if (this.Disposed != null) { this.Disposed(this); } this.listener.LobbyLost(); return(false); } else { /// Connection procedure finished --> send a line state report to the listener. this.clientID = clientID; this.memberCount = lineStates.Length; this.listener.LineStateReport(clientID, lineStates); return(true); } } /// No error but connection procedure not finished. return(true); } else { /// Connection rejected by the server or an error occured --> shutdown. this.connection.Shutdown(); if (this.Disposed != null) { this.Disposed(this); } this.listener.LobbyLost(); return(false); } }