static void HandleCompileGxt2Options(string[] args) { CommandLine.Parse <CompileGxt2Optionns>(args, (opts, gOpts) => { Init(args); if (opts.OutputDirectory == null) { Console.WriteLine("Please provide output directory with -o --output"); return; } var entries = new Dictionary <uint, string>(); ArchiveUtilities.ForEachBinaryFile(Settings.Default.GTAFolder, (string fullFileName, IArchiveBinaryFile file, RageArchiveEncryption7 encryption) => { if (fullFileName.EndsWith(".gxt2") && fullFileName.ToLowerInvariant().Contains(opts.Lang.ToLowerInvariant())) { Console.WriteLine(fullFileName); var gxt2 = new Gxt2File(); byte[] data = Utils.GetBinaryFileData(file, encryption); gxt2.Load(data); for (int i = 0; i < gxt2.TextEntries.Count; i++) { entries[gxt2.TextEntries[i].Hash] = gxt2.TextEntries[i].Text; } } }); var sb = new StringBuilder(); foreach (var entry in entries) { sb.AppendLine(entry.Key + " = " + entry.Value); } File.WriteAllText(opts.OutputDirectory + "\\" + opts.Lang + ".gxt2.txt", sb.ToString()); }); }
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); } } } } }); }
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; } }
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); * } */ }); }
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 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"); } } } }); }
// 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 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"); } } }); }
static void HandleExtractArchiveOptions(string[] args) { CommandLine.Parse <ExtractArchiveOptions>(args, (opts, gOpts) => { EnsurePath(); EnsureKeys(); if (opts.InputFile == null) { Console.WriteLine("Please provide input archive with -i --input"); return; } if (opts.OutputFolder == null) { Console.WriteLine("Please provide output folder with -o --output"); return; } var fileInfo = new FileInfo(opts.InputFile); var fileStream = new FileStream(opts.InputFile, FileMode.Open); var inputArchive = RageArchiveWrapper7.Open(fileStream, fileInfo.Name); var queue = new List <Tuple <string, RageArchiveWrapper7, bool> >() { new Tuple <string, RageArchiveWrapper7, bool>(fileInfo.FullName, inputArchive, false) }; while (queue.Count > 0) { var fullPath = queue[0].Item1; var rpf = queue[0].Item2; var isTmpStream = queue[0].Item3; queue.RemoveAt(0); ArchiveUtilities.ForEachFile(fullPath.Replace(fileInfo.FullName, ""), rpf.Root, rpf.archive_.Encryption, (string fullFileName, IArchiveFile file, RageArchiveEncryption7 encryption) => { string path = opts.OutputFolder + fullFileName; string dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } Console.WriteLine(fullFileName); if (file.Name.EndsWith(".rpf")) { try { var tmpStream = new FileStream(Path.GetTempFileName(), FileMode.Open); file.Export(tmpStream); RageArchiveWrapper7 archive = RageArchiveWrapper7.Open(tmpStream, file.Name); queue.Add(new Tuple <string, RageArchiveWrapper7, bool>(fullFileName, archive, true)); } catch (Exception e) { Console.Error.WriteLine(e.Message); } } else { if (file.Name.EndsWith(".xml") || file.Name.EndsWith(".meta")) { byte[] data = Utils.GetBinaryFileData((IArchiveBinaryFile)file, encryption); string xml; if (data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF) // Detect BOM { xml = Encoding.UTF8.GetString(data, 3, data.Length - 3); } else { xml = Encoding.UTF8.GetString(data); } File.WriteAllText(path, xml, Encoding.UTF8); } else { file.Export(path); } } }); var stream = (FileStream)rpf.archive_.BaseStream; string fileName = stream.Name; rpf.Dispose(); if (isTmpStream) { File.Delete(fileName); } } }); }
static void HandleCreateArchiveOptions(string[] args) { CommandLine.Parse <CreateArchiveOptions>(args, (opts, gOpts) => { EnsurePath(); EnsureKeys(); if (opts.InputFolder == null) { Console.WriteLine("Please provide input folder with -i --input"); return; } if (opts.OutputFolder == null) { Console.WriteLine("Please provide output folder with -o --output"); return; } if (opts.Name == null) { Console.WriteLine("Please provide rpf name with -n --name"); return; } string rpfPath = opts.OutputFolder + "\\" + opts.Name + ".rpf"; using (RageArchiveWrapper7 rpf = RageArchiveWrapper7.Create(rpfPath)) { var queue = new List <Tuple <string, IArchiveDirectory, RageArchiveWrapper7> >() { new Tuple <string, IArchiveDirectory, RageArchiveWrapper7>(opts.InputFolder, rpf.Root, rpf) }; var subRpfs = new List <Tuple <DirectoryInfo, IArchiveDirectory, RageArchiveWrapper7> >(); rpf.archive_.Encryption = RageArchiveEncryption7.NG; var rpfs = new List <RageArchiveWrapper7>(); while (queue.Count > 0) { var folder = queue[0].Item1; var curr = queue[0].Item2; var currRpf = queue[0].Item3; if (rpfs.IndexOf(currRpf) == -1) { rpfs.Add(currRpf); } Console.WriteLine(folder); queue.RemoveAt(0); string newFolder = null; IArchiveDirectory newCurr = null; RageArchiveWrapper7 newCurrRpf = null; string[] folders = Directory.GetDirectories(folder); string[] files = Directory.GetFiles(folder); for (int i = 0; i < folders.Length; i++) { var folderInfo = new DirectoryInfo(folders[i]); newFolder = folders[i]; if (folders[i].EndsWith(".rpf")) { var tmpStream = new FileStream(Path.GetTempFileName(), FileMode.Open); var subRpf = RageArchiveWrapper7.Create(tmpStream, folderInfo.Name); subRpf.archive_.Encryption = RageArchiveEncryption7.NG; subRpfs.Add(new Tuple <DirectoryInfo, IArchiveDirectory, RageArchiveWrapper7>(folderInfo, curr, subRpf)); newCurr = subRpf.Root; newCurrRpf = subRpf; } else { var directory = curr.CreateDirectory(); directory.Name = folderInfo.Name; newCurr = directory; newCurrRpf = currRpf; } queue.Add(new Tuple <string, IArchiveDirectory, RageArchiveWrapper7>(newFolder, newCurr, newCurrRpf)); } if (folders.Length + files.Length == 0) { Console.WriteLine(" .\\.empty"); var binFile = curr.CreateBinaryFile(); binFile.Name = ".empty"; var ms = new MemoryStream(1); ms.WriteByte(0); ms.Flush(); binFile.Import(ms); } for (int i = 0; i < files.Length; i++) { string file = files[i]; var fileInfo = new FileInfo(file); bool isResource = false; for (int j = 0; j < ResourceFileTypes_GTA5_pc.AllTypes.Count; j++) { var type = ResourceFileTypes_GTA5_pc.AllTypes[j]; if (file.EndsWith(type.Extension)) { Console.WriteLine(" " + file); isResource = true; var resource = curr.CreateResourceFile(); resource.Name = fileInfo.Name; resource.Import(file); break; } } if (!isResource) { Console.WriteLine(" " + file); var binFile = curr.CreateBinaryFile(); binFile.Name = fileInfo.Name; binFile.Import(file); } } } rpfs.Reverse(); for (int i = 0; i < subRpfs.Count; i++) { var subRpf = subRpfs[i]; var file = subRpf.Item2.CreateBinaryFile(); file.Name = subRpf.Item1.Name; subRpf.Item3.Flush(); file.Import(subRpf.Item3.archive_.BaseStream); } for (int i = 0; i < rpfs.Count; i++) { rpfs[i].Flush(); if (i + 1 < rpfs.Count) { var stream = (FileStream)rpfs[i].archive_.BaseStream; string fileName = stream.Name; rpfs[i].Dispose(); File.Delete(fileName); } } } }); }
static void HandleFixArchiveOptions(string[] args) { CommandLine.Parse <FixArchiveOptions>(args, (opts, gOpts) => { EnsurePath(); EnsureKeys(); if (opts.InputFiles != null) { var inputFiles = Utils.Expand(opts.InputFiles); for (int i = 0; i < inputFiles.Length; i++) { var fileInfo = inputFiles[i]; Console.WriteLine(fileInfo.FullName); using (RageArchiveWrapper7 inputArchive = RageArchiveWrapper7.Open(fileInfo.FullName)) { var rpfs = new List <Tuple <string, RageArchiveWrapper7> >(); if (opts.Recursive) { ArchiveUtilities.ForEachFile(fileInfo.FullName.Replace(Settings.Default.GTAFolder, ""), inputArchive.Root, inputArchive.archive_.Encryption, (string fullFileName, IArchiveFile file, RageArchiveEncryption7 encryption) => { if (fullFileName.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase)) { try { var binFile = (RageArchiveBinaryFileWrapper7)file; var tmpStream = new FileStream(Path.GetTempFileName(), FileMode.Open); binFile.Export(tmpStream); RageArchiveWrapper7 archive = RageArchiveWrapper7.Open(tmpStream, file.Name); var wrapper = RageArchiveWrapper7.Open(tmpStream, binFile.Name); rpfs.Add(new Tuple <string, RageArchiveWrapper7>(fullFileName, wrapper)); } catch (Exception e) { Console.Error.WriteLine(e.Message); } } }); rpfs.Sort((a, b) => { return(b.Item1.Replace('\\', '/').Split('/').Length - a.Item1.Replace('\\', '/').Split('/').Length); }); } bool found = false; if (opts.Recursive) { for (int j = 0; j < rpfs.Count; j++) { var fullName = rpfs[j].Item1; var wrapper = rpfs[j].Item2; if (wrapper.archive_.Encryption != RageArchiveEncryption7.None) { Console.WriteLine("SKIP " + fullName); continue; } found = true; wrapper.archive_.Encryption = RageArchiveEncryption7.NG; wrapper.Flush(); wrapper.Dispose(); Console.WriteLine("ENCRYPT " + fullName); } } if (inputArchive.archive_.Encryption != RageArchiveEncryption7.None && !found) { Console.WriteLine("SKIP " + fileInfo.Name); continue; } inputArchive.archive_.Encryption = RageArchiveEncryption7.NG; inputArchive.Flush(); inputArchive.Dispose(); Console.WriteLine("ENCRYPT " + fileInfo.Name); rpfs.Reverse(); for (int j = 0; j < rpfs.Count; j++) { rpfs[j].Item2.Dispose(); } } } } }); }
static void HandleGenColOptions(string[] args) { CommandLine.Parse <GenColOptions>(args, (opts, gOpts) => { if (opts.InputFile == null) { Console.WriteLine("Please provide input file with -i --input"); return; } if (opts.OutputFile == null) { Console.WriteLine("Please provide output file with -o --output"); return; } var inputFileInfos = new FileInfo(opts.InputFile); var outputFileInfos = new FileInfo(opts.OutputFile); if (!inputFileInfos.Exists) { Console.WriteLine("Input file does not exists"); return; } if (inputFileInfos.Extension == ".ydr") { var ydr = new YdrFile(); ydr.Load(inputFileInfos.FullName); var modelData = GenCol_GetModelData(ydr.Drawable.DrawableModelsX); var bComposite = GenCol_CreateBoundComposite(modelData); DMesh3 mesh; if (opts.Mode == "copy") { mesh = new DMesh3(); var triangles = new List <DefaultConvexFace <VertexVector3> >(); for (int g = 0; g < modelData.Geometries.Count; g++) { var mGeometry = modelData.Geometries[g]; for (int i = 0; i < mGeometry.Indices.Count - 2; i += 3) { var vert1 = mGeometry.Vertices[mGeometry.Indices[i + 0]]; var vert2 = mGeometry.Vertices[mGeometry.Indices[i + 1]]; var vert3 = mGeometry.Vertices[mGeometry.Indices[i + 2]]; var triangle = new DefaultConvexFace <VertexVector3>() { Vertices = new VertexVector3[] { vert1, vert2, vert3, } }; triangles.Add(triangle); } } mesh = GenCol_CreateMesh(triangles); } else { var hull = ConvexHull.Create(modelData.Vertices); var hullTriangles = hull.Result.Faces.ToList(); mesh = GenCol_CreateMesh(hullTriangles); } GenCol_Reshape(mesh, opts.Smooth, opts.TriangleCount); mesh = GenCol_CleanVertices(mesh); var quantum = (modelData.BbMax - modelData.BbMin) / (2 ^ opts.Qantum); var bGeometry = new BoundGeometry { Type = 4, Vertices = new ResourceSimpleArray <BoundVertex>(), BoundingBoxCenter = (RAGE_Vector3)modelData.BsCenter, BoundingSphereRadius = modelData.BsRadius, BoundingBoxMin = (RAGE_Vector3)modelData.BbMin, BoundingBoxMax = (RAGE_Vector3)modelData.BbMax, CenterGravity = new RAGE_Vector3(0.0f, 0.0f, 0.0f), CenterGeometry = new RAGE_Vector3(0.0f, 0.0f, 0.0f), Margin = 0.04f, Quantum = new RAGE_Vector3(quantum.X, quantum.Y, quantum.Z), Polygons = new ResourceSimpleArray <BoundPolygon>(), Materials = new ResourceSimpleArray <BoundMaterial>(), MaterialColours = new ResourceSimpleArray <uint_r>(), PolygonMaterialIndices = new ResourceSimpleArray <byte_r>(), Unknown_78h_Data = new ResourceSimpleArray <BoundVertex>(), }; var material = new BoundMaterial(); bGeometry.Materials.Add(material); var matColour = new uint_r { Value = 0 }; bGeometry.MaterialColours.Add(matColour); var meshVertices = mesh.Vertices().ToList(); for (int i = 0; i < meshVertices.Count; i++) { var vertex = meshVertices[i]; var bVertex = new BoundVertex { X = Convert.ToInt16(vertex.x / quantum.X), Y = Convert.ToInt16(vertex.y / quantum.Y), Z = Convert.ToInt16(vertex.z / quantum.Z), }; bGeometry.Vertices.Add(bVertex); bGeometry.Unknown_78h_Data.Add(bVertex); } var meshTriangles = mesh.Triangles().ToList(); for (int i = 0; i < meshTriangles.Count; i++) { var polygon = new BoundPolygon(); var triangle = new BoundPolygonTriangle(); triangle.TriArea = 0.0f; int vidx1 = meshTriangles[i].a; int vidx2 = meshTriangles[i].b; int vidx3 = meshTriangles[i].c; if (vidx1 == -1 || vidx2 == -1 || vidx3 == -1) { continue; } triangle.TriIndex1 = (ushort)((triangle.TriIndex1 & ~0x7FFF) | (vidx1 & 0x7FFF)); triangle.TriIndex2 = (ushort)((triangle.TriIndex2 & ~0x7FFF) | (vidx2 & 0x7FFF)); triangle.TriIndex3 = (ushort)((triangle.TriIndex3 & ~0x7FFF) | (vidx3 & 0x7FFF)); triangle.EdgeIndex1 = 0; triangle.EdgeIndex2 = 1; triangle.EdgeIndex3 = 2; polygon.data = new byte[16]; int offset = 0; byte[] bytes = BitConverter.GetBytes(triangle.TriArea); Buffer.BlockCopy(bytes, 0, polygon.data, offset, bytes.Length); offset += bytes.Length; bytes = BitConverter.GetBytes(triangle.TriIndex1); Buffer.BlockCopy(bytes, 0, polygon.data, offset, bytes.Length); offset += bytes.Length; bytes = BitConverter.GetBytes(triangle.TriIndex2); Buffer.BlockCopy(bytes, 0, polygon.data, offset, bytes.Length); offset += bytes.Length; bytes = BitConverter.GetBytes(triangle.TriIndex3); Buffer.BlockCopy(bytes, 0, polygon.data, offset, bytes.Length); offset += bytes.Length; bytes = BitConverter.GetBytes(triangle.EdgeIndex1); Buffer.BlockCopy(bytes, 0, polygon.data, offset, bytes.Length); offset += bytes.Length; bytes = BitConverter.GetBytes(triangle.EdgeIndex2); Buffer.BlockCopy(bytes, 0, polygon.data, offset, bytes.Length); offset += bytes.Length; bytes = BitConverter.GetBytes(triangle.EdgeIndex3); Buffer.BlockCopy(bytes, 0, polygon.data, offset, bytes.Length); offset += bytes.Length; bGeometry.Polygons.Add(polygon); var matIndex = new byte_r { Value = 0 }; bGeometry.PolygonMaterialIndices.Add(matIndex); } bComposite.Children.Add(bGeometry); if (outputFileInfos.Extension == ".ybn") { var ybn = new YbnFile { Bound = bComposite }; ybn.Save(opts.OutputFile); } else if (outputFileInfos.Extension == ".ydr") { ydr.Drawable.Bound = bComposite; ydr.Save(opts.OutputFile); } else { Console.WriteLine("Output file type not valid"); } } else { Console.WriteLine("Input file type not valid"); } }); }
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 HandleGenPedDefsOptions(string[] args) { CommandLine.Parse <GenPedDefsOptions>(args, (opts, gOpts) => { var ymtRegex = new Regex("mp_(m|f)_freemode_01.*\\.ymt$"); var cYddRegex = new Regex("(head|berd|hair|uppr|lowr|hand|feet|teef|accs|task|decl|jbib)_(\\d\\d\\d)_u.ydd$"); var pYddRegex = new Regex("p_(head|ears|mouth|lhand|rhand|lwrist|rwrist|hip|lfoot|rfoot)_(\\d\\d\\d).ydd$"); var fileDlcLevels = new Dictionary <string, int>(); var overrides = new Dictionary <string, List <string> >(); if (opts.CreateMode) { if (opts.OutputDirectory == null) { Console.WriteLine("Please provide input directory with --output"); return; } if (!Directory.Exists(opts.OutputDirectory)) { Directory.CreateDirectory(opts.OutputDirectory); } Init(args); int maxDLCLevel = (Array.IndexOf(DLCList, opts.DLCLevel) == -1) ? DLCList.Length - 1 : Array.IndexOf(DLCList, opts.DLCLevel); var targets = opts.Targets?.ToList() ?? new List <string>(); var dlcpaths = new Dictionary <string, int>(); var dlcdirs = new Dictionary <string, int>(); var processed = new List <string>(); ArchiveUtilities.ForEachFile(Settings.Default.GTAFolder, (fullFileName, file, encryption) => { string[] path = fullFileName.Split('\\'); string folder = path[path.Length - 2]; string fileName = path[path.Length - 1]; string name = fileName.Split('.').First(); string outPath; bool isOverride = false; var ymtMatch = ymtRegex.Match(fileName); var cYddMatch = cYddRegex.Match(fileName); var pYddMatch = pYddRegex.Match(fileName); int dlcLevel = GetDLCLevel(fullFileName); if (dlcLevel > maxDLCLevel) { return; } if (targets.Count > 0 && opts.Targets.Where(e => e == name || (e + "_p") == name || e == folder || (e + "_p") == folder).ToArray().Length == 0) { return; } // Found interesting entry if (ymtMatch.Success || cYddMatch.Success || pYddMatch.Success) { string pathPart; // Found definition file (.ymt) if (ymtMatch.Success) { if (!path[path.Length - 1].Contains("_freemode_01")) { return; } outPath = opts.OutputDirectory; pathPart = path[path.Length - 1]; if (!dlcpaths.ContainsKey(pathPart)) { dlcpaths[pathPart] = dlcLevel; isOverride = true; } else if (dlcLevel > dlcpaths[pathPart]) { dlcpaths[pathPart] = dlcLevel; isOverride = true; } } else // Found model file (component or prop) { if (!path[path.Length - 2].Contains("_freemode_01")) { return; } outPath = opts.OutputDirectory + "\\" + path[path.Length - 2]; pathPart = path[path.Length - 2] + "\\" + path[path.Length - 1]; string dir = path[path.Length - 2]; dlcLevel = GetDLCLevel(fullFileName); // Console.WriteLine(pathPart); if (!dlcpaths.ContainsKey(pathPart)) { dlcpaths[pathPart] = dlcLevel; Console.WriteLine(DLCList[dlcLevel] + " [" + dlcLevel + "] => " + pathPart); dlcdirs[dir] = dlcLevel; isOverride = true; } else if (dlcLevel > dlcdirs[dir]) { Console.WriteLine(DLCList[dlcLevel] + " [" + dlcLevel + "] => " + pathPart); dlcpaths[pathPart] = dlcLevel; dlcdirs[dir] = dlcLevel; isOverride = true; } } Directory.CreateDirectory(outPath); // If dlc level of this directory is superior to current matching one if (isOverride) { // Write higher level ymt if (ymtMatch.Success) { using (var ms = new MemoryStream()) { file.Export(ms); var rMeta = new ResourceFile_GTA5_pc <MetaFile>(); rMeta.Load(ms); string xml = MetaXml.GetXml(rMeta.ResourceData); File.WriteAllText(outPath + "\\" + fileName + ".xml", xml); } } else if (cYddMatch.Success) { foreach (var entry in ComponentFilePrefix) { Directory.CreateDirectory(outPath + "\\components\\" + entry.Value); } } else if (pYddMatch.Success) { foreach (var entry in AnchorFilePrefix) { Directory.CreateDirectory(outPath + "\\props\\" + entry.Value); } } if (cYddMatch.Success || pYddMatch.Success) { dynamic directoryInfos = new JObject(); string dlc = DLCList[dlcLevel]; directoryInfos["dlc"] = dlc; directoryInfos["path"] = Directory.GetParent(fullFileName); var jsonString = JsonConvert.SerializeObject(directoryInfos, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented }); File.WriteAllText(outPath + "\\directory.json", jsonString); } } } }); } else { if (opts.InputDirectory == null) { Console.WriteLine("Please provide input directory with --input"); return; } if (opts.OutputDirectory == null) { Console.WriteLine("Please provide input directory with --output"); return; } Init(args); int maxDLCLevel = (Array.IndexOf(DLCList, opts.DLCLevel) == -1) ? DLCList.Length - 1 : Array.IndexOf(DLCList, opts.DLCLevel); string[] files = Directory.GetFiles(opts.InputDirectory).Where(e => e.EndsWith("ymt.xml")).ToArray(); string[] dirs = Directory.GetDirectories(opts.InputDirectory); var addonDirs = new List <string>(); var ymts = new Dictionary <string, YmtPedDefinitionFile>(); var processedYmts = new Dictionary <string, Tuple < Dictionary <string, Tuple <string, int, int, int, string, string> >, Dictionary <string, int>, Dictionary <string, Tuple <string, int, int, int, string, string> >, Dictionary <string, int> > >(); for (int j = 0; j < files.Length; j++) { string targetMetaXml = files[j]; string targetName = targetMetaXml.Split('\\').Last().Replace(".ymt.xml", ""); string parentDirectoryPath = Directory.GetParent(targetMetaXml).FullName; string parentDirectoryName = parentDirectoryPath.Split('\\').Last(); // Parse .ymt.xml string xml = File.ReadAllText(targetMetaXml); var doc = new XmlDocument(); doc.LoadXml(xml); var meta = XmlMeta.GetMeta(doc); var ymt = new YmtPedDefinitionFile(); ymt.ResourceFile.ResourceData = meta; ymt.Parse(); ymts[targetName] = ymt; } if (opts.FiveMFormat) { Directory.CreateDirectory(opts.OutputDirectory + "\\stream"); File.Create(opts.OutputDirectory + "\\__resource.lua"); } else { Directory.CreateDirectory(opts.OutputDirectory + "\\x64\\models\\cdimages\\streamedpeds_mp.rpf"); Directory.CreateDirectory(opts.OutputDirectory + "\\x64\\models\\cdimages\\streamedpedprops.rpf"); string contentXml = @"<?xml version=""1.0"" encoding=""UTF-8""?> <CDataFileMgr__ContentsOfDataFileXml> <disabledFiles /> <includedXmlFiles /> <includedDataFiles /> <dataFiles> <Item> <filename>dlc_gtauclothes:/%PLATFORM%/models/cdimages/streamedpeds_mp.rpf</filename> <fileType>RPF_FILE</fileType> <overlay value=""true"" /> <disabled value=""true"" /> <persistent value=""true"" /> </Item> <Item> <filename>dlc_gtauclothes:/%PLATFORM%/models/cdimages/streamedpedprops.rpf</filename> <fileType>RPF_FILE</fileType> <overlay value=""true"" /> <disabled value=""true"" /> <persistent value=""true"" /> </Item> </dataFiles> <contentChangeSets> <Item> <changeSetName>gtauclothes_AUTOGEN</changeSetName> <filesToDisable /> <filesToEnable> <Item>dlc_gtauclothes:/%PLATFORM%/models/cdimages/streamedpeds_mp.rpf</Item> <Item>dlc_gtauclothes:/%PLATFORM%/models/cdimages/streamedpedprops.rpf</Item> </filesToEnable> <txdToLoad /> <txdToUnload /> <residentResources /> <unregisterResources /> </Item> </contentChangeSets> <patchFiles /> </CDataFileMgr__ContentsOfDataFileXml>"; string setup2Xml = @"<?xml version=""1.0"" encoding=""UTF-8""?> <SSetupData> <deviceName>dlc_gtauclothes</deviceName> <datFile>content.xml</datFile> <timeStamp>03/30/2018 17:26:39</timeStamp> <nameHash>gtauclothes</nameHash> <contentChangeSetGroups> <Item> <NameHash>GROUP_STARTUP</NameHash> <ContentChangeSets> <Item>gtauclothes_AUTOGEN</Item> </ContentChangeSets> </Item> </contentChangeSetGroups> </SSetupData>"; File.WriteAllText(opts.OutputDirectory + "\\content.xml", contentXml); File.WriteAllText(opts.OutputDirectory + "\\setup2.xml", setup2Xml); } foreach (var ymtEntry in ymts) { var targetName = ymtEntry.Key; var ymt = ymtEntry.Value; // Components var cCount = new Dictionary <Unk_884254308, int>(); var cYddMapping = new Dictionary <string, Tuple <string, int, int, int, string, string> >(); // sourceYddPath => prefix, origPos, pos, count, folder, yddFileName var cTextureCount = new Dictionary <string, int>(); // Props var pCount = new Dictionary <Unk_2834549053, int>(); var pYddMapping = new Dictionary <string, Tuple <string, int, int, int, string, string> >(); // sourceYddPath => prefix, origPos, pos, count, folder, yddFileName var pTextureCount = new Dictionary <string, int>(); // Set component base count Unk_884254308[] cValues = (Unk_884254308[])Enum.GetValues(typeof(Unk_884254308)); foreach (Unk_884254308 component in cValues) { if (component == Unk_884254308.PV_COMP_INVALID || component == Unk_884254308.PV_COMP_MAX) { continue; } cCount[component] = (ymt.Unk_376833625.Components[component] ?? new MUnk_3538495220()).Unk_1756136273.Count; } // Set prop base count Unk_2834549053[] pValues = (Unk_2834549053[])Enum.GetValues(typeof(Unk_2834549053)); foreach (Unk_2834549053 anchor in pValues) { if (anchor == Unk_2834549053.NUM_ANCHORS) { continue; } int max = (opts.ReservePropEntries > ymt.Unk_376833625.PropInfo.Props[anchor].Count) ? opts.ReservePropEntries : ymt.Unk_376833625.PropInfo.Props[anchor].Count; pCount[anchor] = (ymt.Unk_376833625.PropInfo.Props[anchor] ?? new List <MUnk_94549140>()).Count; } foreach (var entry in ComponentFilePrefix) { Unk_884254308 component = entry.Key; string prefix = entry.Value; string targetDirectory = opts.InputDirectory + "\\" + targetName + "\\components\\" + prefix; if (Directory.Exists(targetDirectory)) { IEnumerable <string> addonFilesUnordered = Directory.GetFiles(targetDirectory).Where(e => e.EndsWith(".ydd")); int padLen = 0; if (addonFilesUnordered.Count() > 0) { padLen = addonFilesUnordered.Max(e => e.Length); } string[] addonFiles = addonFilesUnordered.OrderBy(e => e.PadLeft(padLen, '0')).ToArray(); var addons = new List <int>(); for (int k = 0; k < addonFiles.Length; k++) { addons.Add(k); } if (addons.Count > 0) { // Create addon component entries var def = ymt.Unk_376833625.Components[component] ?? new MUnk_3538495220(); for (int k = 0; k < addons.Count; k++) { int addonPos = def.Unk_1756136273.Count(); string textureDirectory = targetDirectory + "\\" + addons[k]; var addonTextures = new List <int>(); var item = new MUnk_1535046754(); IEnumerable <string> texturesUnordered = Directory.GetFiles(textureDirectory).Where(e => e.EndsWith(".ytd")); int padLen1 = 0; if (texturesUnordered.Count() > 0) { padLen1 = texturesUnordered.Max(e => e.Length); } string[] textures = texturesUnordered.OrderBy(e => e.PadLeft(padLen1, '0')).ToArray(); string yddFileName = prefix + "_" + addonPos.ToString().PadLeft(3, '0') + "_u.ydd"; cYddMapping[addonFiles[k]] = new Tuple <string, int, int, int, string, string>(prefix, addons[k], addonPos, addons.Count, targetDirectory, yddFileName); // Create addon texture entries for (int l = 0; l < textures.Length; l++) { addonTextures.Add(l); } cTextureCount[addonFiles[k]] = addonTextures.Count; for (int l = 0; l < addonTextures.Count; l++) { var texture = new MUnk_1036962405(); item.ATexData.Add(texture); // Create componentinfo var cInfo = new MCComponentInfo(); cInfo.Unk_2114993291 = 0; cInfo.Unk_3509540765 = (byte)component; cInfo.Unk_4196345791 = (byte)l; ymt.Unk_376833625.CompInfos.Add(cInfo); } if (File.Exists(addonFiles[k].Replace(".ydd", ".yld"))) { item.ClothData.Unk_2828247905 = 1; } def.Unk_1756136273.Add(item); cCount[component]++; } ymt.Unk_376833625.Components[component] = def; } } } foreach (var entry in AnchorFilePrefix) { Unk_2834549053 anchor = entry.Key; string prefix = entry.Value; string targetDirectory = opts.InputDirectory + "\\" + targetName + "_p" + "\\props\\" + prefix; if (Directory.Exists(targetDirectory)) { IEnumerable <string> addonFilesUnordered = Directory.GetFiles(targetDirectory).Where(e => e.EndsWith(".ydd")); int padLen = 0; if (addonFilesUnordered.Count() > 0) { padLen = addonFilesUnordered.Max(e => e.Length); } string[] addonFiles = addonFilesUnordered.OrderBy(e => e.PadLeft(padLen, '0')).ToArray(); var addons = new List <int>(); for (int k = 0; k < addonFiles.Length; k++) { addons.Add(k); } if (addons.Count > 0) { // Create addon prop entries var defs = ymt.Unk_376833625.PropInfo.Props[anchor] ?? new List <MUnk_94549140>(); for (int k = 0; k < addons.Count; k++) { int addonPos = defs.Count(); string textureDirectory = targetDirectory + "\\" + addons[k]; var addonTextures = new List <int>(); var item = new MUnk_94549140(ymt.Unk_376833625.PropInfo); IEnumerable <string> texturesUnordered = Directory.GetFiles(textureDirectory).Where(e => e.EndsWith(".ytd")); int padLen2 = 0; if (texturesUnordered.Count() > 0) { padLen2 = texturesUnordered.Max(e => e.Length); } string[] textures = texturesUnordered.OrderBy(e => e.PadLeft(padLen2, '0')).ToArray(); string yddFileName = "p_" + prefix + "_" + addonPos.ToString().PadLeft(3, '0') + ".ydd"; item.AnchorId = (byte)anchor; pYddMapping[addonFiles[k]] = new Tuple <string, int, int, int, string, string>(prefix, addons[k], addonPos, addons.Count, targetDirectory, yddFileName); // Create addon texture entries for (int l = 0; l < textures.Length; l++) { addonTextures.Add(l); } pTextureCount[addonFiles[k]] = addonTextures.Count; for (int l = 0; l < addonTextures.Count; l++) { var texture = new MUnk_254518642(); item.TexData.Add(texture); } // Get or create linked anchor var aanchor = ymt.Unk_376833625.PropInfo.AAnchors.Find(e => e.Anchor == anchor); if (aanchor == null) { aanchor = new MCAnchorProps(ymt.Unk_376833625.PropInfo); aanchor.PropsMap[item] = (byte)item.TexData.Count; ymt.Unk_376833625.PropInfo.AAnchors.Add(aanchor); } else { aanchor.PropsMap[item] = (byte)item.TexData.Count; } defs.Add(item); pCount[anchor]++; } ymt.Unk_376833625.PropInfo.Props[anchor] = defs; } } } // Create reserved component entries foreach (Unk_884254308 component in cValues) { if (component == Unk_884254308.PV_COMP_INVALID || component == Unk_884254308.PV_COMP_MAX) { continue; } int count = cCount[component]; int max = (opts.ReservePropEntries > count) ? opts.ReservePropEntries : count; var def = ymt.Unk_376833625.Components[component] ?? new MUnk_3538495220(); for (int i = count; i < max; i++) { var item = new MUnk_1535046754(); var texture = new MUnk_1036962405(); item.ATexData.Add(texture); // Create componentinfo var cInfo = new MCComponentInfo(); cInfo.Unk_2114993291 = 0; cInfo.Unk_3509540765 = (byte)component; cInfo.Unk_4196345791 = (byte)i; ymt.Unk_376833625.CompInfos.Add(cInfo); def.Unk_1756136273.Add(item); } if (def.Unk_1756136273.Count > 0) { ymt.Unk_376833625.Components[component] = def; } } // Create reserved prop entries foreach (Unk_2834549053 anchor in pValues) { if (anchor == Unk_2834549053.NUM_ANCHORS) { continue; } int count = pCount[anchor]; int max = (opts.ReservePropEntries > count) ? opts.ReservePropEntries : count; var defs = ymt.Unk_376833625.PropInfo.Props[anchor] ?? new List <MUnk_94549140>(); for (int i = count; i < max; i++) { var item = new MUnk_94549140(ymt.Unk_376833625.PropInfo); item.AnchorId = (byte)anchor; var texture = new MUnk_254518642(); item.TexData.Add(texture); var aanchor = ymt.Unk_376833625.PropInfo.AAnchors.Find(e => e.Anchor == anchor); if (aanchor == null) { aanchor = new MCAnchorProps(ymt.Unk_376833625.PropInfo); aanchor.Anchor = anchor; aanchor.PropsMap[item] = 1; ymt.Unk_376833625.PropInfo.AAnchors.Add(aanchor); } else { aanchor.PropsMap[item] = 1; } defs.Add(item); } if (defs.Count > 0) { ymt.Unk_376833625.PropInfo.Props[anchor] = defs; } } processedYmts[targetName] = new Tuple < Dictionary <string, Tuple <string, int, int, int, string, string> >, Dictionary <string, int>, Dictionary <string, Tuple <string, int, int, int, string, string> >, Dictionary <string, int> >(cYddMapping, cTextureCount, pYddMapping, pTextureCount); if (opts.FiveMFormat) { ymt.Save(opts.OutputDirectory + "\\stream\\" + targetName + ".ymt"); // var xml2 = MetaXml.GetXml(ymt.ResourceFile.ResourceData); // File.WriteAllText(opts.OutputDirectory + "\\stream\\" + targetMetaYmtFileName + ".xml", xml2); } else { ymt.Save(opts.OutputDirectory + "\\x64\\models\\cdimages\\streamedpeds_mp.rpf\\" + targetName + ".ymt"); } dynamic overrideInfos = new JObject(); overrideInfos["components"] = new JObject(); overrideInfos["props"] = new JObject(); foreach (Unk_884254308 component in cValues) { if (component == Unk_884254308.PV_COMP_INVALID || component == Unk_884254308.PV_COMP_MAX) { continue; } int count = ymt.Unk_376833625.Components[component]?.Unk_1756136273.Count ?? 0; int max = (opts.ReserveEntries > count) ? opts.ReserveEntries : count; overrideInfos["components"][ComponentFilePrefix[component]] = new JObject() { ["start"] = cCount[component], ["end"] = max }; } foreach (Unk_2834549053 anchor in pValues) { if (anchor == Unk_2834549053.NUM_ANCHORS) { continue; } int count = ymt.Unk_376833625.PropInfo.Props[anchor]?.Count ?? 0; int max = (opts.ReservePropEntries > count) ? opts.ReservePropEntries : count; overrideInfos["props"][AnchorFilePrefix[anchor]] = new JObject() { ["start"] = pCount[anchor], ["end"] = max }; } var jsonString = JsonConvert.SerializeObject(overrideInfos, new JsonSerializerSettings() { Formatting = Newtonsoft.Json.Formatting.Indented }); File.WriteAllText(opts.OutputDirectory + "\\" + targetName + ".override.json", jsonString); } // Check which directories contains addon component / props for (int i = 0; i < dirs.Length; i++) { bool found = false; foreach (var entry in ComponentFilePrefix) { string prefix = entry.Value; if (Directory.Exists(dirs[i] + "\\components\\" + prefix) && Directory.GetFiles(dirs[i] + "\\components\\" + prefix).Where(e => e.EndsWith(".ydd")).Count() > 0) { found = true; break; } if (Directory.Exists(dirs[i] + "\\props\\" + prefix) && Directory.GetFiles(dirs[i] + "\\props\\" + prefix).Where(e => e.EndsWith(".ydd")).Count() > 0) { found = true; break; } if (found) { break; } } if (found) { addonDirs.Add(dirs[i]); } } for (int i = 0; i < addonDirs.Count; i++) { Console.WriteLine(addonDirs[i]); string directory = addonDirs[i]; string[] path = directory.Split('\\'); string name = path[path.Length - 1]; string ymtDirName = name; if (ymtDirName.EndsWith("_p")) { ymtDirName = ymtDirName.Substring(0, ymtDirName.Length - 2); } Tuple < Dictionary <string, Tuple <string, int, int, int, string, string> >, Dictionary <string, int>, Dictionary <string, Tuple <string, int, int, int, string, string> >, Dictionary <string, int> > processedYmtData = null; // Copy models / textures with resolved names to build directory if (processedYmts.TryGetValue(ymtDirName, out processedYmtData)) { foreach (var entry in processedYmtData.Item1) { if (opts.FiveMFormat) { GenPedDefs_CreateComponentFiles_FiveM(opts, ymtDirName, entry, processedYmtData.Item2[entry.Key]); } else { GenPedDefs_CreateComponentFiles(opts, ymtDirName, entry, processedYmtData.Item2[entry.Key]); } } foreach (var entry in processedYmtData.Item3) { if (opts.FiveMFormat) { GenPedDefs_CreatePropFiles_FiveM(opts, ymtDirName, entry, processedYmtData.Item4[entry.Key]); } else { GenPedDefs_CreatePropFiles(opts, ymtDirName, entry, processedYmtData.Item4[entry.Key]); } } } } } }); }
static void HandleCompileDrawableShadersOptions(string[] args) { CommandLine.Parse <CompileDrawableShadersOptions>(args, (opts, gOpts) => { EnsurePath(); EnsureKeys(); var shaderNames = new Dictionary <uint, string>(); var shaderParameterSetNames = new Dictionary <uint, string>(); var fxcShaders = new Dictionary <uint, FxcFile>(); ArchiveUtilities.ForEachBinaryFile(Settings.Default.GTAFolder, (fullFileName, binaryFile, encryption) => { if (fullFileName.EndsWith(".fxc")) { string nameLower = binaryFile.Name.ToLowerInvariant().Replace(".fxc", ""); var hash = Jenkins.Hash(nameLower); if (!shaderNames.ContainsKey(hash)) { shaderNames.Add(hash, nameLower); } byte[] data = Utils.GetBinaryFileData((IArchiveBinaryFile)binaryFile, encryption); var fxc = new FxcFile(); fxc.Load(data, nameLower); if (!fxcShaders.ContainsKey(hash)) { fxcShaders.Add(hash, fxc); } } else if (fullFileName.EndsWith(".sps")) { string nameLower = binaryFile.Name.ToLowerInvariant(); var hash = Jenkins.Hash(nameLower); if (!shaderParameterSetNames.ContainsKey(hash)) { shaderParameterSetNames.Add(hash, nameLower); } } }); ArchiveUtilities.ForEachResourceFile(Settings.Default.GTAFolder, (fullFileName, resourceFile, encryption) => { if (fullFileName.EndsWith(".ydr")) { var ms = new MemoryStream(); resourceFile.Export(ms); var ydr = new YdrFile(); ydr.Load(ms); Console.WriteLine(fullFileName.Replace(Settings.Default.GTAFolder, "")); CompileDrawableShaders_ProcessDrawable(ydr.Drawable, shaderNames, fxcShaders); Console.WriteLine(""); } else if (fullFileName.EndsWith(".ydd")) { var ms = new MemoryStream(); resourceFile.Export(ms); var ydd = new YddFile(); ydd.Load(ms); Console.WriteLine(fullFileName.Replace(Settings.Default.GTAFolder, "")); var drawables = ydd.DrawableDictionary.Drawables; for (int d = 0; d < drawables.Count; d++) { var drawable = drawables[d]; Console.WriteLine(" " + drawable.Name.Value); CompileDrawableShaders_ProcessDrawable(drawable, shaderNames, fxcShaders); } Console.WriteLine(""); } }); }); }
static void HandleFindOptions(string[] args) { CommandLine.Parse <FindOptions>(args, (opts, gOpts) => { if (opts.Position == null || opts.Position.Count != 3) { Console.Error.WriteLine("Please specify position with -p --position"); return; } Init(args); 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(""); } } }); }
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 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 HandleGenPropDefsOptions(string[] args) { CommandLine.Parse <GenPropDefsOptions>(args, (opts, gOpts) => { if (opts.InputFiles != null) { var inputFiles = Utils.Expand(opts.InputFiles); var ytyp = new YtypFile(); if (opts.Ytyp != null) { var inputYtyps = Utils.Expand(opts.Ytyp); for (int i = 0; i < inputYtyps.Length; i++) { var ytyp2 = new YtypFile(); ytyp2.Load(inputYtyps[i].FullName); for (int j = 0; j < ytyp2.CMapTypes.Archetypes.Count; j++) { var archetype = ytyp2.CMapTypes.Archetypes[j]; if (Archetypes.TryGetValue(archetype.Name, out MCBaseArchetypeDef arch)) { Archetypes[archetype.Name] = archetype; } else { Archetypes.Add(archetype.Name, archetype); } } } } 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 nameHash = (MetaName)Jenkins.Hash(name); var ydr = new YdrFile(); ydr.Load(fileInfo.FullName); if (Archetypes.TryGetValue(nameHash, out MCBaseArchetypeDef arch)) { 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; } else { arch = new MCBaseArchetypeDef(); 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.OutputDirectory == null) ? @".\props.ytyp" : opts.OutputDirectory + @"\props.ytyp"; ytyp.Save(path); } }); }