/// <summary> /// Locates the entities that are in the sight-range of the owner entity. /// </summary> /// <returns>The entities that are in the sight-range of the owner entity.</returns> public RCSet <Entity> LocateEntities() { /// Collect the entities in sight-range. RCSet <Entity> retList = new RCSet <Entity>(); RCSet <Entity> entitiesToCheck = this.owner.Read().Scenario.GetElementsOnMap <Entity>(this.owner.Read().MotionControl.PositionVector.Read(), this.GetSightRangeOfOwner(), MapObjectLayerEnum.GroundObjects, MapObjectLayerEnum.AirObjects); entitiesToCheck.Remove(this.owner.Read()); RCSet <RCIntVector> visibleQuadCoords = this.VisibleQuadCoords; foreach (Entity entity in entitiesToCheck) { bool breakFlag = false; for (int row = entity.MapObject.QuadraticPosition.Top; !breakFlag && row < entity.MapObject.QuadraticPosition.Bottom; row++) { for (int col = entity.MapObject.QuadraticPosition.Left; !breakFlag && col < entity.MapObject.QuadraticPosition.Right; col++) { if (visibleQuadCoords.Contains(new RCIntVector(col, row))) { retList.Add(entity); breakFlag = true; } } } } return(retList); }
/// <see cref="EntityPlacementConstraint.CheckImpl"/> protected override RCSet <RCIntVector> CheckImpl(Scenario scenario, RCIntVector position, RCSet <Entity> entitiesToIgnore) { RCIntRectangle objArea = new RCIntRectangle(position, scenario.Map.CellToQuadSize(this.EntityType.Area.Read().Size)); RCSet <RCIntVector> retList = new RCSet <RCIntVector>(); for (int absY = objArea.Top; absY < objArea.Bottom; absY++) { for (int absX = objArea.Left; absX < objArea.Right; absX++) { RCIntVector absQuadCoords = new RCIntVector(absX, absY); if (absQuadCoords.X >= 0 && absQuadCoords.X < scenario.Map.Size.X && absQuadCoords.Y >= 0 && absQuadCoords.Y < scenario.Map.Size.Y) { /// Collect all the entities that are on the ground, are too close and not to be ignored. RCIntRectangle checkedQuadRect = new RCIntRectangle(absQuadCoords - this.minimumDistance, this.checkedQuadRectSize); RCNumRectangle checkedArea = (RCNumRectangle)scenario.Map.QuadToCellRect(checkedQuadRect) - new RCNumVector(1, 1) / 2; RCSet <T> entitiesTooClose = scenario.GetElementsOnMap <T>(checkedArea, MapObjectLayerEnum.GroundObjects); if (entitiesTooClose.Any(entityTooClose => !entitiesToIgnore.Contains(entityTooClose))) { retList.Add(absQuadCoords - position); } } } } return(retList); }
/// <see cref="BuildingPlacementSuggestionProvider.GetSuggestionsImpl"/> protected override RCSet <Tuple <RCIntRectangle, RCIntVector> > GetSuggestionsImpl(Scenario scenario, RCIntRectangle area) { RCSet <Tuple <RCIntRectangle, RCIntVector> > retList = new RCSet <Tuple <RCIntRectangle, RCIntVector> >(); RCSet <Addon> processedAddons = new RCSet <Addon>(); for (int x = area.Left; x < area.Right; x++) { for (int y = area.Top; y < area.Bottom; y++) { RCIntVector quadCoords = new RCIntVector(x, y); Addon addon = scenario.GetFixedEntity <Addon>(quadCoords); if (addon == null || processedAddons.Contains(addon) || addon.CurrentMainBuilding != null || !this.BuildingType.HasAddonType(addon.AddonType.Name)) { continue; } retList.Add(Tuple.Create( addon.MapObject.QuadraticPosition, (-1) * this.BuildingType.GetRelativeAddonPosition(scenario.Map, addon.AddonType))); processedAddons.Add(addon); } } return(retList); }
/// <summary> /// Creates the given components from the given assembly. /// </summary> /// <param name="assembly">The assembly of the components.</param> /// <param name="components">The components to create.</param> private static void CreateComponentsFromAssembly(string assembly, RCSet <string> components) { TraceManager.WriteAllTrace(string.Format("Creating components of assembly '{0}'.", assembly), ComponentManager.COMPONENT_MGR_INFO); Assembly asm = Assembly.Load(assembly); if (asm != null) { Type[] types = asm.GetTypes(); foreach (Type type in types) { ComponentAttribute compAttr = GetComponentAttribute(type); if (compAttr == null) { continue; } if (createdComponents.ContainsKey(compAttr.Name)) { continue; } if (components.Contains(compAttr.Name)) { CreateComponentInstance(compAttr.Name, type); } } } else { throw new ComponentModelException(string.Format("Unable to load assembly '{0}'!", assembly)); } }
/// <summary> /// Gets the subdivision that is calculated for the given agent. /// </summary> /// <param name="agent">The given agent.</param> /// <returns>The subdivision that is calculated for the given agent.</returns> public SectorSubdivision GetSubdivisionForAgent(Agent agent) { /// Collect the overlap enabled agents. RCSet <Agent> overlapEnabledAgents = new RCSet <Agent>(); RCSet <Agent> currentlyOverlappingAgents = this.grid[agent.Area.X, agent.Area.Y].GetAgents(agent.MovingSize); foreach (Agent staticAgent in this.staticAgents[agent.MovingSize]) { if (currentlyOverlappingAgents.Contains(staticAgent) || staticAgent.Client.IsOverlapEnabled(agent.Client) || agent.Client.IsOverlapEnabled(staticAgent.Client)) { overlapEnabledAgents.Add(staticAgent); } } /// Try to find an already existing sector subdivision for the agent. SectorSubdivision subdivisionForAgent = this.subdivisions.FirstOrDefault(subdivision => subdivision.MovingSize == agent.MovingSize && subdivision.OverlapEnabledAgents.SetEquals(overlapEnabledAgents)); if (subdivisionForAgent == null) { /// Create a new one if not found. subdivisionForAgent = new SectorSubdivision(this, agent.MovingSize, overlapEnabledAgents); this.subdivisions.Add(subdivisionForAgent); } return(subdivisionForAgent); }
/// <summary> /// Validates the given desired position for the given agent. /// </summary> /// <param name="agent">The agent to be validated.</param> /// <param name="desiredPosition">The desired position of the agent.</param> /// <param name="collidingAgents">The output list of colliding agents if the validation failed; otherwise an empty set.</param> /// <returns>True if the desired position is OK for the given agent; otherwise false.</returns> private bool ValidatePositionForAgent(Agent agent, Cell desiredPosition, out RCSet <Agent> collidingAgents) { collidingAgents = new RCSet <Agent>(); if (desiredPosition == null) { return(false); } if (agent.MovingSize != -1) { /// This is a moving agent. if (desiredPosition.WallCellDistance < agent.MovingSize) { return(false); } Cell currentPosition = this[agent.Area.X, agent.Area.Y]; RCSet <Agent> currentlyCollidingAgents = currentPosition != desiredPosition?currentPosition.GetAgents(agent.MovingSize) : new RCSet <Agent>(); foreach (Agent overlappingAgent in desiredPosition.GetAgents(agent.MovingSize)) { if (agent != overlappingAgent && !currentlyCollidingAgents.Contains(overlappingAgent) && !agent.Client.IsOverlapEnabled(overlappingAgent.Client) && !overlappingAgent.Client.IsOverlapEnabled(agent.Client)) { collidingAgents.Add(overlappingAgent); } } } else { /// This is a static agent. if (this[agent.Area.X, agent.Area.Y] != desiredPosition) { throw new InvalidOperationException("Static agents are not supported to move!"); } for (int row = desiredPosition.Coords.Y; row < desiredPosition.Coords.Y + agent.Area.Height; row++) { for (int column = desiredPosition.Coords.X; column < desiredPosition.Coords.X + agent.Area.Width; column++) { Cell cell = this[column, row]; if (cell == null || cell.WallCellDistance == 0) { return(false); } foreach (Agent overlappingAgent in cell.GetAgents(1)) { if (agent != overlappingAgent && !agent.Client.IsOverlapEnabled(overlappingAgent.Client) && !overlappingAgent.Client.IsOverlapEnabled(agent.Client)) { collidingAgents.Add(overlappingAgent); } } } } } return(collidingAgents.Count == 0); }
/// <summary> /// Creates the package that contains the description of the isometric tiles of the given map. /// </summary> /// <param name="map">Reference to the map.</param> /// <returns>The data package that contains the description of the isometric tiles of the given map.</returns> private RCPackage CreateIsoTileListPackage(IMapAccess map) { RCPackage isotileList = RCPackage.CreateCustomDataPackage(MapFileFormat.ISOTILE_LIST); /// Create the terrain type index table. List <string> terrainTypeList = new List <string>(); Dictionary <ITerrainType, int> terrainTypeIndexTable = new Dictionary <ITerrainType, int>(); int terrainTypeIndex = 0; foreach (ITerrainType terrainType in map.Tileset.TerrainTypes) { terrainTypeList.Add(terrainType.Name); terrainTypeIndexTable.Add(terrainType, terrainTypeIndex); terrainTypeIndex++; } isotileList.WriteStringArray(0, terrainTypeList.ToArray()); /// Create the packages of the isometric tiles. RCSet <IIsoTile> processedIsoTiles = new RCSet <IIsoTile>(); List <RCPackage> isotilePackages = new List <RCPackage>(); int isotileInfoLength = 0; for (int row = 0; row < map.Size.Y; row++) { for (int column = 0; column < map.Size.X; column++) { IIsoTile currIsoTile = map.GetQuadTile(new RCIntVector(column, row)).PrimaryIsoTile; if (!processedIsoTiles.Contains(currIsoTile)) { RCPackage isotilePackage = RCPackage.CreateCustomDataPackage(MapFileFormat.ISOTILE); isotilePackage.WriteShort(0, (short)column); isotilePackage.WriteShort(1, (short)row); isotilePackage.WriteByte(2, (byte)terrainTypeIndexTable[currIsoTile.Type.TerrainA]); isotilePackage.WriteByte(3, currIsoTile.Type.TerrainB != null ? (byte)terrainTypeIndexTable[currIsoTile.Type.TerrainB] : (byte)0); isotilePackage.WriteByte(4, (byte)currIsoTile.Type.Combination); isotilePackage.WriteByte(5, (byte)currIsoTile.VariantIdx); isotilePackages.Add(isotilePackage); processedIsoTiles.Add(currIsoTile); isotileInfoLength += isotilePackage.PackageLength; } } } /// Write the isometric tile packages into the final package byte[] isotileInfoBytes = new byte[isotileInfoLength]; int offset = 0; foreach (RCPackage isotilePackage in isotilePackages) { offset += isotilePackage.WritePackageToBuffer(isotileInfoBytes, offset); } isotileList.WriteByteArray(1, isotileInfoBytes); return(isotileList); }
/// <see cref="IFogOfWarBC.ExecuteUpdateIteration"/> public void ExecuteUpdateIteration() { if (this.ActiveScenario == null) { throw new InvalidOperationException("No active scenario!"); } if (this.runningFowsCount == 0) { return; } int remainingEntitiesInCurrIteration = MAX_ENTITIES_PER_ITERATION; RCSet <FogOfWar> fowsProcessedInCurrIteration = new RCSet <FogOfWar>(); while (remainingEntitiesInCurrIteration > 0) { /// Search the first running FOW starting from the current index. while (this.runningFows[this.fowIndex] == null) { this.fowIndex = (this.fowIndex + 1) % this.runningFows.Length; } /// First running FOW found. Finish the iteration if that FOW has already been processed in this iteration. FogOfWar fowToProcess = this.runningFows[this.fowIndex]; if (fowsProcessedInCurrIteration.Contains(fowToProcess)) { break; } /// Start or continue updating the FOW based on whether this is the first iteration or not. remainingEntitiesInCurrIteration -= this.currentIterationIndex == 0 ? fowToProcess.RestartUpdate(remainingEntitiesInCurrIteration) : fowToProcess.ContinueUpdate(remainingEntitiesInCurrIteration); /// Add the updated FOW to the set of already processed FOWs and move to the next FOW-index. fowsProcessedInCurrIteration.Add(fowToProcess); this.fowIndex = (this.fowIndex + 1) % this.runningFows.Length; } /// Move to the next iteration. this.currentIterationIndex++; /// If all the running FOWs have been updated in this iteration, finish the update if necessary. if (fowsProcessedInCurrIteration.Count == this.runningFowsCount && this.currentIterationIndex == MIN_ITERATIONS_PER_UPDATE) { this.currentIterationIndex = 0; } /// Invalidate the cache if necessary. if (fowsProcessedInCurrIteration.Count > 0) { this.cache.Invalidate(); } }
/// <summary> /// Helper method for stop a set of animations and then start another set of animations of the given entity in one step. /// Animations in the intersection of the given sets won't be touched. /// </summary> /// <param name="animationsToStop">The set of animations to stop.</param> /// <param name="animationsToStart">The set of animations to start.</param> /// <param name="headingVectors">The heading vectors in priority order.</param> protected void StopStartAnimations(Entity entity, RCSet <string> animationsToStop, RCSet <string> animationsToStart, params IValueRead <RCNumVector>[] headingVectors) { foreach (string animationToStop in animationsToStop) { if (!animationsToStart.Contains(animationToStop)) { entity.MapObject.StopAnimation(animationToStop); } } foreach (string animationToStart in animationsToStart) { entity.MapObject.StartAnimation(animationToStart, headingVectors); } }
/// <see cref="ISelectionIndicatorView.GetVisibleSelIndicators"/> public List <SelIndicatorRenderInfo> GetVisibleSelIndicators() { RCSet <int> currentSelection = this.selectionManager.CurrentSelection; if (currentSelection.Count == 0) { return(new List <SelIndicatorRenderInfo>()); } /// Display the selection indicators of the currently visible entities inside the currently visible window of quadratic tiles. List <SelIndicatorRenderInfo> retList = new List <SelIndicatorRenderInfo>(); foreach (MapObject mapObject in this.fogOfWarBC.GetAllMapObjectsToUpdate()) { Entity entity = mapObject.Owner as Entity; if (entity != null && currentSelection.Contains(entity.ID.Read())) { SelIndicatorTypeEnum indicatorType = entity.Owner != null ? (entity.Owner.PlayerIndex == (int)this.selectionManager.LocalPlayer ? SelIndicatorTypeEnum.Friendly : SelIndicatorTypeEnum.Enemy) : SelIndicatorTypeEnum.Neutral; RCNumber hpNorm = entity.Biometrics.HP != -1 ? entity.Biometrics.HP / entity.ElementType.MaxHP.Read() : -1; RCNumber energyNorm = -1; if (entity.Owner != null && entity.Owner.PlayerIndex == (int)this.selectionManager.LocalPlayer) { energyNorm = entity.Biometrics.Energy != -1 ? entity.Biometrics.Energy / entity.ElementType.MaxEnergy.Read() : -1; } retList.Add(new SelIndicatorRenderInfo() { ObjectID = entity.ID.Read(), SelIndicatorType = indicatorType, IndicatorRect = this.MapWindowBC.AttachedWindow.MapToWindowRect(entity.Area), HpNormalized = hpNorm, EnergyNormalized = energyNorm, ShieldNormalized = -1, // TODO: must be based on real data after Protoss will have been implemented! }); } } return(retList); }
/// <summary> /// Raises the mouse button events on the appropriate sensor. /// </summary> private void RaiseMouseButtonEvents(RCSet <UIMouseButton> buttons, RCIntVector newPointerPos, UIMouseSensor targetSensor) { foreach (UIMouseButton btn in this.pressedButtons) { if (!buttons.Contains(btn)) { targetSensor.OnButtonUp(newPointerPos, btn); } } foreach (UIMouseButton btn in buttons) { if (!this.pressedButtons.Contains(btn)) { targetSensor.OnButtonDown(newPointerPos, btn); } } }
/// <summary> /// Unloads the sprite group. /// </summary> public void Unload() { if (!this.isLoaded) { throw new InvalidOperationException("The sprite-group is not loaded!"); } /// Destroy the sprites of this sprite group (be aware of duplicated sprites). RCSet <UISprite> destroyedSprites = new RCSet <UISprite>(); foreach (UISprite sprite in this.spriteList) { if (sprite != null && !destroyedSprites.Contains(sprite)) { UIRoot.Instance.GraphicsPlatform.SpriteManager.DestroySprite(sprite); destroyedSprites.Add(sprite); } } this.spriteList.Clear(); this.isLoaded = false; }
/// <see cref="BuildingPlacementSuggestionProvider.GetSuggestionsImpl"/> protected override RCSet <Tuple <RCIntRectangle, RCIntVector> > GetSuggestionsImpl(Scenario scenario, RCIntRectangle area) { RCSet <Tuple <RCIntRectangle, RCIntVector> > retList = new RCSet <Tuple <RCIntRectangle, RCIntVector> >(); RCSet <VespeneGeyser> processedVespeneGeysers = new RCSet <VespeneGeyser>(); for (int x = area.Left; x < area.Right; x++) { for (int y = area.Top; y < area.Bottom; y++) { RCIntVector quadCoords = new RCIntVector(x, y); VespeneGeyser vespeneGeyser = scenario.GetFixedEntity <VespeneGeyser>(quadCoords); if (vespeneGeyser == null || processedVespeneGeysers.Contains(vespeneGeyser)) { continue; } retList.Add(Tuple.Create(vespeneGeyser.MapObject.QuadraticPosition, new RCIntVector(0, 0))); processedVespeneGeysers.Add(vespeneGeyser); } } return(retList); }
/// <summary> /// Checks the given upgrade type if it is OK to attach to this upgrade type as previous level. /// </summary> /// <param name="potentialPreviousLevel">The upgrade type to check.</param> private void CheckPotentialPreviousLevel(UpgradeType potentialPreviousLevel) { if (potentialPreviousLevel.nextLevel != null) { throw new SimulatorException(string.Format("UpgradeType '{0}' already has a next level!", potentialPreviousLevel.Name)); } RCSet <UpgradeType> levelPath = new RCSet <UpgradeType> { this, potentialPreviousLevel }; UpgradeType currPathNode = potentialPreviousLevel; while (currPathNode.previousLevel != null) { if (levelPath.Contains(currPathNode.previousLevel)) { throw new SimulatorException(string.Format("Cycle found from UpgradeType '{0}' to '{1}'!", potentialPreviousLevel.Name, this.Name)); } levelPath.Add(currPathNode.previousLevel); currPathNode = currPathNode.previousLevel; } }
/// <summary> /// Constructs a ColorPalette object. /// </summary> /// <param name="palette">See ColorPalette.palette for more informations.</param> /// <param name="paletteMask">See ColorPalette.paletteMask for more informations.</param> /// <param name="specialColors">See ColorPalette.specialColors for more informations.</param> /// <remarks> /// Only the first parameter is mandatory. You can give null references for the others. /// </remarks> public ColorPalette(Color[] palette, Color[] paletteMask, Color[] specialColors) { this.palette = null; this.paletteMask = null; this.specialColors = null; /// Checking arguments. if (null == palette || 0 == palette.Length) { throw new ArgumentException("You must define at least 1 color in the palette.", "palette"); } if (null != paletteMask && palette.Length != paletteMask.Length) { throw new ArgumentException("The arrays palette and paletteMask must have the same length."); } /// Saving the color palette. RCSet <Color> paletteSet = new RCSet <Color>(); foreach (Color c in palette) { if (!paletteSet.Contains(c)) { paletteSet.Add(c); } else { throw new ArgumentException("All colors in the array palette must be unique.", "palette"); } } this.palette = palette; /// Saving the paletteMask. this.paletteMask = new Dictionary <Color, int>(); if (null != paletteMask) { int idx = 0; foreach (Color c in paletteMask) { if (!this.paletteMask.ContainsKey(c)) { this.paletteMask.Add(c, idx); idx++; } else { throw new ArgumentException("All colors in the array paletteMask must be unique.", "paletteMask"); } } } else { /// If no palette mask defined, we simply create the inverse of this.palette for (int idx = 0; idx < this.palette.Length; ++idx) { this.paletteMask.Add(this.palette[idx], idx); } } /// Saving the special colors. if (null != specialColors) { RCSet <Color> specColorSet = new RCSet <Color>(); foreach (Color c in specialColors) { if (!specColorSet.Contains(c)) { if (!paletteSet.Contains(c) && !this.paletteMask.ContainsKey(c)) { specColorSet.Add(c); } else { throw new ArgumentException("A color defined in the array specialColors has already been defined in the array palette or paletteMask.", "specialColors"); } } else { throw new ArgumentException("All colors in the array specialColors must be unique.", "specialColors"); } } this.specialColors = specialColors; } }
/// <see cref="IObjectPlacementView.GetObjectPlacementBox"/> public ObjectPlacementBox GetObjectPlacementBox(RCIntVector position) { /// Calculate the top-left quadratic coordinates based on the retrieved object rectangles relative to the quadratic tile at the incoming position. RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> > objRectsRelativeToQuadTileAtPos = this.GetObjectRelativeQuadRectangles(); if (objRectsRelativeToQuadTileAtPos.Count == 0) { return(new ObjectPlacementBox { Sprites = new List <SpriteRenderInfo>(), IllegalParts = new List <RCIntRectangle>(), LegalParts = new List <RCIntRectangle>() }); } RCIntVector navCellCoords = this.MapWindowBC.AttachedWindow.WindowToMapCoords(position).Round(); IQuadTile quadTileAtPos = this.Map.GetCell(navCellCoords).ParentQuadTile; RCIntVector topLeftQuadCoords = quadTileAtPos.MapCoords; foreach (Tuple <RCIntRectangle, SpriteRenderInfo[]> relativeRect in objRectsRelativeToQuadTileAtPos) { RCIntVector rectTopLeftQuadCoords = topLeftQuadCoords + relativeRect.Item1.Location; if (rectTopLeftQuadCoords.X < topLeftQuadCoords.X && rectTopLeftQuadCoords.Y < topLeftQuadCoords.Y || rectTopLeftQuadCoords.X < topLeftQuadCoords.X && rectTopLeftQuadCoords.Y == topLeftQuadCoords.Y || rectTopLeftQuadCoords.X == topLeftQuadCoords.X && rectTopLeftQuadCoords.Y < topLeftQuadCoords.Y) { topLeftQuadCoords = rectTopLeftQuadCoords; } } /// Calculate the object rectangles relative to the calculated top-left quadratic coordinates. RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> > objRectsRelativeToTopLeftQuadTile = new RCSet <Tuple <RCIntRectangle, SpriteRenderInfo[]> >(); foreach (Tuple <RCIntRectangle, SpriteRenderInfo[]> relativeRect in objRectsRelativeToQuadTileAtPos) { objRectsRelativeToTopLeftQuadTile.Add(Tuple.Create( new RCIntRectangle( relativeRect.Item1.Location + quadTileAtPos.MapCoords - topLeftQuadCoords, relativeRect.Item1.Size), relativeRect.Item2)); } /// Get the sprites to be displayed, translate their DisplayCoordinates accordingly from the top-left quadratic tile, /// and collect the violating quadratic coordinates. ObjectPlacementBox placementBox = new ObjectPlacementBox { Sprites = new List <SpriteRenderInfo>(), IllegalParts = new List <RCIntRectangle>(), LegalParts = new List <RCIntRectangle>() }; RCSet <RCIntVector> violatingQuadCoords = this.CheckObjectConstraints(topLeftQuadCoords); foreach (Tuple <RCIntRectangle, SpriteRenderInfo[]> relativeRect in objRectsRelativeToTopLeftQuadTile) { RCIntVector topLeftDisplayCoords = this.MapWindowBC.AttachedWindow.QuadToWindowRect(new RCIntRectangle(topLeftQuadCoords + relativeRect.Item1.Location, new RCIntVector(1, 1))).Location; for (int i = 0; i < relativeRect.Item2.Length; i++) { relativeRect.Item2[i].DisplayCoords += topLeftDisplayCoords; placementBox.Sprites.Add(relativeRect.Item2[i]); } for (int x = relativeRect.Item1.Left; x < relativeRect.Item1.Right; x++) { for (int y = relativeRect.Item1.Top; y < relativeRect.Item1.Bottom; y++) { RCIntVector relativeQuadCoords = new RCIntVector(x, y); RCIntVector absQuadCoords = topLeftQuadCoords + relativeQuadCoords; RCIntRectangle partRect = this.MapWindowBC.AttachedWindow.QuadToWindowRect(new RCIntRectangle(absQuadCoords, new RCIntVector(1, 1))); if (violatingQuadCoords.Contains(relativeQuadCoords)) { placementBox.IllegalParts.Add(partRect); } else { placementBox.LegalParts.Add(partRect); } } } } return(placementBox); }
/// <see cref="PetriNet.AttachThread"/> public void AttachThread(RCSet <PNTransition> extTransitions, Dictionary <PNTransition, PetriNet.PNCallback> callbacks) { if (this.threadAttached.WaitOne(0)) { try { /// Check the parameters. CheckThreadAttachParameters(extTransitions, callbacks); /// First we only allowed to fire external transitions. PetriNet.PNTransitionType stage = PetriNet.PNTransitionType.EXTERNAL; /// Start the thread control loop. while (true) { /// Wait for a fireable transition. this.releaseEvent.WaitOne(); lock (this.lockObject) { while (this.fireableTransitions.Count > 0) { if (stage == PetriNet.PNTransitionType.EXTERNAL) { /// Find the first fireable external transition PNTransition firstExtTr = null; foreach (PNTransition fireableTr in this.fireableTransitions) { if (this.transitions[fireableTr] == PetriNet.PNTransitionType.CALLBACK) { throw new PetriNetException("Invalid type of fireable transition detected!"); } if (firstExtTr == null && this.transitions[fireableTr] == PetriNet.PNTransitionType.EXTERNAL && extTransitions.Contains(fireableTr)) { firstExtTr = fireableTr; } } /// Fire the transition. if (firstExtTr != null) { firstExtTr.Fire(); stage = PetriNet.PNTransitionType.INTERNAL; } else { /// No fireable external transitions have been found. break; } } else if (stage == PetriNet.PNTransitionType.INTERNAL) { /// Find the first fireable internal transition or a callback transition PNTransition trToFire = null; foreach (PNTransition fireableTr in this.fireableTransitions) { if (this.transitions[fireableTr] == PetriNet.PNTransitionType.INTERNAL) { if (trToFire == null) { trToFire = fireableTr; } } else if (this.transitions[fireableTr] == PetriNet.PNTransitionType.CALLBACK) { if (this.fireableTransitions.Count == 1) { /// End of thread attach: fire the transition, invoke the callback and return. fireableTr.Fire(); callbacks[fireableTr](fireableTr.Index); /// Detach the thread and exit from the function. this.threadAttached.Release(); return; } else { throw new PetriNetException("Invalid state during a thread attach!"); } } else { throw new PetriNetException("Invalid type of fireable transition detected!"); } } if (trToFire != null) { trToFire.Fire(); } else { /// No fireable internal transitions have been found. break; } } } } } } catch { /// Error occured --> Detach the thread and re-throw the exception. this.threadAttached.Release(); throw; } } else { throw new PetriNetException("You cannot attach more than one threads to the same transition group at the same time!"); } }
/// <summary> /// Processes the channel events and incoming answers arrived from the guests. /// </summary> private void ProcessGuestChannels(IDssGuestChannel[] channelsToGuests) { RCSet <int> newGuests = new RCSet <int>(); /// First collect the new guests for (int i = 0; i < this.previousChannelStates.Length; i++) { if (this.previousChannelStates[i] != channelsToGuests[i].ChannelState) { /// The state of a channel has changed this.previousChannelStates[i] = channelsToGuests[i].ChannelState; if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_OPENED) { this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideOpened); } else if (channelsToGuests[i].ChannelState == DssChannelState.CHANNEL_CLOSED) { this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideClosed); } else if (channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED) { this.uiCallMarshal.SetGuestControlStatus(i, GuestControlStatus.HostSideEngaged); this.simulator.GetPlayer(i + 1).Activate(); newGuests.Add(i); } } } /// Then process the answers of any other guests. for (int i = 0; i < this.previousChannelStates.Length; i++) { if (!newGuests.Contains(i) && channelsToGuests[i].ChannelState == DssChannelState.GUEST_CONNECTED) { /// If a guest is connected to this channel, process it's answer. RCPackage[] answerFromGuest = channelsToGuests[i].AnswerFromGuest; for (int j = 0; j < answerFromGuest.Length; j++) { if (answerFromGuest[j].PackageFormat.ID == TestClientMessages.COLOR_CHANGE_REQUEST) { /// Color change request arrived from the guest. PlayerColor newColor = (PlayerColor)answerFromGuest[j].ReadByte(0); this.simulator.GetPlayer(i + 1).Color = newColor; /// Notify the other connected guests. for (int k = 0; k < channelsToGuests.Length; k++) { if (!newGuests.Contains(k) && i != k && channelsToGuests[k].ChannelState == DssChannelState.GUEST_CONNECTED) { RCPackage colorChgNotif = RCPackage.CreateNetworkControlPackage(TestClientMessages.COLOR_CHANGE_NOTIFICATION); colorChgNotif.WriteInt(0, i + 1); colorChgNotif.WriteByte(1, (byte)newColor); this.rqs[k].Add(colorChgNotif); } } /// Notify the UI this.uiCallMarshal.SelectNewGuestColor(i, newColor); break; /// Ignore the remaining messages } } } } /// Send a reset message to the new guests foreach (int newGuestIdx in newGuests) { byte[] colors = new byte[this.simulator.MaxNumOfPlayers]; int[] xCoords = new int[this.simulator.MaxNumOfPlayers]; int[] yCoords = new int[this.simulator.MaxNumOfPlayers]; for (int j = 0; j < colors.Length; j++) { colors[j] = (byte)this.simulator.GetPlayer(j).Color; xCoords[j] = this.simulator.GetPlayer(j).Position.X; yCoords[j] = this.simulator.GetPlayer(j).Position.Y; } RCPackage reset = RCPackage.CreateNetworkControlPackage(TestClientMessages.RESET); reset.WriteByteArray(0, colors); reset.WriteIntArray(1, xCoords); reset.WriteIntArray(2, yCoords); this.rqs[newGuestIdx].Add(reset); } }
/// <summary> /// Searches any placeholders in the given format string. /// </summary> /// <param name="format">The format string to search in.</param> /// <returns>The list of the found placeholders.</returns> private static List <PlaceHolder> SearchPlaceHolders(string format) { RCSet <int> escapedOpeningBraces = SearchForwardInFormatString(format, "{{"); RCSet <int> escapedClosingBraces = SearchBackwardInFormatString(format, "}}"); List <PlaceHolder> retList = new List <PlaceHolder>(); int startSearchFrom = 0; while (startSearchFrom < format.Length) { int idxOfOpeningBrace = format.IndexOf('{', startSearchFrom); if (idxOfOpeningBrace == -1) { break; } /// No more placeholders if (escapedOpeningBraces.Contains(idxOfOpeningBrace)) { /// Part of an escaped opening brace startSearchFrom = idxOfOpeningBrace + 2; continue; } if (escapedOpeningBraces.Contains(idxOfOpeningBrace - 1)) { /// Part of an escaped opening brace startSearchFrom = idxOfOpeningBrace + 1; continue; } /// Opening brace of placeholder found, search for closing brace startSearchFrom = idxOfOpeningBrace + 1; if (startSearchFrom == format.Length) { throw new ArgumentException("Format string parsing error!", "format"); } int idxOfClosingBrace = format.IndexOf('}', startSearchFrom); if (idxOfClosingBrace == -1) { throw new ArgumentException("Format string parsing error!", "format"); } if (escapedClosingBraces.Contains(idxOfClosingBrace) || escapedClosingBraces.Contains(idxOfClosingBrace - 1)) { /// Part of an escaped closing brace throw new ArgumentException("Format string parsing error!", "format"); } /// Try to parse the placeholder string string placeholderNumStr = format.Substring(idxOfOpeningBrace + 1, idxOfClosingBrace - idxOfOpeningBrace - 1); int placeholderNum; if (placeholderNumStr == string.Empty || !int.TryParse(placeholderNumStr, out placeholderNum)) { throw new ArgumentException("Format string parsing error!", "format"); } /// Create the new placeholder PlaceHolder newPlaceholder = new PlaceHolder() { StartIndex = idxOfOpeningBrace, Length = idxOfClosingBrace - idxOfOpeningBrace + 1, Number = placeholderNum }; retList.Add(newPlaceholder); startSearchFrom = idxOfClosingBrace + 1; } return(retList); }