public void Init(string name, GameFileCache gfc, bool hidef = true) { Name = name; var modelnamel = name.ToLowerInvariant(); MetaHash modelhash = JenkHash.GenHash(modelnamel); MetaHash modelhashhi = JenkHash.GenHash(modelnamel + "_hi"); var yfthash = hidef ? modelhashhi : modelhash; VehicleInitData vid = null; if (gfc.VehiclesInitDict.TryGetValue(modelhash, out vid)) { bool vehiclechange = NameHash != modelhash; ConvRoofDict = null; ConvRoofClip = null; ModelHash = yfthash; NameHash = modelhash; InitData = vid; Yft = gfc.GetYft(ModelHash); while ((Yft != null) && (!Yft.Loaded)) { Thread.Sleep(20);//kinda hacky Yft = gfc.GetYft(ModelHash); } DisplayMake = GlobalText.TryGetString(JenkHash.GenHash(vid.vehicleMakeName.ToLowerInvariant())); DisplayName = GlobalText.TryGetString(JenkHash.GenHash(vid.gameName.ToLowerInvariant())); if (!string.IsNullOrEmpty(vid.animConvRoofDictName) && (vid.animConvRoofDictName.ToLowerInvariant() != "null")) { var ycdhash = JenkHash.GenHash(vid.animConvRoofDictName.ToLowerInvariant()); var cliphash = JenkHash.GenHash(vid.animConvRoofName?.ToLowerInvariant()); ConvRoofDict = gfc.GetYcd(ycdhash); while ((ConvRoofDict != null) && (!ConvRoofDict.Loaded)) { Thread.Sleep(20);//kinda hacky ConvRoofDict = gfc.GetYcd(ycdhash); } ClipMapEntry cme = null; ConvRoofDict?.ClipMap?.TryGetValue(cliphash, out cme); ConvRoofClip = cme; } } else { ModelHash = 0; NameHash = 0; InitData = null; Yft = null; DisplayMake = "-"; DisplayName = "-"; ConvRoofDict = null; ConvRoofClip = null; } UpdateEntity(); }
private void RenderVehicle() { ClipMapEntry clip = null; if (PlayConvRoofAnim) { clip = SelectedVehicle.ConvRoofClip; } Renderer.RenderVehicle(SelectedVehicle, clip); }
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(); }
public void Update(float newTime) { if (newTime > Duration) { newTime = 0.0f; //stop or loop? } if (newTime >= PlaybackTime) { RaiseEvents(newTime); } else { //reset playback to beginning, and seek to newTime RaiseEvents(Duration);//raise all events up to the end first PlaybackTime = 0.0f; NextLoadEvent = 0; NextPlayEvent = 0; NextCameraCut = 0; NextConcatData = 0; RaiseEvents(newTime); } PlaybackTime = newTime; int cutIndex = 0; float cutStart = 0.0f; for (cutIndex = 0; cutIndex < CameraCutList?.Length; cutIndex++) { var cutTime = CameraCutList[cutIndex]; if (cutTime > newTime) { break; } cutStart = cutTime; } float cutOffset = newTime - cutStart;//offset into the current cut void updateObjectTransform(CutsceneObject obj, ClipMapEntry cme, ushort boneTag, byte posTrack, byte rotTrack) { if (cme != null) { if (cme.Clip is ClipAnimation canim) { if (canim.Animation != null) { var t = canim.GetPlaybackTime(cutOffset); var f = canim.Animation.GetFramePosition(t); var p = canim.Animation.FindBoneIndex(boneTag, posTrack); var r = canim.Animation.FindBoneIndex(boneTag, rotTrack); if (p >= 0) { obj.Position = canim.Animation.EvaluateVector4(f, p, true).XYZ(); } if (r >= 0) { obj.Rotation = canim.Animation.EvaluateQuaternion(f, r, true); } } } else if (cme.Clip is ClipAnimationList alist) { if (alist.Animations?.Data != null) { foreach (var anim in alist.Animations.Data) { var t = anim.GetPlaybackTime(cutOffset); var f = anim.Animation.GetFramePosition(t); var p = anim.Animation.FindBoneIndex(boneTag, posTrack); var r = anim.Animation.FindBoneIndex(boneTag, rotTrack); if (p >= 0) { obj.Position = anim.Animation.EvaluateVector4(f, p, true).XYZ(); } if (r >= 0) { obj.Rotation = anim.Animation.EvaluateQuaternion(f, r, true); } } } } } } var ycd = (cutIndex < (Ycds?.Length ?? 0)) ? Ycds[cutIndex] : null; if (ycd?.CutsceneMap != null) { ClipMapEntry cme = null; if (CameraObject != null) { ycd.CutsceneMap.TryGetValue(CameraObject.Name, out cme); updateObjectTransform(CameraObject, cme, 0, 7, 8); if (cme != null) { var pos = Position; var rot = Rotation; pos = pos + rot.Multiply(CameraObject.Position); rot = rot * CameraObject.Rotation * CameraRotationOffset; CameraObject.Position = pos; CameraObject.Rotation = rot; } } if (SceneObjects != null) { foreach (var obj in SceneObjects.Values) { if (obj.Enabled == false) { continue; } var pos = Position; var rot = Rotation; var animate = (obj.Ped != null) || (obj.Prop != null) || (obj.Vehicle != null) || (obj.Weapon != null); if (animate) { ycd.CutsceneMap.TryGetValue(obj.AnimHash, out cme); if (cme != null) { cme.OverridePlayTime = true; cme.PlayTime = cutOffset; updateObjectTransform(obj, cme, 0, 5, 6); //using root animation bone ids pos = pos + rot.Multiply(obj.Position); rot = rot * obj.Rotation; } obj.AnimClip = cme; } if (obj.Ped != null) { obj.Ped.Position = pos; obj.Ped.Rotation = rot; obj.Ped.UpdateEntity(); obj.Ped.AnimClip = cme; } if (obj.Prop != null) { obj.Prop.Position = pos; obj.Prop.Orientation = rot; } if (obj.Vehicle != null) { obj.Vehicle.Position = pos; obj.Vehicle.Rotation = rot; obj.Vehicle.UpdateEntity(); } if (obj.Weapon != null) { obj.Weapon.Position = pos; obj.Weapon.Rotation = rot; obj.Weapon.UpdateEntity(); } } } } }
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); }