public void SetYmapHasChanged(YmapFile ymap, bool changed) { if (ProjectTreeView.Nodes.Count > 0) { var pnode = ProjectTreeView.Nodes[0]; var ymnode = GetChildTreeNode(pnode, "Ymap"); if (ymnode == null) { return; } string changestr = changed ? "*" : ""; for (int i = 0; i < ymnode.Nodes.Count; i++) { var ynode = ymnode.Nodes[i]; if (ynode.Tag == ymap) { string name = ymap.Name; if (ymap.RpfFileEntry != null) { name = ymap.RpfFileEntry.Name; } ynode.Text = changestr + name; break; } } } }
public void LoadMeta(YmapFile ymap) { string fn; Xml = MetaXml.GetXml(ymap, out fn); FileName = fn; RawPropertyGrid.SelectedObject = ymap; rpfFileEntry = ymap?.RpfFileEntry; modified = false; metaFormat = MetaFormat.XML; if (ymap != null) { if (ymap.Meta != null) { metaFormat = MetaFormat.RSC; } if (ymap.Pso != null) { metaFormat = MetaFormat.PSO; } if (ymap.Rbf != null) { metaFormat = MetaFormat.RBF; } } }
public void SetYmap(YmapFile ymap) { Ymap = ymap; Tag = ymap; UpdateFormTitle(); UpdateYmapUI(); waschanged = ymap?.HasChanged ?? false; }
public void LoadMeta(YmapFile ymap) { string fn; Xml = MetaXml.GetXml(ymap, out fn); FileName = fn; RawPropertyGrid.SelectedObject = ymap; modified = false; }
public bool ContainsYmap(YmapFile ymap) { foreach (var f in YmapFiles) { if (f == ymap) { return(true); } } return(false); }
private void LoadYmapTreeNodes(YmapFile ymap, TreeNode node) { if (ymap == null) { return; } if (!string.IsNullOrEmpty(node.Name)) { return; //named nodes are eg Entities and CarGens } node.Nodes.Clear(); if ((ymap.AllEntities != null) && (ymap.AllEntities.Length > 0)) { var entsnode = node.Nodes.Add("Entities (" + ymap.AllEntities.Length.ToString() + ")"); entsnode.Name = "Entities"; entsnode.Tag = ymap; var ents = ymap.AllEntities; for (int i = 0; i < ents.Length; i++) { var ent = ents[i]; var edef = ent.CEntityDef; var enode = entsnode.Nodes.Add(edef.archetypeName.ToString()); enode.Tag = ent; } } if ((ymap.CarGenerators != null) && (ymap.CarGenerators.Length > 0)) { var cargensnode = node.Nodes.Add("Car Generators (" + ymap.CarGenerators.Length.ToString() + ")"); cargensnode.Name = "CarGens"; cargensnode.Tag = ymap; var cargens = ymap.CarGenerators; for (int i = 0; i < cargens.Length; i++) { var cargen = cargens[i]; var ccgnode = cargensnode.Nodes.Add(cargen.ToString()); ccgnode.Tag = cargen; } } if ((ymap.GrassInstanceBatches != null) && (ymap.GrassInstanceBatches.Length > 0)) { var grassbatchesnodes = node.Nodes.Add("Grass Batches (" + ymap.GrassInstanceBatches.Length.ToString() + ")"); grassbatchesnodes.Name = "GrassBatches"; grassbatchesnodes.Tag = ymap; var grassbatches = ymap.GrassInstanceBatches; for (int i = 0; i < grassbatches.Length; i++) { var batch = grassbatches[i]; var gbnode = grassbatchesnodes.Nodes.Add(batch.ToString()); gbnode.Tag = batch; } } }
public bool AddYmapFile(YmapFile ymap) { string relpath = GetRelativePath(ymap.FilePath); if (string.IsNullOrEmpty(relpath)) { relpath = ymap.Name; } if (YmapFilenames.Contains(relpath)) { return(false); } YmapFilenames.Add(relpath); YmapFiles.Add(ymap); return(true); }
public void RemoveYmapFile(YmapFile ymap) { if (ymap == null) { return; } var relpath = GetRelativePath(ymap.FilePath); if (string.IsNullOrEmpty(relpath)) { relpath = ymap.Name; } YmapFiles.Remove(ymap); YmapFilenames.Remove(relpath); HasChanged = true; }
public YmapFile AddYmapFile(string filename) { YmapFile ymap = new YmapFile(); ymap.RpfFileEntry = new RpfResourceFileEntry(); ymap.RpfFileEntry.Name = new FileInfo(filename).Name; ymap.FilePath = GetFullFilePath(filename); ymap.Name = ymap.RpfFileEntry.Name; JenkIndex.Ensure(ymap.Name); JenkIndex.Ensure(Path.GetFileNameWithoutExtension(ymap.Name)); JenkIndex.Ensure(filename); if (!AddYmapFile(ymap)) { return(null); } return(ymap); }
public void LoadMeta(YmapFile ymap) { var fn = (ymap?.RpfFileEntry?.Name) ?? ""; if (ymap.Meta != null) { LoadMeta(ymap.Meta); fn += ".xml"; } else if (ymap.Pso != null) { LoadMeta(ymap.Pso); fn += ".pso.xml"; } else if (ymap.Rbf != null) { LoadMeta(ymap.Rbf); fn += ".rbf.xml"; } FileName = fn; RawPropertyGrid.SelectedObject = ymap; }
private void CentreButton_Click(object sender, EventArgs e) { string filename = mainForm.CurrentListBox; if (!string.IsNullOrEmpty(filename)) { YmapFile ymap = new YmapFile(); ymap.Load(File.ReadAllBytes(filename)); Vector3 extentMin = ymap.CMapData.entitiesExtentsMin; Vector3 extentMax = ymap.CMapData.entitiesExtentsMax; Vector3 centrepoint = new Vector3((extentMin.X + extentMax.X) / 2, (extentMin.Y + extentMax.Y) / 2, (extentMin.Z + extentMax.Z) / 2); vector1.Text = centrepoint.X + ", " + centrepoint.Y + ", " + centrepoint.Z; } else { MessageBox.Show("You don't seem to have a ymap selected on the Main Form.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private void startButton_Click(object sender, EventArgs e) { if (ymapLocationText.Text != null) { string filename = ymapLocationText.Text; YmapFile ymap = new YmapFile(); ymap.Load(File.ReadAllBytes(filename)); if (ymap.AllEntities != null) { foreach (YmapEntityDef yEnts in ymap.AllEntities) { if (yEnts.IsMlo) { long outputNumber = (long.Parse(yEnts.Name) ^ (long)Math.Floor(yEnts.Position.X * 100) ^ (long)Math.Floor(yEnts.Position.Y * 100) ^ (long)Math.Floor(yEnts.Position.Z * 100)) & 0xffffffff; generatedHashText.Text = outputNumber.ToString(); } } } } }
public TreeNode FindYmapTreeNode(YmapFile ymap) { if (ProjectTreeView.Nodes.Count <= 0) { return(null); } var projnode = ProjectTreeView.Nodes[0]; var ymapsnode = GetChildTreeNode(projnode, "Ymap"); if (ymapsnode == null) { return(null); } for (int i = 0; i < ymapsnode.Nodes.Count; i++) { var ymapnode = ymapsnode.Nodes[i]; if (ymapnode.Tag == ymap) { return(ymapnode); } } return(null); }
static void HandleFindPropsOptions(string[] args) { CommandLine.Parse <FindPropsOptions>(args, (opts, gOpts) => { if (opts.Position == null || opts.Position.Count != 3) { Console.Error.WriteLine("Please provide position with --position x,y,z"); return; } var position = new Vector3(opts.Position[0], opts.Position[1], opts.Position[2]); var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; if (fileInfo.Name.EndsWith(".ymap")) { var ymap = new YmapFile(); ymap.Load(fileInfo.FullName); for (int j = 0; j < ymap.CMapData.Entities.Count; j++) { var entity = ymap.CMapData.Entities[j]; float distance = Vector3.Distance(position, entity.Position); if (distance <= opts.Radius) { Console.WriteLine(fileInfo.Name + " => " + entity.Guid); } } } } }); }
private void GenerateButton_Click(object sender, EventArgs e) { //var space = ProjectForm?.WorldForm?.Space; //if (space == null) return; var gameFileCache = ProjectForm?.WorldForm?.GameFileCache; if (gameFileCache == null) { return; } var path = ProjectForm.CurrentProjectFile.GetFullFilePath("lodlights") + "\\"; GenerateButton.Enabled = false; List <YmapFile> projectYmaps = ProjectForm.CurrentProjectFile.YmapFiles; var pname = NameTextBox.Text; Task.Run(() => { var lights = new List <Light>(); foreach (var ymap in projectYmaps) { if (ymap?.AllEntities == null) { continue; } foreach (var ent in ymap.AllEntities) { if (ent.Archetype == null) { continue; } bool waiting = false; var dwbl = gameFileCache.TryGetDrawable(ent.Archetype, out waiting); while (waiting) { dwbl = gameFileCache.TryGetDrawable(ent.Archetype, out waiting); UpdateStatus("Waiting for " + ent.Archetype.AssetName + " to load..."); Thread.Sleep(20); } UpdateStatus("Adding lights from " + ent.Archetype.Name + "..."); if (dwbl != null) { var fphys = (dwbl as FragDrawable)?.OwnerFragmentPhys; ent.EnsureLights(dwbl); var elights = ent.Lights; if (elights != null) { for (int li = 0; li < elights.Length; li++) { var elight = elights[li]; var la = elight.Attributes; uint r = la.ColorR; uint g = la.ColorG; uint b = la.ColorB; uint i = (byte)Math.Max(Math.Min(Math.Round(la.Intensity * 5.3125f), 255), 0);//5.1=255/48 uint c = (i << 24) + (r << 16) + (g << 8) + b; uint h = elight.Hash; //any other way to know if it's a streetlight? //var name = ent.Archetype.Name; var flags = la.Flags; bool isStreetLight = (((flags >> 10) & 1u) == 1); // (name != null) && (name.Contains("street") || name.Contains("traffic")); isStreetLight = false; //TODO: fix this! //@Calcium: //1 = point //2 = spot //4 = capsule uint type = (uint)la.Type; uint unk = isStreetLight ? 1u : 0;//2 bits - isStreetLight low bit, unk high bit uint t = la.TimeFlags | (type << 26) | (unk << 24); var inner = (byte)Math.Round(la.ConeInnerAngle * 1.4117647f); var outer = (byte)Math.Round(la.ConeOuterAngle * 1.4117647f); if (type == 4) { outer = (byte)Math.Max(Math.Max(la.Extent.X, la.Extent.Y), la.Extent.Z); } var light = new Light(); light.position = new MetaVECTOR3(elight.Position); light.colour = c; light.direction = new MetaVECTOR3(elight.Direction); light.falloff = la.Falloff; light.falloffExponent = la.FalloffExponent; light.timeAndStateFlags = t; light.hash = h; light.coneInnerAngle = inner; light.coneOuterAngleOrCapExt = outer; light.coronaIntensity = (byte)(la.CoronaIntensity * 6); light.isStreetLight = isStreetLight; lights.Add(light); } } } } } if (lights.Count == 0) { MessageBox.Show("No lights found in project!"); return; } //final lights should be sorted by isStreetLight (1 first!) and then hash lights.Sort((a, b) => { if (a.isStreetLight != b.isStreetLight) { return(b.isStreetLight.CompareTo(a.isStreetLight)); } return(a.hash.CompareTo(b.hash)); }); var position = new List <MetaVECTOR3>(); var colour = new List <uint>(); var direction = new List <MetaVECTOR3>(); var falloff = new List <float>(); var falloffExponent = new List <float>(); var timeAndStateFlags = new List <uint>(); var hash = new List <uint>(); var coneInnerAngle = new List <byte>(); var coneOuterAngleOrCapExt = new List <byte>(); var coronaIntensity = new List <byte>(); ushort numStreetLights = 0; foreach (var light in lights) { position.Add(light.position); colour.Add(light.colour); direction.Add(light.direction); falloff.Add(light.falloff); falloffExponent.Add(light.falloffExponent); timeAndStateFlags.Add(light.timeAndStateFlags); hash.Add(light.hash); coneInnerAngle.Add(light.coneInnerAngle); coneOuterAngleOrCapExt.Add(light.coneOuterAngleOrCapExt); coronaIntensity.Add(light.coronaIntensity); if (light.isStreetLight) { numStreetLights++; } } UpdateStatus("Creating new ymap files..."); var lodymap = new YmapFile(); var distymap = new YmapFile(); var ll = new YmapLODLights(); var dl = new YmapDistantLODLights(); var cdl = new CDistantLODLight(); distymap.DistantLODLights = dl; lodymap.LODLights = ll; lodymap.Parent = distymap; cdl.category = 1;//0=small, 1=med, 2=large cdl.numStreetLights = numStreetLights; dl.CDistantLODLight = cdl; dl.positions = position.ToArray(); dl.colours = colour.ToArray(); dl.Ymap = distymap; dl.CalcBB(); ll.direction = direction.ToArray(); ll.falloff = falloff.ToArray(); ll.falloffExponent = falloffExponent.ToArray(); ll.timeAndStateFlags = timeAndStateFlags.ToArray(); ll.hash = hash.ToArray(); ll.coneInnerAngle = coneInnerAngle.ToArray(); ll.coneOuterAngleOrCapExt = coneOuterAngleOrCapExt.ToArray(); ll.coronaIntensity = coronaIntensity.ToArray(); ll.Ymap = lodymap; ll.BuildLodLights(dl); ll.CalcBB(); ll.BuildBVH(); lodymap.CalcFlags(); lodymap.CalcExtents(); distymap.CalcFlags(); distymap.CalcExtents(); var lodname = pname + "_lodlights"; var distname = pname + "_distantlights"; lodymap.Name = lodname; lodymap._CMapData.name = JenkHash.GenHash(lodname); lodymap.RpfFileEntry = new RpfResourceFileEntry(); lodymap.RpfFileEntry.Name = lodname + ".ymap"; lodymap.RpfFileEntry.NameLower = lodname + ".ymap"; distymap.Name = distname; distymap._CMapData.name = JenkHash.GenHash(distname); distymap.RpfFileEntry = new RpfResourceFileEntry(); distymap.RpfFileEntry.Name = distname + ".ymap"; distymap.RpfFileEntry.NameLower = distname + ".ymap"; lodymap._CMapData.parent = distymap._CMapData.name; lodymap.Loaded = true; distymap.Loaded = true; UpdateStatus("Adding new ymap files to project..."); ProjectForm.Invoke((MethodInvoker) delegate { ProjectForm.AddYmapToProject(lodymap); ProjectForm.AddYmapToProject(distymap); }); var stats = ""; UpdateStatus("Process complete. " + stats); GenerateComplete(); }); }
private void SelectFile(RpfEntry entry, int offset, int length) { SelectedEntry = entry; SelectedOffset = offset; SelectedLength = length; RpfFileEntry rfe = entry as RpfFileEntry; if (rfe == null) { RpfDirectoryEntry rde = entry as RpfDirectoryEntry; if (rde != null) { FileInfoLabel.Text = rde.Path + " (Directory)"; DataTextBox.Text = "[Please select a data file]"; } else { FileInfoLabel.Text = "[Nothing selected]"; DataTextBox.Text = "[Please select a data file]"; } ShowTextures(null); return; } Cursor = Cursors.WaitCursor; string typestr = "Resource"; if (rfe is RpfBinaryFileEntry) { typestr = "Binary"; } byte[] data = rfe.File.ExtractFile(rfe); int datalen = (data != null) ? data.Length : 0; FileInfoLabel.Text = rfe.Path + " (" + typestr + " file) - " + TextUtil.GetBytesReadable(datalen); if (ShowLargeFileContentsCheckBox.Checked || (datalen < 524287)) //512K { DisplayFileContentsText(rfe, data, length, offset); } else { DataTextBox.Text = "[Filesize >512KB. Select the Show large files option to view its contents]"; } bool istexdict = false; if (rfe.NameLower.EndsWith(".ymap")) { YmapFile ymap = new YmapFile(rfe); ymap.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ymap; } else if (rfe.NameLower.EndsWith(".ytyp")) { YtypFile ytyp = new YtypFile(); ytyp.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ytyp; } else if (rfe.NameLower.EndsWith(".ymf")) { YmfFile ymf = new YmfFile(); ymf.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ymf; } else if (rfe.NameLower.EndsWith(".ymt")) { YmtFile ymt = new YmtFile(); ymt.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ymt; } else if (rfe.NameLower.EndsWith(".ybn")) { YbnFile ybn = new YbnFile(); ybn.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ybn; } else if (rfe.NameLower.EndsWith(".fxc")) { FxcFile fxc = new FxcFile(); fxc.Load(data, rfe); DetailsPropertyGrid.SelectedObject = fxc; } else if (rfe.NameLower.EndsWith(".yft")) { YftFile yft = new YftFile(); yft.Load(data, rfe); DetailsPropertyGrid.SelectedObject = yft; if ((yft.Fragment != null) && (yft.Fragment.Drawable != null) && (yft.Fragment.Drawable.ShaderGroup != null) && (yft.Fragment.Drawable.ShaderGroup.TextureDictionary != null)) { ShowTextures(yft.Fragment.Drawable.ShaderGroup.TextureDictionary); istexdict = true; } } else if (rfe.NameLower.EndsWith(".ydr")) { YdrFile ydr = new YdrFile(); ydr.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ydr; if ((ydr.Drawable != null) && (ydr.Drawable.ShaderGroup != null) && (ydr.Drawable.ShaderGroup.TextureDictionary != null)) { ShowTextures(ydr.Drawable.ShaderGroup.TextureDictionary); istexdict = true; } } else if (rfe.NameLower.EndsWith(".ydd")) { YddFile ydd = new YddFile(); ydd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ydd; //todo: show embedded texdicts in ydd's? is this possible? } else if (rfe.NameLower.EndsWith(".ytd")) { YtdFile ytd = new YtdFile(); ytd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ytd; ShowTextures(ytd.TextureDict); istexdict = true; } else if (rfe.NameLower.EndsWith(".ycd")) { YcdFile ycd = new YcdFile(); ycd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ycd; } else if (rfe.NameLower.EndsWith(".ynd")) { YndFile ynd = new YndFile(); ynd.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ynd; } else if (rfe.NameLower.EndsWith(".ynv")) { YnvFile ynv = new YnvFile(); ynv.Load(data, rfe); DetailsPropertyGrid.SelectedObject = ynv; } else if (rfe.NameLower.EndsWith("_cache_y.dat")) { CacheDatFile cdf = new CacheDatFile(); cdf.Load(data, rfe); DetailsPropertyGrid.SelectedObject = cdf; } else if (rfe.NameLower.EndsWith(".rel")) { RelFile rel = new RelFile(rfe); rel.Load(data, rfe); DetailsPropertyGrid.SelectedObject = rel; } else if (rfe.NameLower.EndsWith(".gxt2")) { Gxt2File gxt2 = new Gxt2File(); gxt2.Load(data, rfe); DetailsPropertyGrid.SelectedObject = gxt2; } else if (rfe.NameLower.EndsWith(".pso")) { JPsoFile pso = new JPsoFile(); pso.Load(data, rfe); DetailsPropertyGrid.SelectedObject = pso; } else { DetailsPropertyGrid.SelectedObject = null; } if (!istexdict) { ShowTextures(null); } Cursor = Cursors.Default; }
// WIP++ static void HandlYmapToYdrOptions(string[] args) { CommandLine.Parse <YmapToYdrOptions>(args, (opts, gOpts) => { Init(args); var files = new Dictionary <uint, string>(); var required = new List <uint>(); var ymap = new YmapFile(); ymap.Load(opts.InputFile); for (int i = 0; i < ymap.CMapData.Entities.Count; i++) { var entity = ymap.CMapData.Entities[i]; if (required.IndexOf(entity.ArchetypeName) == -1) { required.Add(entity.ArchetypeName); } } ArchiveUtilities.ForEachResourceFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { if (file.Name.EndsWith(".ydr")) { uint hash = Utils.Hash(file.Name.ToLowerInvariant().Replace(".ydr", "")); if (required.IndexOf(hash) != -1 && !files.ContainsKey(hash)) { Console.WriteLine(file.Name); string tmp = Path.GetTempFileName(); file.Export(tmp); files.Add(hash, tmp); } } }); YdrFile ydr = null; var bbMin = new Vector3(float.MaxValue); var bbMax = new Vector3(float.MinValue); var bsCenter = Vector3.Zero; foreach (var file in files) { var ydr2 = new YdrFile(); ydr2.Load(file.Value); bbMin = Vector3.Min(bbMin, (Vector3)(Vector4)ydr2.Drawable.BoundingBoxMin); bbMax = Vector3.Max(bbMin, (Vector3)(Vector4)ydr2.Drawable.BoundingBoxMax); if (ydr == null) { ydr = ydr2; continue; } ydr.Drawable.BoundingSphereRadius = ydr2.Drawable.BoundingSphereRadius; for (int i = 0; i < ydr2.Drawable.DrawableModelsHigh.Entries.Count; i++) { var model = ydr2.Drawable.DrawableModelsHigh.Entries[i]; for (int j = 0; j < model.Geometries.Count; j++) { ydr.Drawable.DrawableModelsHigh.Entries[i].Geometries.Add(model.Geometries[j]); } } for (int i = 0; i < ydr2.Drawable.DrawableModelsX.Entries.Count; i++) { var model = ydr2.Drawable.DrawableModelsX.Entries[i]; for (int j = 0; j < model.Geometries.Count; j++) { ydr.Drawable.DrawableModelsX.Entries[i].Geometries.Add(model.Geometries[j]); } } } ydr.Drawable.BoundingBoxMin = (RAGE_Vector4)(Vector4)bbMin; ydr.Drawable.BoundingBoxMax = (RAGE_Vector4)(Vector4)bbMax; ydr.Drawable.BoundingCenter = (RAGE_Vector3)bsCenter; ydr.Save(opts.OutputFile); }); }
static void HandleImportMetaOptions(string[] args) { CommandLine.Parse <ImportMetaOptions>(args, (opts, gOpts) => { if (opts.Metadata) { Init(args); } else { EnsurePath(); EnsureKeys(); EnsureCache(); } if (opts.InputFiles == null) { Console.WriteLine("Please provide input files with -i --input"); return; } else { var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; Console.WriteLine(fileInfo.FullName); var strings = MetaUtilities.GetAllStringsFromXml(fileInfo.FullName); foreach (var str in strings) { Utils.Hash(str.ToLowerInvariant()); } var doc = new XmlDocument(); doc.Load(fileInfo.FullName); var res = new ResourceFile_GTA5_pc <MetaFile>(); res.Version = 2; res.ResourceData = XmlMeta.GetMeta(doc); if (fileInfo.Name.EndsWith(".ymap.xml") && opts.Metadata) { var toDelete = opts.Delete?.Select(e => Convert.ToUInt32(e)).ToList() ?? new List <uint>(); var mappings = new Dictionary <uint, Dictionary <uint, JObject> >(); var basePath = Path.GetDirectoryName(fileInfo.FullName); var ymaps = new List <YmapFile>(); var ymap = new YmapFile(); var nameHashes = new Dictionary <uint, string>(); ymap.ResourceFile = res; ymap.Parse(); var topParent = ImportMeta_GetTopYmapParent((uint)ymap.CMapData.Name); var topParentHash = (uint)topParent["hash"]; var topParentName = (string)topParent["name"]; var topParentPath = (string)topParent["path"]; var topParentYmap = new YmapFile(); Console.WriteLine("Top parent is " + topParentName); var entries = new List <JObject>() { topParent }; entries.AddRange(ImportMeta_GetYmapChildrens(topParent)); for (int j = 0; j < entries.Count; j++) { var entry = entries[j]; var entryHash = (uint)entry["hash"]; var entryName = (string)entry["name"]; var entryPath = (string)entry["path"]; var ymapPath = basePath + "\\" + entryName + ".ymap"; var metadataPath = ymapPath + ".json"; nameHashes.Add(entryHash, entryName); if (!File.Exists(ymapPath)) { Console.WriteLine("ERROR => File not found : " + entryName + ".ymap"); return; } if (!File.Exists(metadataPath)) { Console.WriteLine("ERROR => Metadata not found for " + entryName); return; } var metadataMapping = (JArray)JObject.Parse(File.ReadAllText(metadataPath))["mapping"]; var mapping = new Dictionary <uint, JObject>(); for (int k = 0; k < metadataMapping.Count; k++) { mapping.Add((uint)metadataMapping[k]["guid"], (JObject)metadataMapping[k]); } mappings.Add(entryHash, mapping); if (entryHash == (uint)ymap.CMapData.Name) { ymaps.Add(ymap); } else { var ymap2 = new YmapFile(); ymap2.Load(ymapPath); ymaps.Add(ymap2); } } for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; if (ymap2.CMapData.Parent != 0) { ymap2.CMapData.ParentMapData = ymaps.Find(e => e.CMapData.Name == ymap2.CMapData.Parent).CMapData; } } bool modified; do { modified = false; for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; Console.WriteLine(nameHashes[(uint)ymap2.CMapData.Name]); var toRemove = new List <MCEntityDef>(); var toSet = new List <Tuple <MCEntityDef, MCEntityDef> >(); bool currModified = false; for (int k = 0; k < ymap2.CMapData.Entities.Count; k++) { var entity = ymap2.CMapData.Entities[k]; var oldHasParent = (bool)mappings[(uint)ymap2.CMapData.Name][entity.Guid]["hasParent"]; var currHasParent = entity.ParentIndex != -1; if (oldHasParent) { var oldParent = (uint)mappings[(uint)ymap2.CMapData.Name][entity.Guid]["parent"]; var oldParentYmapName = (string)mappings[(uint)ymap2.CMapData.Name][entity.Guid]["parentYmap"]; var oldParentYmap = Utils.Hash(oldParentYmapName); if (currHasParent) { if (entity.ParentEntity == null || entity.ParentEntity.Guid != oldParent) { var parentYmap = ymaps.Find(e => (uint)e.CMapData.Name == oldParentYmap); var parentIdx = parentYmap.CMapData.Entities.FindIndex(e => e.Guid == oldParent); if (parentIdx == -1) { Console.WriteLine("DELETE " + entity.Guid + " => Missing parent (" + oldParentYmapName + ")"); toRemove.Add(entity); modified = true; currModified = true; } else { Console.WriteLine("ASSIGN parent " + oldParent + " to " + entity.Guid); var parent = parentYmap.CMapData.Entities[parentIdx]; toSet.Add(new Tuple <MCEntityDef, MCEntityDef>(entity, parent)); modified = true; currModified = true; } } else { if (toDelete.IndexOf(oldParent) != -1 || (opts.DeleteScope == "full" && toDelete.IndexOf(entity.Guid) != -1)) { Console.WriteLine("DELETE " + entity.Guid + " => Marked for deletion @" + opts.DeleteMode); toRemove.Add(entity); modified = true; currModified = true; } } } } } if (opts.DeleteMode == "dummy") { for (int k = 0; k < toRemove.Count; k++) { toRemove[k].ArchetypeName = Utils.Hash("gtautil_dummy"); } } else { ymap2.CMapData.RemoveEntities(toRemove); } for (int k = 0; k < toSet.Count; k++) { toSet[k].Item1.ParentEntity = toSet[k].Item2; } if (currModified) { Console.WriteLine("MODIFIED"); } } } while (modified && opts.DeleteMode != "dummy"); for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; var mapping = new Dictionary <uint, int>(); var name = nameHashes[(uint)ymap2.CMapData.Name]; ymap2.Save(basePath + "\\" + name + ".ymap"); var data = new JObject { ["mapping"] = new JArray() }; var dataMapping = (JArray)(data["mapping"]); for (int k = 0; k < ymap2.CMapData.Entities.Count; k++) { var entity = ymap2.CMapData.Entities[k]; if (mapping.ContainsKey(entity.Guid)) { Console.WriteLine("Duplicate GUID found => " + entity.Guid + " at index " + j + " ABORTING"); return; } else { mapping.Add(entity.Guid, k); var entry = new JObject() { ["guid"] = entity.Guid, ["hasParent"] = entity.ParentIndex != -1, }; if (entity.ParentIndex != -1) { entry["parent"] = entity.ParentEntity.Guid; entry["parentName"] = MetaXml.HashString((MetaName)entity.ParentEntity.Guid); entry["parentYmap"] = nameHashes[(uint)entity.ParentEntity.Parent.Name]; } dataMapping.Add(entry); } } var jsonString = JsonConvert.SerializeObject(data, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented }); File.WriteAllText(basePath + "\\" + name + ".ymap.json", jsonString); } } else { string fileName = fileInfo.FullName.Replace(".xml", ""); res.Save(fileName); } } using (StreamWriter writer = new StreamWriter(AssemblyDirectory + "\\strings.txt")) { foreach (var kvp in Jenkins.Index) { writer.Write(kvp.Value + "\n"); } } } }); }
static void HandleInjectEntitiesOptions(string[] args) { CommandLine.Parse <InjectEntitiesOptions>(args, (opts, gOpts) => { if (opts.Ymap == null) { Console.WriteLine("Please provide source ymap file with --ymap"); return; } if (opts.Ytyp == null) { Console.WriteLine("Please provide source ytyp file with --ytyp"); return; } if (opts.Position == null || opts.Position.Count() != 3) { Console.WriteLine("Please provide a correct position ex: --position 120.5,1370.312,769.2"); return; } if (opts.Rotation == null || opts.Rotation.Count() != 4) { Console.WriteLine("Plase provide a correct rotation ex: --rotation 0,0,0,1"); return; } if (opts.Name == null) { Console.WriteLine("Plase provide new generated ytyp name with --name"); return; } Init(args); var ymapInfos = Utils.Expand(opts.Ymap); var ymapNames = ymapInfos.Select(e => Path.GetFileNameWithoutExtension(e.Name)).ToArray(); var position = new Vector3(opts.Position.ElementAt(0), opts.Position.ElementAt(1), opts.Position.ElementAt(2)); var rotation = new Quaternion(opts.Rotation.ElementAt(0), opts.Rotation.ElementAt(1), opts.Rotation.ElementAt(2), opts.Rotation.ElementAt(3)); var ytyp = new YtypFile(); ytyp.Load(opts.Ytyp); MCMloArchetypeDef mlo = null; for (int i = 0; i < ytyp.CMapTypes.MloArchetypes.Count; i++) { if (opts.MloName == null) { mlo = ytyp.CMapTypes.MloArchetypes[i]; break; } else { uint mloNameHash = Jenkins.Hash(opts.MloName.ToLowerInvariant()); if (mloNameHash == ytyp.CMapTypes.MloArchetypes[i].Name) { Console.Error.WriteLine("Found MLO => " + opts.MloName); mlo = ytyp.CMapTypes.MloArchetypes[i]; break; } } } if (mlo == null) { Console.WriteLine("MLO archetype not found"); return; } var ymaps = new List <YmapFile>(); for (int i = 0; i < ymapInfos.Length; i++) { var ymap = new YmapFile(); ymap.Load(ymapInfos[i].FullName); ymaps.Add(ymap); } var missingYmap = new YmapFile(); int missingCount = 0; Console.WriteLine("Calculating rooms extents"); var roomExtents = new Vector3[mlo.Rooms.Count][]; for (int i = 0; i < mlo.Rooms.Count; i++) { var room = mlo.Rooms[i]; var entities = new List <MCEntityDef>(); for (int j = 0; j < room.AttachedObjects.Count; j++) { int idx = (int)room.AttachedObjects[j]; if (idx >= mlo.Entities.Count) { continue; } entities.Add(mlo.Entities[idx]); } var extents = Utils.CalcExtents(entities); roomExtents[i] = extents[0]; } for (int i = 0; i < ymaps.Count; i++) { var ymap = ymaps[i]; var name = ymapNames[i]; if (name.StartsWith("portal_") || name.StartsWith("entityset_")) { continue; } var roomIdx = mlo.Rooms.FindIndex(e => e.Name == name); MCMloRoomDef currRoom = null; if (roomIdx != -1) { currRoom = mlo.Rooms[roomIdx]; } for (int j = 0; j < ymap.CMapData.Entities.Count; j++) { var entity = ymap.CMapData.Entities[j]; var idx = mlo.Entities.FindIndex(e => e.Guid == entity.Guid); var room = currRoom; var originalPosition = entity.Position; var originalRotation = entity.Rotation; Console.WriteLine(name + " => " + j + " (" + idx + "|" + mlo.Entities.Count + ") => " + Utils.HashString((MetaName)entity.ArchetypeName)); Utils.World2Mlo(entity, mlo, position, rotation); if (opts.Static && idx == -1) { if ((entity.Flags & 32) == 0) { Console.WriteLine(" Setting static flag (32)"); entity.Flags = entity.Flags | 32; } } entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_ORPHANHD; if (entity.Guid == 0) { var random = new Random(); do { entity.Guid = (uint)random.Next(1000000, Int32.MaxValue); }while (mlo.Entities.Count(e => e.Guid == entity.Guid) > 0); Console.WriteLine(" Setting random GUID => " + entity.Guid); } if (idx == -1) { idx = mlo.AddEntity(entity); } else { Console.WriteLine(" Found matching GUID => Overriding " + idx); mlo.Entities[idx] = entity; } Console.WriteLine(j + " " + Utils.HashString((MetaName)entity.ArchetypeName)); if (room == null) { room = GetRoomForEntity(mlo, roomExtents, entity); } if (room == null) { entity.Position = originalPosition; entity.Rotation = originalRotation; entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD; missingYmap.CMapData.Entities.Add(entity); missingCount++; continue; } uint id = (uint)idx; if (room.AttachedObjects.IndexOf(id) == -1) { room.AttachedObjects.Add(id); } Console.WriteLine(" Room => " + room.Name); } } if (opts.DeleteMissing) { for (int i = mlo.Entities.Count - 1; i >= 0; i--) { bool found = false; for (int j = 0; j < ymaps.Count; j++) { var ymap = ymaps[j]; if (ymap.CMapData.Entities.FindIndex(e => e.Guid == mlo.Entities[i].Guid) != -1) { found = true; break; } } if (!found) { Console.WriteLine("DELETE " + i); for (int j = 0; j < mlo.Rooms.Count; j++) { for (int k = mlo.Rooms[j].AttachedObjects.Count - 1; k >= 0; k--) { if (mlo.Rooms[j].AttachedObjects[k] == (uint)i) { mlo.Rooms[j].AttachedObjects.RemoveAt(k); } } } } } } var foundEntities = new Dictionary <uint, List <MCEntityDef> >(); for (int i = 0; i < ymaps.Count; i++) { var ymap = ymaps[i]; var name = ymapNames[i]; if (!name.StartsWith("entityset_")) { continue; } string[] split = name.Split('_'); uint nameHash = uint.Parse(split[1]); string roomName = split[2]; if (!foundEntities.TryGetValue(nameHash, out List <MCEntityDef> fEntities)) { fEntities = new List <MCEntityDef>(); } int entitySetIdx = mlo.EntitySets.FindIndex(e => e.Name == nameHash); int roomIdx = mlo.Rooms.FindIndex(e => e.Name == roomName); MCMloEntitySet currEntitySet = null; if (entitySetIdx != -1) { currEntitySet = mlo.EntitySets[entitySetIdx]; } for (int j = 0; j < ymap.CMapData.Entities.Count; j++) { var entity = ymap.CMapData.Entities[j]; var idx = currEntitySet.Entities.FindIndex(e => e.Guid == entity.Guid); var entitySet = currEntitySet; var originalPosition = entity.Position; var originalRotation = entity.Rotation; Console.WriteLine(name + " => " + j + " (" + idx + "|" + currEntitySet.Entities.Count + ") => " + Utils.HashString((MetaName)entity.ArchetypeName)); Utils.World2Mlo(entity, mlo, position, rotation); if (opts.Static && idx == -1) { if ((entity.Flags & 32) == 0) { Console.WriteLine(" Setting static flag (32)"); entity.Flags = entity.Flags | 32; } } entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_ORPHANHD; if (entity.Guid == 0) { var random = new Random(); do { entity.Guid = (uint)random.Next(1000000, Int32.MaxValue); }while (currEntitySet.Entities.Count(e => e.Guid == entity.Guid) > 0); Console.WriteLine(" Setting random GUID => " + entity.Guid); } if (idx == -1) { idx = currEntitySet.AddEntity(entity, roomIdx); } else { Console.WriteLine(" Found matching GUID => Overriding " + idx); currEntitySet.Entities[idx] = entity; } Console.WriteLine(j + " " + Utils.HashString((MetaName)entity.ArchetypeName)); fEntities.Add(entity); } foundEntities[nameHash] = fEntities; } if (opts.DeleteMissing) { foreach (var entry in foundEntities) { var entitySet = mlo.EntitySets.Find(e => e.Name == entry.Key); for (int i = entitySet.Entities.Count - 1; i >= 0; i--) { bool found = false; if (entry.Value.FindIndex(e => e.Guid == entitySet.Entities[i].Guid) != -1) { found = true; } if (!found) { Console.WriteLine("DELETE " + i); entitySet.RemoveEntity(entitySet.Entities[i]); } } } } ytyp.Save(opts.Name + ".ytyp"); if (missingCount > 0) { var extents = Utils.CalcExtents(missingYmap.CMapData.Entities); missingYmap.CMapData.EntitiesExtentsMin = extents[0][0]; missingYmap.CMapData.EntitiesExtentsMax = extents[0][1]; missingYmap.CMapData.StreamingExtentsMin = extents[1][0]; missingYmap.CMapData.StreamingExtentsMax = extents[1][1]; missingYmap.Save(opts.Name + "_exterior.ymap"); } }); }
static void HandleGenLODLightsOptions(string[] args) { CommandLine.Parse <GenLODLigthsOptions>(args, (opts, gOpts) => { if (opts.CreateMode) { if (opts.OutputDirectory == null) { Console.Error.WriteLine("Please provide output directory with --output"); return; } Init(args); if (!Directory.Exists(opts.OutputDirectory)) { Directory.CreateDirectory(opts.OutputDirectory); } var mapping = new Dictionary <string, int>(); ArchiveUtilities.ForEachResourceFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { if (file.Name.EndsWith(".ymap") && file.Name.Contains("lodlights")) { Console.WriteLine(file.Name); int level = GetDLCLevel(fullFileName); int oldLevel; if (!mapping.TryGetValue(file.Name, out oldLevel)) { oldLevel = -1; mapping.Add(file.Name, level); } if (level > oldLevel) { file.Export(opts.OutputDirectory + "\\" + file.Name); } } }); } else if (opts.DeleteMode) { Init(args); if (opts.InputDirectory == null) { Console.Error.WriteLine("Please provide input directory with --input"); return; } if (opts.Position == null || opts.Position.Count != 3) { Console.Error.WriteLine("Please provide position with --position x,y,z"); return; } if (!Directory.Exists(opts.InputDirectory + "\\modified")) { Directory.CreateDirectory(opts.InputDirectory + "\\modified"); } Vector3 position = new Vector3(opts.Position[0], opts.Position[1], opts.Position[2]); string[] files = Directory.GetFiles(opts.InputDirectory, "*.ymap"); var ymaps = new Dictionary <string, YmapFile>(); for (int i = 0; i < files.Length; i++) { string path = files[i]; string name = files[i].Replace(".ymap", ""); var ymap = new YmapFile(); Console.WriteLine("LOAD " + name); ymap.Load(files[i]); ymaps.Add(name, ymap); } var modified = new Dictionary <string, YmapFile>(); foreach (var item in ymaps) { string name = item.Key; YmapFile ymap = item.Value; for (int j = ymap.CMapData.DistantLODLightsSOA.Entries.Count - 1; j >= 0; j--) { var entry = ymap.CMapData.DistantLODLightsSOA.Entries[j]; var children = new Dictionary <string, YmapFile>(); float distance = Vector3.Distance(position, entry.Position); foreach (var item2 in ymaps) { if (item2.Value.CMapData.Parent == ymap.CMapData.Name) { children.Add(item2.Key, item2.Value); } } if (distance <= opts.Radius) { Console.WriteLine("Found DistLODLight in " + name + " at index " + j); Console.WriteLine(" Delete : " + name + "@" + j); ymap.CMapData.DistantLODLightsSOA.Entries.RemoveAt(j); if (!modified.ContainsValue(ymap)) { modified.Add(name, ymap); } foreach (var item2 in children) { string name2 = item2.Key; YmapFile ymap2 = item2.Value; Console.WriteLine(" Delete : " + name2 + "@" + j); item2.Value.CMapData.LODLightsSOA.Entries.RemoveAt(j); if (!modified.ContainsValue(ymap2)) { modified.Add(name2, ymap2); } } } } } foreach (var item in modified) { var descendant = item.Key.Substring(item.Key.LastIndexOf("\\")); item.Value.Save(opts.InputDirectory + "\\" + descendant + ".ymap"); item.Value.Save(opts.InputDirectory + "\\modified\\" + descendant + ".ymap"); } } }); }
private void GenerateButton_Click(object sender, EventArgs e) { //var space = ProjectForm?.WorldForm?.Space; //if (space == null) return; var gameFileCache = ProjectForm?.WorldForm?.GameFileCache; if (gameFileCache == null) { return; } var path = ProjectForm.CurrentProjectFile.GetFullFilePath("lodlights") + "\\"; GenerateButton.Enabled = false; List <YmapFile> projectYmaps = ProjectForm.CurrentProjectFile.YmapFiles; var pname = NameTextBox.Text; Task.Run(() => { var lights = new List <Light>(); var eemin = new Vector3(float.MaxValue); var eemax = new Vector3(float.MinValue); var semin = new Vector3(float.MaxValue); var semax = new Vector3(float.MinValue); //var rnd = new Random(); foreach (var ymap in projectYmaps) { if (ymap?.AllEntities == null) { continue; } foreach (var ent in ymap.AllEntities) { if (ent.Archetype == null) { continue; } bool waiting = false; var dwbl = gameFileCache.TryGetDrawable(ent.Archetype, out waiting); while (waiting) { dwbl = gameFileCache.TryGetDrawable(ent.Archetype, out waiting); UpdateStatus("Waiting for " + ent.Archetype.AssetName + " to load..."); Thread.Sleep(20); } UpdateStatus("Adding lights from " + ent.Archetype.Name + "..."); if (dwbl != null) { Drawable ddwbl = dwbl as Drawable; FragDrawable fdwbl = dwbl as FragDrawable; LightAttributes_s[] lightAttrs = null; if (ddwbl != null) { lightAttrs = ddwbl.LightAttributes?.data_items; } else if (fdwbl != null) { lightAttrs = fdwbl.OwnerFragment?.LightAttributes?.data_items; } if (lightAttrs != null) { eemin = Vector3.Min(eemin, ent.BBMin); eemax = Vector3.Max(eemax, ent.BBMax); semin = Vector3.Min(semin, ent.BBMin - ent._CEntityDef.lodDist); semax = Vector3.Max(semax, ent.BBMax + ent._CEntityDef.lodDist); for (int li = 0; li < lightAttrs.Length; li++) { var la = lightAttrs[li]; //transform this light with the entity position and orientation //generate lights data from it! //gotta transform the light position by the given bone! annoying Bone bone = null; Matrix xform = Matrix.Identity; int boneidx = 0; var skeleton = dwbl.Skeleton; if (skeleton?.Bones?.Data != null) { for (int j = 0; j < skeleton.Bones.Data.Count; j++) { var tbone = skeleton.Bones.Data[j]; if (tbone.Tag == la.BoneId) { boneidx = j; bone = tbone; break; } } if (bone != null) { var modeltransforms = skeleton.Transformations; var fragtransforms = fdwbl?.OwnerFragmentPhys?.OwnerFragPhysLod?.FragTransforms?.Data; var fragtransformid = fdwbl?.OwnerFragmentPhys?.OwnerFragPhysIndex ?? 0; var fragoffset = fdwbl?.OwnerFragmentPhys?.OwnerFragPhysLod.Unknown_30h ?? Vector4.Zero; fragoffset.W = 0.0f; if ((fragtransforms != null) && (fragtransformid < fragtransforms.Length)) { xform = fragtransforms[fragtransformid]; xform.Row4 += fragoffset; } else { //when using the skeleton's matrices, they need to be transformed by parent xform = modeltransforms[boneidx]; xform.Column4 = Vector4.UnitW; //xform = Matrix.Identity; short[] pinds = skeleton.ParentIndices; short parentind = ((pinds != null) && (boneidx < pinds.Length)) ? pinds[boneidx] : (short)-1; while ((parentind >= 0) && (parentind < pinds.Length)) { Matrix ptrans = (parentind < modeltransforms.Length) ? modeltransforms[parentind] : Matrix.Identity; ptrans.Column4 = Vector4.UnitW; xform = Matrix.Multiply(ptrans, xform); parentind = ((pinds != null) && (parentind < pinds.Length)) ? pinds[parentind] : (short)-1; } } } } Vector3 lpos = la.Position; Vector3 ldir = la.Direction; Vector3 bpos = xform.Multiply(lpos); Vector3 bdir = xform.MultiplyRot(ldir); Vector3 epos = ent.Orientation.Multiply(bpos) + ent.Position; Vector3 edir = ent.Orientation.Multiply(bdir); uint r = la.ColorR; uint g = la.ColorG; uint b = la.ColorB; uint i = (byte)Math.Min(la.Intensity * 4, 255); uint c = (i << 24) + (r << 16) + (g << 8) + b; uint h = GetLightHash(ent, li);// (uint)rnd.NextLong(); if (ent._CEntityDef.guid == 91259075) { } //h = 2324437992? should be:19112537 if (ent._CEntityDef.guid == 889043351) { } //h = 422028630 ? should be:4267224866 //any other way to know if it's a streetlight? //var name = ent.Archetype.Name; var flags = la.Flags; bool isStreetLight = (((flags >> 10) & 1u) == 1); // (name != null) && (name.Contains("street") || name.Contains("traffic")); isStreetLight = false; //TODO: fix this! //@Calcium: //1 = point //2 = spot //4 = capsule uint type = (uint)la.Type; uint unk = isStreetLight ? 1u : 0;//2 bits - isStreetLight low bit, unk high bit uint t = la.TimeFlags | (type << 26) | (unk << 24); var maxext = (byte)Math.Max(Math.Max(la.Extent.X, la.Extent.Y), la.Extent.Z); var light = new Light(); light.position = new MetaVECTOR3(epos); light.colour = c; light.direction = new MetaVECTOR3(edir); light.falloff = la.Falloff; light.falloffExponent = la.FalloffExponent; light.timeAndStateFlags = t; light.hash = h; light.coneInnerAngle = (byte)la.ConeInnerAngle; light.coneOuterAngleOrCapExt = Math.Max((byte)la.ConeOuterAngle, maxext); light.coronaIntensity = (byte)(la.CoronaIntensity * 6); light.isStreetLight = isStreetLight; lights.Add(light); } } } } } if (lights.Count == 0) { MessageBox.Show("No lights found in project!"); return; } //final lights should be sorted by isStreetLight (1 first!) and then hash lights.Sort((a, b) => { if (a.isStreetLight != b.isStreetLight) { return(b.isStreetLight.CompareTo(a.isStreetLight)); } return(a.hash.CompareTo(b.hash)); }); var position = new List <MetaVECTOR3>(); var colour = new List <uint>(); var direction = new List <MetaVECTOR3>(); var falloff = new List <float>(); var falloffExponent = new List <float>(); var timeAndStateFlags = new List <uint>(); var hash = new List <uint>(); var coneInnerAngle = new List <byte>(); var coneOuterAngleOrCapExt = new List <byte>(); var coronaIntensity = new List <byte>(); ushort numStreetLights = 0; foreach (var light in lights) { position.Add(light.position); colour.Add(light.colour); direction.Add(light.direction); falloff.Add(light.falloff); falloffExponent.Add(light.falloffExponent); timeAndStateFlags.Add(light.timeAndStateFlags); hash.Add(light.hash); coneInnerAngle.Add(light.coneInnerAngle); coneOuterAngleOrCapExt.Add(light.coneOuterAngleOrCapExt); coronaIntensity.Add(light.coronaIntensity); if (light.isStreetLight) { numStreetLights++; } } UpdateStatus("Creating new ymap files..."); var lodymap = new YmapFile(); var distymap = new YmapFile(); var ll = new YmapLODLights(); var dl = new YmapDistantLODLights(); var cdl = new CDistantLODLight(); cdl.category = 1;//0=small, 1=med, 2=large cdl.numStreetLights = numStreetLights; dl.CDistantLODLight = cdl; dl.positions = position.ToArray(); dl.colours = colour.ToArray(); ll.direction = direction.ToArray(); ll.falloff = falloff.ToArray(); ll.falloffExponent = falloffExponent.ToArray(); ll.timeAndStateFlags = timeAndStateFlags.ToArray(); ll.hash = hash.ToArray(); ll.coneInnerAngle = coneInnerAngle.ToArray(); ll.coneOuterAngleOrCapExt = coneOuterAngleOrCapExt.ToArray(); ll.coronaIntensity = coronaIntensity.ToArray(); lodymap._CMapData.flags = 0; distymap._CMapData.flags = 2; lodymap._CMapData.contentFlags = 128; distymap._CMapData.contentFlags = 256; lodymap._CMapData.entitiesExtentsMin = eemin; lodymap._CMapData.entitiesExtentsMax = eemax; lodymap._CMapData.streamingExtentsMin = semin - 1000f; lodymap._CMapData.streamingExtentsMax = semax + 1000f; //vanilla = ~1km distymap._CMapData.entitiesExtentsMin = eemin; distymap._CMapData.entitiesExtentsMax = eemax; distymap._CMapData.streamingExtentsMin = semin - 5000f; //make it huge distymap._CMapData.streamingExtentsMax = semax + 5000f; //vanilla = ~3km lodymap.LODLights = ll; distymap.DistantLODLights = dl; var lodname = pname + "_lodlights"; var distname = pname + "_distantlights"; lodymap.Name = lodname; lodymap._CMapData.name = JenkHash.GenHash(lodname); lodymap.RpfFileEntry = new RpfResourceFileEntry(); lodymap.RpfFileEntry.Name = lodname + ".ymap"; lodymap.RpfFileEntry.NameLower = lodname + ".ymap"; distymap.Name = distname; distymap._CMapData.name = JenkHash.GenHash(distname); distymap.RpfFileEntry = new RpfResourceFileEntry(); distymap.RpfFileEntry.Name = distname + ".ymap"; distymap.RpfFileEntry.NameLower = distname + ".ymap"; lodymap._CMapData.parent = distymap._CMapData.name; UpdateStatus("Adding new ymap files to project..."); ProjectForm.Invoke((MethodInvoker) delegate { ProjectForm.AddYmapToProject(lodymap); ProjectForm.AddYmapToProject(distymap); }); var stats = ""; UpdateStatus("Process complete. " + stats); GenerateComplete(); }); }
static void HandleMergeYmapOptionsOptions(string[] args) { CommandLine.Parse <MergeYmapOptions>(args, (opts, gOpts) => { if (opts.OutputDirectory == null) { Console.WriteLine("Plase provide output directory with --output"); return; } if (opts.Name == null) { Console.WriteLine("Plase provide name with --name"); return; } if (opts.Ymap == null) { Console.WriteLine("Please provide source ymap files with --ymap"); return; } // Init(args); var ymapInfos = Utils.Expand(opts.Ymap); var bbs = new List <Tuple <Vector3, Vector3> >(); var ymap = new YmapFile(); for (int i = 0; i < ymapInfos.Length; i++) { var _ymap = new YmapFile(); _ymap.Load(ymapInfos[i].FullName); ymap.CMapData.AddEntities(_ymap.CMapData.Entities); } for (int i = 0; i < ymap.CMapData.Entities.Count; i++) { var entity = ymap.CMapData.Entities[i]; var random = new Random(); do { entity.Guid = (uint)random.Next(1000000, Int32.MaxValue); }while (ymap.CMapData.Entities.Count(e => e.Guid == entity.Guid) > 1); Console.WriteLine("[" + i + "] Setting random GUID => " + entity.Guid); } var extents = Utils.CalcExtents(ymap.CMapData.Entities); ymap.CMapData.EntitiesExtentsMin = extents[0][0]; ymap.CMapData.EntitiesExtentsMax = extents[0][1]; ymap.CMapData.StreamingExtentsMin = extents[1][0]; ymap.CMapData.StreamingExtentsMax = extents[1][1]; Directory.CreateDirectory(opts.OutputDirectory); ymap.Save(opts.OutputDirectory + "\\" + opts.Name + ".ymap"); }); }
static void HandleMoveYmapOptionsOptions(string[] args) { CommandLine.Parse <MoveYmapOptions>(args, (opts, gOpts) => { if (opts.OutputDirectory == null) { Console.WriteLine("Plase provide output directory with --output"); return; } if (opts.Name == null) { Console.WriteLine("Plase provide name with --name"); return; } if (opts.Ymap == null) { Console.WriteLine("Please provide source ymap files with --ymap"); return; } if (opts.Position == null) { Console.WriteLine("Please provide position with --position"); return; } if (opts.Rotation == null) { Console.WriteLine("Please provide rotation with --rotation"); return; } // Init(args); var position = new Vector3(opts.Position.ElementAt(0), opts.Position.ElementAt(1), opts.Position.ElementAt(2)); var rotation = new Quaternion(opts.Rotation.ElementAt(0), opts.Rotation.ElementAt(1), opts.Rotation.ElementAt(2), opts.Rotation.ElementAt(3)); var ymap = new YmapFile(); ymap.Load(opts.Ymap); if (ymap.CMapData.Entities == null) { ymap.CMapData.Entities = new List <MCEntityDef>(); } else { for (int i = 0; i < ymap.CMapData.Entities.Count; i++) { var entity = ymap.CMapData.Entities[i]; var placement = Utils.World2Mlo(entity.Position, entity.Rotation, Vector3.Zero, Quaternion.Identity); var entityRotation = new Quaternion(placement.Item2.X, placement.Item2.Y, placement.Item2.Z, placement.Item2.W); entity.Position = placement.Item1; entity.Rotation = placement.Item2; entity.Position += position; entity.Position = Utils.RotateTransform(rotation, entity.Position, Vector3.Zero); var newPlacement = Utils.Mlo2World(entity.Position, entity.Rotation, Vector3.Zero, Quaternion.Identity); entity.Position = newPlacement.Item1; entity.Rotation = newPlacement.Item2; } } if (ymap.CMapData.MloInstances == null) { ymap.CMapData.MloInstances = new List <MCMloInstanceDef>(); } else { for (int i = 0; i < ymap.CMapData.MloInstances.Count; i++) { var mlo = ymap.CMapData.MloInstances[i]; mlo.Position += position; } } ymap.CMapData.Block = new MCBlockDesc(); var extents = Utils.CalcExtents(ymap.CMapData.Entities);; ymap.CMapData.EntitiesExtentsMin = extents[0][0]; ymap.CMapData.EntitiesExtentsMax = extents[0][1]; ymap.CMapData.StreamingExtentsMin = extents[1][0]; ymap.CMapData.StreamingExtentsMax = extents[1][1]; ymap.Save(opts.OutputDirectory + "\\" + opts.Name + ".ymap"); }); }
static void HandleExportMetaOptions(string[] args) { CommandLine.Parse <ExportMetaOptions>(args, (opts, gOpts) => { if (opts.Metadata) { Init(args); } else { EnsurePath(); EnsureKeys(); EnsureCache(); } if (opts.InputFiles == null) { Console.WriteLine("Please provide input files with -i --input"); return; } else { var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; Console.WriteLine(fileInfo.FullName); MetaFile meta = null; if (fileInfo.Name.EndsWith(".ymap") && opts.Metadata) { var ymap = new YmapFile(); ymap.Load(fileInfo.FullName); meta = ymap.ResourceFile.ResourceData; var basePath = Path.GetDirectoryName(fileInfo.FullName); var topParent = ImportMeta_GetTopYmapParent((uint)ymap.CMapData.Name); var topParentHash = (uint)topParent["hash"]; var topParentName = (string)topParent["name"]; var topParentPath = (string)topParent["path"]; var topParentYmap = new YmapFile(); Console.WriteLine("Top parent is " + topParentName); if (File.Exists(basePath + "\\" + topParentName + ".ymap")) { topParentYmap.Load(basePath + "\\" + topParentName + ".ymap"); } else { ArchiveUtilities.ForEachResourceFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { if (fullFileName == topParentPath) { var ms = new MemoryStream(); file.Export(ms); topParentYmap.Load(ms); } }); } var children = ImportMeta_GetYmapChildrens(topParent); var ymaps = new List <YmapFile>() { topParentYmap }; var nameHashes = new Dictionary <uint, string>(); nameHashes.Add((uint)topParent["hash"], (string)topParent["name"]); for (int j = 0; j < children.Count; j++) { var cYmap = new YmapFile(); var child = children[j]; var hash = (uint)child["hash"]; var name = (string)child["name"]; var path = (string)child["path"]; nameHashes.Add(hash, name); if (File.Exists(basePath + "\\" + name + ".ymap")) { cYmap.Load(basePath + "\\" + name + ".ymap"); } else { Console.WriteLine("Grabbing missing " + name + " from install directory (very slowly, needs optimization)"); ArchiveUtilities.ForEachResourceFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { if (fullFileName == path) { var ms = new MemoryStream(); file.Export(ms); cYmap.Load(ms); } }); } ymaps.Add(cYmap); } ymaps[ymaps.FindIndex(e => e.CMapData.Name == ymap.CMapData.Name)] = ymap; for (int j = 0; j < ymaps.Count; j++) { ymaps[j].CMapData.ParentMapData = ymaps.Find(e => e.CMapData.Name == ymaps[j].CMapData.Parent)?.CMapData; } for (int j = 0; j < ymaps.Count; j++) { var ymap2 = ymaps[j]; var mapping = new Dictionary <uint, int>(); var name = nameHashes[(uint)ymap2.CMapData.Name]; ymap2.Save(basePath + "\\" + name + ".ymap"); var data = new JObject { ["mapping"] = new JArray() }; var dataMapping = (JArray)(data["mapping"]); for (int k = 0; k < ymap2.CMapData.Entities.Count; k++) { var entity = ymap2.CMapData.Entities[k]; if (mapping.ContainsKey(entity.Guid)) { Console.WriteLine("Duplicate GUID found => " + entity.Guid + " at index " + j + " ABORTING"); return; } else { mapping.Add(entity.Guid, k); var entry = new JObject() { ["guid"] = entity.Guid, ["hasParent"] = entity.ParentIndex != -1, }; if (entity.ParentIndex != -1) { entry["parent"] = entity.ParentEntity.Guid; entry["parentName"] = MetaXml.HashString((MetaName)entity.ParentEntity.Guid); entry["parentYmap"] = nameHashes[(uint)entity.ParentEntity.Parent.Name]; } dataMapping.Add(entry); } } var jsonString = JsonConvert.SerializeObject(data, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented }); File.WriteAllText(basePath + "\\" + name + ".ymap.json", jsonString); } } else { var res = new ResourceFile_GTA5_pc <MetaFile>(); res.Load(fileInfo.FullName); meta = res.ResourceData; } var xml = MetaXml.GetXml(meta); string fileName = fileInfo.FullName + ".xml"; File.WriteAllText(fileName, xml); } } }); }
static void HandleExtractEntitiesOptions(string[] args) { CommandLine.Parse <ExtractEntitiesOptions>(args, (opts, gOpts) => { if (opts.Ytyp == null) { Console.WriteLine("Please provide source ytyp file with --ytyp"); return; } if (opts.Position == null || opts.Position.Count() != 3) { Console.WriteLine("Please provide a correct position ex: --position 120.5,1370.312,769.2"); return; } if (opts.Rotation == null || opts.Rotation.Count() != 4) { Console.WriteLine("Plase provide a correct rotation ex: --rotation 0,0,0,1"); return; } if (opts.Name == null) { Console.WriteLine("Plase output directory name with --name"); return; } Init(args); var position = new Vector3(opts.Position.ElementAt(0), opts.Position.ElementAt(1), opts.Position.ElementAt(2)); var rotation = new Quaternion(opts.Rotation.ElementAt(0), opts.Rotation.ElementAt(1), opts.Rotation.ElementAt(2), opts.Rotation.ElementAt(3)); var ytyp = new YtypFile(); ytyp.Load(opts.Ytyp); if (!File.Exists(opts.Name + ".original.ytyp")) { File.Copy(opts.Ytyp, opts.Name + ".original.ytyp"); } MCMloArchetypeDef mlo = null; for (int i = 0; i < ytyp.CMapTypes.MloArchetypes.Count; i++) { if (opts.MloName == null) { mlo = ytyp.CMapTypes.MloArchetypes[i]; break; } else { uint mloNameHash = Jenkins.Hash(opts.MloName.ToLowerInvariant()); if (mloNameHash == ytyp.CMapTypes.MloArchetypes[i].Name) { Console.Error.WriteLine("Found MLO => " + opts.MloName); mlo = ytyp.CMapTypes.MloArchetypes[i]; break; } } } if (mlo == null) { Console.WriteLine("MLO archetype not found"); return; } for (int roomId = 0; roomId < mlo.Rooms.Count; roomId++) { var room = mlo.Rooms[roomId]; var ymap = new YmapFile(); var ymapEntities = new List <MCEntityDef>(); Console.WriteLine("Room => " + room.Name + " (" + room.AttachedObjects.Count + " entities)"); for (int i = 0; i < room.AttachedObjects.Count; i++) { int idx = (int)room.AttachedObjects[i]; if (idx >= mlo.Entities.Count) { continue; } var entity = mlo.Entities[idx]; var entityRotation = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W); Utils.Mlo2World(entity, mlo, position, rotation); entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD; if (entity.Guid == 0) { var random = new Random(); do { entity.Guid = (uint)random.Next(1000000, Int32.MaxValue); }while (mlo.Entities.Count(e => e.Guid == entity.Guid) == 1); Console.WriteLine("[" + i + "] Setting random GUID => " + entity.Guid); } ymapEntities.Add(entity); } ymap.CMapData.Entities = ymapEntities; var extents = Utils.CalcExtents(ymap.CMapData.Entities); ymap.CMapData.EntitiesExtentsMin = extents[0][0]; ymap.CMapData.EntitiesExtentsMax = extents[0][1]; ymap.CMapData.StreamingExtentsMin = extents[1][0]; ymap.CMapData.StreamingExtentsMax = extents[1][1]; Console.WriteLine(extents[0][0].X + " " + extents[0][0].Y + " " + extents[0][0].Z); Console.WriteLine(extents[0][1].X + " " + extents[0][1].Y + " " + extents[0][1].Z); Directory.CreateDirectory(opts.Name); ymap.Save(opts.Name + "\\" + room.Name + ".ymap"); } if (mlo.EntitySets != null) { for (int i = 0; i < mlo.EntitySets.Count; i++) { var entitySet = mlo.EntitySets[i]; Directory.CreateDirectory(opts.Name + "\\entitysets\\" + entitySet.Name); for (int roomId = 0; roomId < mlo.Rooms.Count; roomId++) { var room = mlo.Rooms[roomId]; var ymap = new YmapFile(); var ymapEntities = new List <MCEntityDef>(); Console.WriteLine("EntitySet => " + entitySet.Name + " [" + room.Name + "] (" + entitySet.Entities.Count + " entities)"); for (int j = 0; j < entitySet.Entities.Count; j++) { int targetRoom = (int)entitySet.Locations[j]; if (targetRoom != roomId) { continue; } var entity = entitySet.Entities[j]; var entityRotation = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W); Utils.Mlo2World(entity, mlo, position, rotation); entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD; if (entity.Guid == 0) { var random = new Random(); do { entity.Guid = (uint)random.Next(1000000, Int32.MaxValue); }while (mlo.Entities.Count(e => e.Guid == entity.Guid) == 1); Console.WriteLine("[" + i + "] Setting random GUID => " + entity.Guid); } ymapEntities.Add(entity); } ymap.CMapData.Entities = ymapEntities; var extents = Utils.CalcExtents(ymap.CMapData.Entities); ymap.CMapData.EntitiesExtentsMin = extents[0][0]; ymap.CMapData.EntitiesExtentsMax = extents[0][1]; ymap.CMapData.StreamingExtentsMin = extents[1][0]; ymap.CMapData.StreamingExtentsMax = extents[1][1]; Console.WriteLine(extents[0][0].X + " " + extents[0][0].Y + " " + extents[0][0].Z); Console.WriteLine(extents[0][1].X + " " + extents[0][1].Y + " " + extents[0][1].Z); ymap.Save(opts.Name + "\\entitysets\\" + entitySet.Name + "\\entityset_" + entitySet.Name + "_" + room.Name + ".ymap"); } } } /* * for(int portalId=0; portalId < mlo.Portals.Count; portalId++) * { * var portal = mlo.Portals[portalId]; * var ymap = new YmapFile(); * var ymapEntities = new List<MCEntityDef>(); * var entitiesExtents = new List<Tuple<Vector3, Vector3>>(); * var streamingExtents = new List<Tuple<Vector3, Vector3>>(); * * Console.WriteLine("Portal => " + portalId + " (" + portal.AttachedObjects.Count + " entities)"); * * for (int i = 0; i < portal.AttachedObjects.Count; i++) * { * int idx = (int)portal.AttachedObjects[i]; * * if (idx >= mlo.Entities.Count) * continue; * * var entity = mlo.Entities[idx]; * var entityRotation = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W); * * Utils.Mlo2World(entity, mlo, position, rotation); * * entity.LodLevel = Unk_1264241711.LODTYPES_DEPTH_HD; * * if (entity.Guid == 0) * { * var random = new Random(); * * do * { * entity.Guid = (uint)random.Next(1000000, Int32.MaxValue); * } * while (mlo.Entities.Count(e => e.Guid == entity.Guid) == 1); * * Console.WriteLine("[" + i + "] Setting random GUID => " + entity.Guid); * } * * ymapEntities.Add(entity); * } * * ymap.CMapData.Entities = ymapEntities; * * var extents = Utils.CalcExtents(ymap.CMapData.Entities); * * ymap.CMapData.EntitiesExtentsMin = extents[0][0]; * ymap.CMapData.EntitiesExtentsMax = extents[0][1]; * ymap.CMapData.StreamingExtentsMin = extents[1][0]; * ymap.CMapData.StreamingExtentsMax = extents[1][1]; * * Console.WriteLine(extents[0][0].X + " " + extents[0][0].Y + " " + extents[0][0].Z); * Console.WriteLine(extents[0][1].X + " " + extents[0][1].Y + " " + extents[0][1].Z); * * Directory.CreateDirectory(opts.Name); * * ymap.Save(opts.Name + "\\portal_" + portalId.ToString().PadLeft(3, '0') + ".ymap"); * * var data = new JObject() * { * ["corners"] = new JArray() * { * new JObject() { ["x"] = portal.Corners[0][0], ["y"] = portal.Corners[0][1], ["z"] = portal.Corners[0][2] }, * new JObject() { ["x"] = portal.Corners[1][0], ["y"] = portal.Corners[1][1], ["z"] = portal.Corners[1][2] }, * new JObject() { ["x"] = portal.Corners[2][0], ["y"] = portal.Corners[2][1], ["z"] = portal.Corners[2][2] }, * new JObject() { ["x"] = portal.Corners[3][0], ["y"] = portal.Corners[3][1], ["z"] = portal.Corners[3][2] }, * }, * ["flags"] = portal.Flags, * ["mirrorPriority"] = portal.MirrorPriority, * ["opacity"] = portal.Opacity, * ["roomFrom"] = portal.RoomFrom, * ["roomTo"] = portal.RoomTo, * }; * * var jsonString = JsonConvert.SerializeObject(data, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented }); * * File.WriteAllText(opts.Name + "\\portal_" + portalId.ToString().PadLeft(3, '0') + ".json", jsonString); * } */ }); }
public RenderableLODLights GetRenderableLODLights(YmapFile ymap) { return(lodlights.Get(ymap)); }
private void startButton_Click(object sender, EventArgs e) { timerTime = DateTime.Now; watch = new System.Threading.Timer(Tick, null, 0, 10); cancelButton.Enabled = true; var errorFiles = new List <string>() { }; new Thread(() => { Thread.CurrentThread.IsBackground = true; //while (cancelLoop) //{ for (var j = 0; j < CurrentList.Items.Count; j++) { string filename = CurrentList.Items[j].ToString(); FilesAddedLabel.Text = "Processing " + Path.GetFileName(filename) + " (" + (j + 1) + " of " + CurrentList.Items.Count + ")"; Vector3 moveVec = new Vector3(float.Parse(xMove.Text), float.Parse(yMove.Text), float.Parse(zMove.Text)); //Quaternion rotVec = Quaternion.RotationYawPitchRoll(float.Parse(xRotate.Text), float.Parse(yRotate.Text), float.Parse(zRotate.Text)); if (backupFilesToolStripMenuItem.Checked) { if (!filename.Contains(".rpf")) { File.Copy(filename, $"{filename}.old", true); } else { string fileDirectory = StringFunctions.TopMostRPF(filename); File.Copy(fileDirectory, Path.Combine(fileDirectory, ".old")); } } if (filename.EndsWith(".ybn")) { YbnFile ybn = new YbnFile(); RpfDirectoryEntry RPFFilesDirectory; byte[] oldData; if (filename.Contains(".rpf")) { string fileDirectory = StringFunctions.TopMostRPF(filename); if (File.Exists(filename)) { RPFFilesDirectory = null; oldData = File.ReadAllBytes(filename); } else { RpfFile TopRPF = new RpfFile(fileDirectory, fileDirectory); TopRPF.ScanStructure(null, null); (RPFFilesDirectory, oldData) = RPFFunctions.GetFileData(TopRPF, Path.GetFileName(filename)); } } else { RPFFilesDirectory = null; oldData = File.ReadAllBytes(filename); } try { ybn.Load(oldData); if (ybn.Bounds != null) { ybn.Bounds.BoxCenter += moveVec; ybn.Bounds.BoxMax += moveVec; ybn.Bounds.BoxMin += moveVec; ybn.Bounds.SphereCenter += moveVec; BoundComposite boundcomp = ybn.Bounds as BoundComposite; var compchilds = boundcomp?.Children?.data_items; if (boundcomp.BVH != null) { Vector3 boundcompBBC = MathFunctions.ConvertToVec3(boundcomp.BVH.BoundingBoxCenter); Vector3 boundcompBBMax = MathFunctions.ConvertToVec3(boundcomp.BVH.BoundingBoxMax); Vector3 boundcompBBMin = MathFunctions.ConvertToVec3(boundcomp.BVH.BoundingBoxMin); boundcomp.BVH.BoundingBoxCenter = new Vector4(boundcompBBC + moveVec, boundcomp.BVH.BoundingBoxCenter.W); boundcomp.BVH.BoundingBoxMax = new Vector4(boundcompBBMax + moveVec, boundcomp.BVH.BoundingBoxMax.W); boundcomp.BVH.BoundingBoxMin = new Vector4(boundcompBBMin + moveVec, boundcomp.BVH.BoundingBoxMin.W); } if (compchilds != null) { for (int i = 0; i < compchilds.Length; i++) { compchilds[i].BoxCenter += moveVec; compchilds[i].BoxMax += moveVec; compchilds[i].BoxMin += moveVec; compchilds[i].SphereCenter += moveVec; BoundBVH bgeom = compchilds[i] as BoundBVH; if (bgeom != null) { if (bgeom.BVH != null) { Vector3 bgeomBBC = MathFunctions.ConvertToVec3(bgeom.BVH.BoundingBoxCenter); Vector3 bgeomBBMax = MathFunctions.ConvertToVec3(bgeom.BVH.BoundingBoxMax); Vector3 bgeomBBMin = MathFunctions.ConvertToVec3(bgeom.BVH.BoundingBoxMin); bgeom.BVH.BoundingBoxCenter = new Vector4(bgeomBBC + moveVec, bgeom.BVH.BoundingBoxCenter.W); bgeom.BVH.BoundingBoxMax = new Vector4(bgeomBBMax + moveVec, bgeom.BVH.BoundingBoxMax.W); bgeom.BVH.BoundingBoxMin = new Vector4(bgeomBBMin + moveVec, bgeom.BVH.BoundingBoxMin.W); } bgeom.CenterGeom = bgeom.CenterGeom + moveVec; } } } } byte[] newData = ybn.Save(); if (filename.Contains(".rpf")) { if (File.Exists(filename)) { RPFFilesDirectory = null; oldData = File.ReadAllBytes(filename); } else { RPFFunctions.AddFileBackToRPF(RPFFilesDirectory, filename, newData); } } else { File.WriteAllBytes(filename, newData); } } catch (Exception) { errorFiles.Add(filename); } } else if (filename.EndsWith(".ymap")) { YmapFile ymap = new YmapFile(); RpfDirectoryEntry RPFFilesDirectory; byte[] oldData; if (filename.Contains(".rpf")) { string fileDirectory = StringFunctions.TopMostRPF(filename); if (File.Exists(filename)) { RPFFilesDirectory = null; oldData = File.ReadAllBytes(filename); } else { RpfFile TopRPF = new RpfFile(fileDirectory, fileDirectory); TopRPF.ScanStructure(null, null); (RPFFilesDirectory, oldData) = RPFFunctions.GetFileData(TopRPF, Path.GetFileName(filename)); } } else { RPFFilesDirectory = null; oldData = File.ReadAllBytes(filename); } try { ymap.Load(oldData); if (ymap.CarGenerators != null) { foreach (YmapCarGen yEnts in ymap.CarGenerators) { yEnts.SetPosition(yEnts.Position + moveVec); //yEnts.Orientation = Quaternion.Add(yEnts.Orientation, rotVec); } } if (ymap.AllEntities != null) { foreach (YmapEntityDef yEnts in ymap.AllEntities) { yEnts.SetPosition(yEnts.Position + moveVec); //yEnts.Orientation = Quaternion.Add(yEnts.Orientation, rotVec); } } if (ymap.DistantLODLights != null) { int lightCount = ymap._CMapData.DistantLODLightsSOA.position.Count1; for (int i = 0; i < lightCount; i++) { Vector3 vector3 = ymap.DistantLODLights.positions[i].ToVector3() + moveVec; MetaVECTOR3 metaVec = new MetaVECTOR3 { x = vector3.X, y = vector3.Y, z = vector3.Z }; ymap.DistantLODLights.positions[i] = metaVec; } } if (ymap.GrassInstanceBatches != null) { foreach (YmapGrassInstanceBatch yEnts in ymap.GrassInstanceBatches) { yEnts.Position += moveVec; yEnts.AABBMin += moveVec; yEnts.AABBMax += moveVec; } } ymap._CMapData.streamingExtentsMax = ymap.CMapData.streamingExtentsMax + moveVec; ymap._CMapData.streamingExtentsMin = ymap.CMapData.streamingExtentsMin + moveVec; ymap._CMapData.entitiesExtentsMax = ymap.CMapData.entitiesExtentsMax + moveVec; ymap._CMapData.entitiesExtentsMin = ymap.CMapData.entitiesExtentsMin + moveVec; byte[] newData = ymap.Save(); if (filename.Contains(".rpf")) { if (File.Exists(filename)) { RPFFilesDirectory = null; oldData = File.ReadAllBytes(filename); } else { RPFFunctions.AddFileBackToRPF(RPFFilesDirectory, filename, newData); } } else { File.WriteAllBytes(filename, newData); } } catch (Exception) { errorFiles.Add(filename); } } } if (errorFiles.Count != 0) { string message = "The following file(s) were corrupted and were not edited.\n\n"; foreach (string item in errorFiles) { message = message + item + "\n"; } MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } FilesAddedLabel.Text = "Complete"; cancelButton.Enabled = false; watch.Dispose(); //} }).Start(); }
private void EntitySearchButton_Click(object sender, EventArgs e) { var s = EntitySearchTextBox.Text; var loadedOnly = EntitySearchLoadedOnlyCheckBox.Checked; var gfc = WorldForm.GameFileCache; if (!gfc.IsInited) { MessageBox.Show("Please wait for CodeWalker to initialise."); return; } if (s.Length == 0) { MessageBox.Show("Please enter a search term."); return; } if (s.Length < 2) { MessageBox.Show("You don't really want to search for that do you?"); return; } EntitySearchTextBox.Enabled = false; EntitySearchButton.Enabled = false; EntitySearchAbortButton.Enabled = true; EntitySearchLoadedOnlyCheckBox.Enabled = false; EntitySearchExportResultsButton.Enabled = false; AbortOperation = false; EntityResults.Clear(); EntityResultsListView.VirtualListSize = 0; s = s.ToLowerInvariant(); //var h = JenkHash.GenHash(s, JenkHashInputEncoding.UTF8); Task.Run(() => { var rpfman = gfc.RpfMan; var rpflist = loadedOnly ? gfc.ActiveMapRpfFiles.Values.ToList() : rpfman.AllRpfs; var results = new List <YmapEntityDef>(); foreach (var rpf in rpflist) { foreach (var entry in rpf.AllEntries) { try { if (AbortOperation) { EntitySearchUpdateStatus("Search aborted!"); EntitySearchComplete(); return; } if (entry.NameLower.EndsWith(".ymap")) { EntitySearchUpdateStatus(entry.Path); YmapFile ymap = rpfman.GetFile <YmapFile>(entry); if (ymap == null) { continue; } if (ymap.AllEntities == null) { continue; } foreach (var ent in ymap.AllEntities) { //if (ent._CEntityDef.archetypeName.Hash == h) if (ent.Name.ToLowerInvariant().Contains(s)) { EntitySearchAddResult(ent); results.Add(ent); } } } } catch (Exception ex) { EntitySearchUpdateStatus(ex.Message); } } } EntitySearchUpdateStatus("Search complete. " + results.Count.ToString() + " entities found."); EntitySearchComplete(); }); }
static void HandleBuildCacheOptions(string[] args) { CommandLine.Parse <BuildCacheOptions>(args, (opts, gOpts) => { Init(args); dynamic cache = new JObject(); cache["ymap"] = new JArray(); cache["ytyp"] = new JArray(); Console.WriteLine("Building strings"); var names = FileUtilities.GetAllFileNamesWithoutExtension(Settings.Default.GTAFolder); foreach (var name in names) { Utils.Hash(name.ToLowerInvariant().Replace("_children", "")); } using (StreamWriter writer = new StreamWriter(AssemblyDirectory + "\\strings.txt")) { foreach (var kvp in Jenkins.Index) { writer.Write(kvp.Value + "\n"); } } Console.WriteLine("Bulding cache"); ArchiveUtilities.ForEachFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { string fileNameWithoutExtension = FileUtilities.RemoveExtension(file.Name); try { if (file.Name.EndsWith(".ymap")) { Console.WriteLine(fullFileName); var ymap = new YmapFile(); using (MemoryStream ms = new MemoryStream()) { file.Export(ms); ymap.Load(ms, new object[] { true }); } dynamic entry = new JObject() { ["name"] = fileNameWithoutExtension, ["path"] = fullFileName, ["hash"] = Jenkins.Hash(fileNameWithoutExtension), ["parent"] = (uint)ymap.CMapData.Parent, ["entitiesExtentsMin"] = new JObject() { ["x"] = ymap.CMapData.EntitiesExtentsMin.X, ["y"] = ymap.CMapData.EntitiesExtentsMin.Y, ["z"] = ymap.CMapData.EntitiesExtentsMin.Z, }, ["entitiesExtentsMax"] = new JObject() { ["x"] = ymap.CMapData.EntitiesExtentsMax.X, ["y"] = ymap.CMapData.EntitiesExtentsMax.Y, ["z"] = ymap.CMapData.EntitiesExtentsMax.Z, }, ["mloInstances"] = new JArray(), }; if (ymap.CMapData.MloInstances != null) { for (int i = 0; i < ymap.CMapData.MloInstances.Count; i++) { var mloInstance = ymap.CMapData.MloInstances[i]; var mloInstanceEntry = new JObject() { ["name"] = ymap.CMapData.MloInstances[i].ArchetypeName, ["position"] = new JObject() { ["x"] = mloInstance.Position.X, ["y"] = mloInstance.Position.Y, ["z"] = mloInstance.Position.Z, }, ["rotation"] = new JObject() { ["x"] = mloInstance.Rotation.X, ["y"] = mloInstance.Rotation.Y, ["z"] = mloInstance.Rotation.Z, ["w"] = mloInstance.Rotation.W, } }; entry["mloInstances"].Add(mloInstanceEntry); } } cache["ymap"].Add(entry); } else if (file.Name.EndsWith(".ytyp")) { Console.WriteLine(fullFileName); var ytyp = new YtypFile(); using (MemoryStream ms = new MemoryStream()) { file.Export(ms); ytyp.Load(ms); } dynamic entry = new JObject() { ["name"] = fileNameWithoutExtension, ["path"] = fullFileName, ["hash"] = Jenkins.Hash(fileNameWithoutExtension), ["mloArchetypes"] = new JArray(), }; if (ytyp.CMapTypes.MloArchetypes != null) { for (int i = 0; i < ytyp.CMapTypes.MloArchetypes.Count; i++) { var archetype = ytyp.CMapTypes.MloArchetypes[i]; var mloEntry = new JObject { ["name"] = archetype.Name, ["rooms"] = new JArray(), }; if (archetype.Rooms != null) { for (int j = 0; j < archetype.Rooms.Count; j++) { var room = archetype.Rooms[j]; var roomEntry = new JObject { ["name"] = room.Name, ["bbMin"] = new JObject() { ["x"] = room.BbMin.X, ["y"] = room.BbMin.Y, ["z"] = room.BbMin.Z, }, ["bbMax"] = new JObject() { ["x"] = room.BbMax.X, ["y"] = room.BbMax.Y, ["z"] = room.BbMax.Z, } }; ((JArray)mloEntry["rooms"]).Add(roomEntry); } } entry["mloArchetypes"].Add(mloEntry); } } cache["ytyp"].Add(entry); } } catch (Exception e) { Console.WriteLine(e.Message); } }); var jsonString = JsonConvert.SerializeObject(cache, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.None }); File.WriteAllText(AssemblyDirectory + "\\cache.json", jsonString); }); }
static void Main(string[] args) { EnsurePath(); EnsureKeys(); EnsureCache(); CommandLine.Parse <GenPropDefsOptions>(args, opts => { if (opts.InputFiles != null) { var inputFiles = Utils.Expand(opts.InputFiles); var ytyp = new YtypFile(); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; string name = ""; var split = fileInfo.Name.Split('.'); for (int j = 0; j < split.Length; j++) { if (j < split.Length - 1) { if (j > 0) { name += "."; } name += split[j]; } } Console.WriteLine(name); try { switch (fileInfo.Extension) { case ".ydr": { var ydr = new YdrFile(); var arch = new RageLib.GTA5.ResourceWrappers.PC.Meta.Structures.CBaseArchetypeDef(); var nameHash = (MetaName)Jenkins.Hash(name); ydr.Load(fileInfo.FullName); arch.Name = nameHash; arch.AssetName = nameHash; arch.TextureDictionary = nameHash; arch.PhysicsDictionary = (MetaName)Jenkins.Hash("prop_" + name); arch.Flags = 32; arch.AssetType = Unk_1991964615.ASSET_TYPE_DRAWABLE; arch.BbMin = (Vector3)(Vector4)ydr.Drawable.BoundingBoxMin; arch.BbMax = (Vector3)(Vector4)ydr.Drawable.BoundingBoxMax; arch.BsCentre = (Vector3)ydr.Drawable.BoundingCenter; arch.BsRadius = ydr.Drawable.BoundingSphereRadius; arch.LodDist = 500f; arch.HdTextureDist = 5; ytyp.CMapTypes.Archetypes.Add(arch); break; } case ".ydd": // TODO { break; } default: break; } } catch (Exception e) { Console.Error.WriteLine("ERROR => " + e.Message); } } string path = (opts.Directory == null) ? @".\props.ytyp" : opts.Directory + @"\props.ytyp"; ytyp.Save(path); } }); CommandLine.Parse <ImportMetaOptions>(args, opts => { if (opts.InputFiles != null && opts.Directory != null) { var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; Console.WriteLine(fileInfo.FullName); var doc = new XmlDocument(); doc.Load(fileInfo.FullName); var res = new ResourceFile_GTA5_pc <MetaFile>(); res.Version = 2; res.ResourceData = XmlMeta.GetMeta(doc);; string fileName = fileInfo.FullName.Replace(".xml", ""); res.Save(fileName); } } }); CommandLine.Parse <ExportMetaOptions>(args, opts => { if (opts.InputFiles != null && opts.Directory != null) { var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; Console.WriteLine(fileInfo.FullName); var res = new ResourceFile_GTA5_pc <MetaFile>(); res.Load(fileInfo.FullName); var xml = MetaXml.GetXml(res.ResourceData); File.WriteAllText(opts.Directory + "\\" + fileInfo.Name + ".xml", xml); } } }); CommandLine.Parse <InjectEntitiesOptions>(args, opts => { if (opts.Ymap == null) { Console.WriteLine("Please provide source ymap file with --ymap"); return; } if (opts.Ytyp == null) { Console.WriteLine("Please provide source ytyp file with --ytyp"); return; } if (opts.Room == null) { Console.WriteLine("Please provide mlo room name with --room"); return; } if (opts.Position == null || opts.Position.Count() != 3) { Console.WriteLine("Please provide a correct position ex: --position 120.5,1370.312,769.2"); return; } if (opts.Rotation == null || opts.Rotation.Count() != 4) { Console.WriteLine("Plase provide a correct rotation ex: --rotation 0,0,0,1"); return; } if (opts.Name == null) { Console.WriteLine("Plase provide new generated ytyp name with --name"); return; } var position = new Vector3(opts.Position.ElementAt(0), opts.Position.ElementAt(1), opts.Position.ElementAt(2)); var rotation = new Quaternion(opts.Rotation.ElementAt(0), opts.Rotation.ElementAt(1), opts.Rotation.ElementAt(2), opts.Rotation.ElementAt(3)); var ymap = new YmapFile(); var ytyp = new YtypFile(); ymap.Load(opts.Ymap); ytyp.Load(opts.Ytyp); RageLib.GTA5.ResourceWrappers.PC.Meta.Structures.CMloArchetypeDef mlo = null; for (int i = 0; i < ytyp.CMapTypes.MloArchetypes.Count; i++) { mlo = ytyp.CMapTypes.MloArchetypes[i]; break; } if (mlo == null) { Console.WriteLine("MLO archetype not found"); return; } RageLib.GTA5.ResourceWrappers.PC.Meta.Structures.CMloRoomDef room = null; for (int i = 0; i < mlo.Rooms.Count; i++) { if (mlo.Rooms[i].Name == opts.Room) { room = mlo.Rooms[i]; break; } } if (room == null) { Console.WriteLine("MLO room not found"); return; } var mloEntities = new List <RageLib.GTA5.ResourceWrappers.PC.Meta.Structures.CEntityDef>(); var attachedObjects = new List <uint>(); mloEntities.AddRange(mlo.Entities); attachedObjects.AddRange(room.AttachedObjects); for (int i = 0; i < ymap.CMapData.Entities.Count; i++) { var entity = ymap.CMapData.Entities[i]; var mloRot = rotation; var objRot = new Quaternion(entity.Rotation.X, entity.Rotation.Y, entity.Rotation.Z, entity.Rotation.W); var rotationDiff = objRot * mloRot; // Multiply initial entity rotation by mlo rotation entity.Position -= position; // Substract mlo world coords from entity world coords entity.Position = Utils.RotateTransform(Quaternion.Conjugate(mloRot), entity.Position, Vector3.Zero); // Rotate entity around center of mlo instance (mlo entities rotations in space are inverted) entity.Rotation = new Vector4(rotationDiff.X, rotationDiff.Y, rotationDiff.Z, rotationDiff.W); mloEntities.Add(entity); attachedObjects.Add((uint)mloEntities.IndexOf(entity)); } mlo.Entities = mloEntities; room.AttachedObjects = attachedObjects; ytyp.Save(opts.Name.EndsWith(".ytyp") ? opts.Name : opts.Name + ".ytyp"); }); CommandLine.Parse <FindOptions>(args, opts => { if (opts.Position == null || opts.Position.Count != 3) { Console.Error.WriteLine("Please specify position with -p --position"); return; } if (Cache == null) { Console.Error.WriteLine("Please build cache first with buildcache"); return; } var c = CultureInfo.InvariantCulture; for (int i = 0; i < Cache["ymap"].Count; i++) { var cYmap = Cache["ymap"][i]; var entitiesExtentsMin = new Vector3((float)cYmap["entitiesExtentsMin"]["x"], (float)cYmap["entitiesExtentsMin"]["y"], (float)cYmap["entitiesExtentsMin"]["z"]); var entitiesExtentsMax = new Vector3((float)cYmap["entitiesExtentsMax"]["x"], (float)cYmap["entitiesExtentsMax"]["y"], (float)cYmap["entitiesExtentsMax"]["z"]); if ( opts.Position[0] >= entitiesExtentsMin.X && opts.Position[0] <= entitiesExtentsMax.X && opts.Position[1] >= entitiesExtentsMin.Y && opts.Position[1] <= entitiesExtentsMax.Y && opts.Position[2] >= entitiesExtentsMin.Z && opts.Position[2] <= entitiesExtentsMax.Z ) { Console.WriteLine("ymap: " + ((string)cYmap["path"]).Split('\\').Last()); for (int j = 0; j < cYmap["mloInstances"].Count; j++) { var cMloInstance = cYmap["mloInstances"][j]; var cMloInstanceHash = (uint)cMloInstance["name"]; var instancePos = new Vector3((float)cMloInstance["position"]["x"], (float)cMloInstance["position"]["y"], (float)cMloInstance["position"]["z"]); var instanceRot = new Quaternion((float)cMloInstance["rotation"]["x"], (float)cMloInstance["rotation"]["y"], (float)cMloInstance["rotation"]["z"], (float)cMloInstance["rotation"]["w"]); for (int k = 0; k < Cache["ytyp"].Count; k++) { var cYtyp = Cache["ytyp"][k]; var cYtypHash = (uint)cYtyp["hash"]; for (int l = 0; l < cYtyp["mloArchetypes"].Count; l++) { var cMloArch = cYtyp["mloArchetypes"][l]; var cMloArchHash = (uint)cMloArch["name"]; if (cMloInstanceHash == cMloArchHash) { Console.WriteLine(" ytyp => " + ((string)cYtyp["path"]).Split('\\').Last()); Console.WriteLine(" mlo => " + Jenkins.GetString(cMloArchHash)); Console.WriteLine(" position => " + instancePos.X.ToString(c) + "," + instancePos.Y.ToString(c) + "," + instancePos.Z.ToString(c)); Console.WriteLine(" rotation => " + instanceRot.X.ToString(c) + "," + instanceRot.Y.ToString(c) + "," + instanceRot.Z.ToString(c) + "," + instanceRot.W.ToString(c)); for (int m = 0; m < cMloArch["rooms"].Count; m++) { var cMloRoom = cMloArch["rooms"][m]; var roomBbMin = new Vector3((float)cMloRoom["bbMin"]["x"], (float)cMloRoom["bbMin"]["y"], (float)cMloRoom["bbMin"]["z"]); var roomBbMax = new Vector3((float)cMloRoom["bbMax"]["x"], (float)cMloRoom["bbMax"]["y"], (float)cMloRoom["bbMax"]["z"]); var roomBbMinWorld = instancePos + roomBbMin; var roomBbMaxWorld = instancePos + roomBbMax; roomBbMinWorld = Utils.RotateTransform(Quaternion.Conjugate(instanceRot), roomBbMinWorld, Vector3.Zero); roomBbMaxWorld = Utils.RotateTransform(Quaternion.Conjugate(instanceRot), roomBbMaxWorld, Vector3.Zero); if ( opts.Position[0] >= roomBbMinWorld.X && opts.Position[0] <= roomBbMaxWorld.X && opts.Position[1] >= roomBbMinWorld.Y && opts.Position[1] <= roomBbMaxWorld.Y && opts.Position[2] >= roomBbMinWorld.Z && opts.Position[2] <= roomBbMaxWorld.Z ) { Console.WriteLine(" room => " + cMloRoom["name"]); } } } } } } Console.WriteLine(""); } } }); CommandLine.Parse <BuildCacheOptions>(args, opts => { dynamic cache = new JObject(); cache["ymap"] = new JArray(); cache["ytyp"] = new JArray(); ArchiveUtilities.ForEachFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { Console.WriteLine(fullFileName); string fileNameWithoutExtension = file.Name.Split('.').First(); Jenkins.Ensure(fileNameWithoutExtension); if (file.Name.EndsWith(".ymap")) { var ymap = new YmapFile(); using (MemoryStream ms = new MemoryStream()) { file.Export(ms); ymap.Load(ms); } dynamic entry = new JObject() { ["name"] = fileNameWithoutExtension, ["path"] = fullFileName, ["hash"] = Jenkins.Hash(fileNameWithoutExtension), ["entitiesExtentsMin"] = new JObject() { ["x"] = ymap.CMapData.EntitiesExtentsMin.X, ["y"] = ymap.CMapData.EntitiesExtentsMin.Y, ["z"] = ymap.CMapData.EntitiesExtentsMin.Z, }, ["entitiesExtentsMax"] = new JObject() { ["x"] = ymap.CMapData.EntitiesExtentsMax.X, ["y"] = ymap.CMapData.EntitiesExtentsMax.Y, ["z"] = ymap.CMapData.EntitiesExtentsMax.Z, }, ["mloInstances"] = new JArray(), }; if (ymap.CMapData.MloInstances != null) { for (int i = 0; i < ymap.CMapData.MloInstances.Count; i++) { var mloInstance = ymap.CMapData.MloInstances[i]; var mloInstanceEntry = new JObject() { ["name"] = ymap.CMapData.MloInstances[i].ArchetypeName, ["position"] = new JObject() { ["x"] = mloInstance.Position.X, ["y"] = mloInstance.Position.Y, ["z"] = mloInstance.Position.Z, }, ["rotation"] = new JObject() { ["x"] = mloInstance.Rotation.X, ["y"] = mloInstance.Rotation.Y, ["z"] = mloInstance.Rotation.Z, ["w"] = mloInstance.Rotation.W, } }; entry["mloInstances"].Add(mloInstanceEntry); } } cache["ymap"].Add(entry); } else if (file.Name.EndsWith(".ytyp")) { var ytyp = new YtypFile(); using (MemoryStream ms = new MemoryStream()) { file.Export(ms); ytyp.Load(ms); } dynamic entry = new JObject() { ["name"] = fileNameWithoutExtension, ["path"] = fullFileName, ["hash"] = Jenkins.Hash(fileNameWithoutExtension), ["mloArchetypes"] = new JArray(), }; if (ytyp.CMapTypes.MloArchetypes != null) { for (int i = 0; i < ytyp.CMapTypes.MloArchetypes.Count; i++) { var archetype = ytyp.CMapTypes.MloArchetypes[i]; var mloEntry = new JObject { ["name"] = archetype.Name, ["rooms"] = new JArray(), }; if (archetype.Rooms != null) { for (int j = 0; j < archetype.Rooms.Count; j++) { var room = archetype.Rooms[j]; var roomEntry = new JObject { ["name"] = room.Name, ["bbMin"] = new JObject() { ["x"] = room.BbMin.X, ["y"] = room.BbMin.Y, ["z"] = room.BbMin.Z, }, ["bbMax"] = new JObject() { ["x"] = room.BbMax.X, ["y"] = room.BbMax.Y, ["z"] = room.BbMax.Z, } }; ((JArray)mloEntry["rooms"]).Add(roomEntry); } } entry["mloArchetypes"].Add(mloEntry); } } cache["ytyp"].Add(entry); } }); var jsonString = JsonConvert.SerializeObject(cache, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.None }); File.WriteAllText(AssemblyDirectory + "\\cache.json", jsonString); using (StreamWriter writer = new StreamWriter(AssemblyDirectory + "\\strings.txt")) { foreach (var kvp in Jenkins.Index) { writer.Write(kvp.Value + "\n"); } } }); if (args.Length == 0 || args[0] == "help") { Console.Error.Write(CommandLine.GenHelp()); return; } }