public void Run(ModData modData, string[] args) { Game.ModData = modData; map = new Map(modData, modData.ModFiles.OpenPackage(args[1])); Console.WriteLine("Resizing map {0} from {1} to {2},{3}", map.Title, map.MapSize, width, height); map.Resize(width, height); var forRemoval = new List<MiniYamlNode>(); foreach (var kv in map.ActorDefinitions) { var actor = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var location = actor.InitDict.Get<LocationInit>().Value(null); if (!map.Contains(location)) { Console.WriteLine("Removing actor {0} located at {1} due being outside of the new map boundaries.".F(actor.Type, location)); forRemoval.Add(kv); } } foreach (var kv in forRemoval) map.ActorDefinitions.Remove(kv); map.Save((IReadWritePackage)map.Package); }
public void Run(Action<string> emitError, Action<string> emitWarning, Map map) { var players = new MapPlayers(map.PlayerDefinitions).Players; var playerNames = players.Values.Select(p => p.Name).ToHashSet(); foreach (var player in players.Values) { foreach (var ally in player.Allies) if (!playerNames.Contains(ally)) emitError("Allies contains player {0} that is not in list.".F(ally)); foreach (var enemy in player.Enemies) if (!playerNames.Contains(enemy)) emitError("Enemies contains player {0} that is not in list.".F(enemy)); if (player.OwnsWorld && (player.Enemies.Any() || player.Allies.Any())) emitWarning("The player {0} owning the world should not have any allies or enemies.".F(player.Name)); } var worldActor = map.Rules.Actors["world"]; var factions = worldActor.TraitInfos<FactionInfo>().Select(f => f.InternalName).ToHashSet(); foreach (var player in players.Values) if (!string.IsNullOrWhiteSpace(player.Faction) && !factions.Contains(player.Faction)) emitError("Invalid faction {0} chosen for player {1}.".F(player.Faction, player.Name)); if (worldActor.HasTraitInfo<MPStartLocationsInfo>()) { var playerCount = players.Count(p => p.Value.Playable); var spawns = new List<CPos>(); foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); spawns.Add(s.InitDict.Get<LocationInit>().Value(null)); } if (playerCount > spawns.Count) emitError("The map allows {0} possible players, but defines only {1} spawn points".F(playerCount, spawns.Count)); if (spawns.Distinct().Count() != spawns.Count) emitError("Duplicate spawn point locations detected."); } foreach (var kv in map.ActorDefinitions) { var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var ownerInit = actorReference.InitDict.GetOrDefault<OwnerInit>(); if (ownerInit == null) emitError("Actor {0} is not owned by any player.".F(kv.Key)); else { var ownerName = ownerInit.PlayerName; if (!playerNames.Contains(ownerName)) emitError("Actor {0} is owned by unknown player {1}.".F(actorReference.Type, ownerName)); } } }
static void ReadOverlay(Map map, IniFile file, int2 fullSize) { var overlaySection = file.GetSection("OverlayPack"); var overlayCompressed = Convert.FromBase64String(overlaySection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayPack = new byte[1 << 18]; var temp = new byte[1 << 18]; UnpackLCW(overlayCompressed, overlayPack, temp); var overlayDataSection = file.GetSection("OverlayDataPack"); var overlayDataCompressed = Convert.FromBase64String(overlayDataSection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayDataPack = new byte[1 << 18]; UnpackLCW(overlayDataCompressed, overlayDataPack, temp); var overlayIndex = new CellLayer <int>(map); overlayIndex.Clear(0xFF); for (var y = 0; y < fullSize.Y; y++) { for (var x = fullSize.X * 2 - 2; x >= 0; x--) { var dx = (ushort)x; var dy = (ushort)(y * 2 + x % 2); var uv = new MPos(dx / 2, dy); var rx = (ushort)((dx + dy) / 2 + 1); var ry = (ushort)(dy - rx + fullSize.X + 1); if (!map.Resources.Contains(uv)) { continue; } overlayIndex[uv] = rx + 512 * ry; } } foreach (var cell in map.AllCells) { var overlayType = overlayPack[overlayIndex[cell]]; if (overlayType == 0xFF) { continue; } string actorType; if (OverlayToActor.TryGetValue(overlayType, out actorType)) { if (string.IsNullOrEmpty(actorType)) { continue; } var shape = new Size(1, 1); if (OverlayShapes.TryGetValue(overlayType, out shape)) { // Only import the top-left cell of multi-celled overlays var aboveType = overlayPack[overlayIndex[cell - new CVec(1, 0)]]; if (shape.Width > 1 && aboveType != 0xFF) { string a; if (OverlayToActor.TryGetValue(aboveType, out a) && a == actorType) { continue; } } var leftType = overlayPack[overlayIndex[cell - new CVec(0, 1)]]; if (shape.Height > 1 && leftType != 0xFF) { string a; if (OverlayToActor.TryGetValue(leftType, out a) && a == actorType) { continue; } } } var ar = new ActorReference(actorType) { new LocationInit(cell), new OwnerInit("Neutral") }; DamageState damageState; if (OverlayToHealth.TryGetValue(overlayType, out damageState)) { var health = 100; if (damageState == DamageState.Critical) { health = 25; } else if (damageState == DamageState.Heavy) { health = 50; } else if (damageState == DamageState.Medium) { health = 75; } if (health != 100) { ar.Add(new HealthInit(health)); } } map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); continue; } var resourceType = ResourceFromOverlay .Where(kv => kv.Value.Contains(overlayType)) .Select(kv => kv.Key) .FirstOrDefault(); if (resourceType != 0) { map.Resources[cell] = new ResourceTile(resourceType, overlayDataPack[overlayIndex[cell]]); continue; } Console.WriteLine("{0} unknown overlay {1}", cell, overlayType); } }
public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference reference, PlayerReference owner) { ID = id; this.reference = reference; Owner = owner; this.worldRenderer = worldRenderer; if (!reference.Contains <FactionInit>()) { reference.Add(new FactionInit(owner.Faction)); } if (!reference.Contains <OwnerInit>()) { reference.Add(new OwnerInit(owner.Name)); } var world = worldRenderer.World; if (!world.Map.Rules.Actors.TryGetValue(reference.Type.ToLowerInvariant(), out Info)) { throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, reference.Type.ToLowerInvariant())); } CenterPosition = PreviewPosition(world, reference); var location = reference.Get <LocationInit>().Value; var ios = Info.TraitInfoOrDefault <IOccupySpaceInfo>(); var subCellInit = reference.GetOrDefault <SubCellInit>(); var subCell = subCellInit != null ? subCellInit.Value : SubCell.Any; var radarColorInfo = Info.TraitInfoOrDefault <RadarColorFromTerrainInfo>(); RadarColor = radarColorInfo == null ? owner.Color : radarColorInfo.GetColorFromTerrain(world); if (ios != null) { Footprint = ios.OccupiedCells(Info, location, subCell); } else { var footprint = new Dictionary <CPos, SubCell>() { { location, SubCell.FullCell } }; Footprint = new ReadOnlyDictionary <CPos, SubCell>(footprint); } tooltip = Info.TraitInfos <EditorOnlyTooltipInfo>().FirstOrDefault(info => info.EnabledByDefault) as TooltipInfoBase ?? Info.TraitInfos <TooltipInfo>().FirstOrDefault(info => info.EnabledByDefault); DescriptiveName = tooltip != null ? tooltip.Name : Info.Name; GeneratePreviews(); // Bounds are fixed from the initial render. // If this is a problem, then we may need to fetch the area from somewhere else var r = previews.SelectMany(p => p.ScreenBounds(worldRenderer, CenterPosition)); Bounds = r.Union(); SelectionBox = new SelectionBoxAnnotationRenderable(new WPos(CenterPosition.X, CenterPosition.Y, 8192), new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, Bounds.Height), Color.White); }
/// <summary> /// Creates an <see cref="ActorProxy"/> of the specified type. /// </summary> /// <typeparam name="TActor"></typeparam> /// <param name="reference"></param> /// <returns></returns> public static TActor Bind <TActor>(this ActorReference reference) { Contract.Requires <ArgumentNullException>(reference != null); return((TActor)reference.Bind(typeof(TActor))); }
public virtual void SaveWaypoint(int waypointNumber, ActorReference waypointReference) { var waypointName = "waypoint" + waypointNumber; Map.ActorDefinitions.Add(new MiniYamlNode(waypointName, waypointReference.Save())); }
public bool HandleMouseInput(MouseInput mi) { // Exclusively uses left and right mouse buttons, but nothing else if (mi.Button != MouseButton.Left && mi.Button != MouseButton.Right) return false; if (mi.Button == MouseButton.Right) { if (mi.Event == MouseInputEvent.Up) { editorWidget.ClearBrush(); return true; } return false; } var cell = worldRenderer.Viewport.ViewToWorld(mi.Location); if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down) { // Check the actor is inside the map if (!footprint.All(c => world.Map.Tiles.Contains(cell + locationOffset + c))) return true; var newActorReference = new ActorReference(Actor.Name); newActorReference.Add(new OwnerInit(owner.Name)); cell += locationOffset; newActorReference.Add(new LocationInit(cell)); var ios = Actor.TraitInfoOrDefault<IOccupySpaceInfo>(); if (ios != null && ios.SharesCell) { var subcell = editorLayer.FreeSubCellAt(cell); if (subcell != SubCell.Invalid) newActorReference.Add(new SubCellInit(subcell)); } var initDict = newActorReference.InitDict; if (Actor.HasTraitInfo<IFacingInfo>()) initDict.Add(new FacingInit(facing)); if (Actor.HasTraitInfo<TurretedInfo>()) initDict.Add(new TurretFacingInit(facing)); editorLayer.Add(newActorReference); } return true; }
void Awake() { _actorRef = GetComponent <ActorReference>(); }
/// <summary> /// Catalogs the provided actor and its identity into this registry. /// This method expects an external transaction to be provided for managing atomicity /// </summary> /// <param name="tx">The <see cref="ITransaction"/> this Add operation is part of.</param> /// <param name="reference"><see cref="ActorReference"/> to store into internal state</param> /// <param name="identity">The underlying identity of the provided actor. This is not the actor id</param> /// <param name="cancellationToken"><see cref="CancellationToken"/></param> /// <returns><see cref="Task"/></returns> protected async Task AddActorAsync(ITransaction tx, ActorReference reference, Identity identity, CancellationToken cancellationToken) { var referenceMap = await GetReferenceMapAsync(); var indexMap = await GetIndexMapAsync(); var indexableRef = new IndexableActorReference(reference); var indexLookup = await referenceMap.TryGetValueAsync(tx, indexableRef, ReliableCollectionDefaults.ReadTimeout, cancellationToken); long index; IndexState state; if (indexLookup.HasValue) { index = indexLookup.Value; var stateLookup = await indexMap.TryGetValueAsync(tx, index, ReliableCollectionDefaults.ReadTimeout, cancellationToken); if (!stateLookup.HasValue) { throw new InvalidOperationException($"{indexableRef.StringRepresentation} is missing its internal IndexState"); } state = stateLookup.Value; IndexState newState; if (Equals(state.Identity, identity)) { newState = state; } else { newState = new IndexState { Reference = reference, Identity = identity, Index = index }; // replace old state await indexMap.SetAsync(tx, index, newState, ReliableCollectionDefaults.WriteTimeout, cancellationToken); } await OnUpdateActorAsync(tx, state, newState, cancellationToken); } else { var identityMap = await GetIdentityMapAsync(); var existingIndex = await identityMap.TryGetValueAsync(tx, identity, ReliableCollectionDefaults.ReadTimeout, cancellationToken); if (existingIndex.HasValue) { var existingState = await indexMap.TryGetValueAsync(tx, existingIndex.Value); throw new InvalidOperationException($"{identity} is already registered to Actor {new IndexableActorReference(existingState.Value.Reference).StringRepresentation}"); } var propertiesMap = await GetPropertiesMapAsync(); index = (long)await propertiesMap.AddOrUpdateAsync(tx, "currentIndex", 1L, (key, value) => (long)value + 1, ReliableCollectionDefaults.WriteTimeout, cancellationToken); state = new IndexState { Reference = reference, Identity = identity, Index = index }; await referenceMap.AddAsync(tx, indexableRef, index, ReliableCollectionDefaults.WriteTimeout, cancellationToken); await indexMap.AddAsync(tx, index, state, ReliableCollectionDefaults.WriteTimeout, cancellationToken); await identityMap.AddAsync(tx, identity, index, ReliableCollectionDefaults.WriteTimeout, cancellationToken); await OnAddActorAsync(tx, state, cancellationToken); } }
static void ReadTerrainActors(Map map, IniFile file, int2 fullSize) { var terrainSection = file.GetSection("Terrain", true); foreach (var kv in terrainSection) { var pos = int.Parse(kv.Key); var ry = pos / 1000; var rx = pos - ry * 1000; var dx = rx - ry + fullSize.X - 1; var dy = rx + ry - fullSize.X - 1; var cell = new MPos(dx / 2, dy).ToCPos(map); var name = kv.Value.ToLowerInvariant(); if (ReplaceActors.ContainsKey(name)) { name = ReplaceActors[name]; } var ar = new ActorReference(name); ar.Add(new LocationInit(cell)); ar.Add(new OwnerInit("Neutral")); if (!map.Rules.Actors.ContainsKey(name)) Console.WriteLine("Ignoring unknown actor type: `{0}`".F(name)); else map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); } }
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List <Pair <MPos, Color> > destinationBuffer) { var tileSet = map.Rules.TileSet; var color = tileSet[tileSet.GetTerrainIndex(TerrainType)].Color; for (var i = 0; i < map.MapSize.X; i++) { for (var j = 0; j < map.MapSize.Y; j++) { var cell = new MPos(i, j); if (map.Resources[cell].Type == ResourceType) { destinationBuffer.Add(new Pair <MPos, Color>(cell, color)); } } } }
public EditorActorPreview Add(ActorReference reference) { return(Add(NextActorName(), reference)); }
void ReadTrees(IniFile file) { var terrain = file.GetSection("TERRAIN", true); if (terrain == null) return; foreach (var kv in terrain) { var loc = Exts.ParseIntegerInvariant(kv.Key); var treeActor = ParseTreeActor(kv.Value); var ar = new ActorReference(treeActor) { new LocationInit(ParseActorLocation(treeActor, loc)), new OwnerInit("Neutral") }; var actorCount = Map.ActorDefinitions.Count; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } }
void LoadWaypoints(IniSection waypointSection) { var actorCount = Map.ActorDefinitions.Count; var wps = waypointSection .Where(kv => Exts.ParseIntegerInvariant(kv.Value) > 0) .Select(kv => Pair.New(Exts.ParseIntegerInvariant(kv.Key), LocationFromMapOffset(Exts.ParseIntegerInvariant(kv.Value), MapSize))); // Add waypoint actors skipping duplicate entries foreach (var kv in wps.DistinctBy(location => location.Second)) { if (!singlePlayer && kv.First <= 7) { var ar = new ActorReference("mpspawn") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); spawnCount++; } else { var ar = new ActorReference("waypoint") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; SaveWaypoint(kv.First, ar); } } }
static void ReadOverlay(Map map, IniFile file, int2 fullSize) { var overlaySection = file.GetSection("OverlayPack"); var overlayCompressed = Convert.FromBase64String(overlaySection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayPack = new byte[1 << 18]; var temp = new byte[1 << 18]; UnpackLCW(overlayCompressed, overlayPack, temp); var overlayDataSection = file.GetSection("OverlayDataPack"); var overlayDataCompressed = Convert.FromBase64String(overlayDataSection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayDataPack = new byte[1 << 18]; UnpackLCW(overlayDataCompressed, overlayDataPack, temp); for (var y = 0; y < fullSize.Y; y++) { for (var x = fullSize.X * 2 - 2; x >= 0; x--) { var dx = (ushort)x; var dy = (ushort)(y * 2 + x % 2); var uv = new MPos(dx / 2, dy); var rx = (ushort)((dx + dy) / 2 + 1); var ry = (ushort)(dy - rx + fullSize.X + 1); if (!map.Resources.Contains(uv)) continue; var idx = rx + 512 * ry; var overlayType = overlayPack[idx]; if (overlayType == 0xFF) continue; string actorType; if (OverlayToActor.TryGetValue(overlayType, out actorType)) { var ar = new ActorReference(actorType) { new LocationInit(uv.ToCPos(map)), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); continue; } var resourceType = ResourceFromOverlay .Where(kv => kv.Value.Contains(overlayType)) .Select(kv => kv.Key) .FirstOrDefault(); if (resourceType != 0) { map.Resources[uv] = new ResourceTile(resourceType, overlayDataPack[idx]); continue; } Console.WriteLine("{0} unknown overlay {1}", uv, overlayType); } } }
public T CreateActorProxy <T>(ActorReference actorReference) where T : IActor => CreateActorProxy <T>(actorReference.ServiceUri, actorReference.ActorId, actorReference.ListenerName);
static void ReadOverlay(Map map, IniFile file, int2 fullSize) { var overlaySection = file.GetSection("OverlayPack"); var overlayCompressed = Convert.FromBase64String(overlaySection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayPack = new byte[1 << 18]; var temp = new byte[1 << 18]; UnpackLCW(overlayCompressed, overlayPack, temp); var overlayDataSection = file.GetSection("OverlayDataPack"); var overlayDataCompressed = Convert.FromBase64String(overlayDataSection.Aggregate(string.Empty, (a, b) => a + b.Value)); var overlayDataPack = new byte[1 << 18]; UnpackLCW(overlayDataCompressed, overlayDataPack, temp); var overlayIndex = new CellLayer<int>(map); overlayIndex.Clear(0xFF); for (var y = 0; y < fullSize.Y; y++) { for (var x = fullSize.X * 2 - 2; x >= 0; x--) { var dx = (ushort)x; var dy = (ushort)(y * 2 + x % 2); var uv = new MPos(dx / 2, dy); var rx = (ushort)((dx + dy) / 2 + 1); var ry = (ushort)(dy - rx + fullSize.X + 1); if (!map.Resources.Contains(uv)) continue; overlayIndex[uv] = rx + 512 * ry; } } foreach (var cell in map.AllCells) { var overlayType = overlayPack[overlayIndex[cell]]; if (overlayType == 0xFF) continue; string actorType; if (OverlayToActor.TryGetValue(overlayType, out actorType)) { var shape = new Size(1, 1); if (OverlayShapes.TryGetValue(overlayType, out shape)) { // Only import the top-left cell of multi-celled overlays var aboveType = overlayPack[overlayIndex[cell - new CVec(1, 0)]]; if (shape.Width > 1 && aboveType != 0xFF) { string a; if (OverlayToActor.TryGetValue(aboveType, out a) && a == actorType) continue; } var leftType = overlayPack[overlayIndex[cell - new CVec(0, 1)]]; if (shape.Height > 1 && leftType != 0xFF) { string a; if (OverlayToActor.TryGetValue(leftType, out a) && a == actorType) continue; } } var ar = new ActorReference(actorType) { new LocationInit(cell), new OwnerInit("Neutral") }; DamageState damageState; if (OverlayToHealth.TryGetValue(overlayType, out damageState)) { var health = 100; if (damageState == DamageState.Critical) health = 25; else if (damageState == DamageState.Heavy) health = 50; else if (damageState == DamageState.Medium) health = 75; if (health != 100) ar.Add(new HealthInit(health)); } map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); continue; } var resourceType = ResourceFromOverlay .Where(kv => kv.Value.Contains(overlayType)) .Select(kv => kv.Key) .FirstOrDefault(); if (resourceType != 0) { map.Resources[cell] = new ResourceTile(resourceType, overlayDataPack[overlayIndex[cell]]); continue; } Console.WriteLine("{0} unknown overlay {1}", cell, overlayType); } }
public ActorPreviewInitializer(ActorInfo actor, WorldRenderer worldRenderer, TypeDictionary dict) { Actor = actor; WorldRenderer = worldRenderer; reference = new ActorReference(actor.Name, dict); }
public void LoadActors(IniFile file, string section, List<string> players, int mapSize, Map map) { foreach (var s in file.GetSection(section, true)) { // Structures: num=owner,type,health,location,turret-facing,trigger // Units: num=owner,type,health,location,facing,action,trigger // Infantry: num=owner,type,health,location,subcell,action,facing,trigger try { var parts = s.Value.Split(','); if (parts[0] == "") parts[0] = "Neutral"; if (!players.Contains(parts[0])) players.Add(parts[0]); var loc = Exts.ParseIntegerInvariant(parts[3]); var health = Exts.ParseIntegerInvariant(parts[2]) * 100 / 256; var facing = (section == "INFANTRY") ? Exts.ParseIntegerInvariant(parts[6]) : Exts.ParseIntegerInvariant(parts[4]); var actorType = parts[1].ToLowerInvariant(); var actor = new ActorReference(actorType) { new LocationInit(ParseActorLocation(actorType, loc)), new OwnerInit(parts[0]), }; var initDict = actor.InitDict; if (health != 100) initDict.Add(new HealthInit(health)); if (facing != 0) initDict.Add(new FacingInit(255 - facing)); if (section == "INFANTRY") actor.Add(new SubCellInit(Exts.ParseIntegerInvariant(parts[4]))); var actorCount = map.ActorDefinitions.Count; if (!map.Rules.Actors.ContainsKey(parts[1].ToLowerInvariant())) Console.WriteLine("Ignoring unknown actor type: `{0}`".F(parts[1].ToLowerInvariant())); else map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, actor.Save())); } catch (Exception) { Console.WriteLine("Malformed actor definition: `{0}`".F(s)); } } }
public ActorPreviewInitializer(ActorReference actor, WorldRenderer worldRenderer) { Actor = worldRenderer.World.Map.Rules.Actors[actor.Type]; reference = actor; WorldRenderer = worldRenderer; }
void FillMap() { while (stream.Position < stream.Length) { var tileInfo = stream.ReadUInt16(); var tileSpecialInfo = stream.ReadUInt16(); var tile = GetTile(tileInfo); var locationOnMap = GetCurrentTilePositionOnMap(); map.MapTiles.Value[locationOnMap] = tile; // Spice if (tileSpecialInfo == 1) map.MapResources.Value[locationOnMap] = new ResourceTile(1, 1); if (tileSpecialInfo == 2) map.MapResources.Value[locationOnMap] = new ResourceTile(1, 2); // Actors if (actorDataByActorCode.ContainsKey(tileSpecialInfo)) { var kvp = actorDataByActorCode[tileSpecialInfo]; if (!rules.Actors.ContainsKey(kvp.First.ToLower())) throw new InvalidOperationException("Actor with name {0} could not be found in the rules YAML file!".F(kvp.First)); var a = new ActorReference(kvp.First) { new LocationInit(locationOnMap), new OwnerInit(kvp.Second) }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, a.Save())); } } }
/// <summary> /// Gets <see cref="ActorId"/> for the actor./> /// </summary> /// <typeparam name="TIActor">Actor interface type.</typeparam> /// <param name="actor">Actor object to get ActorId for.</param> /// <returns><see cref="ActorId"/> for the actor.</returns> public static ActorId GetActorId<TIActor>(this TIActor actor) where TIActor : IActor { var r = ActorReference.Get(actor); return r.ActorId; }
public void Run(Action <string> emitError, Action <string> emitWarning, ModData modData, Map map) { var players = new MapPlayers(map.PlayerDefinitions).Players; var worldOwnerFound = false; var playerNames = players.Values.Select(p => p.Name).ToHashSet(); foreach (var player in players.Values) { foreach (var ally in player.Allies) { if (!playerNames.Contains(ally)) { emitError("Allies contains player {0} that is not in list.".F(ally)); } } foreach (var enemy in player.Enemies) { if (!playerNames.Contains(enemy)) { emitError("Enemies contains player {0} that is not in list.".F(enemy)); } } if (player.OwnsWorld) { worldOwnerFound = true; if (player.Enemies.Any() || player.Allies.Any()) { emitWarning("The player {0} owning the world should not have any allies or enemies.".F(player.Name)); } if (player.Playable) { emitError("The player {0} owning the world can't be playable.".F(player.Name)); } } else if (map.Visibility == MapVisibility.MissionSelector && player.Playable && !player.LockFaction) { // Missions must lock the faction of the player to force the server to override the default Random faction emitError("The player {0} must specify LockFaction: True.".F(player.Name)); } } if (!worldOwnerFound) { emitError("Found no player owning the world."); } var worldActor = map.Rules.Actors["world"]; var factions = worldActor.TraitInfos <FactionInfo>().Select(f => f.InternalName).ToHashSet(); foreach (var player in players.Values) { if (!string.IsNullOrWhiteSpace(player.Faction) && !factions.Contains(player.Faction)) { emitError("Invalid faction {0} chosen for player {1}.".F(player.Faction, player.Name)); } } if (worldActor.HasTraitInfo <MPStartLocationsInfo>()) { var playerCount = players.Count(p => p.Value.Playable); var spawns = new List <CPos>(); foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); spawns.Add(s.InitDict.Get <LocationInit>().Value(null)); } if (playerCount > spawns.Count) { emitError("The map allows {0} possible players, but defines only {1} spawn points".F(playerCount, spawns.Count)); } if (spawns.Distinct().Count() != spawns.Count) { emitError("Duplicate spawn point locations detected."); } } // Check for actors that require specific owners var actorsWithRequiredOwner = map.Rules.Actors .Where(a => a.Value.HasTraitInfo <RequiresSpecificOwnersInfo>()) .ToDictionary(a => a.Key, a => a.Value.TraitInfo <RequiresSpecificOwnersInfo>()); foreach (var kv in map.ActorDefinitions) { var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var ownerInit = actorReference.InitDict.GetOrDefault <OwnerInit>(); if (ownerInit == null) { emitError("Actor {0} is not owned by any player.".F(kv.Key)); } else { var ownerName = ownerInit.PlayerName; if (!playerNames.Contains(ownerName)) { emitError("Actor {0} is owned by unknown player {1}.".F(kv.Key, ownerName)); } RequiresSpecificOwnersInfo info; if (actorsWithRequiredOwner.TryGetValue(kv.Value.Value, out info)) { if (!info.ValidOwnerNames.Contains(ownerName)) { emitError("Actor {0} owner {1} is not one of ValidOwnerNames: {2}".F(kv.Key, ownerName, info.ValidOwnerNames.JoinWith(", "))); } } } } }
/// <summary> /// Gets <see cref="ActorReference"/> for the actor. /// </summary> /// <param name="actor">Actor object to get ActorReference for.</param> /// <returns><see cref="ActorReference"/> for the actor.</returns> public static ActorReference GetActorReference(this IActor actor) { return ActorReference.Get(actor); }
public override void SaveWaypoint(int waypointNumber, ActorReference waypointReference) { var waypointName = "waypoint" + waypointNumber; if (waypointNumber == 25) waypointName = "DefaultFlareLocation"; else if (waypointNumber == 26) waypointName = "DefaultCameraPosition"; else if (waypointNumber == 27) waypointName = "DefaultChinookTarget"; Map.ActorDefinitions.Add(new MiniYamlNode(waypointName, waypointReference.Save())); }
void LoadActors() { for (var a = 0; a < numberOfActors; a++) { var id = stream.ReadInt32(); var type = stream.ReadInt32(); var x = (int)Math.Round((float)stream.ReadInt32() / map.Grid.TileSize.Width); var y = (int)Math.Round((float)stream.ReadInt32() / map.Grid.TileSize.Height); var invalidLocation = false; if (x < 0 || x > mapSize.Width || y < 0 || y > mapSize.Height) { Console.WriteLine("Invalid coordinates {0},{1} for actor type {2}.".F(x, y, type)); invalidLocation = true; } stream.Seek(4, SeekOrigin.Current); var numberOfProperties = stream.ReadInt32(); stream.Seek(4, SeekOrigin.Current); if (numberOfProperties > 0) { for (var p = 0; p < numberOfProperties; p++) { var key = stream.ReadASCII(128); var value = stream.ReadInt32(); Console.WriteLine(key + ": " + value); } } if (!ActorMap.ContainsKey(type)) { Console.WriteLine("Ignoring unknown actor type: `{0}` @ {1},{2}".F(type, x, y)); continue; } if (invalidLocation) { continue; } var actorInfo = ActorMap[type]; var actorType = actorInfo.ActorType.ToLowerInvariant(); var actor = new ActorReference(actorType) { new LocationInit(new CPos(x + MapCordonWidth, y + MapCordonWidth)), }; if (actorInfo.Color == Color.White) { actor.Add(new OwnerInit("Neutral")); } if (actorInfo.Color == Color.Green) { actor.Add(new OwnerInit("Ants")); } if (actorInfo.Color == Color.Blue) { actor.Add(new OwnerInit("Beetles")); } if (actorInfo.Color == Color.Red) { actor.Add(new OwnerInit("Spiders")); } if (actorInfo.Color == Color.Yellow) { actor.Add(new OwnerInit("Wasps")); } if (actorInfo.Color == Color.Black) { actor.Add(new OwnerInit("Creeps")); } AddPlayer(actorInfo.Color); var actorCount = map.ActorDefinitions.Count; if (!map.Rules.Actors.ContainsKey(actorType)) { Console.WriteLine("Ignoring unknown actor type: `{0}`".F(actorType)); } else { map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, actor.Save())); } } }
public void LoadActors(IniFile file, string section, List <string> players, int mapSize, Map map) { foreach (var s in file.GetSection(section, true)) { // Structures: num=owner,type,health,location,turret-facing,trigger // Units: num=owner,type,health,location,facing,action,trigger // Infantry: num=owner,type,health,location,subcell,action,facing,trigger try { var parts = s.Value.Split(','); if (parts[0] == "") { parts[0] = "Neutral"; } if (!players.Contains(parts[0])) { players.Add(parts[0]); } var loc = Exts.ParseIntegerInvariant(parts[3]); var health = Exts.ParseIntegerInvariant(parts[2]) * 100 / 256; var facing = (section == "INFANTRY") ? Exts.ParseIntegerInvariant(parts[6]) : Exts.ParseIntegerInvariant(parts[4]); var actorType = parts[1].ToLowerInvariant(); var actor = new ActorReference(actorType) { new LocationInit(ParseActorLocation(actorType, loc)), new OwnerInit(parts[0]), }; if (health != 100) { actor.Add(new HealthInit(health)); } if (facing != 0) { actor.Add(new FacingInit(new WAngle(1024 - 4 * facing))); } if (section == "INFANTRY") { actor.Add(new SubCellInit((SubCell)Exts.ParseByte(parts[4]))); } var actorCount = map.ActorDefinitions.Count; if (!map.Rules.Actors.ContainsKey(parts[1].ToLowerInvariant())) { Console.WriteLine("Ignoring unknown actor type: `{0}`".F(parts[1].ToLowerInvariant())); } else { map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, actor.Save())); } } catch (Exception) { Console.WriteLine("Malformed actor definition: `{0}`".F(s)); } } }
public void ConvertIniMap(string iniFile) { var file = new IniFile(FileSystem.Open(iniFile)); var basic = file.GetSection("Basic"); var map = file.GetSection("Map"); var legacyMapFormat = (IniMapFormat)int.Parse(basic.GetValue("NewINIFormat", "0")); var XOffset = int.Parse(map.GetValue("X", "0")); var YOffset = int.Parse(map.GetValue("Y", "0")); var Width = int.Parse(map.GetValue("Width", "0")); var Height = int.Parse(map.GetValue("Height", "0")); MapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; Map.Title = basic.GetValue("Name", "(null)"); Map.Author = "Westwood Studios"; Map.Tileset = Truncate(map.GetValue("Theater", "TEMPERAT"), 8); Map.MapSize.X = MapSize; Map.MapSize.Y = MapSize; Map.Bounds = Rectangle.FromLTRB(XOffset, YOffset, XOffset + Width, YOffset + Height); Map.Selectable = true; Map.Smudges = Lazy.New(() => new List <SmudgeReference>()); Map.Actors = Lazy.New(() => new Dictionary <string, ActorReference>()); Map.MapResources = Lazy.New(() => new TileReference <byte, byte> [MapSize, MapSize]); Map.MapTiles = Lazy.New(() => new TileReference <ushort, byte> [MapSize, MapSize]); if (legacyMapFormat == IniMapFormat.RedAlert) { UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); ReadRATrees(file); } else // CNC { UnpackCncTileData(FileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")); ReadCncOverlay(file); ReadCncTrees(file); } LoadActors(file, "STRUCTURES"); LoadActors(file, "UNITS"); LoadActors(file, "INFANTRY"); LoadSmudges(file, "SMUDGE"); foreach (var p in Players) { LoadPlayer(file, p, (legacyMapFormat == IniMapFormat.RedAlert)); } var wps = file.GetSection("Waypoints") .Where(kv => int.Parse(kv.Value) > 0) .Select(kv => Pair.New(int.Parse(kv.Key), LocationFromMapOffset(int.Parse(kv.Value), MapSize))) .ToArray(); // Add waypoint actors foreach (var kv in wps) { var a = new ActorReference("mpspawn"); a.Add(new LocationInit((CPos)kv.Second)); a.Add(new OwnerInit("Neutral")); Map.Actors.Value.Add("spawn" + kv.First, a); } }
public bool HandleMouseInput(MouseInput mi) { // Exclusively uses left and right mouse buttons, but nothing else if (mi.Button != MouseButton.Left && mi.Button != MouseButton.Right) { return(false); } if (mi.Button == MouseButton.Right) { if (mi.Event == MouseInputEvent.Up) { editorWidget.ClearBrush(); return(true); } return(false); } var cell = worldRenderer.Viewport.ViewToWorld(mi.Location); if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down) { // Check the actor is inside the map if (!footprint.All(c => world.Map.Tiles.Contains(cell + locationOffset + c))) { return(true); } var newActorReference = new ActorReference(Actor.Name); newActorReference.Add(new OwnerInit(owner.Name)); cell += locationOffset; newActorReference.Add(new LocationInit(cell)); var ios = Actor.TraitInfoOrDefault <IOccupySpaceInfo>(); if (ios != null && ios.SharesCell) { var subcell = editorLayer.FreeSubCellAt(cell); if (subcell != SubCell.Invalid) { newActorReference.Add(new SubCellInit(subcell)); } } var initDict = newActorReference.InitDict; if (Actor.HasTraitInfo <IFacingInfo>()) { initDict.Add(new FacingInit(facing)); } if (Actor.HasTraitInfo <TurretedInfo>()) { initDict.Add(new TurretFacingInit(facing)); } editorLayer.Add(newActorReference); } return(true); }
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List <Pair <MPos, Color> > destinationBuffer) { var tileSet = map.Rules.TileSet; Color color; if (!string.IsNullOrEmpty(Terrain)) { color = tileSet[tileSet.GetTerrainIndex(Terrain)].Color; } else if (Color != default(Color)) { color = Color; } else { var owner = map.PlayerDefinitions.Where(p => s.InitDict.Get <OwnerInit>().PlayerName == p.Value.Nodes.First(k => k.Key == "Name").Value.Value).First(); var colorValue = owner.Value.Nodes.Where(n => n.Key == "Color"); var ownerColor = colorValue.Any() ? colorValue.First().Value.Value : "FFFFFF"; Color.TryParse(ownerColor, out color); } var ios = ai.TraitInfo <IOccupySpaceInfo>(); var cells = ios.OccupiedCells(ai, s.InitDict.Get <LocationInit>().Value(null)); foreach (var cell in cells) { destinationBuffer.Add(new Pair <MPos, Color>(cell.Key.ToMPos(map), color)); } }
void IMapPreviewSignatureInfo.PopulateMapPreviewSignatureCells(Map map, ActorInfo ai, ActorReference s, List <(MPos, Color)> destinationBuffer)
public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference actor, PlayerReference owner) { ID = id; this.actor = actor; this.Owner = owner; this.worldRenderer = worldRenderer; if (!actor.InitDict.Contains <FactionInit>()) { actor.InitDict.Add(new FactionInit(owner.Faction)); } if (!actor.InitDict.Contains <OwnerInit>()) { actor.InitDict.Add(new OwnerInit(owner.Name)); } var world = worldRenderer.World; if (!world.Map.Rules.Actors.TryGetValue(actor.Type.ToLowerInvariant(), out Info)) { throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, actor.Type.ToLowerInvariant())); } CenterPosition = PreviewPosition(world, actor.InitDict); var location = actor.InitDict.Get <LocationInit>().Value(worldRenderer.World); var ios = Info.TraitInfoOrDefault <IOccupySpaceInfo>(); var subCellInit = actor.InitDict.GetOrDefault <SubCellInit>(); var subCell = subCellInit != null?subCellInit.Value(worldRenderer.World) : SubCell.Any; if (ios != null) { Footprint = ios.OccupiedCells(Info, location, subCell); } else { var footprint = new Dictionary <CPos, SubCell>() { { location, SubCell.FullCell } }; Footprint = new ReadOnlyDictionary <CPos, SubCell>(footprint); } var tooltip = Info.TraitInfoOrDefault <EditorOnlyTooltipInfo>() as TooltipInfoBase ?? Info.TraitInfoOrDefault <TooltipInfo>(); Tooltip = (tooltip == null ? " < " + Info.Name + " >" : tooltip.Name) + "\n" + owner.Name + " (" + owner.Faction + ")" + "\nID: " + ID + "\nType: " + Info.Name; GeneratePreviews(); // Bounds are fixed from the initial render. // If this is a problem, then we may need to fetch the area from somewhere else var r = previews .SelectMany(p => p.Render(worldRenderer, CenterPosition)) .Select(rr => rr.PrepareRender(worldRenderer)); if (r.Any()) { Bounds = r.First().ScreenBounds(worldRenderer); foreach (var rr in r.Skip(1)) { Bounds = Rectangle.Union(Bounds, rr.ScreenBounds(worldRenderer)); } } }
void LoadActors(IniFile file, string section) { foreach (var s in file.GetSection(section, true)) { //Structures: num=owner,type,health,location,turret-facing,trigger //Units: num=owner,type,health,location,facing,action,trigger //Infantry: num=owner,type,health,location,subcell,action,facing,trigger var parts = s.Value.Split(','); var loc = int.Parse(parts[3]); if (parts[0] == "") parts[0] = "Neutral"; if (!Players.Contains(parts[0])) Players.Add(parts[0]); var stance = ActorStance.Stance.None; switch(parts[5]) { case "Area Guard": case "Guard": stance = ActorStance.Stance.Guard; break; case "Defend Base": stance = ActorStance.Stance.Defend; break; case "Hunt": case "Rampage": case "Attack Base": case "Attack Units": case "Attack Civil.": case "Attack Tarcom": stance = ActorStance.Stance.Hunt; break; case "Retreat": case "Return": stance = ActorStance.Stance.Retreat; break; // do we care about `Harvest' and `Sticky'? } var actor = new ActorReference(parts[1].ToLowerInvariant()) { new LocationInit(new int2(loc % MapSize, loc / MapSize)), new OwnerInit(parts[0]), new HealthInit(float.Parse(parts[2])/256), new FacingInit((section == "INFANTRY") ? int.Parse(parts[6]) : int.Parse(parts[4])), new ActorStanceInit(stance), }; if (section == "INFANTRY") actor.Add(new SubcellInit(int.Parse(parts[4]))); Map.Actors.Add("Actor" + ActorCount++,actor); } }
void ReadOverlay(IniFile file) { var overlay = file.GetSection("OVERLAY", true); if (overlay == null) return; foreach (var kv in overlay) { var loc = Exts.ParseIntegerInvariant(kv.Key); var cell = new CPos(loc % MapSize, loc / MapSize); var res = Pair.New((byte)0, (byte)0); var type = kv.Value.ToLowerInvariant(); if (overlayResourceMapping.ContainsKey(type)) res = overlayResourceMapping[type]; Map.Resources[cell] = new ResourceTile(res.First, res.Second); if (overlayActors.Contains(type)) { var ar = new ActorReference(type) { new LocationInit(cell), new OwnerInit("Neutral") }; var actorCount = Map.ActorDefinitions.Count; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } } }
static void ReadWaypoints(Map map, IniFile file, int2 fullSize) { var waypointsSection = file.GetSection("Waypoints", true); foreach (var kv in waypointsSection) { var pos = int.Parse(kv.Value); var ry = pos / 1000; var rx = pos - ry * 1000; var dx = rx - ry + fullSize.X - 1; var dy = rx + ry - fullSize.X - 1; var cell = new MPos(dx / 2, dy).ToCPos(map); int wpindex; var ar = new ActorReference((!int.TryParse(kv.Key, out wpindex) || wpindex > 7) ? "waypoint" : "mpspawn"); ar.Add(new LocationInit(cell)); ar.Add(new OwnerInit("Neutral")); map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); } }
EditorActorPreview Add(string id, ActorReference reference, bool initialSetup = false) { var owner = Players.Players[reference.InitDict.Get<OwnerInit>().PlayerName]; var preview = new EditorActorPreview(worldRenderer, id, reference, owner); previews.Add(preview); screenMap.Add(preview, preview.Bounds); foreach (var kv in preview.Footprint) { List<EditorActorPreview> list; if (!cellMap.TryGetValue(kv.Key, out list)) { list = new List<EditorActorPreview>(); cellMap.Add(kv.Key, list); } list.Add(preview); } if (!initialSetup) { UpdateNeighbours(preview.Footprint); if (reference.Type == "mpspawn") SyncMultiplayerCount(); } return preview; }
static void ReadActors(Map map, IniFile file, string type, int2 fullSize) { var structuresSection = file.GetSection(type, true); foreach (var kv in structuresSection) { var isDeployed = false; var entries = kv.Value.Split(','); var name = entries[1].ToLowerInvariant(); if (DeployableActors.ContainsKey(name)) { name = DeployableActors[name]; isDeployed = true; } if (ReplaceActors.ContainsKey(name)) { name = ReplaceActors[name]; } var health = short.Parse(entries[2]); var rx = int.Parse(entries[3]); var ry = int.Parse(entries[4]); var facing = (byte)(byte.Parse(entries[5]) + 96); var dx = rx - ry + fullSize.X - 1; var dy = rx + ry - fullSize.X - 1; var cell = new MPos(dx / 2, dy).ToCPos(map); var ar = new ActorReference(name) { new LocationInit(cell), new OwnerInit("Neutral"), new HealthInit(100 * health / 256), new FacingInit(facing), }; if (isDeployed) ar.Add(new DeployStateInit(DeployState.Deployed)); if (!map.Rules.Actors.ContainsKey(name)) Console.WriteLine("Ignoring unknown actor type: `{0}`".F(name)); else map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); } }
public static CPos Location(this ActorReference ar) { return((CPos)ar.InitDict.Get <LocationInit>().value); }
ColorPalette GetPaletteForActor(ActorReference ar) { var ownerInit = ar.InitDict.GetOrDefault<OwnerInit>(); if (ownerInit == null) return null; return GetPaletteForPlayer(ownerInit.PlayerName); }
public void Run(Action <string> emitError, Action <string> emitWarning, Map map) { var players = new MapPlayers(map.PlayerDefinitions).Players; var playerNames = players.Values.Select(p => p.Name).ToHashSet(); foreach (var player in players.Values) { foreach (var ally in player.Allies) { if (!playerNames.Contains(ally)) { emitError("Allies contains player {0} that is not in list.".F(ally)); } } foreach (var enemy in player.Enemies) { if (!playerNames.Contains(enemy)) { emitError("Enemies contains player {0} that is not in list.".F(enemy)); } } if (player.OwnsWorld && (player.Enemies.Any() || player.Allies.Any())) { emitWarning("The player {0} owning the world should not have any allies or enemies.".F(player.Name)); } } var worldActor = map.Rules.Actors["world"]; var factions = worldActor.TraitInfos <FactionInfo>().Select(f => f.InternalName).ToHashSet(); foreach (var player in players.Values) { if (!string.IsNullOrWhiteSpace(player.Faction) && !factions.Contains(player.Faction)) { emitError("Invalid faction {0} chosen for player {1}.".F(player.Faction, player.Name)); } } if (worldActor.HasTraitInfo <MPStartLocationsInfo>()) { var playerCount = players.Count(p => p.Value.Playable); var spawns = new List <CPos>(); foreach (var kv in map.ActorDefinitions.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); spawns.Add(s.InitDict.Get <LocationInit>().Value(null)); } if (playerCount > spawns.Count) { emitError("The map allows {0} possible players, but defines only {1} spawn points".F(playerCount, spawns.Count)); } if (spawns.Distinct().Count() != spawns.Count) { emitError("Duplicate spawn point locations detected."); } } foreach (var kv in map.ActorDefinitions) { var actorReference = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); var ownerInit = actorReference.InitDict.GetOrDefault <OwnerInit>(); if (ownerInit == null) { emitError("Actor {0} is not owned by any player.".F(kv.Key)); } else { var ownerName = ownerInit.PlayerName; if (!playerNames.Contains(ownerName)) { emitError("Actor {0} is owned by unknown player {1}.".F(kv.Key, ownerName)); } else if (kv.Value.Value == "mpspawn" && !players[ownerName].OwnsWorld) { emitError("Actor {0} needs to be owned by the player that owns the world. ".F(kv.Key) + "Use the `Spawn` and `LockSpawn` player properties to force players onto a particular spawn instead."); } } } }
public EditorActorPreview Add(ActorReference reference) { return Add(NextActorName(), reference); }
/// <summary> /// Registers an Actor as a subscriber for messages. /// </summary> /// <param name="actor">Reference to the actor to register.</param> /// <param name="messageTypeName">Full type name of message object.</param> public async Task RegisterSubscriberAsync(ActorReference actor, string messageTypeName) { var actorReference = new ActorReferenceWrapper(actor); await RegisterSubscriberAsync(actorReference, messageTypeName); }
/// <summary> /// Unregisters an Actor as a subscriber for messages. /// </summary> /// <param name="actor">Reference to the actor to unsubscribe.</param> /// <param name="messageTypeName">Full type name of message object.</param> /// <param name="flushQueue">Publish any remaining messages.</param> public async Task UnregisterSubscriberAsync(ActorReference actor, string messageTypeName, bool flushQueue) { var actorReference = new ActorReferenceWrapper(actor); await UnregisterSubscriberAsync(actorReference, messageTypeName); }
enum IniMapFormat { RedAlert = 3 } // otherwise, cnc (2 variants exist, we don't care to differentiate) public void ConvertIniMap(string iniFile) { using (var stream = GlobalFileSystem.Open(iniFile)) { var file = new IniFile(stream); var basic = file.GetSection("Basic"); var mapSection = file.GetSection("Map"); var legacyMapFormat = (IniMapFormat)Exts.ParseIntegerInvariant(basic.GetValue("NewINIFormat", "0")); var offsetX = Exts.ParseIntegerInvariant(mapSection.GetValue("X", "0")); var offsetY = Exts.ParseIntegerInvariant(mapSection.GetValue("Y", "0")); var width = Exts.ParseIntegerInvariant(mapSection.GetValue("Width", "0")); var height = Exts.ParseIntegerInvariant(mapSection.GetValue("Height", "0")); mapSize = (legacyMapFormat == IniMapFormat.RedAlert) ? 128 : 64; var tileset = Truncate(mapSection.GetValue("Theater", "TEMPERAT"), 8); map = new Map(rules.TileSets[tileset], mapSize, mapSize) { Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(iniFile)), Author = "Westwood Studios" }; var tl = new MPos(offsetX, offsetY); var br = new MPos(offsetX + width - 1, offsetY + height - 1); map.SetBounds(tl, br); if (legacyMapFormat == IniMapFormat.RedAlert) { UnpackRATileData(ReadPackedSection(file.GetSection("MapPack"))); UnpackRAOverlayData(ReadPackedSection(file.GetSection("OverlayPack"))); ReadRATrees(file); } else { // CnC using (var s = GlobalFileSystem.Open(iniFile.Substring(0, iniFile.Length - 4) + ".bin")) UnpackCncTileData(s); ReadCncOverlay(file); ReadCncTrees(file); } LoadVideos(file, "BASIC"); LoadActors(file, "STRUCTURES"); LoadActors(file, "UNITS"); LoadActors(file, "INFANTRY"); LoadActors(file, "SHIPS"); LoadSmudges(file, "SMUDGE"); var wps = file.GetSection("Waypoints") .Where(kv => Exts.ParseIntegerInvariant(kv.Value) > 0) .Select(kv => Pair.New(Exts.ParseIntegerInvariant(kv.Key), LocationFromMapOffset(Exts.ParseIntegerInvariant(kv.Value), mapSize))); // Add waypoint actors foreach (var kv in wps) { if (kv.First <= 7) { var ar = new ActorReference("mpspawn") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } else { var ar = new ActorReference("waypoint") { new LocationInit((CPos)kv.Second), new OwnerInit("Neutral") }; map.ActorDefinitions.Add(new MiniYamlNode("waypoint" + kv.First, ar.Save())); } } // Create default player definitions only if there are no players to import mapPlayers = new MapPlayers(map.Rules, (players.Count == 0) ? map.SpawnPoints.Value.Length : 0); foreach (var p in players) { LoadPlayer(file, p, legacyMapFormat == IniMapFormat.RedAlert); } map.PlayerDefinitions = mapPlayers.ToMiniYaml(); } }
void UnpackOverlayData(MemoryStream ms) { for (var j = 0; j < MapSize; j++) { for (var i = 0; i < MapSize; i++) { var o = ms.ReadUInt8(); var res = Pair.New((byte)0, (byte)0); if (o != 255 && overlayResourceMapping.ContainsKey(redAlertOverlayNames[o])) res = overlayResourceMapping[redAlertOverlayNames[o]]; var cell = new CPos(i, j); Map.Resources[cell] = new ResourceTile(res.First, res.Second); if (o != 255 && overlayActors.Contains(redAlertOverlayNames[o])) { var ar = new ActorReference(redAlertOverlayNames[o]) { new LocationInit(cell), new OwnerInit("Neutral") }; var actorCount = Map.ActorDefinitions.Count; Map.ActorDefinitions.Add(new MiniYamlNode("Actor" + actorCount++, ar.Save())); } } } }
static void ReadOverlay(Map map, IniFile file, int2 fullSize) { var overlaySection = file.GetSection("OverlayPack"); var overlayCompressed = Convert.FromBase64String(string.Concat(overlaySection.Select(kvp => kvp.Value))); var overlayPack = new byte[1 << 18]; var temp = new byte[1 << 18]; UnpackLCW(overlayCompressed, overlayPack, temp); var overlayDataSection = file.GetSection("OverlayDataPack"); var overlayDataCompressed = Convert.FromBase64String(string.Concat(overlayDataSection.Select(kvp => kvp.Value))); var overlayDataPack = new byte[1 << 18]; UnpackLCW(overlayDataCompressed, overlayDataPack, temp); var overlayIndex = new CellLayer <int>(map); overlayIndex.Clear(0xFF); for (var y = 0; y < fullSize.Y; y++) { for (var x = fullSize.X * 2 - 2; x >= 0; x--) { var dx = (ushort)x; var dy = (ushort)(y * 2 + x % 2); var uv = new MPos(dx / 2, dy); var rx = (ushort)((dx + dy) / 2 + 1); var ry = (ushort)(dy - rx + fullSize.X + 1); if (!map.Resources.Contains(uv)) { continue; } overlayIndex[uv] = rx + 512 * ry; } } foreach (var cell in map.AllCells) { var overlayType = overlayPack[overlayIndex[cell]]; if (overlayType == 0xFF) { continue; } if (OverlayToActor.TryGetValue(overlayType, out var actorType)) { if (string.IsNullOrEmpty(actorType)) { continue; } var shape = new Size(1, 1); if (OverlayShapes.TryGetValue(overlayType, out shape)) { // Only import the top-left cell of multi-celled overlays var aboveType = overlayPack[overlayIndex[cell - new CVec(1, 0)]]; if (shape.Width > 1 && aboveType != 0xFF) { if (OverlayToActor.TryGetValue(aboveType, out var a) && a == actorType) { continue; } } var leftType = overlayPack[overlayIndex[cell - new CVec(0, 1)]]; if (shape.Height > 1 && leftType != 0xFF) { if (OverlayToActor.TryGetValue(leftType, out var a) && a == actorType) { continue; } } } // Fix position of vein hole actors var location = cell; if (actorType == "veinhole") { location -= new CVec(1, 1); } var ar = new ActorReference(actorType) { new LocationInit(location), new OwnerInit("Neutral") }; if (OverlayToHealth.TryGetValue(overlayType, out var damageState)) { var health = 100; if (damageState == DamageState.Critical) { health = 25; } else if (damageState == DamageState.Heavy) { health = 50; } else if (damageState == DamageState.Medium) { health = 75; } if (health != 100) { ar.Add(new HealthInit(health)); } } map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save())); continue; } // TS maps encode the non-harvestable border tiles as overlay // Only convert to vein resources if the overlay data specifies non-border frames if (overlayType == 0x7E) { var frame = overlayDataPack[overlayIndex[cell]]; if (frame < 48 || frame > 60) { continue; } // Pick half or full density based on the frame map.Resources[cell] = new ResourceTile(3, (byte)(frame == 52 ? 1 : 2)); continue; } var resourceType = ResourceFromOverlay .Where(kv => kv.Value.Contains(overlayType)) .Select(kv => kv.Key) .FirstOrDefault(); if (resourceType != 0) { map.Resources[cell] = new ResourceTile(resourceType, overlayDataPack[overlayIndex[cell]]); continue; } Console.WriteLine("{0} unknown overlay {1}", cell, overlayType); } }