/// <summary> /// /// </summary> /// <param name="package"></param> /// <returns></returns> public static string ComputeUID(IReadOnlyPackage package) { 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); // } // } // ms.Seek(0, SeekOrigin.Begin); // return CryptoUtil.SHA1Hash(ms); //} var streams = new List <Stream>(); try { foreach (var filename in contents) { if (filename.EndsWith(".yaml") || filename.EndsWith(".bin") || filename.EndsWith(".lua")) { streams.Add(package.GetStream(filename)); } } //Take the SHA1 if (streams.Count == 0) { return(CryptoUtil.SHA1Hash(new byte[0])); } var merged = streams[0]; for (var i = 1; i < streams.Count; i++) { merged = new MergedStream(merged, streams[i]); } return(CryptoUtil.SHA1Hash(merged)); } finally{ foreach (var stream in streams) { stream.Dispose(); } } }
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 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 IReadOnlyPackage OpenPackage(string filename, IReadOnlyPackage parent) { // HACK: limit support to zip and folder until we generalize the PackageLoader support if (parent is Folder) { var path = Path.Combine(parent.Name, filename); // HACK: work around SharpZipLib's lack of support for writing to in-memory files if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) { return(new ZipFile(this, path)); } if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) { return(new ZipFile(this, path)); } var subFolder = Platform.ResolvePath(path); if (Directory.Exists(subFolder)) { return(new Folder(subFolder)); } } if (filename.EndsWith(".zip", StringComparison.InvariantCultureIgnoreCase)) { return(new ZipFile(this, filename, parent.GetStream(filename))); } if (filename.EndsWith(".oramap", StringComparison.InvariantCultureIgnoreCase)) { return(new ZipFile(this, filename, parent.GetStream(filename))); } 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)); } return(null); }
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", stringPool: cache.StringPool)).ToDictionary(); } Package = p; parentPackage = parent; var newData = innerData.Clone(); newData.GridType = gridType; newData.Class = classification; if (yaml.TryGetValue("MapFormat", out var temp)) { var format = FieldLoader.GetValue <int>("MapFormat", temp.Value); if (format != Map.SupportedMapFormat) { throw new InvalidDataException($"Map format {format} is not supported."); } } 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; } if (yaml.TryGetValue("MapFormat", out temp)) { newData.MapFormat = FieldLoader.GetValue <int>("MapFormat", temp.Value); } newData.Status = mapCompatibility == null || mapCompatibility.Contains(requiresMod) ? MapStatus.Available : MapStatus.Unavailable; try { // Actor definitions may change if the map format changes if (yaml.TryGetValue("Actors", out var 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.Get <LocationInit>().Value); } newData.SpawnPoints = spawns.ToArray(); } else { newData.SpawnPoints = Array.Empty <CPos>(); } } catch (Exception) { newData.SpawnPoints = Array.Empty <CPos>(); newData.Status = MapStatus.Unavailable; } try { // Player definitions may change if the map format changes if (yaml.TryGetValue("Players", out var playerDefinitions)) { newData.Players = new MapPlayers(playerDefinitions.Nodes); newData.PlayerCount = newData.Players.Players.Count(x => x.Value.Playable); } } catch (Exception) { newData.Status = MapStatus.Unavailable; } newData.SetCustomRules(modData, this, yaml); if (p.Contains("map.png")) { using (var dataStream = p.GetStream("map.png")) newData.Preview = new Png(dataStream); } // Assign the new data atomically innerData = newData; }
public Manifest(string modId, IReadOnlyPackage package) { Id = modId; Package = package; var nodes = MiniYaml.FromStream(package.GetStream("mod.yaml"), "mod.yaml"); for (var i = nodes.Count - 1; i >= 0; i--) { if (nodes[i].Key != "Include") { continue; } // Replace `Includes: filename.yaml` with the contents of filename.yaml var filename = nodes[i].Value.Value; var contents = package.GetStream(filename); if (contents == null) { throw new YamlException("{0}: File `{1}` not found.".F(nodes[i].Location, filename)); } nodes.RemoveAt(i); nodes.InsertRange(i, MiniYaml.FromStream(contents, filename)); } // Merge inherited overrides yaml = new MiniYaml(null, MiniYaml.Merge(new[] { nodes })).ToDictionary(); Metadata = FieldLoader.Load <ModMetadata>(yaml["Metadata"]); // TODO: Use fieldloader MapFolders = YamlDictionary(yaml, "MapFolders"); if (yaml.TryGetValue("Packages", out var packages)) { Packages = packages.ToDictionary(x => x.Value); } 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"); 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); } if (yaml.ContainsKey("VideoFormats")) { VideoFormats = FieldLoader.GetValue <string[]>("VideoFormats", yaml["VideoFormats"].Value); } }
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 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 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 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 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 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 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 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); } }