public IncreaseBiodiversity(AutoEvoConfiguration configuration, PatchMap map, Patch patch, Random random) { this.map = map; this.patch = patch; this.configuration = configuration; this.random = new Random(random.Next()); }
public SimulationConfiguration(AutoEvoConfiguration autoEvoConfiguration, PatchMap initialConditions, int steps = 1) { AutoEvoConfiguration = autoEvoConfiguration; OriginalMap = initialConditions; StepsLeft = Math.Max(1, steps); }
public FindBestMigration(AutoEvoConfiguration configuration, PatchMap map, Species species, Random random, int migrationsToTry, bool allowNoMigration) : base(migrationsToTry, allowNoMigration) { this.configuration = configuration; this.map = map; this.species = species; this.random = new Random(random.Next()); }
/// <summary> /// Prints to log a summary of the results /// </summary> public void PrintSummary(PatchMap previousPopulations = null) { GD.Print("Start of auto-evo results summary (entries: ", results.Count, ")"); GD.Print(MakeSummary(previousPopulations)); GD.Print("End of results summary"); }
public CalculatePopulation(AutoEvoConfiguration configuration, PatchMap map, List <Species> extraSpecies = null, List <Species> excludedSpecies = null, bool collectEnergyInfo = false) { this.configuration = configuration; this.map = map; this.extraSpecies = extraSpecies; this.excludedSpecies = excludedSpecies; this.collectEnergyInfo = collectEnergyInfo; }
public void SetMap(PatchMap map) { mapDrawer.Map = map; }
public static PatchMap Generate(WorldGenerationSettings settings, Species defaultSpecies) { // TODO: implement actual generation based on settings _ = settings; var map = new PatchMap(); // Predefined patches Patch patch0 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_VENTS"), 0, GetBiomeTemplate("aavolcanic_vent")); patch0.Depth[0] = 2500; patch0.Depth[1] = 3000; patch0.AddSpecies(defaultSpecies); patch0.ScreenCoordinates = new Vector2(100, 400); map.AddPatch(patch0); Patch patch1 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_MESOPELAGIC"), 1, GetBiomeTemplate("mesopelagic")); patch1.Depth[0] = 200; patch1.Depth[1] = 1000; patch1.ScreenCoordinates = new Vector2(200, 200); map.AddPatch(patch1); Patch patch2 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_EPIPELAGIC"), 2, GetBiomeTemplate("default")); patch2.Depth[0] = 0; patch2.Depth[1] = 200; patch2.ScreenCoordinates = new Vector2(200, 100); map.AddPatch(patch2); Patch patch3 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_TIDEPOOL"), 3, GetBiomeTemplate("tidepool")); patch3.Depth[0] = 0; patch3.Depth[1] = 10; patch3.ScreenCoordinates = new Vector2(300, 100); map.AddPatch(patch3); Patch patch4 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_BATHYPELAGIC"), 4, GetBiomeTemplate("bathypelagic")); patch4.Depth[0] = 1000; patch4.Depth[1] = 4000; patch4.ScreenCoordinates = new Vector2(200, 300); map.AddPatch(patch4); Patch patch5 = new Patch(TranslationServer.Translate("PATHCH_PANGONIAN_ABYSSOPELAGIC"), 5, GetBiomeTemplate("abyssopelagic")); patch5.Depth[0] = 4000; patch5.Depth[1] = 6000; patch5.ScreenCoordinates = new Vector2(300, 400); map.AddPatch(patch5); Patch patch6 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_COAST"), 6, GetBiomeTemplate("coastal")); patch6.Depth[0] = 0; patch6.Depth[1] = 200; patch6.ScreenCoordinates = new Vector2(100, 100); map.AddPatch(patch6); Patch patch7 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_ESTUARY"), 7, GetBiomeTemplate("estuary")); patch7.Depth[0] = 0; patch7.Depth[1] = 200; patch7.ScreenCoordinates = new Vector2(70, 160); map.AddPatch(patch7); Patch patch8 = new Patch(TranslationServer.Translate("PATCH_CAVE"), 8, GetBiomeTemplate("underwater_cave")); patch8.Depth[0] = 200; patch8.Depth[1] = 1000; patch8.ScreenCoordinates = new Vector2(300, 200); map.AddPatch(patch8); Patch patch9 = new Patch(TranslationServer.Translate("PATCH_ICE_SHELF"), 9, GetBiomeTemplate("ice_shelf")); patch9.Depth[0] = 0; patch9.Depth[1] = 200; patch9.ScreenCoordinates = new Vector2(200, 30); map.AddPatch(patch9); Patch patch10 = new Patch(TranslationServer.Translate("PATCH_PANGONIAN_SEAFLOOR"), 10, GetBiomeTemplate("seafloor")); patch10.Depth[0] = 4000; patch10.Depth[1] = 6000; patch10.ScreenCoordinates = new Vector2(200, 400); map.AddPatch(patch10); // Connections patch0.AddNeighbour(patch10); patch1.AddNeighbour(patch4); patch1.AddNeighbour(patch2); patch1.AddNeighbour(patch8); patch2.AddNeighbour(patch1); patch2.AddNeighbour(patch3); patch2.AddNeighbour(patch6); patch2.AddNeighbour(patch9); patch3.AddNeighbour(patch2); patch4.AddNeighbour(patch5); patch4.AddNeighbour(patch1); patch4.AddNeighbour(patch10); patch5.AddNeighbour(patch10); patch5.AddNeighbour(patch4); patch6.AddNeighbour(patch2); patch6.AddNeighbour(patch7); patch7.AddNeighbour(patch6); patch8.AddNeighbour(patch1); patch9.AddNeighbour(patch2); patch10.AddNeighbour(patch4); patch10.AddNeighbour(patch5); patch10.AddNeighbour(patch0); map.CurrentPatch = patch0; return(map); }
/// <summary> /// Makes summary text /// </summary> /// <param name="previousPopulations">If provided comparisons to previous populations is included</param> /// <param name="playerReadable">if true ids are removed from the output</param> /// <param name="effects">if not null these effects are applied to the population numbers</param> /// <returns>The generated summary text</returns> public LocalizedStringBuilder MakeSummary(PatchMap previousPopulations = null, bool playerReadable = false, List <ExternalEffect> effects = null) { const bool resolveMigrations = true; const bool resolveSplits = true; var builder = new LocalizedStringBuilder(500); LocalizedStringBuilder PatchString(Patch patch) { var builder2 = new LocalizedStringBuilder(80); if (!playerReadable) { builder2.Append(patch.ID); } builder2.Append(' '); builder2.Append(new LocalizedString(patch.Name)); return(builder2); } void OutputPopulationForPatch(Species species, Patch patch, long population) { builder.Append(" "); var patchName = PatchString(patch); if (population > 0) { builder.Append(patchName); builder.Append(' '); builder.Append(new LocalizedString("POPULATION")); builder.Append(' '); builder.Append(population); } else { // For some reason this line had one more space padding than the case that the population // wasn't extinct in this patch builder.Append(new LocalizedString("WENT_EXTINCT_IN", patchName)); } if (previousPopulations != null) { builder.Append(' '); builder.Append(new LocalizedString("PREVIOUS")); builder.Append(' '); builder.Append(previousPopulations.GetPatch(patch.ID).GetSpeciesPopulation(species)); } builder.Append('\n'); } foreach (var entry in results.Values.OrderByDescending(s => s.Species.PlayerSpecies) .ThenBy(s => s.Species.FormattedName)) { builder.Append(playerReadable ? entry.Species.FormattedName : entry.Species.FormattedIdentifier); builder.Append(":\n"); if (entry.SplitFrom != null) { builder.Append(' '); builder.Append(new LocalizedString("RUN_RESULT_SPLIT_FROM", playerReadable ? entry.SplitFrom.FormattedName : entry.SplitFrom.FormattedIdentifier)); builder.Append('\n'); } if (entry.NewlyCreated != null) { builder.Append(' '); switch (entry.NewlyCreated.Value) { case NewSpeciesType.FillNiche: builder.Append(new LocalizedString("RUN_RESULT_NICHE_FILL")); break; case NewSpeciesType.SplitDueToMutation: builder.Append(new LocalizedString("RUN_RESULT_SELECTION_PRESSURE_SPLIT")); break; default: GD.PrintErr("Unhandled newly created species type: ", entry.NewlyCreated.Value); builder.Append(entry.NewlyCreated.Value); break; } builder.Append('\n'); } if (entry.SplitOff != null) { if (entry.SplitOffPatches == null) { throw new InvalidOperationException("List of split off patches is null"); } builder.Append(' '); builder.Append(new LocalizedString("RUN_RESULT_SPLIT_OFF_TO", playerReadable ? entry.SplitOff.FormattedName : entry.SplitOff.FormattedIdentifier)); builder.Append('\n'); foreach (var patch in entry.SplitOffPatches) { builder.Append(" "); builder.Append(new LocalizedString(patch.Name)); builder.Append('\n'); } } if (entry.MutatedProperties != null) { builder.Append(' '); builder.Append(new LocalizedString("RUN_RESULT_HAS_A_MUTATION")); if (!playerReadable) { builder.Append(", "); builder.Append(new LocalizedString("RUN_RESULT_GENE_CODE")); builder.Append(' '); builder.Append(entry.MutatedProperties.StringCode); } builder.Append('\n'); } if (entry.SpreadToPatches.Count > 0) { builder.Append(' '); builder.Append(new LocalizedString("RUN_RESULT_SPREAD_TO_PATCHES")); builder.Append('\n'); foreach (var spreadEntry in entry.SpreadToPatches) { if (playerReadable) { builder.Append(" "); builder.Append(new LocalizedString("RUN_RESULT_BY_SENDING_POPULATION", new LocalizedString(spreadEntry.To.Name), spreadEntry.Population, new LocalizedString(spreadEntry.From.Name))); } else { builder.Append(" "); builder.Append(new LocalizedString(spreadEntry.To.Name)); builder.Append(" pop: "); builder.Append(spreadEntry.Population); builder.Append(" from: "); builder.Append(new LocalizedString(spreadEntry.From.Name)); } builder.Append('\n'); } } builder.Append(' '); builder.Append(new LocalizedString("RUN_RESULT_POP_IN_PATCHES")); builder.Append('\n'); foreach (var patchPopulation in entry.NewPopulationInPatches) { long adjustedPopulation = patchPopulation.Value; if (resolveMigrations) { adjustedPopulation += CountSpeciesSpreadPopulation(entry.Species, patchPopulation.Key); } if (resolveSplits) { if (entry.SplitOffPatches?.Contains(patchPopulation.Key) == true) { // All population splits off adjustedPopulation = 0; } } // Apply external effects if (effects != null && previousPopulations != null && previousPopulations.CurrentPatch.ID == patchPopulation.Key.ID) { foreach (var effect in effects) { if (effect.Species == entry.Species) { adjustedPopulation += effect.Constant + (long)(effect.Species.Population * effect.Coefficient) - effect.Species.Population; } } } // As the populations are added to all patches, even when the species is not there, we remove those // from output if there is currently no population in a patch and there isn't one in // previousPopulations var include = false; if (adjustedPopulation > 0) { include = true; } else { if (previousPopulations?.GetPatch(patchPopulation.Key.ID).GetSpeciesPopulation(entry.Species) > 0) { include = true; } } if (include) { OutputPopulationForPatch(entry.Species, patchPopulation.Key, adjustedPopulation); } } // Also print new patches the species moved to (as the moves don't get // included in newPopulationInPatches if (resolveMigrations) { foreach (var spreadEntry in entry.SpreadToPatches) { var found = false; var to = spreadEntry.To; foreach (var populationEntry in entry.NewPopulationInPatches) { if (populationEntry.Key == to) { found = true; break; } } if (!found) { OutputPopulationForPatch(entry.Species, to, CountSpeciesSpreadPopulation(entry.Species, to)); } } } // Print populations from splits // Warning suppressed on resolveSplits to allow keeping the variable // ReSharper disable once RedundantLogicalConditionalExpressionOperand if (resolveSplits && entry.SplitFrom != null) { var splitFrom = results[entry.SplitFrom]; // Skip if the SplitFrom variable was used just to indicate this didn't pop out of thin air if (splitFrom.SplitOff == entry.Species) { foreach (var patchPopulation in splitFrom.SplitOffPatches) { OutputPopulationForPatch(entry.Species, patchPopulation, splitFrom.NewPopulationInPatches[patchPopulation]); } } } if (GetGlobalPopulation(entry.Species, resolveMigrations, resolveSplits) <= 0) { builder.Append(' '); builder.Append(new LocalizedString("WENT_EXTINCT_FROM_PLANET")); builder.Append('\n'); } if (playerReadable) { builder.Append('\n'); } } return(builder); }
/// <summary> /// Makes summary text /// </summary> /// <param name="previousPopulations">If provided comparisons to previous populations is included</param> /// <param name="playerReadable">if true ids are removed from the output</param> /// <param name="effects">if not null these effects are applied to the population numbers</param> public string MakeSummary(PatchMap previousPopulations = null, bool playerReadable = false, List <ExternalEffect> effects = null) { const bool resolveMoves = true; var builder = new StringBuilder(500); string PatchString(Patch patch) { var builder2 = new StringBuilder(80); if (!playerReadable) { builder2.Append(patch.ID); } builder2.Append(" "); builder2.Append(patch.Name); return(builder2.ToString()); } void OutputPopulationForPatch(Species species, Patch patch, long population) { if (population > 0) { builder.Append(" "); builder.Append(PatchString(patch)); builder.Append(" "); builder.Append(TranslationServer.Translate("POPULATION")); builder.Append(" "); builder.Append(population); } else { builder.Append(" "); builder.Append(" went extinct in "); builder.Append(PatchString(patch)); } if (previousPopulations != null) { builder.Append(" "); builder.Append(TranslationServer.Translate("PREVIOUS")); builder.Append(" "); builder.Append(previousPopulations.GetPatch(patch.ID).GetSpeciesPopulation(species)); } builder.Append("\n"); } foreach (var entry in results.Values) { builder.Append(playerReadable ? entry.Species.FormattedName : entry.Species.FormattedIdentifier); builder.Append(":\n"); if (entry.MutatedProperties != null) { builder.Append(" "); builder.Append(TranslationServer.Translate("RUNRESULT_HAS_A_MUTATION")); if (!playerReadable) { builder.Append(", "); builder.Append(TranslationServer.Translate("RUNRESULT_GENE_CODE")); builder.Append(" "); builder.Append(entry.MutatedProperties.StringCode); } builder.Append("\n"); } if (entry.SpreadToPatches.Count > 0) { builder.Append(" "); builder.Append(TranslationServer.Translate("RUNRESULT_SPREAD_TO_PATCHES")); builder.Append("\n"); foreach (var spreadEntry in entry.SpreadToPatches) { if (playerReadable) { builder.Append(" "); builder.Append(string.Format(CultureInfo.CurrentCulture, TranslationServer.Translate("RUNRESULT_BY_SENDING_POPULATION"), spreadEntry.To.Name, spreadEntry.Population, spreadEntry.From.Name)); } else { builder.Append(" "); builder.Append(spreadEntry.To.Name); builder.Append(" pop: "); builder.Append(spreadEntry.Population); builder.Append(" from: "); builder.Append(spreadEntry.From.Name); } builder.Append("\n"); } } builder.Append(" "); builder.Append(TranslationServer.Translate("RUNRESULT_POP_IN_PATCHES")); builder.Append("\n"); foreach (var patchPopulation in entry.NewPopulationInPatches) { long adjustedPopulation = patchPopulation.Value; if (resolveMoves) { adjustedPopulation += CountSpeciesSpreadPopulation(entry.Species, patchPopulation.Key); } // Apply external effects if (effects != null && previousPopulations != null && previousPopulations.CurrentPatch.ID == patchPopulation.Key.ID) { foreach (var effect in effects) { if (effect.Species == entry.Species) { adjustedPopulation += effect.Constant + (long)(effect.Species.Population * effect.Coefficient) - effect.Species.Population; } } } // As the populations are added to all patches, even when the species is not there, we remove those // from output if there is currently no population in a patch and there isn't one in // previousPopulations var include = false; if (adjustedPopulation > 0) { include = true; } else if (previousPopulations != null) { if (previousPopulations.GetPatch(patchPopulation.Key.ID).GetSpeciesPopulation(entry.Species) > 0) { include = true; } } if (include) { OutputPopulationForPatch(entry.Species, patchPopulation.Key, adjustedPopulation); } } // Also print new patches the species moved to (as the moves don't get // included in newPopulationInPatches if (resolveMoves) { foreach (var spreadEntry in entry.SpreadToPatches) { var found = false; var to = spreadEntry.To; foreach (var populationEntry in entry.NewPopulationInPatches) { if (populationEntry.Key == to) { found = true; break; } } if (!found) { OutputPopulationForPatch(entry.Species, to, CountSpeciesSpreadPopulation(entry.Species, to)); } } } if (GetGlobalPopulation(entry.Species, resolveMoves) <= 0) { builder.Append(" "); builder.Append("went extinct from the planet"); builder.Append("\n"); } if (playerReadable) { builder.Append("\n"); } } return(builder.ToString()); }
public int DumpPatches(string outputFormat) { var offset = 8; // skip to the tone map byte[] buffer; (buffer, offset) = Util.GetNextBytes(this.data, offset, PatchMap.Size); var patchMap = new PatchMap(buffer); List <int> patchNumbers = new List <int>(); var patchCount = 0; for (var i = 0; i < PatchMap.PatchCount; i++) { if (patchMap[i]) { patchCount += 1; //Console.Write(i + 1); //Console.Write(" "); patchNumbers.Add(i); } } var minimumPatchSize = SingleCommonSettings.DataSize + 2 * KSynthLib.K5000.Source.DataSize; var totalPatchSize = 0; // the total size of all the single patches var allPatchInfos = new List <PatchInfo>(); var singlePatches = new List <SinglePatch>(); foreach (var patchNumber in patchNumbers) { var startOffset = offset; // save the current offset because we need to copy more bytes later var sizeToRead = Math.Max(minimumPatchSize, this.data.Length - offset); // We don't know yet how many bytes the patch is, but it is at least the minimum size (buffer, offset) = Util.GetNextBytes(this.data, offset, sizeToRead); // the offset has now been updated past the read size, so need to adjust it back later //Console.Error.WriteLine(Util.HexDump(buffer)); //Console.Error.WriteLine($"checksum = {buffer[0]:X2}H"); var patch = new SinglePatch(buffer); // Find out how many PCM and ADD sources var pcmCount = 0; var addCount = 0; foreach (var source in patch.Sources) { if (source.IsAdditive) { addCount += 1; } else { pcmCount += 1; } } // Figure out the total size of the single patch based on the counts var patchSize = 1 + SingleCommonSettings.DataSize // includes the checksum + patch.Sources.Length * KSynthLib.K5000.Source.DataSize // all sources have this part + addCount * AdditiveKit.DataSize; //Console.WriteLine($"{pcmCount}PCM {addCount}ADD size={patchSize} bytes"); offset = startOffset; // back up to the start of the patch data // Read the whole patch now that we know its size //Console.WriteLine($"About to read {patchSize} bytes starting from offset {offset:X4}h"); (buffer, offset) = Util.GetNextBytes(this.data, offset, patchSize); totalPatchSize += patchSize; singlePatches.Add(patch); } foreach (var patch in singlePatches) { if (outputFormat.Equals("text")) { Console.WriteLine(patch); } else if (outputFormat.Equals("json")) { string jsonString = JsonConvert.SerializeObject( patch, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter() ); Console.WriteLine(jsonString); } } return(0); }
public static PatchMap Generate(WorldGenerationSettings settings, Species defaultSpecies) { // TODO: implement actual generation based on settings _ = settings; var map = new PatchMap(); // Predefined patches Patch patch0 = new Patch("Pangonian vents", 0, GetBiomeTemplate("aavolcanic_vent")); patch0.Depth[0] = 2500; patch0.Depth[1] = 3000; patch0.AddSpecies(defaultSpecies); patch0.ScreenCoordinates = new Vector2(100, 400); map.AddPatch(patch0); Patch patch1 = new Patch("Pangonian Mesopelagic", 1, GetBiomeTemplate("mesopelagic")); patch1.Depth[0] = 200; patch1.Depth[1] = 1000; patch1.ScreenCoordinates = new Vector2(200, 200); map.AddPatch(patch1); Patch patch2 = new Patch("Pangonian Epipelagic", 2, GetBiomeTemplate("default")); patch2.Depth[0] = 0; patch2.Depth[1] = 200; patch2.ScreenCoordinates = new Vector2(200, 100); map.AddPatch(patch2); Patch patch3 = new Patch("Pangonian Tidepool", 3, GetBiomeTemplate("tidepool")); patch3.Depth[0] = 0; patch3.Depth[1] = 10; patch3.ScreenCoordinates = new Vector2(300, 100); map.AddPatch(patch3); Patch patch4 = new Patch("Pangonian Bathypelagic", 4, GetBiomeTemplate("bathypelagic")); patch4.Depth[0] = 1000; patch4.Depth[1] = 4000; patch4.ScreenCoordinates = new Vector2(200, 300); map.AddPatch(patch4); Patch patch5 = new Patch("Pangonian Abyssopelagic", 5, GetBiomeTemplate("abyssopelagic")); patch5.Depth[0] = 4000; patch5.Depth[1] = 6000; patch5.ScreenCoordinates = new Vector2(300, 400); map.AddPatch(patch5); Patch patch6 = new Patch("Pangonian Coast", 6, GetBiomeTemplate("coastal")); patch6.Depth[0] = 0; patch6.Depth[1] = 200; patch6.ScreenCoordinates = new Vector2(100, 100); map.AddPatch(patch6); Patch patch7 = new Patch("Pangonian Estuary", 7, GetBiomeTemplate("estuary")); patch7.Depth[0] = 0; patch7.Depth[1] = 200; patch7.ScreenCoordinates = new Vector2(70, 160); map.AddPatch(patch7); Patch patch8 = new Patch("Cave", 8, GetBiomeTemplate("underwater_cave")); patch8.Depth[0] = 200; patch8.Depth[1] = 1000; patch8.ScreenCoordinates = new Vector2(300, 200); map.AddPatch(patch8); Patch patch9 = new Patch("Ice Shelf", 9, GetBiomeTemplate("ice_shelf")); patch9.Depth[0] = 0; patch9.Depth[1] = 200; patch9.ScreenCoordinates = new Vector2(200, 30); map.AddPatch(patch9); Patch patch10 = new Patch("Pangonian Sea Floor", 10, GetBiomeTemplate("seafloor")); patch10.Depth[0] = 4000; patch10.Depth[1] = 6000; patch10.ScreenCoordinates = new Vector2(200, 400); map.AddPatch(patch10); // Connections patch0.AddNeighbour(patch10); patch1.AddNeighbour(patch4); patch1.AddNeighbour(patch2); patch1.AddNeighbour(patch8); patch2.AddNeighbour(patch1); patch2.AddNeighbour(patch3); patch2.AddNeighbour(patch6); patch2.AddNeighbour(patch9); patch3.AddNeighbour(patch2); patch4.AddNeighbour(patch5); patch4.AddNeighbour(patch1); patch4.AddNeighbour(patch10); patch5.AddNeighbour(patch10); patch5.AddNeighbour(patch4); patch6.AddNeighbour(patch2); patch6.AddNeighbour(patch7); patch7.AddNeighbour(patch6); patch8.AddNeighbour(patch1); patch9.AddNeighbour(patch2); patch10.AddNeighbour(patch4); patch10.AddNeighbour(patch5); patch10.AddNeighbour(patch0); map.CurrentPatch = patch0; return(map); }
public FindBestMigration(PatchMap map, Species species, int migrationsToTry, bool allowNoMigration) : base(migrationsToTry, allowNoMigration) { this.map = map; this.species = species; }
/// <summary> /// Makes summary text /// </summary> /// <param name="previousPopulations">If provided comparisons to previous populations is included</param> /// <param name="playerReadable">if true ids are removed from the output</param> /// <param name="effects">if not null these effects are applied to the population numbers</param> public string MakeSummary(PatchMap previousPopulations = null, bool playerReadable = false, List <ExternalEffect> effects = null) { const bool resolveMoves = true; var builder = new StringBuilder(500); string PatchString(Patch patch) { var builder2 = new StringBuilder(80); if (!playerReadable) { builder2.Append(patch.ID); } builder2.Append(" "); builder2.Append(patch.Name); return(builder2.ToString()); } void OutputPopulationForPatch(Species species, Patch patch, int population) { builder.Append(" "); builder.Append(PatchString(patch)); builder.Append(" population: "); builder.Append(Math.Max(population, 0)); if (previousPopulations != null) { builder.Append(" previous: "); builder.Append(previousPopulations.GetPatch(patch.ID).GetSpeciesPopulation(species)); } builder.Append("\n"); } foreach (var entry in results.Values) { builder.Append(playerReadable ? entry.Species.FormattedName : entry.Species.FormattedIdentifier); builder.Append(":\n"); if (entry.MutatedProperties != null) { builder.Append(" has a mutation"); if (!playerReadable) { builder.Append(", gene code: "); builder.Append(entry.MutatedProperties.StringCode); } builder.Append("\n"); } if (entry.SpreadToPatches.Count > 0) { builder.Append(" spread to patches:\n"); foreach (var spreadEntry in entry.SpreadToPatches) { if (playerReadable) { builder.Append(" "); builder.Append(spreadEntry.To.Name); builder.Append(" by sending: "); builder.Append(spreadEntry.Population); builder.Append(" population"); builder.Append(" from patch: "); builder.Append(spreadEntry.From.Name); } else { builder.Append(" "); builder.Append(spreadEntry.To.Name); builder.Append(" pop: "); builder.Append(spreadEntry.Population); builder.Append(" from: "); builder.Append(spreadEntry.From.Name); } builder.Append("\n"); } } builder.Append(" population in patches:\n"); foreach (var patchPopulation in entry.NewPopulationInPatches) { var adjustedPopulation = patchPopulation.Value; if (resolveMoves) { adjustedPopulation += CountSpeciesSpreadPopulation(entry.Species, patchPopulation.Key); } // Apply external effects if (effects != null && previousPopulations != null && previousPopulations.CurrentPatch.ID == patchPopulation.Key.ID) { foreach (var effect in effects) { if (effect.Species == entry.Species) { adjustedPopulation += effect.Amount; } } } // As the populations are added to all patches, even when the species is not there, we remove those // from output if there is currently no population in a patch and there isn't one in // previousPopulations bool include = false; if (adjustedPopulation > 0) { include = true; } else if (previousPopulations != null) { if (previousPopulations.GetPatch(patchPopulation.Key.ID).GetSpeciesPopulation(entry.Species) > 0) { include = true; } } if (include) { OutputPopulationForPatch(entry.Species, patchPopulation.Key, adjustedPopulation); } } // Also print new patches the species moved to (as the moves don't get // included in newPopulationInPatches if (resolveMoves) { foreach (var spreadEntry in entry.SpreadToPatches) { bool found = false; var to = spreadEntry.To; foreach (var populationEntry in entry.NewPopulationInPatches) { if (populationEntry.Key == to) { found = true; break; } } if (!found) { OutputPopulationForPatch(entry.Species, to, CountSpeciesSpreadPopulation(entry.Species, to)); } } } if (playerReadable) { builder.Append("\n"); } } return(builder.ToString()); }
private static void ProcessMessage(byte[] message) { Console.WriteLine($"Message length = {message.Length} bytes"); var header = new SystemExclusiveHeader(message); //Console.WriteLine("{0}", header); var functionNames = new Dictionary <SystemExclusiveFunction, string>() { { SystemExclusiveFunction.OneBlockDumpRequest, "One Block Dump Request" }, { SystemExclusiveFunction.AllBlockDumpRequest, "All Block Dump Request" }, { SystemExclusiveFunction.ParameterSend, "Parameter Send" }, { SystemExclusiveFunction.TrackControl, "Track Control" }, { SystemExclusiveFunction.OneBlockDump, "One Block Dump" }, { SystemExclusiveFunction.AllBlockDump, "All Block Dump" }, { SystemExclusiveFunction.ModeChange, "Mode Change" }, { SystemExclusiveFunction.Remote, "Remote" }, { SystemExclusiveFunction.WriteComplete, "Write Complete" }, { SystemExclusiveFunction.WriteError, "Write Error" }, { SystemExclusiveFunction.WriteErrorByProtect, "Write Error (Protect)" }, { SystemExclusiveFunction.WriteErrorByMemoryFull, "Write Error (Memory Full)" }, { SystemExclusiveFunction.WriteErrorByNoExpandMemory, "Write Error (No Expansion Memory)" } }; var function = (SystemExclusiveFunction)header.Function; string functionName; if (functionNames.TryGetValue(function, out functionName)) { Console.Error.WriteLine("Function = {0}", functionName); } else { Console.Error.WriteLine("Unknown function: {0}", function); } switch (header.Substatus1) { case 0x00: Console.WriteLine("Single"); break; case 0x20: Console.WriteLine("Multi"); break; case 0x10: Console.WriteLine("Drum Kit"); // K5000W only break; case 0x11: Console.WriteLine("Drum Inst"); // K5000W only break; default: Console.Error.WriteLine(string.Format("Unknown substatus1: {0:X2}", header.Substatus1)); break; } switch (header.Substatus2) { case 0x00: Console.WriteLine("Add Bank A"); break; case 0x01: Console.WriteLine("PCM Bank B"); // K5000W break; case 0x02: Console.WriteLine("Add Bank D"); break; case 0x03: Console.WriteLine("Exp Bank E"); break; case 0x04: Console.WriteLine("Exp Bank F"); break; default: Console.WriteLine("Substatus2 is first data byte"); break; } switch (function) { case SystemExclusiveFunction.OneBlockDump: Console.WriteLine("One Block Dump"); int toneNumber = message[8] + 1; Console.WriteLine($"Tone No = {toneNumber} ({message[8]})"); break; case SystemExclusiveFunction.AllBlockDump: Console.WriteLine("All Block Dump"); break; default: Console.WriteLine($"Unknown function: {function}"); break; } if (function == SystemExclusiveFunction.AllBlockDump) { var patchMapData = new byte[PatchMap.Size]; Array.Copy(message, SystemExclusiveHeader.DataSize, patchMapData, 0, PatchMap.Size); var patchMap = new PatchMap(patchMapData); Console.WriteLine("Patches included:"); for (var i = 0; i < PatchMap.PatchCount; i++) { if (patchMap[i]) { Console.Write(i + 1); Console.Write(" "); } } Console.WriteLine(); var dataLength = message.Length - SystemExclusiveHeader.DataSize - PatchMap.Size; var data = new byte[dataLength]; Array.Copy(message, SystemExclusiveHeader.DataSize + PatchMap.Size, data, 0, dataLength); //Console.WriteLine(Util.HexDump(data)); var offset = 0; byte checksum = data[offset]; Console.WriteLine($"checksum = {checksum:X2}"); offset += 1; } // Single additive patch for bank A or D: if (header.Substatus1 == 0x00 && (header.Substatus2 == 0x00 || header.Substatus2 == 0x02)) { var dataLength = message.Length - SystemExclusiveHeader.DataSize - PatchMap.Size; var data = new byte[dataLength]; Array.Copy(message, SystemExclusiveHeader.DataSize + PatchMap.Size, data, 0, dataLength); //Console.WriteLine(Util.HexDump(data)); // Chop the data into individual buffers based on the declared sizes var offset = 0; byte checksum = data[offset]; Console.WriteLine($"checksum = {checksum:X2}"); offset += 1; var commonData = new byte[SingleCommonSettings.DataSize]; Array.Copy(data, offset, commonData, 0, SingleCommonSettings.DataSize); //Console.WriteLine(Util.HexDump(commonData)); offset += SingleCommonSettings.DataSize; var patch = new SinglePatch(data); Console.WriteLine($"Name = {patch.SingleCommon.Name}"); } }
public SimulationConfiguration(PatchMap initialConditions, int steps = 1) { OriginalMap = initialConditions; StepsLeft = Math.Max(1, steps); }
public static PatchMap Generate(WorldGenerationSettings settings, Species defaultSpecies) { // TODO: implement actual generation based on settings _ = settings; var map = new PatchMap(); // Predefined patches var vents = new Patch("PATCH_PANGONIAN_VENTS", 0, GetBiomeTemplate("aavolcanic_vent")) { Depth = { [0] = 2500, [1] = 3000, }, ScreenCoordinates = new Vector2(100, 400), }; vents.AddSpecies(defaultSpecies); map.AddPatch(vents); var mesopelagic = new Patch("PATCH_PANGONIAN_MESOPELAGIC", 1, GetBiomeTemplate("mesopelagic")) { Depth = { [0] = 200, [1] = 1000, }, ScreenCoordinates = new Vector2(200, 200), }; map.AddPatch(mesopelagic); var epipelagic = new Patch("PATCH_PANGONIAN_EPIPELAGIC", 2, GetBiomeTemplate("default")) { Depth = { [0] = 0, [1] = 200, }, ScreenCoordinates = new Vector2(200, 100), }; map.AddPatch(epipelagic); var tidepool = new Patch("PATCH_PANGONIAN_TIDEPOOL", 3, GetBiomeTemplate("tidepool")) { Depth = { [0] = 0, [1] = 10, }, ScreenCoordinates = new Vector2(300, 100), }; map.AddPatch(tidepool); var bathypelagic = new Patch("PATCH_PANGONIAN_BATHYPELAGIC", 4, GetBiomeTemplate("bathypelagic")) { Depth = { [0] = 1000, [1] = 4000, }, ScreenCoordinates = new Vector2(200, 300), }; map.AddPatch(bathypelagic); var abyssopelagic = new Patch("PATHCH_PANGONIAN_ABYSSOPELAGIC", 5, GetBiomeTemplate("abyssopelagic")) { Depth = { [0] = 4000, [1] = 6000, }, ScreenCoordinates = new Vector2(300, 400), }; map.AddPatch(abyssopelagic); var coast = new Patch("PATCH_PANGONIAN_COAST", 6, GetBiomeTemplate("coastal")) { Depth = { [0] = 0, [1] = 200, }, ScreenCoordinates = new Vector2(100, 100), }; map.AddPatch(coast); var estuary = new Patch("PATCH_PANGONIAN_ESTUARY", 7, GetBiomeTemplate("estuary")) { Depth = { [0] = 0, [1] = 200, }, ScreenCoordinates = new Vector2(70, 160), }; map.AddPatch(estuary); var cave = new Patch("PATCH_CAVE", 8, GetBiomeTemplate("underwater_cave")) { Depth = { [0] = 200, [1] = 1000, }, ScreenCoordinates = new Vector2(300, 200), }; map.AddPatch(cave); var iceShelf = new Patch("PATCH_ICE_SHELF", 9, GetBiomeTemplate("ice_shelf")) { Depth = { [0] = 0, [1] = 200, }, ScreenCoordinates = new Vector2(200, 30), }; map.AddPatch(iceShelf); var seafloor = new Patch("PATCH_PANGONIAN_SEAFLOOR", 10, GetBiomeTemplate("seafloor")) { Depth = { [0] = 4000, [1] = 6000, }, ScreenCoordinates = new Vector2(200, 400), }; map.AddPatch(seafloor); // Connections LinkPatches(vents, seafloor); LinkPatches(seafloor, bathypelagic); LinkPatches(seafloor, abyssopelagic); LinkPatches(bathypelagic, abyssopelagic); LinkPatches(bathypelagic, mesopelagic); LinkPatches(mesopelagic, epipelagic); LinkPatches(mesopelagic, cave); LinkPatches(epipelagic, tidepool); LinkPatches(epipelagic, iceShelf); LinkPatches(epipelagic, coast); LinkPatches(coast, estuary); map.CurrentPatch = vents; return(map); }
public CalculatePopulation(PatchMap map) { this.map = map; }
public void SaveZone(bool backup) { if (BUSY && !backup) { if ( MessageBox.Show("Zone Edit is busy - save as backup?", "Warning!", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes) { return; } backup = true; } BUSY = true; string path = (backup ? PATH + "_backup" : PATH); if (!backup) { //if (Directory.Exists(PATH + "_backup")) { // Directory.Delete(PATH + "_backup", true); //} Loading.Update("Initiating save process.."); Loading.ShowLoading(true); } else { if (Directory.Exists(PATH + "_backup")) { if (Directory.Exists(PATH + "_backup_bak")) { Directory.Delete(PATH + "_backup_bak", true); } Directory.Move(PATH + "_backup", PATH + "_backup_bak"); } } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } #region datXXX.mpk int bwillow = 0; { string p = string.Format("dat{0}.mpk", ZoneID.ToString("D3")); string pp = path + "\\" + p; Loading.Update("Saving " + p + "..."); if (!Directory.Exists(pp)) { Directory.CreateDirectory(pp); } #region SECTOR.DAT { Loading.Update("Saving " + p + "... - sector.dat"); var s = new INIStreamer(string.Format("{0}\\SECTOR.DAT" + (backup ? ".bak" : ""), pp)); s.ReadIni(); s.Header.Clear(); s.SetItem("terrain", "scalefactor", TerrainScaleFactor.ToString()); s.SetItem("terrain", "offsetfactor", TerrainOffsetFactor.ToString()); //Rivers int rivers = 0; foreach (Polygon pl in Polygon.Polygons) { if (pl.Type != ePolygon.Water) { continue; } //Save this river string pre = string.Format("river{0:D2}", rivers); if (s.GetTopic(pre) != null) { s.RemTopic(pre); } s.SetItem(pre, "texture", pl.WTexture); s.SetItem(pre, "multitexture", pl.WMultiTexture); s.SetItem(pre, "flow", pl.WFlow.ToString()); s.SetItem(pre, "height", pl.WHeight.ToString()); s.SetItem(pre, "Tesselation", pl.WTesselation.ToString()); s.SetItem(pre, "type", pl.WType.ToString().ToUpper()); s.SetItem(pre, "bankpoints", (pl.Points.Count / 2).ToString()); s.SetItem(pre, "name", pre); for (int a = 0; a < pl.Points.Count; a += 2) { var x1 = (int)(pl.Points[a].X / 256); var y1 = (int)(pl.Points[a].Y / 256); var x2 = (int)(pl.Points[a + 1].X / 256); var y2 = (int)(pl.Points[a + 1].Y / 256); lock (pl.Points) { pl.Points[a] = new Vector2(x1 * 256, y1 * 256); pl.Points[a + 1] = new Vector2(x2 * 256, y2 * 256); } s.SetItem(pre, string.Format("left{0:D2}", a / 2), string.Format("{0},{1},0", x1, y1)); s.SetItem(pre, string.Format("right{0:D2}", a / 2), string.Format("{0},{1},0", x2, y2)); } rivers++; } s.SetItem("waterdefs", "num", rivers.ToString()); s.WriteIni(); } #endregion #region terrain.pcx/offset.pcx { Loading.Update("Saving " + p + "... - Heightmaps"); var terrain = new byte[256, 256]; var offset = new byte[256, 256]; for (int x = 0; x <= 255; x++) { for (int y = 0; y <= 255; y++) { int o = HeightMap[x, y] / TerrainOffsetFactor; if (o > 255) { o = 255; } int remaining = HeightMap[x, y] - o * TerrainOffsetFactor; int t = remaining / TerrainScaleFactor; if (t > 255) { t = 255; //some information may get lost } offset[x, y] = (byte)(o); terrain[x, y] = (byte)(t); } } PCXImage.Save(string.Format("{0}\\terrain.pcx", pp), terrain); PCXImage.Save(string.Format("{0}\\offset.pcx", pp), offset); } #endregion #region bound.csv { Loading.Update("Saving " + p + "... - Bounds"); var rs = new StreamWriter(string.Format("{0}\\bound.csv", pp)); foreach (Polygon pl in Polygon.Polygons) { if (pl.Type != ePolygon.Bounding) { continue; } //?, count, x,y, x2,y2, x3, y3, .. string vectors = ""; foreach (Vector2 v in pl.Points) { vectors += string.Format(",{0},{1}", (int)v.X, (int)v.Y); } rs.WriteLine("{0},{1}{2}", 0, pl.Points.Count, vectors); } rs.Flush(); rs.Close(); } #endregion #region water.pcx { Loading.Update("Saving " + p + "... - Water"); var data = new byte[256, 256]; for (int x = 0; x < 256; x++) { for (int y = 0; y < 256; y++) { int height = (HeightMap[x, y]); bool isUnderwater = false; int n = -1; foreach (Polygon pl in Polygon.Polygons) { if (pl.Type != ePolygon.Water) { continue; } if (!isUnderwater) { n++; } if (pl.WHeight < height) { continue; } //Check if point is inside var pnt = new Vector2(x, y); for (int idx = 0; idx < pl.Points.Count - 2; idx += 2) { Vector2 l1 = pl.Points[idx]; Vector2 r1 = pl.Points[idx + 1]; Vector2 l2 = pl.Points[idx + 2]; Vector2 r2 = pl.Points[idx + 3]; var _l1 = new Vector3(l1.X, l1.Y, 0); var _r1 = new Vector3(r1.X, r1.Y, 0); var _l2 = new Vector3(l2.X, l2.Y, 0); var _r2 = new Vector3(r2.X, r2.Y, 0); var rayStart = new Vector3(pnt.X * 256, pnt.Y * 256, 1.0f); var rayDir = new Vector3(0, 0, -1); IntersectInformation i; if (Geometry.IntersectTri(_l1, _r1, _l2, rayStart, rayDir, out i) || Geometry.IntersectTri(_r1, _r2, _l2, rayStart, rayDir, out i)) { isUnderwater = true; break; } } } data[x, y] = (byte)(isUnderwater ? n : 255); } } for (int i = 0; i < 2; i++) { WaterDilatation(data); } PCXImage.Save(string.Format("{0}\\water.pcx", pp), data); } #endregion #region nifs.csv { Loading.Update("Saving " + p + "... - NIFs"); var rs = new StreamWriter(string.Format("{0}\\nifs.csv", pp)); rs.WriteLine("Grid Nifs,,,Ambient,Merlin Data"); rs.WriteLine( "NIF,Textual Name,Filename,Only,Shadow,Color,Animate,Collide,Ground,MinAngle,MaxAngle,MinScale,MaxScale,Radius,LOD 1,LOD 2,LOD 3,LOD 4,Ref Height,Ref Width,Unique,Local,Terrain"); int id = 1; var clones = new List <Objects.NIF>(); foreach (Objects.NIF n in Objects.NIFs.Values) { clones.Add(n); } Objects.NIFs.Clear(); foreach (Objects.NIF n in clones) { n.ID = id; Objects.NIFs.Add(n.ID, n); rs.Write(id); rs.Write("," + n.FileName + "|" + n.Group); //name rs.Write("," + n.FileName); //filename rs.Write("," + 0); //ambient only rs.Write("," + 0); //merlin shadow data rs.Write("," + 0); //color rs.Write("," + (n.IsDoor ? 1 : 0)); //animate rs.Write("," + n.Collision); //collide rs.Write("," + 1); //on ground rs.Write("," + 0); //min angle rs.Write("," + 0); //max angle rs.Write("," + n.MinScale); //min scale rs.Write("," + n.MaxScale); //max scale rs.Write("," + n.CollideRadius); //radius rs.Write("," + 0); //lod1 rs.Write("," + 0); //lod2 rs.Write("," + 0); //lod3 rs.Write("," + 0); //lod4 rs.Write("," + 16); //ref height rs.Write("," + 16); //ref width rs.Write("," + 0); //unique rs.Write("," + 0); //local rs.Write("," + 0); //terrain rs.WriteLine(); id++; } rs.Flush(); rs.Close(); } #endregion #region fixtures.csv { Loading.Update("Saving " + p + "... - Fixtures"); var rs = new StreamWriter(string.Format("{0}\\fixtures.csv", pp)); rs.WriteLine("Fixtures,,,,,,,,NIF,Collide,,On,,,,,,,"); rs.WriteLine( "ID,NIF #,Textual Name,X,Y,Z,A,Scale,Collide,Radius,Animate,Ground,Flip,Cave,Unique ID, 3D Angle, 3D Axis X, 3D Axis Y, 3D Axis Z"); var freeIDs = new List <int>(); int id = 1; foreach (Objects.Fixture f in Objects.Fixtures) { if (f.NIF.FileName.ToLower().Contains("bwillow")) { bwillow++; } if (f.NIF.IsDoor) //lock ID { for (int i = id; i < f.ID; i++) { freeIDs.Add(i); } id = f.ID + 1; } else { if (freeIDs.Count > 0) { f.ID = freeIDs[0]; freeIDs.RemoveAt(0); } else { f.ID = id++; } } rs.Write(f.ID); rs.Write("," + f.NIF_ID); rs.Write("," + f.Name); rs.Write("," + f.X.ToString().Replace(',', '.')); rs.Write("," + f.Y.ToString().Replace(',', '.')); rs.Write("," + f.Z.ToString().Replace(',', '.')); rs.Write("," + 0); //A (angle?) rs.Write("," + f.Scale); rs.Write("," + f.NIF.Collision); //collide rs.Write("," + f.NIF.CollideRadius); //radius rs.Write("," + 0); //animate rs.Write("," + (f.OnGround ? 1 : 0)); //ground rs.Write("," + 0); //flip rs.Write("," + 0); //cave rs.Write("," + f.ID); //uid rs.Write("," + f.Rotation.ToString().Replace(',', '.')); //3d angle rs.Write("," + f.AxisX.ToString().Replace(',', '.')); //); //3d x rs.Write("," + f.AxisY.ToString().Replace(',', '.')); //3d y rs.Write("," + f.AxisZ.ToString().Replace(',', '.')); //3d z rs.WriteLine(); } rs.Flush(); rs.Close(); } #endregion #region zonejump.csv { Loading.Update("Saving " + p + "... - Zonejumps"); var rs = new StreamWriter(string.Format("{0}\\zonejump.csv", pp)); int index = 1; foreach (Zonejump j in Zonejump.Zonejumps) { //ID, Name, X, Y, X2, Y2, Z1, Z2, JID rs.Write(index++); rs.Write("," + j.Name); rs.Write("," + (int)j.First.X); rs.Write("," + (int)j.First.Y); rs.Write("," + (int)j.Second.X); rs.Write("," + (int)j.Second.Y); rs.Write("," + (int)j.First.Z); rs.Write("," + (int)j.Second.Z); rs.Write("," + j.ID); rs.WriteLine(); } rs.Flush(); rs.Close(); } #endregion #region lights.csv { Loading.Update("Saving " + p + "... - Lights"); var rs = new StreamWriter(string.Format("{0}\\lights.csv", pp)); foreach (Light l in Light.Lights) { //46473, 54362, 2910, 3 //X, Y, Z, Intensity rs.Write(l.X); rs.Write(", " + l.Y); rs.Write(", " + (l.Z + l.ZOffset)); rs.Write(", " + ((int)l.Color + ((l.Intensity - 1) * 10))); rs.WriteLine(); } rs.Flush(); rs.Close(); } #endregion } #endregion #region terXXX.mpk { string p = string.Format("ter{0}.mpk", ZoneID.ToString("D3")); string pp = path + "\\" + p; Loading.Update("Saving Textures.."); if (!Directory.Exists(pp)) { Directory.CreateDirectory(pp); } PatchMap.Save(pp + "\\", backup); } #endregion Loading.Update("Saving Sounds..."); SoundMgr.Save(path); if (!backup) { if (bwillow >= 2000) { MessageBox.Show("For every bwillow you will now have to close one Messagebox..!"); Loading.Update("Annoying you..."); for (int i = bwillow; i <= bwillow; i++) { MessageBox.Show("bwillow " + bwillow); } } } if (!backup) { LAST_SAVE = DateTime.UtcNow.Ticks; } GC.Collect(); Loading.Update("Done."); Loading.CloseLoading(); BUSY = false; }
public int ListPatches() { // SysEx header at this point should be "F0 40 00 21 00 0A 00 00" followed by the tone map var offset = 8; // skip to the tone map //Console.Error.WriteLine($"offset = {offset}"); // For a block data dump, need to parse the tone map byte[] buffer; (buffer, offset) = Util.GetNextBytes(this.data, offset, PatchMap.Size); // now the offset has been updated to past the tone map //Console.Error.WriteLine($"offset = {offset}"); var patchMap = new PatchMap(buffer); List <int> patchNumbers = new List <int>(); //Console.WriteLine("Patches included:"); var patchCount = 0; for (var i = 0; i < PatchMap.PatchCount; i++) { if (patchMap[i]) { patchCount += 1; //Console.Write(i + 1); //Console.Write(" "); patchNumbers.Add(i); } } //Console.WriteLine($"\nTotal = {patchCount} patches"); // Whatever the first patch is, it must be at least this many bytes (always has at least two sources) var minimumPatchSize = SingleCommonSettings.DataSize + 2 * KSynthLib.K5000.Source.DataSize; //Console.Error.WriteLine($"minimum patch size = {minimumPatchSize}"); var totalPatchSize = 0; // the total size of all the single patches var allPatchInfos = new List <PatchInfo>(); var singlePatches = new List <SinglePatch>(); foreach (var patchNumber in patchNumbers) { var startOffset = offset; // save the current offset because we need to copy more bytes later var sizeToRead = Math.Max(minimumPatchSize, this.data.Length - offset); //Console.WriteLine($"About to read {sizeToRead} bytes starting from offset {offset:X4}h"); // We don't know yet how many bytes the patch is, but it is at least the minimum size (buffer, offset) = Util.GetNextBytes(this.data, offset, sizeToRead); // the offset has now been updated past the read size, so need to adjust it back later //Console.Error.WriteLine(Util.HexDump(buffer)); //Console.Error.WriteLine($"checksum = {buffer[0]:X2}H"); var patch = new SinglePatch(buffer); // Find out how many PCM and ADD sources var pcmCount = 0; var addCount = 0; foreach (var source in patch.Sources) { if (source.IsAdditive) { addCount += 1; } else { pcmCount += 1; } } // Figure out the total size of the single patch based on the counts var patchSize = 1 + SingleCommonSettings.DataSize // includes the checksum + patch.Sources.Length * KSynthLib.K5000.Source.DataSize // all sources have this part + addCount * AdditiveKit.DataSize; //Console.WriteLine($"{pcmCount}PCM {addCount}ADD size={patchSize} bytes"); offset = startOffset; // back up to the start of the patch data // Read the whole patch now that we know its size //Console.WriteLine($"About to read {patchSize} bytes starting from offset {offset:X4}h"); (buffer, offset) = Util.GetNextBytes(this.data, offset, patchSize); totalPatchSize += patchSize; singlePatches.Add(patch); var patchInfo = new PatchInfo { Bank = this.Header.Bank, PatchNumber = patchNumber + 1, PatchName = patch.SingleCommon.Name, PCMSourceCount = pcmCount, AdditiveSourceCount = addCount, }; Console.WriteLine($"{patchInfo.Bank}{patchInfo.PatchNumber:D3} | {patchInfo.PatchName,8} | {patchInfo.PCMSourceCount}PCM {patchInfo.AdditiveSourceCount}ADD"); allPatchInfos.Add(patchInfo); } foreach (var patchInfo in allPatchInfos) { Console.WriteLine($"{patchInfo.Bank}{patchInfo.PatchNumber:D3} | {patchInfo.PatchName,8} | {patchInfo.PCMSourceCount}PCM {patchInfo.AdditiveSourceCount}ADD"); } return(0); }