private void ArchetypeNameTextBox_TextChanged(object sender, EventArgs e) { var archetypeHash = JenkHash.GenHash(ArchetypeNameTextBox.Text); var archetype = ProjectForm.GameFileCache.GetArchetype(archetypeHash); if (archetype == null) { HashLabel.Text = $@"Hash: {archetypeHash} (invalid)"; return; } CurrentBatch.Archetype = archetype; var b = CurrentBatch.Batch; b.archetypeName = archetypeHash; CurrentBatch.Batch = b; ProjectForm.WorldForm.UpdateGrassBatchGraphics(CurrentBatch); HashLabel.Text = $@"Hash: {archetypeHash}"; UpdateFormTitle(); CurrentBatch.HasChanged = true; ProjectForm.SetGrassBatchHasChanged(false); ProjectForm.SetYmapHasChanged(true); }
private void ArchetypeNameTextBox_TextChanged(object sender, EventArgs e) { var hash = 0u; if (!uint.TryParse(ArchetypeNameTextBox.Text, out hash))//don't re-hash hashes { hash = JenkHash.GenHash(ArchetypeNameTextBox.Text); } if (CurrentArchetype._BaseArchetypeDef.name != hash) { CurrentArchetype._BaseArchetypeDef.name = hash; UpdateFormTitle(); TreeNode tn = ProjectForm.ProjectExplorer?.FindArchetypeTreeNode(CurrentArchetype); if (tn != null) { tn.Text = ArchetypeNameTextBox.Text ?? "0"; // using the text box text because the name may not be in the gfc. } ProjectForm.SetYtypHasChanged(true); } }
private void SetYmapPhysicsDictionariesFromTextbox() { if (populatingui) { return; } if (Ymap == null) { return; } List <MetaHash> hashes = new List <MetaHash>(); var strs = YmapPhysicsDictionariesTextBox.Text.Split('\n'); foreach (var str in strs) { var tstr = str.Trim(); if (!string.IsNullOrEmpty(tstr)) { uint h = 0; if (uint.TryParse(tstr, out h)) { hashes.Add(h); } else { h = JenkHash.GenHash(tstr.ToLowerInvariant()); hashes.Add(h); } } } lock (ProjectForm.ProjectSyncRoot) { Ymap.physicsDictionaries = (hashes.Count > 0) ? hashes.ToArray() : null; SetYmapHasChanged(true); } }
private void YmapParentTextBox_TextChanged(object sender, EventArgs e) { if (populatingui) { return; } uint hash = 0; string name = YmapParentTextBox.Text; if (!uint.TryParse(name, out hash))//don't re-hash hashes { hash = JenkHash.GenHash(name); JenkIndex.Ensure(name); } YmapParentHashLabel.Text = "Hash: " + hash.ToString(); if (hash != 0) { var entry = ProjectForm.FindParentYmapEntry(hash); if (entry == null) { YmapParentHashLabel.Text += " (not found!)"; } } if (Ymap != null) { lock (ProjectForm.ProjectSyncRoot) { if (Ymap._CMapData.parent.Hash != hash) { Ymap._CMapData.parent = new MetaHash(hash); SetYmapHasChanged(true); //TODO: confirm entity parent linkage? } } } }
private void TextureDictTextBox_TextChanged(object sender, EventArgs e) { // Check that the form is not null before locking... if (ProjectForm == null) { return; } lock (ProjectForm.ProjectSyncRoot) { // Embedded... if (TextureDictTextBox.Text == ArchetypeNameTextBox.Text) { TextureDictHashLabel.Text = "Embedded"; CurrentArchetype._BaseArchetypeDef.textureDictionary = CurrentArchetype._BaseArchetypeDef.name; return; } var hash = 0u; if (!uint.TryParse(TextureDictTextBox.Text, out hash))//don't re-hash hashes { hash = JenkHash.GenHash(TextureDictTextBox.Text); } if (CurrentArchetype._BaseArchetypeDef.textureDictionary != hash) { var ytd = ProjectForm.GameFileCache.GetYtd(hash); if (ytd == null) { TextureDictHashLabel.Text = "Hash: " + hash.ToString() + " (invalid)"; ProjectForm.SetYtypHasChanged(true); return; } CurrentArchetype._BaseArchetypeDef.textureDictionary = hash; ProjectForm.SetYtypHasChanged(true); } TextureDictHashLabel.Text = "Hash: " + hash.ToString(); } }
private void LoadStringsButton_Click(object sender, EventArgs e) { if (OpenFileDialog.ShowDialog(this) != DialogResult.OK) { return; } string file = OpenFileDialog.FileName; if (!File.Exists(file)) { return; } try { string txt = File.ReadAllText(file); string[] lines = txt.Split('\n'); foreach (string line in lines) { string str = line.Trim(); if (str.Length > 2) //remove double quotes from start and end, if both present... { if ((str[0] == '\"') && (str[str.Length - 1] == '\"')) { str = str.Substring(1, str.Length - 2); } } var hash = JenkHash.GenHash(str); extraStrings[hash] = str; } MessageBox.Show(lines.Length.ToString() + " strings imported successfully."); } catch { MessageBox.Show("Error reading file."); } }
private void PhysicsDictionaryTextBox_TextChanged(object sender, EventArgs e) { lock (ProjectForm.ProjectSyncRoot) { if (ProjectForm == null) { return; } // Embedded... if (PhysicsDictionaryTextBox.Text == ArchetypeNameTextBox.Text) { PhysicsDictHashLabel.Text = "Embedded"; CurrentArchetype._BaseArchetypeDef.physicsDictionary = CurrentArchetype._BaseArchetypeDef.name; return; } var hash = 0u; if (!uint.TryParse(PhysicsDictionaryTextBox.Text, out hash))//don't re-hash hashes { hash = JenkHash.GenHash(PhysicsDictionaryTextBox.Text); } if (CurrentArchetype._BaseArchetypeDef.physicsDictionary != hash) { var ytd = ProjectForm.GameFileCache.GetYbn(hash); if (ytd == null) { PhysicsDictHashLabel.Text = "Hash: " + hash.ToString() + " (invalid)"; ProjectForm.SetYtypHasChanged(true); return; } CurrentArchetype._BaseArchetypeDef.physicsDictionary = hash; ProjectForm.SetYtypHasChanged(true); } PhysicsDictHashLabel.Text = "Hash: " + hash.ToString(); } }
private void LoadGxt2(CutEvent e) { if (GameFileCache == null) { return; } if (Gxt2File != null) { } var args = e.EventArgs as CutFinalNameEventArgs; if (args == null) { return; } var namel = args.cName?.ToLowerInvariant(); var namehash = JenkHash.GenHash(namel); RpfFileEntry gxt2entry = null; GameFileCache.Gxt2Dict.TryGetValue(namehash, out gxt2entry); if (gxt2entry != null) //probably should do this load async { Gxt2File = GameFileCache.RpfMan.GetFile <Gxt2File>(gxt2entry); if (Gxt2File != null) { for (int i = 0; i < Gxt2File.TextEntries.Length; i++) { var te = Gxt2File.TextEntries[i]; GlobalText.Ensure(te.Text, te.Hash); } } } }
private void Timecycle2TextBox_TextChanged(object sender, EventArgs e) { if (populatingui) { return; } if (CurrentRoom == null) { return; } var hash = JenkHash.GenHash(Timecycle2TextBox.Text); lock (ProjectForm.ProjectSyncRoot) { if (CurrentRoom._Data.secondaryTimecycleName != hash) { CurrentRoom._Data.secondaryTimecycleName = hash; ProjectForm.SetYtypHasChanged(true); JenkIndex.Ensure(Timecycle2TextBox.Text); } } }
public void LoadVehicle() { var modelname = VehicleModelComboBox.Text; var modelnamel = modelname.ToLowerInvariant(); MetaHash modelhash = JenkHash.GenHash(modelnamel); MetaHash modelhashhi = JenkHash.GenHash(modelnamel + "_hi"); bool hidet = VehicleHighDetailCheckBox.Checked; var yfthash = hidet ? modelhashhi : modelhash; VehicleInitData vid = null; if (GameFileCache.VehiclesInitDict.TryGetValue(modelhash, out vid)) { bool vehiclechange = SelectedVehicleHash != modelhash; SelectedModelHash = yfthash; SelectedVehicleHash = modelhash; SelectedVehicleInit = vid; SelectedVehicleYft = GameFileCache.GetYft(SelectedModelHash); while ((SelectedVehicleYft != null) && (!SelectedVehicleYft.Loaded)) { Thread.Sleep(20);//kinda hacky SelectedVehicleYft = GameFileCache.GetYft(SelectedModelHash); } LoadModel(SelectedVehicleYft, vehiclechange); VehicleMakeLabel.Text = GlobalText.TryGetString(JenkHash.GenHash(vid.vehicleMakeName.ToLower())); VehicleNameLabel.Text = GlobalText.TryGetString(JenkHash.GenHash(vid.gameName.ToLower())); } else { SelectedModelHash = 0; SelectedVehicleHash = 0; SelectedVehicleInit = null; SelectedVehicleYft = null; VehicleMakeLabel.Text = "-"; VehicleNameLabel.Text = "-"; } }
private void EntitySetNameTextBox_TextChanged(object sender, EventArgs e) { if (populatingui) { return; } if (CurrentEntitySet == null) { return; } var str = EntitySetNameTextBox.Text; if (CurrentEntitySet.Name != str) { uint h = 0; if (uint.TryParse(str, out h)) { CurrentEntitySet._Data.name = h; } else { JenkIndex.Ensure(str); CurrentEntitySet._Data.name = JenkHash.GenHash(str); } TreeNode tn = ProjectForm.ProjectExplorer?.FindMloEntitySetTreeNode(CurrentEntitySet); if (tn != null) { tn.Text = CurrentEntitySet.Name; } UpdateFormTitle(); ProjectForm.SetYtypHasChanged(true); } }
public void SetComponentDrawable(int index, string name, string tex, GameFileCache gfc) { if (string.IsNullOrEmpty(name)) { DrawableNames[index] = null; Drawables[index] = null; Textures[index] = null; Expressions[index] = null; return; } MetaHash namehash = JenkHash.GenHash(name.ToLowerInvariant()); Drawable d = null; if (Ydd?.Dict != null) { Ydd.Dict.TryGetValue(namehash, out d); } if ((d == null) && (DrawableFilesDict != null)) { RpfFileEntry file = null; if (DrawableFilesDict.TryGetValue(namehash, out file)) { var ydd = gfc.GetFileUncached <YddFile>(file); while ((ydd != null) && (!ydd.Loaded)) { Thread.Sleep(1);//kinda hacky gfc.TryLoadEnqueue(ydd); } if (ydd?.Drawables?.Length > 0) { d = ydd.Drawables[0];//should only be one in this dict } } } MetaHash texhash = JenkHash.GenHash(tex.ToLowerInvariant()); Texture t = null; if (Ytd?.TextureDict?.Dict != null) { Ytd.TextureDict.Dict.TryGetValue(texhash, out t); } if ((t == null) && (TextureFilesDict != null)) { RpfFileEntry file = null; if (TextureFilesDict.TryGetValue(texhash, out file)) { var ytd = gfc.GetFileUncached <YtdFile>(file); while ((ytd != null) && (!ytd.Loaded)) { Thread.Sleep(1);//kinda hacky gfc.TryLoadEnqueue(ytd); } if (ytd?.TextureDict?.Textures?.data_items.Length > 0) { t = ytd.TextureDict.Textures.data_items[0];//should only be one in this dict } } } CharacterCloth cc = null; if (Yld?.Dict != null) { Yld.Dict.TryGetValue(namehash, out cc); } if ((cc == null) && (ClothFilesDict != null)) { RpfFileEntry file = null; if (ClothFilesDict.TryGetValue(namehash, out file)) { var yld = gfc.GetFileUncached <YldFile>(file); while ((yld != null) && (!yld.Loaded)) { Thread.Sleep(1);//kinda hacky gfc.TryLoadEnqueue(yld); } if (yld?.ClothDictionary?.Clothes?.data_items?.Length > 0) { cc = yld.ClothDictionary.Clothes.data_items[0];//should only be one in this dict } } } ClothInstance c = null; if (cc != null) { c = new ClothInstance(); c.Init(cc, Skeleton); } Expression e = null; if (Yed?.ExprMap != null) { Yed.ExprMap.TryGetValue(namehash, out e); } if (d != null) { Drawables[index] = d.ShallowCopy() as Drawable; } if (t != null) { Textures[index] = t; } if (c != null) { Clothes[index] = c; } if (e != null) { Expressions[index] = e; } DrawableNames[index] = name; }
public void Init(MetaHash pedhash, GameFileCache gfc) { Name = string.Empty; NameHash = 0; InitData = null; Ydd = null; Ytd = null; Yld = null; Ycd = null; Yed = null; Yft = null; Ymt = null; AnimClip = null; for (int i = 0; i < 12; i++) { Drawables[i] = null; Textures[i] = null; Expressions[i] = null; } CPedModelInfo__InitData initdata = null; if (!gfc.PedsInitDict.TryGetValue(pedhash, out initdata)) { return; } var ycdhash = JenkHash.GenHash(initdata.ClipDictionaryName.ToLowerInvariant()); var yedhash = JenkHash.GenHash(initdata.ExpressionDictionaryName.ToLowerInvariant()); //bool pedchange = NameHash != pedhash; //Name = pedname; NameHash = pedhash; InitData = initdata; Ydd = gfc.GetYdd(pedhash); Ytd = gfc.GetYtd(pedhash); Ycd = gfc.GetYcd(ycdhash); Yed = gfc.GetYed(yedhash); Yft = gfc.GetYft(pedhash); PedFile pedFile = null; gfc.PedVariationsDict?.TryGetValue(pedhash, out pedFile); Ymt = pedFile; Dictionary <MetaHash, RpfFileEntry> peddict = null; gfc.PedDrawableDicts.TryGetValue(NameHash, out peddict); DrawableFilesDict = peddict; DrawableFiles = DrawableFilesDict?.Values.ToArray(); gfc.PedTextureDicts.TryGetValue(NameHash, out peddict); TextureFilesDict = peddict; TextureFiles = TextureFilesDict?.Values.ToArray(); gfc.PedClothDicts.TryGetValue(NameHash, out peddict); ClothFilesDict = peddict; ClothFiles = ClothFilesDict?.Values.ToArray(); RpfFileEntry clothFile = null; if (ClothFilesDict?.TryGetValue(pedhash, out clothFile) ?? false) { Yld = gfc.GetFileUncached <YldFile>(clothFile); while ((Yld != null) && (!Yld.Loaded)) { Thread.Sleep(1);//kinda hacky gfc.TryLoadEnqueue(Yld); } } while ((Ydd != null) && (!Ydd.Loaded)) { Thread.Sleep(1);//kinda hacky Ydd = gfc.GetYdd(pedhash); } while ((Ytd != null) && (!Ytd.Loaded)) { Thread.Sleep(1);//kinda hacky Ytd = gfc.GetYtd(pedhash); } while ((Ycd != null) && (!Ycd.Loaded)) { Thread.Sleep(1);//kinda hacky Ycd = gfc.GetYcd(ycdhash); } while ((Yed != null) && (!Yed.Loaded)) { Thread.Sleep(1);//kinda hacky Yed = gfc.GetYed(yedhash); } while ((Yft != null) && (!Yft.Loaded)) { Thread.Sleep(1);//kinda hacky Yft = gfc.GetYft(pedhash); } Skeleton = Yft?.Fragment?.Drawable?.Skeleton?.Clone(); MetaHash cliphash = JenkHash.GenHash("idle"); ClipMapEntry cme = null; Ycd?.ClipMap?.TryGetValue(cliphash, out cme); AnimClip = cme; var exprhash = JenkHash.GenHash(initdata.ExpressionName.ToLowerInvariant()); Expression expr = null; Yed?.ExprMap?.TryGetValue(exprhash, out expr); Expression = expr; UpdateEntity(); }
private void ParamTextBox_TextChanged(object sender, EventArgs e) { var tb = sender as TextBox; var parm = tb?.Tag as ShaderParameter; var txt = tb?.Text; if (parm == null) { return; } if (parm.DataType == 0)//texture { var tex = parm.Data as TextureBase; var ttex = tex as Texture; if (ttex == null)//don't do this for embedded textures! { tex.Name = txt; tex.NameHash = JenkHash.GenHash(txt.ToLowerInvariant()); } else { //TODO: modify embedded textures! } } else if (parm.DataType == 1)//Vector4 { parm.Data = FloatUtil.ParseVector4String(txt); } else //Vector4 array { var strs = txt.Split(';'); var vecs = new Vector4[parm.DataType]; for (int i = 0; i < parm.DataType; i++) { var vec = Vector4.Zero; if (i < strs.Length) { vec = FloatUtil.ParseVector4String(strs[i].Trim()); } vecs[i] = vec; } parm.Data = vecs; } var geom = ModelsTreeView.SelectedNode?.Tag as DrawableGeometry; if (geom != null) { if (Drawable != null) { UpdateRenderableParams(Drawable, geom.Shader); } if (DrawableDict != null) { foreach (var dwbl in DrawableDict.Values) { UpdateRenderableParams(dwbl, geom.Shader); } } } ModelForm.OnModelModified(); }
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(); }); }
public void UpdateYmapUI() { if (Ymap == null) { YmapNameTextBox.Text = "<No ymap selected>"; YmapNameHashLabel.Text = "Hash: 0"; YmapParentTextBox.Text = string.Empty; YmapParentHashLabel.Text = "Hash: 0"; YmapFlagsTextBox.Text = string.Empty; YmapContentFlagsTextBox.Text = string.Empty; YmapCFlagsHDCheckBox.Checked = false; YmapCFlagsLODCheckBox.Checked = false; YmapCFlagsSLOD2CheckBox.Checked = false; YmapCFlagsInteriorCheckBox.Checked = false; YmapCFlagsSLODCheckBox.Checked = false; YmapCFlagsOcclusionCheckBox.Checked = false; YmapCFlagsPhysicsCheckBox.Checked = false; YmapCFlagsLODLightsCheckBox.Checked = false; YmapCFlagsDistLightsCheckBox.Checked = false; YmapCFlagsCriticalCheckBox.Checked = false; YmapCFlagsGrassCheckBox.Checked = false; YmapFlagsScriptedCheckBox.Checked = false; YmapFlagsLODCheckBox.Checked = false; YmapPhysicsDictionariesTextBox.Text = string.Empty; YmapEntitiesExtentsMinTextBox.Text = string.Empty; YmapEntitiesExtentsMaxTextBox.Text = string.Empty; YmapStreamingExtentsMinTextBox.Text = string.Empty; YmapStreamingExtentsMaxTextBox.Text = string.Empty; YmapFileLocationTextBox.Text = string.Empty; YmapProjectPathTextBox.Text = string.Empty; } else { populatingui = true; var md = Ymap.CMapData; if (md.name.Hash == 0) { string name = Path.GetFileNameWithoutExtension(Ymap.Name); JenkIndex.Ensure(name); md.name = new MetaHash(JenkHash.GenHash(name)); } var project = ProjectForm?.CurrentProjectFile; YmapNameTextBox.Text = md.name.ToString(); YmapNameHashLabel.Text = "Hash: " + md.name.Hash.ToString(); YmapParentTextBox.Text = md.parent.ToString(); YmapParentHashLabel.Text = "Hash: " + md.parent.Hash.ToString(); YmapEntitiesExtentsMinTextBox.Text = FloatUtil.GetVector3String(md.entitiesExtentsMin); YmapEntitiesExtentsMaxTextBox.Text = FloatUtil.GetVector3String(md.entitiesExtentsMax); YmapStreamingExtentsMinTextBox.Text = FloatUtil.GetVector3String(md.streamingExtentsMin); YmapStreamingExtentsMaxTextBox.Text = FloatUtil.GetVector3String(md.streamingExtentsMax); YmapFileLocationTextBox.Text = Ymap.RpfFileEntry?.Path ?? Ymap.FilePath; YmapProjectPathTextBox.Text = (project != null) ? project.GetRelativePath(Ymap.FilePath) : Ymap.FilePath; UpdateYmapFlagsUI(true, true); UpdateYmapPhysicsDictionariesUI(); populatingui = false; ////struct CMapData: //MetaHash name { get; set; } //8 8: Hash: 0: name //MetaHash parent { get; set; } //12 12: Hash: 0: parent //uint flags { get; set; } //16 16: UnsignedInt: 0: flags //uint contentFlags { get; set; } //20 20: UnsignedInt: 0: contentFlags//1785155637 //Vector3 streamingExtentsMin { get; set; } //32 32: Float_XYZ: 0: streamingExtentsMin//3710026271 //Vector3 streamingExtentsMax { get; set; } //48 48: Float_XYZ: 0: streamingExtentsMax//2720965429 //Vector3 entitiesExtentsMin { get; set; } //64 64: Float_XYZ: 0: entitiesExtentsMin//477478129 //Vector3 entitiesExtentsMax { get; set; } //80 80: Float_XYZ: 0: entitiesExtentsMax//1829192759 //Array_StructurePointer entities { get; set; } //96 96: Array: 0: entities {0: StructurePointer: 0: 256} //Array_Structure containerLods { get; set; } //112 112: Array: 0: containerLods//2935983381 {0: Structure: 372253349: 256} //Array_Structure boxOccluders { get; set; } //128 128: Array: 0: boxOccluders//3983590932 {0: Structure: SectionUNKNOWN7: 256} //Array_Structure occludeModels { get; set; } //144 144: Array: 0: occludeModels//2132383965 {0: Structure: SectionUNKNOWN5: 256} //Array_uint physicsDictionaries { get; set; } //160 160: Array: 0: physicsDictionaries//949589348 {0: Hash: 0: 256} //rage__fwInstancedMapData instancedData { get; set; } //176 176: Structure: rage__fwInstancedMapData: instancedData//2569067561 //Array_Structure timeCycleModifiers { get; set; } //224 224: Array: 0: timeCycleModifiers {0: Structure: CTimeCycleModifier: 256} //Array_Structure carGenerators { get; set; } //240 240: Array: 0: carGenerators//3254823756 {0: Structure: CCarGen: 256} //CLODLight LODLightsSOA { get; set; } //256 256: Structure: CLODLight: LODLightsSOA//1774371066 //CDistantLODLight DistantLODLightsSOA { get; set; } //392 392: Structure: CDistantLODLight: DistantLODLightsSOA//2954466641 //CBlockDesc block { get; set; } //440 440: Structure: CBlockDesc//3072355914: block } }
private void EntityArchetypeTextBox_TextChanged(object sender, EventArgs e) { if (populatingui) { return; } if (CurrentEntity == null) { return; } uint hash = 0; string name = EntityArchetypeTextBox.Text; if (!uint.TryParse(name, out hash))//don't re-hash hashes { hash = JenkHash.GenHash(name); JenkIndex.Ensure(name); } EntityArchetypeHashLabel.Text = "Hash: " + hash.ToString(); var arch = ProjectForm.GameFileCache.GetArchetype(hash); if (arch == null) { EntityArchetypeHashLabel.Text += " (not found)"; } TreeNode tn = ProjectForm.ProjectExplorer?.FindEntityTreeNode(CurrentEntity); if (tn != null) { tn.Text = name; } else { tn = ProjectForm.ProjectExplorer?.FindMloEntityTreeNode(CurrentMCEntity); if (tn != null) { tn.Text = name; } } if (CurrentEntity != null) { lock (ProjectForm.ProjectSyncRoot) { CurrentEntity._CEntityDef.archetypeName = new MetaHash(hash); if (CurrentMCEntity != null) { CurrentMCEntity._Data.archetypeName = new MetaHash(hash); } if (CurrentEntity.Archetype != arch) { CurrentEntity.SetArchetype(arch); if (CurrentEntity.IsMlo) { CurrentEntity.MloInstance.InitYmapEntityArchetypes(ProjectForm.GameFileCache); } ProjectItemChanged(); } } } }
public byte[] BuildYcd() { YcdFile ycd = new YcdFile(); ycd.ClipDictionary = new ClipDictionary(); var clipmap = new List <ClipMapEntry>(); var animmap = new List <AnimationMapEntry>(); foreach (var onim in OnimFiles) { var anim = new Animation(); anim.Hash = JenkHash.GenHash(onim.Name.ToLowerInvariant()); anim.Frames = (ushort)onim.Frames; anim.SequenceFrameLimit = (ushort)onim.SequenceFrameLimit; anim.Duration = onim.Duration; JenkIndex.Ensure(onim.Name.ToLowerInvariant());//just to make it nicer to debug really bool isUV = false; bool hasRootMotion = false; var boneIds = new List <AnimationBoneId>(); var seqs = new List <Sequence>(); var aseqs = new List <List <AnimSequence> >(); foreach (var oseq in onim.SequenceList) { var boneid = new AnimationBoneId(); boneid.BoneId = (ushort)oseq.BoneID; //TODO: bone ID mapping boneid.Unk0 = 0; //what to use here? switch (oseq.Track) { case "BonePosition": boneid.Track = 0; break; case "BoneRotation": boneid.Track = 1; break; case "ModelPosition": boneid.Track = 5; hasRootMotion = true; break; case "ModelRotation": boneid.Track = 6; hasRootMotion = true; break; case "UV0": boneid.Track = 17; isUV = true; break; case "UV1": boneid.Track = 18; isUV = true; break; case "LightColor": boneid.Track = 0; //what should this be? break; case "LightRange": boneid.Track = 0; //what should this be? break; case "LightIntensity1": boneid.Track = 0; //what should this be? break; case "LightIntensity2": boneid.Track = 0; //what should this be? break; case "LightDirection": boneid.Track = 0; //what should this be? break; case "Type21": boneid.Track = 0; //what should this be? break; case "CameraPosition": boneid.Track = 7; break; case "CameraRotation": boneid.Track = 8; break; case "CameraFOV": boneid.Track = 0; //what should this be? break; case "CameraDof": boneid.Track = 0; //what should this be? break; case "CameraMatrixRotateFactor": boneid.Track = 0; //what should this be? break; case "CameraControl": boneid.Track = 0; //what should this be? break; case "ActionFlags": //not sure what this is for? just ignore it for now continue; default: break; } boneIds.Add(boneid); for (int i = 0; i < oseq.FramesData.Count; i++) { var framesData = oseq.FramesData[i]; if (i > 0) { } Sequence seq = null; List <AnimSequence> aseqlist = null; while (i >= seqs.Count) { seq = new Sequence(); seqs.Add(seq); aseqlist = new List <AnimSequence>(); aseqs.Add(aseqlist); } seq = seqs[i]; aseqlist = aseqs[i]; var chanlist = new List <AnimChannel>(); if (framesData.IsStatic) { var vals = (framesData.Channels.Count > 0) ? framesData.Channels[0].Values : null; if (vals != null) { if (vals.Length == 1) { var acsf = new AnimChannelStaticFloat(); acsf.Value = vals[0]; chanlist.Add(acsf); } else if (vals.Length == 3) { var acsv = new AnimChannelStaticVector3(); acsv.Value = new Vector3(vals[0], vals[1], vals[2]); chanlist.Add(acsv); } else if (vals.Length == 4) { var acsq = new AnimChannelStaticQuaternion(); acsq.Value = new Quaternion(vals[0], vals[1], vals[2], vals[3]); chanlist.Add(acsq); } else { } } else { } } else { int chanCount = framesData.Channels.Count; for (int c = 0; c < chanCount; c++) { var ochan = framesData.Channels[c]; var vals = ochan.Values; if (vals.Length == 1)//static channel... { var acsf = new AnimChannelStaticFloat(); acsf.Value = vals[0]; chanlist.Add(acsf); } else //if (vals.Length == onim.Frames) { float minval = float.MaxValue; float maxval = float.MinValue; float lastval = 0; float mindelta = float.MaxValue; foreach (var val in vals) { minval = Math.Min(minval, val); maxval = Math.Max(maxval, val); if (val != lastval) { float adelta = Math.Abs(val - lastval); mindelta = Math.Min(mindelta, adelta); } lastval = val; } if (mindelta == float.MaxValue) { mindelta = 0; } float range = maxval - minval; float minquant = range / 1048576.0f; float quantum = Math.Max(mindelta, minquant); var acqf = new AnimChannelQuantizeFloat(); acqf.Values = vals; acqf.Offset = minval; acqf.Quantum = quantum; chanlist.Add(acqf); } } if (chanCount == 4) { //assume it's a quaternion... add the extra quaternion channel var acq1 = new AnimChannelCachedQuaternion(AnimChannelType.CachedQuaternion2); acq1.QuatIndex = 3;//what else should it be? chanlist.Add(acq1); } } if (chanlist.Count == 4) { } //shouldn't happen AnimSequence aseq = new AnimSequence(); aseq.Channels = chanlist.ToArray(); aseqlist.Add(aseq); } } int remframes = anim.Frames; for (int i = 0; i < seqs.Count; i++) { var seq = seqs[i]; var aseqlist = aseqs[i]; seq.Unknown_00h = 0;//what to set this??? seq.NumFrames = (ushort)Math.Max(Math.Min(anim.SequenceFrameLimit, remframes), 0); seq.Sequences = aseqlist.ToArray(); seq.AssociateSequenceChannels(); remframes -= anim.SequenceFrameLimit; } anim.BoneIds = new ResourceSimpleList64_s <AnimationBoneId>(); anim.BoneIds.data_items = boneIds.ToArray(); anim.Sequences = new ResourcePointerList64 <Sequence>(); anim.Sequences.data_items = seqs.ToArray(); anim.Unknown_10h = hasRootMotion ? (byte)16 : (byte)0; anim.Unknown_1Ch = 0; //??? anim.AssignSequenceBoneIds(); var cliphash = anim.Hash; if (isUV) { var name = onim.Name.ToLowerInvariant(); var uvind = name.IndexOf("_uv_"); if (uvind < 0) { } var modelname = name.Substring(0, uvind); var geoindstr = name.Substring(uvind + 4); var geoind = 0u; uint.TryParse(geoindstr, out geoind); cliphash = JenkHash.GenHash(modelname) + geoind + 1; } else { } var clip = new ClipAnimation(); clip.Animation = anim; clip.StartTime = 0.0f; clip.EndTime = anim.Duration; clip.Rate = 1.0f; clip.Name = "pack:/" + onim.Name + ".clip"; //pack:/name.clip clip.Unknown_30h = 0; //what's this then? clip.Properties = new ClipPropertyMap(); clip.Properties.CreatePropertyMap(null); //TODO? clip.Tags = new ClipTagList(); //TODO? var cme = new ClipMapEntry(); cme.Clip = clip; cme.Hash = cliphash; clipmap.Add(cme); var ame = new AnimationMapEntry(); ame.Hash = anim.Hash;//is this right? what else to use? ame.Animation = anim; animmap.Add(ame); } ycd.ClipDictionary.CreateClipsMap(clipmap.ToArray()); ycd.ClipDictionary.CreateAnimationsMap(animmap.ToArray()); ycd.ClipDictionary.BuildMaps(); ycd.ClipDictionary.UpdateUsageCounts(); ycd.InitDictionaries(); byte[] data = ycd.Save(); return(data); }
public void Init(GameFileCache gameFileCache, Action <string> updateStatus) { Inited = false; GameFileCache = gameFileCache; var rpfman = gameFileCache.RpfMan; string filename = "common.rpf\\data\\levels\\gta5\\popzone.ipl"; if (gameFileCache.EnableDlc) { filename = "update\\update.rpf\\common\\data\\levels\\gta5\\popzone.ipl"; } string ipltext = rpfman.GetFileUTF8Text(filename); if (string.IsNullOrEmpty(ipltext)) { ipltext = ""; } Groups.Clear(); var ipllines = ipltext.Split('\n'); bool inzone = false; foreach (var iplline in ipllines) { var linet = iplline.Trim(); if (linet == "zone") { inzone = true; } else if (linet == "end") { inzone = false; } else if (inzone) { PopZoneBox box = new PopZoneBox(); box.Init(linet); PopZone group; if (!Groups.TryGetValue(box.NameLabel, out group)) { group = new PopZone(); group.NameLabel = box.NameLabel; Groups[box.NameLabel] = group; } group.Boxes.Add(box); } } foreach (var group in Groups.Values) { var hash = JenkHash.GenHash(group.NameLabel.ToLowerInvariant()); group.Name = GlobalText.TryGetString(hash); } BuildVertices(); Inited = true; }
private ShaderFX TryConvertMaterial(FbxNode matNode) { var shader = new ShaderFX(); var spsName = "default"; var texConns = new List <FbxNode>(); var texNames = new List <string>(); #region 3dsmax/GIMS properties //var floatValueNames = new List<string>(); //var floatValues = new List<Vector4>(); //var texValueNames = new List<string>(); //var texValues = new List<FbxNode>(); //var matProps = matNode["Properties70"]; //foreach (var matProp in matProps.Nodes)//currently broken due to GIMS not doing things right //{ // if (matProp == null) continue; // if (matProp.Name != "P") continue; // var propStr = GetStringFromObjectList(matProp.Properties, 4); // var propId = matProp.Value as string; // if (propId == null) continue; // if (propId == "3dsMax|params|SPSName") spsName = propStr?.ToLowerInvariant() ?? "default"; // if (propId.StartsWith("3dsMax|params|FloatValueNames|FloatValueNames")) floatValueNames.Add(propStr); // if (propId.StartsWith("3dsMax|params|FloatValues|FloatValues")) floatValues.Add(GetVector4FromObjectList(matProp.Properties, 4)); // if (propId.StartsWith("3dsMax|params|TexValueNames|TexValueNames")) texValueNames.Add(propStr); // if (propId.StartsWith("3dsMax|params|TexValues|TexValues")) texValues.Add(matProp); //} #endregion foreach (var conn in matNode.Connections) { if (conn.Name == "Texture") { texConns.Add(conn); var texName = GetStringFromObjectList(conn.Properties, 1)?.Replace("Texture::", ""); var ftexName = conn["FileName"]?.Value as string; if (ftexName != null) { try { texName = Path.GetFileNameWithoutExtension(ftexName); } catch { } } texNames.Add(texName); } } if (texNames.Count > 1) { spsName = "normal"; } var spsFileName = spsName + ".sps"; shader.Name = JenkHash.GenHash(spsName); shader.FileName = JenkHash.GenHash(spsFileName); shader.ParametersList = new ShaderParametersBlock(); var paramsBlock = shader.ParametersList; var pNames = new List <ShaderParamNames>(); var pVals = new List <ShaderParameter>(); shader.Unknown_Ch = 0; shader.RenderBucket = 0; shader.Unknown_12h = 32768;//shrugs shader.Unknown_1Ch = 0; shader.Unknown_24h = 0; shader.Unknown_26h = 0; shader.Unknown_28h = 0; switch (spsName) { default: case "default": //shader.RenderBucket = 3; //shader.ParameterSize = 208; //shader.ParameterDataSize = 272; AddShaderParam(pNames, pVals, ShaderParamNames.DiffuseSampler, GetTextureBaseParam(texNames, 0)); //assume first texture is diffuse... AddShaderParam(pNames, pVals, ShaderParamNames.matMaterialColorScale, new Vector4(1, 0, 0, 1)); AddShaderParam(pNames, pVals, ShaderParamNames.HardAlphaBlend, new Vector4(0, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.useTessellation, new Vector4(0, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.wetnessMultiplier, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV1, new Vector4(0, 1, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV0, new Vector4(1, 0, 0, 0)); break; case "normal": //shader.RenderBucket = 0; //shader.ParameterSize = 320; //shader.ParameterDataSize = 400; AddShaderParam(pNames, pVals, ShaderParamNames.DiffuseSampler, GetTextureBaseParam(texNames, 0)); //assume first texture is diffuse... AddShaderParam(pNames, pVals, ShaderParamNames.BumpSampler, GetTextureBaseParam(texNames, 1)); //assume 2nd texture is normalmap.. AddShaderParam(pNames, pVals, ShaderParamNames.HardAlphaBlend, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.useTessellation, new Vector4(0, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.wetnessMultiplier, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.bumpiness, new Vector4(1, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.specularIntensityMult, new Vector4(0.5f, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.specularFalloffMult, new Vector4(20, 0, 0, 0)); //too metallic? AddShaderParam(pNames, pVals, ShaderParamNames.specularFresnel, new Vector4(0.9f, 0, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV1, new Vector4(0, 1, 0, 0)); AddShaderParam(pNames, pVals, ShaderParamNames.globalAnimUV0, new Vector4(1, 0, 0, 0)); break; } for (int i = 0; i < pVals.Count; i++) { var pVal = pVals[i]; if (pVal.DataType == 1) { pVal.Unknown_1h = (byte)(160 + ((pVals.Count - 1) - i));//seriously wtf is this and why } } MetaName[] nameHashes = new MetaName[pNames.Count]; for (int i = 0; i < pNames.Count; i++) { nameHashes[i] = (MetaName)pNames[i]; } paramsBlock.Hashes = nameHashes; paramsBlock.Parameters = pVals.ToArray(); paramsBlock.Count = pVals.Count; shader.ParameterSize = paramsBlock.ParametersSize; shader.ParameterDataSize = (ushort)(paramsBlock.BlockLength + 36);//but why +36? shader.ParameterCount = (byte)pVals.Count; shader.TextureParametersCount = paramsBlock.TextureParamsCount; shader.RenderBucketMask = (1u << shader.RenderBucket) | 0xFF00; return(shader); }
private void Search() { SearchResultsGrid.SelectedObject = null; if (CurrentFile?.RelDatasSorted == null) { return; } bool textsearch = SearchTextRadio.Checked; var text = SearchTextBox.Text; var textl = text.ToLowerInvariant(); uint hash = 0; uint hashl = 0; if (!uint.TryParse(text, out hash))//don't re-hash hashes { hash = JenkHash.GenHash(text); JenkIndex.Ensure(text); hashl = JenkHash.GenHash(textl); JenkIndex.Ensure(textl); } else { hashl = hash; } var results = new List <RelData>(); foreach (var rd in CurrentFile.RelDatasSorted) { if (textsearch) { if (((rd.Name?.ToLowerInvariant().Contains(textl)) ?? false) || (rd.NameHash == hash) || (rd.NameHash == hashl) || (rd.NameHash.ToString().ToLowerInvariant().Contains(textl))) { results.Add(rd); } } else { if ((rd.NameHash == hash) || (rd.NameHash == hashl)) { SearchResultsGrid.SelectedObject = rd; return; } } } if (textsearch && (results.Count > 0)) { SearchResultsGrid.SelectedObject = results.ToArray(); } else { SearchResultsGrid.SelectedObject = null; } }
public void Init(GameFileCache gameFileCache, XmlNode node) { Name = Xml.GetChildInnerText(node, "Name"); NameHash = new MetaHash(JenkHash.GenHash(Name.ToLower())); Sun = Xml.GetChildFloatAttribute(node, "Sun", "value"); Cloud = Xml.GetChildFloatAttribute(node, "Cloud", "value"); WindMin = Xml.GetChildFloatAttribute(node, "WindMin", "value"); WindMax = Xml.GetChildFloatAttribute(node, "WindMax", "value"); Rain = Xml.GetChildFloatAttribute(node, "Rain", "value"); Snow = Xml.GetChildFloatAttribute(node, "Snow", "value"); SnowMist = Xml.GetChildFloatAttribute(node, "SnowMist", "value"); Fog = Xml.GetChildFloatAttribute(node, "Fog", "value"); RippleBumpiness = Xml.GetChildFloatAttribute(node, "RippleBumpiness", "value"); RippleMinBumpiness = Xml.GetChildFloatAttribute(node, "RippleMinBumpiness", "value"); RippleMaxBumpiness = Xml.GetChildFloatAttribute(node, "RippleMaxBumpiness", "value"); RippleBumpinessWindScale = Xml.GetChildFloatAttribute(node, "RippleBumpinessWindScale", "value"); RippleScale = Xml.GetChildFloatAttribute(node, "RippleScale", "value"); RippleSpeed = Xml.GetChildFloatAttribute(node, "RippleSpeed", "value"); RippleVelocityTransfer = Xml.GetChildFloatAttribute(node, "RippleVelocityTransfer", "value"); OceanBumpiness = Xml.GetChildFloatAttribute(node, "OceanBumpiness", "value"); DeepOceanScale = Xml.GetChildFloatAttribute(node, "DeepOceanScale", "value"); OceanNoiseMinAmplitude = Xml.GetChildFloatAttribute(node, "OceanNoiseMinAmplitude", "value"); OceanWaveAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveAmplitude", "value"); ShoreWaveAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveAmplitude", "value"); OceanWaveWindScale = Xml.GetChildFloatAttribute(node, "OceanWaveWindScale", "value"); ShoreWaveWindScale = Xml.GetChildFloatAttribute(node, "ShoreWaveWindScale", "value"); OceanWaveMinAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveMinAmplitude", "value"); ShoreWaveMinAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveMinAmplitude", "value"); OceanWaveMaxAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveMaxAmplitude", "value"); ShoreWaveMaxAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveMaxAmplitude", "value"); OceanFoamIntensity = Xml.GetChildFloatAttribute(node, "OceanFoamIntensity", "value"); OceanFoamScale = Xml.GetChildFloatAttribute(node, "OceanFoamScale", "value"); RippleDisturb = Xml.GetChildFloatAttribute(node, "RippleDisturb", "value"); Lightning = Xml.GetChildFloatAttribute(node, "Lightning", "value"); Sandstorm = Xml.GetChildFloatAttribute(node, "Sandstorm", "value"); OldSettingName = Xml.GetChildInnerText(node, "OldSettingName"); DropSettingName = Xml.GetChildInnerText(node, "DropSettingName"); MistSettingName = Xml.GetChildInnerText(node, "MistSettingName"); GroundSettingName = Xml.GetChildInnerText(node, "GroundSettingName"); TimeCycleFilename = Xml.GetChildInnerText(node, "TimeCycleFilename"); CloudSettingsName = Xml.GetChildInnerText(node, "CloudSettingsName"); if (!string.IsNullOrEmpty(TimeCycleFilename)) { //TODO: RpfMan should be able to get the right version? or maybe let gameFileCache do it! string fname = TimeCycleFilename.ToLower(); bool useupd = gameFileCache.EnableDlc; if (useupd) { fname = fname.Replace("common:", "update/update.rpf/common"); } XmlDocument tcxml = gameFileCache.RpfMan.GetFileXml(fname); if (useupd && !tcxml.HasChildNodes) { fname = TimeCycleFilename.ToLower(); tcxml = gameFileCache.RpfMan.GetFileXml(fname); } foreach (XmlNode cycle in tcxml.DocumentElement.ChildNodes) { TimeCycleData = new WeatherCycleKeyframeData(); TimeCycleData.Init(cycle); } } }
public void Init(GameFileCache gameFileCache, bool sounds = true, bool game = true) { var rpfman = gameFileCache.RpfMan; var datrelentries = new Dictionary <uint, RpfFileEntry>(); var awcentries = new Dictionary <uint, RpfFileEntry>(); void addRpfDatRels(RpfFile rpffile) { if (rpffile.AllEntries == null) { return; } foreach (var entry in rpffile.AllEntries) { if (entry is RpfFileEntry) { var fentry = entry as RpfFileEntry; //if (entry.NameLower.EndsWith(".rel")) //{ // datrels[entry.NameHash] = fentry; //} if (sounds && entry.NameLower.EndsWith(".dat54.rel")) { datrelentries[entry.NameHash] = fentry; } if (game && entry.NameLower.EndsWith(".dat151.rel")) { datrelentries[entry.NameHash] = fentry; } } } } void addRpfAwcs(RpfFile rpffile) { if (rpffile.AllEntries == null) { return; } foreach (var entry in rpffile.AllEntries) { if (entry is RpfFileEntry) { var fentry = entry as RpfFileEntry; if (entry.NameLower.EndsWith(".awc")) { var shortname = entry.GetShortNameLower(); var parentname = entry.Parent?.GetShortNameLower() ?? ""; if (string.IsNullOrEmpty(parentname) && (entry.Parent?.File != null)) { parentname = entry.Parent.File.NameLower; int ind = parentname.LastIndexOf('.'); if (ind > 0) { parentname = parentname.Substring(0, ind); } } var contname = parentname + "/" + shortname; var hash = JenkHash.GenHash(contname); awcentries[hash] = fentry; } } } } var audrpf = rpfman.FindRpfFile("x64\\audio\\audio_rel.rpf"); if (audrpf != null) { addRpfDatRels(audrpf); } foreach (var baserpf in gameFileCache.BaseRpfs) { addRpfAwcs(baserpf); } if (gameFileCache.EnableDlc) { var updrpf = rpfman.FindRpfFile("update\\update.rpf"); if (updrpf != null) { addRpfDatRels(updrpf); } foreach (var dlcrpf in gameFileCache.DlcActiveRpfs) //load from current dlc rpfs { addRpfDatRels(dlcrpf); addRpfAwcs(dlcrpf); } } var soundsdb = new Dictionary <uint, Dat54Sound>(); var gamedb = new Dictionary <uint, Dat151RelData>(); foreach (var datentry in datrelentries.Values) { var relfile = rpfman.GetFile <RelFile>(datentry); if (relfile?.RelDatas != null) { foreach (var rd in relfile.RelDatas) { if (rd is Dat54Sound sd) { soundsdb[sd.NameHash] = sd; } else if (rd is Dat151RelData gd) { gamedb[gd.NameHash] = gd; } } } } ContainerDB = awcentries; if (sounds) { SoundsDB = soundsdb; } if (game) { GameDB = gamedb; } IsInited = true; }
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 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("navmeshes") + "\\"; GenerateButton.Enabled = false; List <YmapFile> projectYmaps = ProjectForm.CurrentProjectFile.YmapFiles; var pname = NameTextBox.Text; Task.Run(() => { 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>(); var eemin = new Vector3(float.MaxValue); var eemax = new Vector3(float.MinValue); var semin = new Vector3(float.MaxValue); var semax = new Vector3(float.MinValue); foreach (var ymap in projectYmaps) { 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; } else if (fdwbl != null) { lightAttrs = fdwbl.OwnerFragment?.LightAttributes; } 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); foreach (var la in lightAttrs) { //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.Id == 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; ushort[] pinds = skeleton.ParentIndices; ushort parentind = ((pinds != null) && (boneidx < pinds.Length)) ? pinds[boneidx] : (ushort)65535; while (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] : (ushort)65535; } } } } Vector3 lpos = new Vector3(la.PositionX, la.PositionY, la.PositionZ); Vector3 ldir = new Vector3(la.DirectionX, la.DirectionY, la.DirectionZ); 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 = 123456; //TODO: what hash to use??? //@Calcium: //1 = point //2 = spot //4 = capsule uint type = 1; uint t = la.TimeFlags + (type << 26); var maxext = (byte)Math.Max(Math.Max(la.ExtentX, la.ExtentY), la.ExtentZ); position.Add(new MetaVECTOR3(epos)); colour.Add(c); direction.Add(new MetaVECTOR3(edir)); falloff.Add(la.Falloff); falloffExponent.Add(la.FalloffExponent); timeAndStateFlags.Add(t); hash.Add(h); coneInnerAngle.Add((byte)la.ConeInnerAngle); coneOuterAngleOrCapExt.Add(Math.Max((byte)la.ConeOuterAngle, maxext)); coronaIntensity.Add((byte)la.CoronaIntensity); } } } } } if (position.Count == 0) { MessageBox.Show("No lights found in project!"); return; } var lodymap = new YmapFile(); var distymap = new YmapFile(); var ll = new YmapLODLights(); var dl = new YmapDistantLODLights(); var cdl = new CDistantLODLight(); cdl.category = 1; 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; distymap._CMapData.entitiesExtentsMin = eemin; distymap._CMapData.entitiesExtentsMax = eemax; distymap._CMapData.streamingExtentsMin = semin - 5000f; //make it huge distymap._CMapData.streamingExtentsMax = semax + 5000f; 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; ProjectForm.Invoke((MethodInvoker) delegate { ProjectForm.AddYmapToProject(lodymap); ProjectForm.AddYmapToProject(distymap); }); var stats = ""; UpdateStatus("Process complete. " + stats); GenerateComplete(); }); }