public ZipFile(Stream stream, string name, IReadOnlyPackage parent = null) { // SharpZipLib breaks when asked to update archives loaded from outside streams or files // We can work around this by creating a clean in-memory-only file, cutting all outside references pkgStream = new MemoryStream(); stream.CopyTo(pkgStream); pkgStream.Position = 0; Name = name; Parent = parent as IReadWritePackage; pkg = new SZipFile(pkgStream); }
public void LoadMaps() { // Utility mod that does not support maps if (!modData.Manifest.Contains <MapGrid>()) { return; } var mapGrid = modData.Manifest.Get <MapGrid>(); foreach (var kv in MapLocations) { foreach (var map in kv.Key.Contents) { IReadOnlyPackage mapPackage = null; try { using (new Support.PerfTimer(map)) { mapPackage = modData.ModFiles.OpenPackage(map, kv.Key); if (mapPackage == null) { continue; } var uid = Map.ComputeUID(mapPackage); previews[uid].UpdateFromMap(mapPackage, kv.Key, kv.Value, modData.Manifest.MapCompatibility, mapGrid.Type); } } catch (Exception e) { if (mapPackage != null) { mapPackage.Dispose(); } Console.WriteLine("Failed to load map: {0}", map); Console.WriteLine("Details: {0}", e); Log.Write("debug", "Failed to load map: {0}", map); Log.Write("debug", "Details: {0}", e); } } } }
public bool Unmount(IReadOnlyPackage package) { var mountCount = 0; if (!mountedPackages.TryGetValue(package, out mountCount)) { return(false); } if (--mountCount <= 0) { foreach (var packagesForFile in fileIndex.Values) { packagesForFile.RemoveAll(p => p == package); } mountedPackages.Remove(package); var explicitKeys = explicitMounts.Where(kv => kv.Value == package) .Select(kv => kv.Key) .ToList(); foreach (var key in explicitKeys) { explicitMounts.Remove(key); } // Mod packages aren't owned by us, so we shouldn't dispose them if (modPackages.Contains(package)) { modPackages.Remove(package); } else { package.Dispose(); } } else { mountedPackages[package] = mountCount; } return(true); }
static Manifest LoadMod(string id, string path) { IReadOnlyPackage package = null; try { if (Directory.Exists(path)) { package = new Folder(path); } else { try { using (var fileStream = File.OpenRead(path)) package = new ZipFile(fileStream, path); } catch { throw new InvalidDataException(path + " is not a valid mod package"); } } if (!package.Contains("mod.yaml")) { throw new InvalidDataException(path + " is not a valid mod package"); } // Mods in the support directory and oramod packages (which are listed later // in the CandidateMods list) override mods in the main install. return(new Manifest(id, package)); } catch (Exception) { if (package != null) { package.Dispose(); } return(null); } }
bool IPackageLoader.TryParsePackage(Stream s, string filename, FS context, out IReadOnlyPackage package) { if (!filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) { package = null; return(false); } // Load the global mix database if (globalFilenames == null) { if (context.TryOpen("global mix database.dat", out var mixDatabase)) { using (var db = new XccGlobalDatabase(mixDatabase)) globalFilenames = db.Entries.Distinct().ToArray(); } } package = new MixFile(s, filename, globalFilenames ?? Array.Empty <string>()); return(true); }
public bool TryParsePackage(Stream s, string filename, FS context, out IReadOnlyPackage package) { if (filename.EndsWith(".lpk") || // Spritesheet container filename.EndsWith(".bpk") || // Image container filename.EndsWith(".spk") || // Sound set filename.EndsWith(".lps") || // Singleplayer map filename.EndsWith(".lpm") || // Multiplayer map filename.EndsWith(".mpk")) // Matrix set (destroyable map part, tile replacements) { s = Crypter.Decrypt(s); } var signature = s.ReadASCII(4); var version = Version.UNKNOWN; if (signature.Equals("DATA")) { version = Version.KKND1; } if (signature.Equals("DAT2")) { version = Version.KKND2; } if (version == Version.UNKNOWN) { s.Position -= 4; package = null; return(false); } var tmp = s.ReadBytes(4); // Big-Endian var dataLength = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3]; package = new LvlPackage(new SegmentStream(s, 8, dataLength), filename, context); return(true); }
bool IPackageLoader.TryParsePackage(Stream s, string filename, FS context, out IReadOnlyPackage package) { if (!filename.EndsWith(".mix", StringComparison.InvariantCultureIgnoreCase)) { package = null; return(false); } // Load the global mix database var allPossibleFilenames = new HashSet <string>(); if (context.TryOpen("global mix database.dat", out var mixDatabase)) { using (var db = new XccGlobalDatabase(mixDatabase)) foreach (var e in db.Entries) { allPossibleFilenames.Add(e); } } package = new MixFile(s, filename, allPossibleFilenames); return(true); }
string GetSourceDisplayName(IReadOnlyPackage source) { if (source == null) { return("All Packages"); } // Packages that are explicitly mounted in the filesystem use their explicit mount name var fs = (OpenRA.FileSystem.FileSystem)modData.DefaultFileSystem; var name = fs.GetPrefix(source); // Fall back to the path relative to the mod, engine, or support dir if (name == null) { name = source.Name; var compare = Platform.CurrentPlatform == PlatformType.Windows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; if (name.StartsWith(modData.Manifest.Package.Name, compare)) { name = "$" + modData.Manifest.Id + "/" + name.Substring(modData.Manifest.Package.Name.Length + 1); } else if (name.StartsWith(Platform.EngineDir, compare)) { name = "./" + name.Substring(Platform.EngineDir.Length); } else if (name.StartsWith(Platform.SupportDir, compare)) { name = "^" + name.Substring(Platform.SupportDir.Length); } } if (name.Length > 18) { name = "..." + name.Substring(name.Length - 15); } return(name); }
Manifest LoadMod(string id, string path) { IReadOnlyPackage package = null; try { if (!Directory.Exists(path)) { throw new InvalidDataException(path + " is not a valid mod package"); } package = new Folder(path); if (!package.Contains("mod.yaml")) { throw new InvalidDataException(path + " is not a valid mod package"); } using (var stream = package.GetStream("icon.png")) if (stream != null) { using (var bitmap = new Bitmap(stream)) icons[id] = sheetBuilder.Add(bitmap); } return(new Manifest(id, package)); } catch (Exception) { if (package != null) { package.Dispose(); } return(null); } }
public Manifest(string modId, IReadOnlyPackage package) { Id = modId; Package = package; yaml = new MiniYaml(null, MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml")).ToDictionary(); Metadata = FieldLoader.Load <ModMetadata>(yaml["Metadata"]); // TODO: Use fieldloader MapFolders = YamlDictionary(yaml, "MapFolders"); MiniYaml packages; if (yaml.TryGetValue("Packages", out packages)) { Packages = packages.ToDictionary(x => x.Value).AsReadOnly(); } Rules = YamlList(yaml, "Rules"); Sequences = YamlList(yaml, "Sequences"); ModelSequences = YamlList(yaml, "ModelSequences"); Cursors = YamlList(yaml, "Cursors"); Chrome = YamlList(yaml, "Chrome"); Assemblies = YamlList(yaml, "Assemblies"); ChromeLayout = YamlList(yaml, "ChromeLayout"); Weapons = YamlList(yaml, "Weapons"); Voices = YamlList(yaml, "Voices"); Notifications = YamlList(yaml, "Notifications"); Music = YamlList(yaml, "Music"); Translations = YamlList(yaml, "Translations"); TileSets = YamlList(yaml, "TileSets"); ChromeMetrics = YamlList(yaml, "ChromeMetrics"); Missions = YamlList(yaml, "Missions"); Hotkeys = YamlList(yaml, "Hotkeys"); ServerTraits = YamlList(yaml, "ServerTraits"); if (!yaml.TryGetValue("LoadScreen", out LoadScreen)) { throw new InvalidDataException("`LoadScreen` section is not defined."); } // Allow inherited mods to import parent maps. var compat = new List <string> { Id }; if (yaml.ContainsKey("SupportsMapsFrom")) { compat.AddRange(yaml["SupportsMapsFrom"].Value.Split(',').Select(c => c.Trim())); } MapCompatibility = compat.ToArray(); if (yaml.ContainsKey("PackageFormats")) { PackageFormats = FieldLoader.GetValue <string[]>("PackageFormats", yaml["PackageFormats"].Value); } if (yaml.ContainsKey("SoundFormats")) { SoundFormats = FieldLoader.GetValue <string[]>("SoundFormats", yaml["SoundFormats"].Value); } if (yaml.ContainsKey("SpriteFormats")) { SpriteFormats = FieldLoader.GetValue <string[]>("SpriteFormats", yaml["SpriteFormats"].Value); } }
public bool TryParsePackage(Stream s, string filename, OpenRA.FileSystem.FileSystem context, out IReadOnlyPackage package) { var position = s.Position; var id = s.ReadUInt32(); var version = s.ReadUInt32(); s.Position = position; if (id != UnencryptedMegID || version != MegVersion) { package = null; return(false); } package = new MegFile(s, filename); return(true); }
bool IPackageLoader.TryParsePackage(Stream s, string filename, FileSystem.FileSystem context, out IReadOnlyPackage package) { if (!filename.EndsWith(".rs", StringComparison.InvariantCultureIgnoreCase)) { package = null; return(false); } package = new D2kSoundResources(s, filename); return(true); }
/// <summary> /// ╪сть╣ьм╪ /// </summary> public void LoadMaps() { if (!this.modData.Manifest.Contains <MapGrid>()) { return; } //Enumerate map directories foreach (var kv in modData.Manifest.MapFolders) { var name = kv.Key; var classification = string.IsNullOrEmpty(kv.Value) ? MapClassification.Unknown : Enum <MapClassification> .Parse(kv.Value); IReadOnlyPackage package; var optional = name.StartsWith("~", StringComparison.Ordinal); if (optional) { name = name.Substring(1); } try { package = modData.ModFiles.OpenPackage(name); } catch { if (optional) { continue; } throw; } mapLocations.Add(package, classification); } var mapGrid = this.modData.Manifest.Get <MapGrid>(); foreach (var kv in MapLocations) { foreach (var map in kv.Key.Contents) { IReadOnlyPackage mapPackage = null; try { using (new Support.PerfTimer(map)) { mapPackage = kv.Key.OpenPackage(map, modData.ModFiles); if (mapPackage == null) { continue; } var uid = Map.ComputeUID(mapPackage); previews[uid].UpdateFromMap(mapPackage, kv.Key, kv.Value, modData.Manifest.MapCompatibility, mapGrid.Type); } } catch (Exception e) { if (mapPackage != null) { mapPackage.Dispose(); } } } } }
bool ShowSourceDropdown(DropDownButtonWidget dropdown) { Func<IReadOnlyPackage, ScrollItemWidget, ScrollItemWidget> setupItem = (source, itemTemplate) => { var item = ScrollItemWidget.Setup(itemTemplate, () => assetSource == source, () => { assetSource = source; PopulateAssetList(); }); item.Get<LabelWidget>("LABEL").GetText = () => source != null ? Platform.UnresolvePath(source.Name) : "All Packages"; return item; }; var sources = new[] { (IReadOnlyPackage)null }.Concat(acceptablePackages); dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, setupItem); return true; }
public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType) { Dictionary <string, MiniYaml> yaml; using (var yamlStream = p.GetStream("map.yaml")) { if (yamlStream == null) { throw new FileNotFoundException("Required file map.yaml not present in this map"); } yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, "map.yaml")).ToDictionary(); } Package = p; parentPackage = parent; var newData = innerData.Clone(); newData.GridType = gridType; newData.Class = classification; MiniYaml temp; if (yaml.TryGetValue("MapFormat", out temp)) { var format = FieldLoader.GetValue <int>("MapFormat", temp.Value); if (format != Map.SupportedMapFormat) { throw new InvalidDataException("Map format {0} is not supported.".F(format)); } } if (yaml.TryGetValue("Title", out temp)) { newData.Title = temp.Value; } if (yaml.TryGetValue("Categories", out temp)) { newData.Categories = FieldLoader.GetValue <string[]>("Categories", temp.Value); } if (yaml.TryGetValue("Tileset", out temp)) { newData.TileSet = temp.Value; } if (yaml.TryGetValue("Author", out temp)) { newData.Author = temp.Value; } if (yaml.TryGetValue("Bounds", out temp)) { newData.Bounds = FieldLoader.GetValue <Rectangle>("Bounds", temp.Value); } if (yaml.TryGetValue("Visibility", out temp)) { newData.Visibility = FieldLoader.GetValue <MapVisibility>("Visibility", temp.Value); } string requiresMod = string.Empty; if (yaml.TryGetValue("RequiresMod", out temp)) { requiresMod = temp.Value; } newData.Status = mapCompatibility == null || mapCompatibility.Contains(requiresMod) ? MapStatus.Available : MapStatus.Unavailable; try { // Actor definitions may change if the map format changes MiniYaml actorDefinitions; if (yaml.TryGetValue("Actors", out actorDefinitions)) { var spawns = new List <CPos>(); foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); spawns.Add(s.InitDict.Get <LocationInit>().Value(null)); } newData.SpawnPoints = spawns.ToArray(); } else { newData.SpawnPoints = new CPos[0]; } } catch (Exception) { newData.SpawnPoints = new CPos[0]; newData.Status = MapStatus.Unavailable; } try { // Player definitions may change if the map format changes MiniYaml playerDefinitions; if (yaml.TryGetValue("Players", out playerDefinitions)) { newData.Players = new MapPlayers(playerDefinitions.Nodes); newData.PlayerCount = newData.Players.Players.Count(x => x.Value.Playable); } } catch (Exception) { newData.Status = MapStatus.Unavailable; } newData.SetRulesetGenerator(modData, () => { var ruleDefinitions = LoadRuleSection(yaml, "Rules"); var weaponDefinitions = LoadRuleSection(yaml, "Weapons"); var voiceDefinitions = LoadRuleSection(yaml, "Voices"); var musicDefinitions = LoadRuleSection(yaml, "Music"); var notificationDefinitions = LoadRuleSection(yaml, "Notifications"); var sequenceDefinitions = LoadRuleSection(yaml, "Sequences"); var modelSequenceDefinitions = LoadRuleSection(yaml, "ModelSequences"); var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions, modelSequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); return(Pair.New(rules, flagged)); }); if (p.Contains("map.png")) { using (var dataStream = p.GetStream("map.png")) newData.Preview = new Bitmap(dataStream); } // Assign the new data atomically innerData = newData; }
public Manifest(string modId, IReadOnlyPackage package) { Id = modId; Package = package; yaml = new MiniYaml(null, MiniYaml.FromStream(Package.GetStream("mod.yaml"), "mod.yaml")).ToDictionary(); Metadata = FieldLoader.Load <ModMetadata>(yaml["Metadata"]); MapFolders = YamlDictionary(yaml, "MapFolders"); MiniYaml packages; if (yaml.TryGetValue("Packages", out packages)) { Packages = packages.ToDictionary(x => x.Value).AsReadOnly(); } Rules = YamlList(yaml, "Rules"); Sequences = YamlList(yaml, "Sequences"); ModelSequences = YamlList(yaml, "ModelSequences"); Assemblies = YamlList(yaml, "Assemblies"); Weapons = YamlList(yaml, "Weapons"); Voices = YamlList(yaml, "Voices"); Notifications = YamlList(yaml, "Notifications"); Music = YamlList(yaml, "Music"); TileSets = YamlList(yaml, "TileSets"); Missions = YamlList(yaml, "Missions"); ServerTraits = YamlList(yaml, "ServerTraits"); Chrome = YamlList(yaml, "Chrome"); ChromeLayout = YamlList(yaml, "ChromeLayout"); ChromeMetrics = YamlList(yaml, "ChromeMetrics"); Fonts = yaml["Fonts"].ToDictionary(my => { var nd = my.ToDictionary(); return(Pair.New(nd["Font"].Value, Exts.ParseIntegerInvariant(nd["Size"].Value))); }); if (!yaml.TryGetValue("LoadScreen", out LoadScreen)) { throw new InvalidDataException("'LoadScreen' section is not defined."); } var compat = new List <string> { Id }; if (yaml.ContainsKey("SupportsMapsFrom")) { compat.AddRange(yaml["SupportsMapsFrom"].Value.Split(',').Select(c => c.Trim())); } MapCompatibility = compat.ToArray(); if (yaml.ContainsKey("SpriteFormats")) { SpriteFormats = FieldLoader.GetValue <string[]>("SpriteFormats", yaml["SpriteFormats"].Value); } if (yaml.ContainsKey("PackageFormats")) { PackageFormats = FieldLoader.GetValue <string[]>("PackageFormats", yaml["PackageFormats"].Value); } if (yaml.ContainsKey("SoundFormats")) { SoundFormats = FieldLoader.GetValue <string[]>("SoundFormats", yaml["SoundFormats"].Value); } }
static Dictionary <string, ModMetadata> ValidateMods() { var ret = new Dictionary <string, ModMetadata>(); foreach (var pair in GetCandidateMods()) { IReadOnlyPackage package = null; try { if (Directory.Exists(pair.Second)) { package = new Folder(pair.Second); } else { try { package = new ZipFile(null, pair.Second); } catch { throw new InvalidDataException(pair.Second + " is not a valid mod package"); } } if (!package.Contains("mod.yaml")) { package.Dispose(); continue; } var yaml = new MiniYaml(null, MiniYaml.FromStream(package.GetStream("mod.yaml"))); var nd = yaml.ToDictionary(); if (!nd.ContainsKey("Metadata")) { package.Dispose(); continue; } var metadata = FieldLoader.Load <ModMetadata>(nd["Metadata"]); metadata.Id = pair.First; metadata.Package = package; if (nd.ContainsKey("RequiresMods")) { metadata.RequiresMods = nd["RequiresMods"].ToDictionary(my => my.Value); } else { metadata.RequiresMods = new Dictionary <string, string>(); } if (nd.ContainsKey("ContentInstaller")) { metadata.Content = FieldLoader.Load <ContentInstaller>(nd["ContentInstaller"]); } // Mods in the support directory and oramod packages (which are listed later // in the CandidateMods list) override mods in the main install. ret[pair.First] = metadata; } catch (Exception ex) { if (package != null) { package.Dispose(); } Console.WriteLine("An exception occurred when trying to load ModMetadata for `{0}`:".F(pair.First)); Console.WriteLine(ex.Message); } } return(ret); }
bool IReadOnlyFileSystem.TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename) { // Packages aren't supported inside maps return modData.DefaultFileSystem.TryGetPackageContaining(path, out package, out filename); }
bool LoadAsset(IReadOnlyPackage package, string filename) { ClearLoadedAssets(); if (string.IsNullOrEmpty(filename)) { return(false); } if (!package.Contains(filename)) { return(false); } isLoadError = false; try { currentPackage = package; currentFilename = filename; var prefix = ""; if (modData.DefaultFileSystem is OpenRA.FileSystem.FileSystem fs) { prefix = fs.GetPrefix(package); if (prefix != null) { prefix += "|"; } } var fileExtension = Path.GetExtension(filename.ToLowerInvariant()); if (allowedSpriteExtensions.Contains(fileExtension)) { currentSprites = world.Map.Rules.Sequences.SpriteCache[prefix + filename]; currentFrame = 0; if (frameSlider != null) { frameSlider.MaximumValue = (float)currentSprites.Length - 1; frameSlider.Ticks = currentSprites.Length; } currentVoxel = null; } else if (allowedModelExtensions.Contains(fileExtension)) { var voxelName = Path.GetFileNameWithoutExtension(filename); currentVoxel = world.ModelCache.GetModel(voxelName); currentSprites = null; } else if (allowedAudioExtensions.Contains(fileExtension)) { // Mute music so it doesn't interfere with the current asset. MuteSounds(); currentAudioStream = Game.ModData.DefaultFileSystem.Open(prefix + filename); foreach (var modDataSoundLoader in Game.ModData.SoundLoaders) { if (modDataSoundLoader.TryParseSound(currentAudioStream, out currentSoundFormat)) { if (frameSlider != null) { frameSlider.MaximumValue = currentSoundFormat.LengthInSeconds * currentSoundFormat.SampleRate; frameSlider.Ticks = 0; } break; } } } else if (allowedVideoExtensions.Contains(fileExtension)) { // Mute music so it doesn't interfere with the current asset. MuteSounds(); var video = VideoLoader.GetVideo(Game.ModData.DefaultFileSystem.Open(filename), true, Game.ModData.VideoLoaders); if (video != null) { player = panel.Get <VideoPlayerWidget>("PLAYER"); player.Load(prefix + filename); player.DrawOverlay = false; isVideoLoaded = true; if (frameSlider != null) { frameSlider.MaximumValue = (float)player.Video.FrameCount - 1; frameSlider.Ticks = 0; } } } else { return(false); } } catch (Exception ex) { isLoadError = true; Log.AddChannel("assetbrowser", "assetbrowser.log"); Log.Write("assetbrowser", "Error reading {0}:{3} {1}{3}{2}", filename, ex.Message, ex.StackTrace, Environment.NewLine); return(false); } return(true); }
public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassification classification, string[] mapCompatibility, MapGridType gridType) { Dictionary<string, MiniYaml> yaml; using (var yamlStream = p.GetStream("map.yaml")) { if (yamlStream == null) throw new FileNotFoundException("Required file map.yaml not present in this map"); yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, "map.yaml")).ToDictionary(); } Package = p; parentPackage = parent; var newData = innerData.Clone(); newData.GridType = gridType; newData.Class = classification; MiniYaml temp; if (yaml.TryGetValue("MapFormat", out temp)) { var format = FieldLoader.GetValue<int>("MapFormat", temp.Value); if (format != Map.SupportedMapFormat) throw new InvalidDataException("Map format {0} is not supported.".F(format)); } if (yaml.TryGetValue("Title", out temp)) newData.Title = temp.Value; if (yaml.TryGetValue("Categories", out temp)) newData.Categories = FieldLoader.GetValue<string[]>("Categories", temp.Value); if (yaml.TryGetValue("Tileset", out temp)) newData.TileSet = temp.Value; if (yaml.TryGetValue("Author", out temp)) newData.Author = temp.Value; if (yaml.TryGetValue("Bounds", out temp)) newData.Bounds = FieldLoader.GetValue<Rectangle>("Bounds", temp.Value); if (yaml.TryGetValue("Visibility", out temp)) newData.Visibility = FieldLoader.GetValue<MapVisibility>("Visibility", temp.Value); string requiresMod = string.Empty; if (yaml.TryGetValue("RequiresMod", out temp)) requiresMod = temp.Value; newData.Status = mapCompatibility == null || mapCompatibility.Contains(requiresMod) ? MapStatus.Available : MapStatus.Unavailable; try { // Actor definitions may change if the map format changes MiniYaml actorDefinitions; if (yaml.TryGetValue("Actors", out actorDefinitions)) { var spawns = new List<CPos>(); foreach (var kv in actorDefinitions.Nodes.Where(d => d.Value.Value == "mpspawn")) { var s = new ActorReference(kv.Value.Value, kv.Value.ToDictionary()); spawns.Add(s.InitDict.Get<LocationInit>().Value(null)); } newData.SpawnPoints = spawns.ToArray(); } else newData.SpawnPoints = new CPos[0]; } catch (Exception) { newData.SpawnPoints = new CPos[0]; newData.Status = MapStatus.Unavailable; } try { // Player definitions may change if the map format changes MiniYaml playerDefinitions; if (yaml.TryGetValue("Players", out playerDefinitions)) { newData.Players = new MapPlayers(playerDefinitions.Nodes); newData.PlayerCount = newData.Players.Players.Count(x => x.Value.Playable); } } catch (Exception) { newData.Status = MapStatus.Unavailable; } newData.SetRulesetGenerator(modData, () => { var ruleDefinitions = LoadRuleSection(yaml, "Rules"); var weaponDefinitions = LoadRuleSection(yaml, "Weapons"); var voiceDefinitions = LoadRuleSection(yaml, "Voices"); var musicDefinitions = LoadRuleSection(yaml, "Music"); var notificationDefinitions = LoadRuleSection(yaml, "Notifications"); var sequenceDefinitions = LoadRuleSection(yaml, "Sequences"); var rules = Ruleset.Load(modData, this, TileSet, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, musicDefinitions, sequenceDefinitions); var flagged = Ruleset.DefinesUnsafeCustomRules(modData, this, ruleDefinitions, weaponDefinitions, voiceDefinitions, notificationDefinitions, sequenceDefinitions); return Pair.New(rules, flagged); }); if (p.Contains("map.png")) using (var dataStream = p.GetStream("map.png")) newData.Preview = new Bitmap(dataStream); // Assign the new data atomically innerData = newData; }
public Map(ModData modData, IReadOnlyPackage package) { this.modData = modData; Package = package; if (!Package.Contains("map.yaml") || !Package.Contains("map.bin")) throw new InvalidDataException("Not a valid map\n File: {0}".F(package.Name)); var yaml = new MiniYaml(null, MiniYaml.FromStream(Package.GetStream("map.yaml"), package.Name)); foreach (var field in YamlFields) field.Deserialize(this, yaml.Nodes); if (MapFormat != SupportedMapFormat) throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, package.Name)); PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors"); Grid = modData.Manifest.Get<MapGrid>(); var size = new Size(MapSize.X, MapSize.Y); Tiles = new CellLayer<TerrainTile>(Grid.Type, size); Resources = new CellLayer<ResourceTile>(Grid.Type, size); Height = new CellLayer<byte>(Grid.Type, size); using (var s = Package.GetStream("map.bin")) { var header = new BinaryDataHeader(s, MapSize); if (header.TilesOffset > 0) { s.Position = header.TilesOffset; for (var i = 0; i < MapSize.X; i++) { for (var j = 0; j < MapSize.Y; j++) { var tile = s.ReadUInt16(); var index = s.ReadUInt8(); // TODO: Remember to remove this when rewriting tile variants / PickAny if (index == byte.MaxValue) index = (byte)(i % 4 + (j % 4) * 4); Tiles[new MPos(i, j)] = new TerrainTile(tile, index); } } } if (header.ResourcesOffset > 0) { s.Position = header.ResourcesOffset; for (var i = 0; i < MapSize.X; i++) { for (var j = 0; j < MapSize.Y; j++) { var type = s.ReadUInt8(); var density = s.ReadUInt8(); Resources[new MPos(i, j)] = new ResourceTile(type, density); } } } if (header.HeightsOffset > 0) { s.Position = header.HeightsOffset; for (var i = 0; i < MapSize.X; i++) for (var j = 0; j < MapSize.Y; j++) Height[new MPos(i, j)] = s.ReadUInt8().Clamp((byte)0, Grid.MaximumTerrainHeight); } } if (Grid.MaximumTerrainHeight > 0) { Tiles.CellEntryChanged += UpdateProjection; Height.CellEntryChanged += UpdateProjection; } PostInit(); Uid = ComputeUID(Package); }
bool IPackageLoader.TryParsePackage(Stream s, string filename, FileSystem context, out IReadOnlyPackage package) { // Take a peek at the file signature var signature = s.ReadUInt32(); s.Position -= 4; if (signature != 0x8C655D13) { package = null; return(false); } package = new InstallShieldPackage(s, filename); return(true); }
public static string ComputeUID(IReadOnlyPackage package) { // UID is calculated by taking an SHA1 of the yaml and binary data var requiredFiles = new[] { "map.yaml", "map.bin" }; var contents = package.Contents.ToList(); foreach (var required in requiredFiles) if (!contents.Contains(required)) throw new FileNotFoundException("Required file {0} not present in this map".F(required)); using (var ms = new MemoryStream()) { foreach (var filename in contents) if (filename.EndsWith(".yaml") || filename.EndsWith(".bin") || filename.EndsWith(".lua")) using (var s = package.GetStream(filename)) s.CopyTo(ms); // Take the SHA1 ms.Seek(0, SeekOrigin.Begin); return CryptoUtil.SHA1Hash(ms); } }
public bool TryParsePackage(Stream s, string filename, OpenRA.FileSystem.FileSystem context, out IReadOnlyPackage package) { if (!filename.EndsWith("DDF")) { package = null; return(false); } package = new DdfPackage(s, context.Open(filename.Replace(".DDF", ".ANI")), filename); return(true); }
public void LoadMaps() { // Utility mod that does not support maps if (!modData.Manifest.Contains <MapGrid>()) { return; } // Enumerate map directories foreach (var kv in modData.Manifest.MapFolders) { var name = kv.Key; var classification = string.IsNullOrEmpty(kv.Value) ? MapClassification.Unknown : Enum <MapClassification> .Parse(kv.Value); IReadOnlyPackage package; var optional = name.StartsWith("~", StringComparison.Ordinal); if (optional) { name = name.Substring(1); } try { // HACK: If the path is inside the the support directory then we may need to create it if (Platform.IsPathRelativeToSupportDirectory(name)) { // Assume that the path is a directory if there is not an existing file with the same name var resolved = Platform.ResolvePath(name); if (!File.Exists(resolved)) { Directory.CreateDirectory(resolved); } } package = modData.ModFiles.OpenPackage(name); } catch { if (optional) { continue; } throw; } mapLocations.Add(package, classification); } var mapGrid = modData.Manifest.Get <MapGrid>(); foreach (var kv in MapLocations) { foreach (var map in kv.Key.Contents) { IReadOnlyPackage mapPackage = null; try { using (new Support.PerfTimer(map)) { mapPackage = kv.Key.OpenPackage(map, modData.ModFiles); if (mapPackage == null) { continue; } var uid = Map.ComputeUID(mapPackage); previews[uid].UpdateFromMap(mapPackage, kv.Key, kv.Value, modData.Manifest.MapCompatibility, mapGrid.Type); } } catch (Exception e) { if (mapPackage != null) { mapPackage.Dispose(); } Console.WriteLine("Failed to load map: {0}", map); Console.WriteLine("Details: {0}", e); Log.Write("debug", "Failed to load map: {0}", map); Log.Write("debug", "Details: {0}", e); } } } }
public bool TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename) { return(modData.DefaultFileSystem.TryGetPackageContaining(path, out package, out filename)); }
bool IPackageLoader.TryParsePackage(Stream s, string filename, FileSystem context, out IReadOnlyPackage package) { // Take a peek at the file signature var signature = s.ReadASCII(4); s.Position -= 4; if (signature != "BIGF") { package = null; return(false); } package = new BigFile(s, filename); return(true); }
public bool TryParsePackage(Stream stream, string filename, OpenRA.FileSystem.FileSystem filesystem, out IReadOnlyPackage package) { if (!filename.EndsWith(".stf")) { package = null; return(false); } package = new StfFile(stream, filename, filesystem); return(true); }
public void Mount(IReadOnlyPackage package, string explicitName = null) { var mountCount = 0; if (mountedPackages.TryGetValue(package, out mountCount)) { // Package is already mounted // Increment the mount count and bump up the file loading priority mountedPackages[package] = mountCount + 1; foreach (var filename in package.Contents) { fileIndex[filename].Remove(package); fileIndex[filename].Add(package); } } else { // Mounting the package for the first time mountedPackages.Add(package, 1); if (explicitName != null) explicitMounts.Add(explicitName, package); foreach (var filename in package.Contents) fileIndex[filename].Add(package); } }
public Map(ModData modData, IReadOnlyPackage package) { this.modData = modData; Package = package; if (!Package.Contains("map.yaml") || !Package.Contains("map.bin")) { throw new InvalidDataException("Not a valid map\n File: {0}".F(package.Name)); } var yaml = new MiniYaml(null, MiniYaml.FromStream(Package.GetStream("map.yaml"), package.Name)); foreach (var field in YamlFields) { field.Deserialize(this, yaml.Nodes); } if (MapFormat != SupportedMapFormat) { throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, package.Name)); } PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); ActorDefinitions = MiniYaml.NodesOrEmpty(yaml, "Actors"); Grid = modData.Manifest.Get <MapGrid>(); var size = new Size(MapSize.X, MapSize.Y); Tiles = new CellLayer <TerrainTile>(Grid.Type, size); Resources = new CellLayer <ResourceTile>(Grid.Type, size); Height = new CellLayer <byte>(Grid.Type, size); using (var s = Package.GetStream("map.bin")) { var header = new BinaryDataHeader(s, MapSize); if (header.TilesOffset > 0) { s.Position = header.TilesOffset; for (var i = 0; i < MapSize.X; i++) { for (var j = 0; j < MapSize.Y; j++) { var tile = s.ReadUInt16(); var index = s.ReadUInt8(); // TODO: Remember to remove this when rewriting tile variants / PickAny if (index == byte.MaxValue) { index = (byte)(i % 4 + (j % 4) * 4); } Tiles[new MPos(i, j)] = new TerrainTile(tile, index); } } } if (header.ResourcesOffset > 0) { s.Position = header.ResourcesOffset; for (var i = 0; i < MapSize.X; i++) { for (var j = 0; j < MapSize.Y; j++) { var type = s.ReadUInt8(); var density = s.ReadUInt8(); Resources[new MPos(i, j)] = new ResourceTile(type, density); } } } if (header.HeightsOffset > 0) { s.Position = header.HeightsOffset; for (var i = 0; i < MapSize.X; i++) { for (var j = 0; j < MapSize.Y; j++) { Height[new MPos(i, j)] = s.ReadUInt8().Clamp((byte)0, Grid.MaximumTerrainHeight); } } } } if (Grid.MaximumTerrainHeight > 0) { Tiles.CellEntryChanged += UpdateProjection; Height.CellEntryChanged += UpdateProjection; } PostInit(); Uid = ComputeUID(Package); }
public IReadOnlyPackage OpenPackage(string filename, IReadOnlyPackage parent) { // HACK: limit support to zip and folder until we generalize the PackageLoader support if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase) || filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) { using (var s = parent.GetStream(filename)) return new ZipFile(s, filename, parent); } if (parent is ZipFile) return new ZipFolder(this, (ZipFile)parent, filename, filename); if (parent is ZipFolder) { var folder = (ZipFolder)parent; return new ZipFolder(this, folder.Parent, folder.Name + "/" + filename, filename); } if (parent is Folder) { var subFolder = Platform.ResolvePath(Path.Combine(parent.Name, filename)); if (Directory.Exists(subFolder)) return new Folder(subFolder); } return null; }
public string GetPrefix(IReadOnlyPackage package) { return(explicitMounts.ContainsValue(package) ? explicitMounts.First(f => f.Value == package).Key : null); }
public bool TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename) { var explicitSplit = path.IndexOf('|'); if (explicitSplit > 0 && explicitMounts.TryGetValue(path.Substring(0, explicitSplit), out package)) { filename = path.Substring(explicitSplit + 1); return true; } package = fileIndex[path].LastOrDefault(x => x.Contains(path)); filename = path; return package != null; }
public IReadOnlyPackage OpenPackage(string filename, IReadOnlyPackage parent) { // TODO: Make legacy callers access the parent package directly return(parent.OpenPackage(filename, this)); }
public bool Unmount(IReadOnlyPackage package) { var mountCount = 0; if (!mountedPackages.TryGetValue(package, out mountCount)) return false; if (--mountCount <= 0) { foreach (var packagesForFile in fileIndex.Values) packagesForFile.RemoveAll(p => p == package); mountedPackages.Remove(package); var explicitKeys = explicitMounts.Where(kv => kv.Value == package) .Select(kv => kv.Key) .ToList(); foreach (var key in explicitKeys) explicitMounts.Remove(key); // Mod packages aren't owned by us, so we shouldn't dispose them if (modPackages.Contains(package)) modPackages.Remove(package); else package.Dispose(); } else mountedPackages[package] = mountCount; return true; }