/// <summary> /// Returns true if the given prop matches the options selected /// on the form. /// </summary> /// <param name="prop">The prop to check.</param> /// <param name="notFoundInDb"> /// Default value for props that couldn't be found in the loaded /// data while filters are applied. /// </param> /// <returns></returns> public bool Matches(Prop prop, bool notFoundInDb) { if (this.ChkAllProps.Checked) { return(true); } if (!PropDb.TryGetEntry(prop.Id, out var data)) { return(notFoundInDb); } if (this.ChkMatchID.Checked) { if (data.ClassID.ToString() != this.TxtMatchID.Text.Trim()) { return(false); } } if (this.ChkMatchClassName.Checked) { if (data.ClassName != this.TxtMatchClassName.Text.Trim()) { return(false); } } if (this.ChkNotMatchClassName.Checked) { if (string.Compare(data.ClassName, this.TxtNotMatchClassName.Text.Trim(), true) == 0) { return(false); } } if (this.ChkMatchTag.Checked) { if (!data.StringID.Matches(this.TxtMatchTag.Text)) { return(false); } } if (this.ChkNotMatchTag.Checked) { if (data.StringID.Matches(this.TxtNotMatchTag.Text)) { return(false); } } if (this.ChkTerrain.Checked) { if (this.ChkTerrainYes.Checked) { if (!data.IsTerrainBlock) { return(false); } } else if (data.IsTerrainBlock) { return(false); } } return(true); }
/// <summary> /// Reads given folders and generates regioninfo.dat. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private async void BtnCreate_Click(object sender, EventArgs e) { this.UpdateProgressBar(-1); this.BtnCreate.Enabled = false; this.TxtSources.Enabled = false; this.LblStatus.Text = "Reading files..."; var regions = new Dictionary <int, MabiWorld.Region>(); // Run in task to not block UI await Task.Run(() => { // Read regions from folders foreach (var line in this.TxtSources.Lines) { var trimmedLine = line.Trim(); if (trimmedLine == "" || trimmedLine.StartsWith("//")) { continue; } if (!Directory.Exists(line)) { this.Invoke((MethodInvoker) delegate { MessageBox.Show(this, $"Directory '{line}' not found.", "", MessageBoxButtons.OK, MessageBoxIcon.Error); }); continue; } if (Directory.EnumerateFiles(line, "*.pack", SearchOption.TopDirectoryOnly).Any()) { this.GetRegionsFromPacks(line, ref regions); } else { this.GetRegionsFromFolder(line, ref regions); } } // Remove props from areas that are only enabled during // certain events or when features are enabled that are // currently not. // TODO: Include all props and let the server handle this. foreach (var area in regions.Values.SelectMany(a => a.Areas)) { area.Props.RemoveAll(prop => { if (!PropDb.TryGetEntry(prop.Id, out var data)) { return(false); } if (data.StringID.Value.Contains("/event/") && data.UsedServer) { return(true); } // Some invisible prop at Dunbarton's Unicorn statue if (data.StringID.Value.Contains("/weekly_concert/")) { return(true); } // Invisible Emain cooking contest props if (data.StringID.Value.Contains("/contest/")) { return(true); } // Invisible Emain concert hall barricade if (data.ClassName == "scene_emain_concert_hall_barricade01") { return(true); } // Invisible Gairech Halloween event prop if (data.ClassName == "field_gairech_halloween2018_portal_place01") { // Controlled by the locale ExtraXML property, // where "usa" is not negated while the event is // active <_> WHY DO YOU HATE SERVER SIDED PROPS // DEVCAT!? >__> // ExtraXML="<xml locale="!korea|usa|japan|!taiwan|!china"/>" if (data.ExtraXML.Contains("!usa")) { return(true); } } if (!string.IsNullOrWhiteSpace(data.Feature) && !Features.IsEnabled(data.Feature)) { return(true); } return(false); }); } }); // Update UI and move region info this.Invoke((MethodInvoker) delegate { this.UpdateProgressBar(0); this.UpdateStatus($"Found {regions.Count} regions."); this.BtnCreate.Enabled = true; this.TxtSources.Enabled = true; if (regions.Count == 0) { MessageBox.Show(this, "No regions found.", "", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } var result = this.SfdRegionInfo.ShowDialog(); if (result == DialogResult.OK) { this.BtnCreate.Select(); var filePath = this.SfdRegionInfo.FileName; var folderPath = Path.GetDirectoryName(filePath); Settings.Default.SaveFolder = folderPath; this.Export(filePath, regions); this.UpdateStatus($"Saved region info at '{filePath}'."); } else { this.UpdateStatus($"Saving cancelled."); } }); }
/// <summary> /// Reads world.trn in packs and all regions that are listed within. /// </summary> /// <param name="path"></param> /// <param name="regions"></param> private void GetRegionsFromPacks(string path, ref Dictionary <int, MabiWorld.Region> regions) { using (var pack = new PackReader(path)) { var worldEntry = pack.GetEntry(@"world\world.trn"); if (worldEntry == null) { this.Invoke((MethodInvoker) delegate { MessageBox.Show(this, $"File 'world.trn' not found in pack folder '{path}'.", "", MessageBoxButtons.OK, MessageBoxIcon.Error); }); return; } var propEntry = pack.GetEntry(@"db\propdb.xml"); if (propEntry != null) { PropDb.Clear(); PropDb.Load(propEntry.GetDataAsStream()); } var featureEntry = pack.GetEntry(@"features.xml.compiled"); if (featureEntry != null) { Features.Clear(); Features.Load(featureEntry.GetDataAsStream()); Features.SelectSetting("USA", false, false); } using (var ms = worldEntry.GetDataAsStream()) using (var trnReader = new XmlTextReader(ms)) { if (!trnReader.ReadToDescendant("regions")) { throw new FormatException("Tag 'regions' not found in world.trn."); } using (var trnRegionsReader = trnReader.ReadSubtree()) { while (trnRegionsReader.ReadToFollowing("region")) { var workDir = trnRegionsReader.GetAttribute("workdir"); var fileName = trnReader.GetAttribute("name"); var regionFilePath = Path.Combine("world", workDir, fileName + ".rgn"); var regionEntry = pack.GetEntry(regionFilePath); if (regionEntry == null) { continue; } using (var regionStream = regionEntry.GetDataAsStream()) { this.UpdateStatus($"Reading {fileName}..."); var region = MabiWorld.Region.ReadFrom(regionStream); regions[region.Id] = region; for (var i = 0; i < region.AreaFileNames.Count; ++i) { var areaFileName = region.AreaFileNames[i]; var areaFilePath = Path.Combine("world", workDir, areaFileName + ".area"); using (var areaStream = pack.GetEntry(areaFilePath).GetDataAsStream()) { var area = Area.ReadFrom(areaStream); area.AreaPlanes.Clear(); region.Areas.Add(area); } } } } } } } }