CodeWalker/World/CutsceneForm.cs

1252 lines
38 KiB
C#
Raw Normal View History

2019-11-25 17:44:16 +08:00
using CodeWalker.GameFiles;
2019-11-25 22:26:28 +08:00
using CodeWalker.Rendering;
2019-11-25 17:44:16 +08:00
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CodeWalker.World
{
public partial class CutsceneForm : Form
{
private WorldForm WorldForm;
private GameFileCache GameFileCache;
private Cutscene Cutscene = null;
private bool AnimateCamera = true;
private bool Playing = false;
class CutsceneDropdownItem
{
public RpfEntry RpfEntry { get; set; }
public override string ToString()
{
return RpfEntry?.Path ?? "";
}
}
public CutsceneForm(WorldForm worldForm)
{
WorldForm = worldForm;
GameFileCache = WorldForm.GameFileCache;
InitializeComponent();
}
public void UpdateAnimation(float elapsed)
{
if (Cutscene != null)
{
if (Playing)
{
var newt = Cutscene.PlaybackTime + elapsed;
Cutscene.Update(newt);
}
if (AnimateCamera && (Cutscene.CameraObject != null))
{
var pos = Cutscene.CameraObject.Position;
var rot = Cutscene.CameraObject.Rotation;
2019-11-25 17:44:16 +08:00
WorldForm.SetCameraTransform(pos, rot);
if (Cutscene.CameraClipUpdate)
{
WorldForm.SetCameraClipPlanes(Cutscene.CameraNearClip, Cutscene.CameraFarClip);
Cutscene.CameraClipUpdate = false;
}
2019-11-25 17:44:16 +08:00
}
}
}
public void GetVisibleYmaps(Camera camera, Dictionary<MetaHash, YmapFile> ymaps)
{
2019-11-25 22:26:28 +08:00
//use a temporary ymap for entities?
var renderer = WorldForm?.Renderer;
if (renderer == null) return;
if (Cutscene == null) return;
Cutscene.Render(renderer);
2019-11-25 17:44:16 +08:00
}
private void SelectCutscene(CutsceneDropdownItem dditem)
{
Cursor = Cursors.WaitCursor;
Task.Run(() =>
{
CutFile cutFile = null;
Cutscene cutscene = null;
if (GameFileCache.IsInited)
{
var entry = dditem?.RpfEntry as RpfFileEntry;
if (entry != null)
{
cutFile = new CutFile(entry);
GameFileCache.RpfMan.LoadFile(cutFile, entry);
cutscene = new Cutscene();
cutscene.Init(cutFile, GameFileCache, WorldForm);
2019-11-25 17:44:16 +08:00
}
}
CutsceneLoaded(cutscene);
});
}
private void CutsceneLoaded(Cutscene cs)
{
if (InvokeRequired)
{
try
{
Invoke(new Action(() => { CutsceneLoaded(cs); }));
}
catch
{ }
return;
}
Cutscene = cs;
LoadTreeView(cs);
TimeTrackBar.Maximum = (int)(cs.Duration * 10.0f);
TimeTrackBar.Value = 0;
UpdateTimeLabel();
Cursor = Cursors.Default;
}
private void LoadTreeView(Cutscene cs)
{
CutsceneTreeView.Nodes.Clear();
var cutFile = cs?.CutFile;
var cf = cutFile?.CutsceneFile2;
if (cf != null)
{
var csnode = CutsceneTreeView.Nodes.Add(cutFile.FileEntry?.Name);
csnode.Tag = cs;
2019-11-25 22:26:28 +08:00
if (cs.SceneObjects != null)
2019-11-25 17:44:16 +08:00
{
var objsnode = csnode.Nodes.Add("Objects");
objsnode.Name = "Objects";
2019-11-25 22:26:28 +08:00
foreach (var obj in cs.SceneObjects.Values)
2019-11-25 17:44:16 +08:00
{
var objnode = objsnode.Nodes.Add(obj.ToString());
objnode.Tag = obj;
}
}
if (cf.pCutsceneEventList != null)
{
var evtsnode = csnode.Nodes.Add("Events");
evtsnode.Name = "Events";
foreach (var evt in cf.pCutsceneEventList)
{
var evtnode = evtsnode.Nodes.Add(evt.ToString());
evtnode.Tag = evt;
}
}
if (cf.pCutsceneLoadEventList != null)
{
var ldesnode = csnode.Nodes.Add("Load Events");
ldesnode.Name = "Load Events";
foreach (var lev in cf.pCutsceneLoadEventList)
{
var ldenode = ldesnode.Nodes.Add(lev.ToString());
ldenode.Tag = lev;
}
}
csnode.Expand();
CutsceneTreeView.SelectedNode = csnode;
}
}
private void UpdateTimeTrackBar()
{
var tim = Cutscene?.PlaybackTime ?? 0.0f;
var itim = (int)(tim * 10.0f);
TimeTrackBar.Value = itim;
}
private void UpdateTimeLabel()
{
var tim = Cutscene?.PlaybackTime ?? 0.0f;
var dur = Cutscene?.Duration ?? 0.0f;
TimeLabel.Text = tim.ToString("0.00") + " / " + dur.ToString("0.00");
}
private void CutsceneForm_Load(object sender, EventArgs e)
{
if (!GameFileCache.IsInited) return;//what to do here?
var rpfman = GameFileCache.RpfMan;
var rpflist = rpfman.AllRpfs; //loadedOnly ? gfc.ActiveMapRpfFiles.Values.ToList() :
var dditems = new List<CutsceneDropdownItem>();
foreach (var rpf in rpflist)
{
foreach (var entry in rpf.AllEntries)
{
if (entry.NameLower.EndsWith(".cut"))
{
var dditem = new CutsceneDropdownItem();
dditem.RpfEntry = entry;
dditems.Add(dditem);
}
}
}
CutsceneComboBox.Items.Clear();
CutsceneComboBox.Items.AddRange(dditems.ToArray());
}
private void CutsceneForm_FormClosed(object sender, FormClosedEventArgs e)
{
WorldForm?.OnCutsceneFormClosed();
}
private void CutsceneComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
var item = CutsceneComboBox.SelectedItem as CutsceneDropdownItem;
SelectCutscene(item);
}
private void CutsceneTreeView_AfterSelect(object sender, TreeViewEventArgs e)
{
InfoPropertyGrid.SelectedObject = CutsceneTreeView.SelectedNode?.Tag;
}
private void AnimateCameraCheckBox_CheckedChanged(object sender, EventArgs e)
{
AnimateCamera = AnimateCameraCheckBox.Checked;
if (!AnimateCamera)
{
WorldForm?.ResetCameraClipPlanes();
}
else
{
if (Cutscene != null)
{
Cutscene.CameraClipUpdate = true;
}
}
2019-11-25 17:44:16 +08:00
}
private void PlayStopButton_Click(object sender, EventArgs e)
{
if (Playing)
{
Playing = false;
PlayStopButton.Text = "Play";
PlaybackTimer.Enabled = false;
}
else
{
Playing = true;
PlayStopButton.Text = "Stop";
PlaybackTimer.Enabled = true;
}
}
private void PlaybackTimer_Tick(object sender, EventArgs e)
{
if (Playing)
{
UpdateTimeTrackBar();
UpdateTimeLabel();
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Cutscene
{
public CutFile CutFile { get; set; } = null;
private GameFileCache GameFileCache = null;
private WorldForm WorldForm = null;
2019-11-25 17:44:16 +08:00
public float[] CameraCutList { get; set; } = null;
public YcdFile[] Ycds { get; set; } = null;
public float Duration { get; set; } = 0.0f;
public float PlaybackTime { get; set; } = 0.0f;
public Dictionary<int, CutObject> Objects { get; set; } = null;
public Dictionary<int, CutsceneObject> SceneObjects { get; set; } = null;
public CutEvent[] LoadEvents { get; set; } = null;
public CutEvent[] PlayEvents { get; set; } = null;
2019-11-25 23:50:30 +08:00
public CutConcatData[] ConcatDatas { get; set; } = null;
2019-11-25 17:44:16 +08:00
public int NextLoadEvent { get; set; } = 0;
public int NextPlayEvent { get; set; } = 0;
public int NextCameraCut { get; set; } = 0;
2019-11-25 23:50:30 +08:00
public int NextConcatData { get; set; } = 0;
2019-11-25 17:44:16 +08:00
public Gxt2File Gxt2File { get; set; } = null;
public Vector3 Position { get; set; }
public Quaternion Rotation { get; set; }
public CutsceneObject CameraObject = null;
public float CameraNearClip { get; set; } = 0.5f;
public float CameraFarClip { get; set; } = 12000.0f;
public bool CameraClipUpdate = false;//signal to the form to update the camera clip planes
public Quaternion CameraRotationOffset = Quaternion.RotationAxis(Vector3.UnitX, -1.57079632679f) * Quaternion.RotationAxis(Vector3.UnitZ, 3.141592653f);
2019-11-25 17:44:16 +08:00
public void Init(CutFile cutFile, GameFileCache gfc, WorldForm wf)
2019-11-25 17:44:16 +08:00
{
CutFile = cutFile;
GameFileCache = gfc;
WorldForm = wf;
2019-11-25 17:44:16 +08:00
var csf = cutFile?.CutsceneFile2;
if (csf == null) return;
if (gfc == null) return;
Duration = csf.fTotalDuration;
CameraCutList = csf.cameraCutList;
Position = csf.vOffset;
Rotation = Quaternion.RotationAxis(Vector3.UnitZ, csf.fRotation);
Objects = csf.ObjectsDict;
LoadEvents = RecastArray<CutEvent>(csf.pCutsceneLoadEventList);
PlayEvents = RecastArray<CutEvent>(csf.pCutsceneEventList);
2019-11-25 23:50:30 +08:00
ConcatDatas = csf.concatDataList;
2019-11-25 17:44:16 +08:00
LoadYcds();
CreateSceneObjects();
RaiseEvents(0.0f);
}
private void LoadYcds()
{
int cutListCount = (CameraCutList?.Length ?? 0) + 1;
var shortName = CutFile.FileEntry?.GetShortNameLower() ?? "";
Ycds = new YcdFile[cutListCount];
if (!string.IsNullOrEmpty(shortName))
{
for (int i = 0; i < cutListCount; i++)
{
var ycdname = shortName + "-" + i.ToString();
var ycdhash = JenkHash.GenHash(ycdname);
var ycd = GameFileCache.GetYcd(ycdhash);
while ((ycd != null) && (!ycd.Loaded))
{
Thread.Sleep(1);//bite me
2019-11-25 17:44:16 +08:00
ycd = GameFileCache.GetYcd(ycdhash);
}
if (ycd != null)
{
ycd.BuildCutsceneMap(i);
}
Ycds[i] = ycd;
}
}
}
public void Update(float newTime)
{
2019-11-25 19:00:01 +08:00
if (newTime > Duration)
{
newTime = 0.0f; //stop or loop?
}
2019-11-25 17:44:16 +08:00
if (newTime >= PlaybackTime)
{
RaiseEvents(newTime);
}
else
{
//reset playback to beginning, and seek to newTime
2019-11-25 19:00:01 +08:00
RaiseEvents(Duration);//raise all events up to the end first
PlaybackTime = 0.0f;
NextLoadEvent = 0;
NextPlayEvent = 0;
NextCameraCut = 0;
2019-11-25 23:50:30 +08:00
NextConcatData = 0;
2019-11-25 19:00:01 +08:00
RaiseEvents(newTime);
2019-11-25 17:44:16 +08:00
}
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
2019-11-25 22:26:28 +08:00
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);
}
}
}
}
}
2019-11-25 17:44:16 +08:00
var ycd = (cutIndex < (Ycds?.Length ?? 0)) ? Ycds[cutIndex] : null;
if (ycd?.CutsceneMap != null)
{
2019-11-25 22:26:28 +08:00
ClipMapEntry cme = null;
2019-11-25 17:44:16 +08:00
if (CameraObject != null)
{
ycd.CutsceneMap.TryGetValue(CameraObject.Name, out cme);
2019-11-25 22:26:28 +08:00
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;
}
2019-11-25 22:26:28 +08:00
}
if (SceneObjects != null)
{
foreach (var obj in SceneObjects.Values)
2019-11-25 17:44:16 +08:00
{
2019-11-26 20:35:08 +08:00
if (obj.Enabled == false) continue;
2019-11-26 17:47:47 +08:00
var pos = Position;
var rot = Rotation;
2019-11-27 10:32:07 +08:00
var animate = (obj.Ped != null) || (obj.Prop != null) || (obj.Vehicle != null) || (obj.Weapon != null);
2019-11-26 17:47:47 +08:00
if (animate)
2019-11-25 17:44:16 +08:00
{
ycd.CutsceneMap.TryGetValue(obj.AnimHash, out cme);
2019-11-25 22:26:28 +08:00
if (cme != null)
2019-11-25 17:44:16 +08:00
{
2019-11-25 22:26:28 +08:00
cme.OverridePlayTime = true;
cme.PlayTime = cutOffset;
2019-11-26 17:47:47 +08:00
updateObjectTransform(obj, cme, 0, 5, 6); //using root animation bone ids
2019-11-25 23:50:30 +08:00
pos = pos + rot.Multiply(obj.Position);
2019-11-25 22:26:28 +08:00
rot = rot * obj.Rotation;
}
2019-11-27 10:32:07 +08:00
obj.AnimClip = cme;
2019-11-26 17:47:47 +08:00
}
if (obj.Ped != null)
{
2019-11-25 22:26:28 +08:00
obj.Ped.Position = pos;
obj.Ped.Rotation = rot;
obj.Ped.UpdateEntity();
2019-11-25 22:26:28 +08:00
obj.Ped.AnimClip = cme;
}
if (obj.Prop != null)
{
obj.Prop.Position = pos;
obj.Prop.Orientation = rot;
}
2019-11-26 17:47:47 +08:00
if (obj.Vehicle != null)
{
obj.Vehicle.Position = pos;
obj.Vehicle.Rotation = rot;
obj.Vehicle.UpdateEntity();
}
2019-11-27 10:32:07 +08:00
if (obj.Weapon != null)
{
obj.Weapon.Position = pos;
obj.Weapon.Rotation = rot;
obj.Weapon.UpdateEntity();
}
2019-11-25 17:44:16 +08:00
}
2019-11-25 22:26:28 +08:00
}
2019-11-25 17:44:16 +08:00
}
}
2019-11-25 22:26:28 +08:00
public void Render(Renderer renderer)
{
if (SceneObjects != null)
{
foreach (var obj in SceneObjects.Values)
{
2019-11-26 20:35:08 +08:00
if (obj.Enabled == false) continue;
2019-11-25 22:26:28 +08:00
if (obj.Ped != null)
{
renderer.RenderPed(obj.Ped);
}
if (obj.Prop != null)
{
renderer.RenderArchetype(obj.Prop.Archetype, obj.Prop, null, true, obj.AnimClip);
}
2019-11-26 17:47:47 +08:00
if (obj.Vehicle != null)
{
renderer.RenderVehicle(obj.Vehicle, obj.AnimClip);
}
2019-11-27 10:32:07 +08:00
if (obj.Weapon != null)
{
renderer.RenderWeapon(obj.Weapon, obj.AnimClip);
}
2019-11-25 22:26:28 +08:00
}
foreach (var obj in SceneObjects.Values)
{
if (obj.Enabled == false) continue;
if (obj.HideEntity != null)
{
renderer.RenderHideEntity(obj.HideEntity);
}
}
2019-11-25 22:26:28 +08:00
}
}
2019-11-25 17:44:16 +08:00
private void RaiseEvents(float upToTime)
{
int i;
for (i = NextLoadEvent; i < LoadEvents?.Length; i++)
{
var e = LoadEvents[i];
if (e != null)
{
if (e.fTime > upToTime) break;
RaiseEvent(e);
}
}
NextLoadEvent = i;
for (i = NextPlayEvent; i < PlayEvents?.Length; i++)
{
var e = PlayEvents[i];
if (e != null)
{
if (e.fTime > upToTime) break;
RaiseEvent(e);
}
}
NextPlayEvent = i;
for (i = NextCameraCut; i < CameraCutList?.Length; i++)
{
var c = CameraCutList[i];
if (c > upToTime) break;
}
NextCameraCut = i;
2019-11-25 23:50:30 +08:00
for (i = NextConcatData; i < ConcatDatas?.Length; i++)
{
var c = ConcatDatas[i];
if (c.fStartTime > upToTime) break;
if (c.cSceneName == 0) break;
Position = c.vOffset;
Rotation = Quaternion.RotationAxis(Vector3.UnitZ, c.fRotation * 0.0174532925f); //is this right?
}
NextConcatData = i;
2019-11-25 17:44:16 +08:00
}
private void RaiseEvent(CutEvent e)
{
switch (e.iEventId)
{
case CutEventType.LoadScene: LoadScene(e); break;
case CutEventType.LoadAnimation: LoadAnimation(e); break;
case CutEventType.LoadAudio: LoadAudio(e); break;
case CutEventType.LoadModels: LoadModels(e); break;
case CutEventType.LoadRayfireDes: LoadRayfireDes(e); break;
case CutEventType.LoadParticles: LoadParticles(e); break;
case CutEventType.LoadOverlays: LoadOverlays(e); break;
case CutEventType.LoadGxt2: LoadGxt2(e); break;
case CutEventType.UnloadModels: UnloadModels(e); break;
case CutEventType.UnloadRayfireDes: UnloadRayfireDes(e); break;
case CutEventType.EnableScreenFade: EnableScreenFade(e); break;
case CutEventType.EnableHideObject: EnableHideObject(e); break;
case CutEventType.EnableFixupModel: EnableFixupModel(e); break;
case CutEventType.EnableBlockBounds: EnableBlockBounds(e); break;
case CutEventType.EnableAnimation: EnableAnimation(e); break;
case CutEventType.EnableParticleEffect: EnableParticleEffect(e); break;
case CutEventType.EnableOverlay: EnableOverlay(e); break;
case CutEventType.EnableAudio: EnableAudio(e); break;
case CutEventType.EnableCamera: EnableCamera(e); break;
case CutEventType.EnableLight: EnableLight(e); break;
case CutEventType.DisableScreenFade: DisableScreenFade(e); break;
case CutEventType.DisableHideObject: DisableHideObject(e); break;
case CutEventType.DisableBlockBounds: DisableBlockBounds(e); break;
case CutEventType.DisableAnimation: DisableAnimation(e); break;
case CutEventType.DisableParticleEffect: DisableParticleEffect(e); break;
case CutEventType.DisableOverlay: DisableOverlay(e); break;
case CutEventType.DisableAudio: DisableAudio(e); break;
case CutEventType.DisableCamera: DisableCamera(e); break;
case CutEventType.DisableLight: DisableLight(e); break;
case CutEventType.Subtitle: Subtitle(e); break;
case CutEventType.PedVariation: PedVariation(e); break;
case CutEventType.CameraCut: CameraCut(e); break;
case CutEventType.CameraShadowCascade: CameraShadowCascade(e); break;
case CutEventType.CameraUnk1: CameraUnk1(e); break;
case CutEventType.CameraUnk2: CameraUnk2(e); break;
case CutEventType.CameraUnk3: CameraUnk3(e); break;
case CutEventType.CameraUnk4: CameraUnk4(e); break;
case CutEventType.CameraUnk5: CameraUnk5(e); break;
case CutEventType.CameraUnk6: CameraUnk6(e); break;
case CutEventType.CameraUnk7: CameraUnk7(e); break;
case CutEventType.CameraUnk8: CameraUnk8(e); break;
case CutEventType.DecalUnk1: DecalUnk1(e); break;
case CutEventType.DecalUnk2: DecalUnk2(e); break;
case CutEventType.PropUnk1: PropUnk1(e); break;
case CutEventType.Unk1: Unk1(e); break;
case CutEventType.Unk2: Unk2(e); break;
case CutEventType.VehicleUnk1: VehicleUnk1(e); break;
case CutEventType.PedUnk1: PedUnk1(e); break;
default: break;
}
}
private void LoadScene(CutEvent e)
{
var args = e.EventArgs as CutLoadSceneEventArgs;
if (args == null)
{ return; }
Position = args.vOffset;
Rotation = Quaternion.RotationAxis(Vector3.UnitZ, args.fRotation * 0.0174532925f);//is this right?
}
private void LoadAnimation(CutEvent e)
{
var args = e.EventArgs as CutNameEventArgs;
if (args == null)
{ return; }
}
private void LoadAudio(CutEvent e)
{
var args = e.EventArgs as CutNameEventArgs;
if (args == null)
{ return; }
}
private void LoadModels(CutEvent e)
{
var args = e.EventArgs as CutObjectIdListEventArgs;
if (args == null)
{ return; }
2019-11-26 20:35:08 +08:00
if (args.iObjectIdList == null) return;
foreach (var objid in args.iObjectIdList)
{
CutsceneObject obj = null;
SceneObjects.TryGetValue(objid, out obj);
if (obj != null)
{
obj.Enabled = true;
}
}
2019-11-25 17:44:16 +08:00
}
private void LoadRayfireDes(CutEvent e)
{
}
private void LoadParticles(CutEvent e)
{
var args = e.EventArgs as CutObjectIdListEventArgs;
if (args == null)
{ return; }
}
private void LoadOverlays(CutEvent e)
{
var args = e.EventArgs as CutObjectIdListEventArgs;
if (args == null)
{ return; }
}
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 UnloadModels(CutEvent e)
{
var args = e.EventArgs as CutObjectIdListEventArgs;
if (args == null)
{ return; }
2019-11-26 20:35:08 +08:00
if (args.iObjectIdList == null) return;
foreach (var objid in args.iObjectIdList)
{
CutsceneObject obj = null;
SceneObjects.TryGetValue(objid, out obj);
if (obj != null)
{
obj.Enabled = false;
}
}
2019-11-25 17:44:16 +08:00
}
private void UnloadRayfireDes(CutEvent e)
{
}
private void EnableHideObject(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
CutsceneObject cso = null;
SceneObjects.TryGetValue(oe.iObjectId, out cso);
if (cso != null)
{
cso.Enabled = true;
}
2019-11-25 17:44:16 +08:00
}
private void EnableFixupModel(CutEvent e)
{
}
private void EnableBlockBounds(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
}
private void EnableScreenFade(CutEvent e)
{
}
private void EnableAnimation(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
}
private void EnableParticleEffect(CutEvent e)
{
}
private void EnableOverlay(CutEvent e)
{
}
private void EnableAudio(CutEvent e)
{
var args = e.EventArgs as CutNameEventArgs;
if (args == null)
{ return; }
}
private void EnableCamera(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
}
private void EnableLight(CutEvent e)
{
}
private void DisableHideObject(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
CutsceneObject cso = null;
SceneObjects.TryGetValue(oe.iObjectId, out cso);
if (cso != null)
{
cso.Enabled = false;
}
2019-11-25 17:44:16 +08:00
}
private void DisableBlockBounds(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
}
private void DisableScreenFade(CutEvent e)
{
}
private void DisableAnimation(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
}
private void DisableParticleEffect(CutEvent e)
{
}
private void DisableOverlay(CutEvent e)
{
}
private void DisableAudio(CutEvent e)
{
var args = e.EventArgs as CutNameEventArgs;
if (args == null)
{ return; }
}
private void DisableCamera(CutEvent e)
{
var oe = e as CutObjectIdEvent;
if (oe == null) return;
2019-11-25 17:44:16 +08:00
}
private void DisableLight(CutEvent e)
{
}
private void Subtitle(CutEvent e)
{
var args = e.EventArgs as CutSubtitleEventArgs;
if (args == null)
{ return; }
if (WorldForm != null)
{
var txt = args.cName.ToString();
var dur = args.fSubtitleDuration;
txt = txt.Replace("~z~", "");
2019-11-25 22:26:28 +08:00
txt = txt.Replace("~c~~n~", "\n - ");
txt = txt.Replace("~n~", "\n");
txt = txt.Replace("~c~", " - ");
2019-11-25 22:26:28 +08:00
txt = txt.Replace("~t~", " - ");
WorldForm.ShowSubtitle(txt, dur);
}
2019-11-25 17:44:16 +08:00
}
private void PedVariation(CutEvent e)
{
var args = e.EventArgs as CutObjectVariationEventArgs;
if (args == null)
{ return; }
var oe = e as CutObjectIdEvent;
if (oe == null)
{ return; }
2019-11-26 10:14:46 +08:00
CutsceneObject cso = null;
SceneObjects.TryGetValue(oe.iObjectId, out cso);
if (cso?.Ped != null)
{
int comp = args.iComponent;
int drbl = args.iDrawable;
int texx = args.iTexture;
Task.Run(() =>
{
cso.Ped.SetComponentDrawable(comp, drbl, 0, texx, GameFileCache);
});
}
2019-11-25 17:44:16 +08:00
}
private void CameraCut(CutEvent e)
{
var args = e.EventArgs as CutCameraCutEventArgs;
if (args == null)
{ return; }
var oe = e as CutObjectIdEvent;
if (oe == null)
{ return; }
CutsceneObject obj = null;
SceneObjects.TryGetValue(oe.iObjectId, out obj);
if (obj == null)
{ return; }
var pos = Position;
var rot = Rotation * Quaternion.RotationAxis(Vector3.UnitX, 1.57079632679f);
obj.Position = pos + rot.Multiply(args.vPosition);
obj.Rotation = rot * args.vRotationQuaternion;
2019-11-25 17:44:16 +08:00
CameraNearClip = (args.fNearDrawDistance > 0) ? Math.Min(args.fNearDrawDistance, 0.5f) : 0.5f;
CameraFarClip = (args.fFarDrawDistance > 0) ? Math.Max(args.fFarDrawDistance, 1000.0f) : 12000.0f;
CameraClipUpdate = true;
2019-11-25 17:44:16 +08:00
CameraObject = obj;
}
private void CameraShadowCascade(CutEvent e)
{
}
private void CameraUnk1(CutEvent e)
{
}
private void CameraUnk2(CutEvent e)
{
}
private void CameraUnk3(CutEvent e)
{
}
private void CameraUnk4(CutEvent e)
{
}
private void CameraUnk5(CutEvent e)
{
}
private void CameraUnk6(CutEvent e)
{
}
private void CameraUnk7(CutEvent e)
{
}
private void CameraUnk8(CutEvent e)
{
}
private void DecalUnk1(CutEvent e)
{
}
private void DecalUnk2(CutEvent e)
{
}
private void PropUnk1(CutEvent e)
{
}
private void Unk1(CutEvent e)
{
}
private void Unk2(CutEvent e)
{
}
private void VehicleUnk1(CutEvent e)
{
}
private void PedUnk1(CutEvent e)
{
}
private T[] RecastArray<T>(object[] arr) where T : class
{
if (arr == null) return null;
var r = new T[arr.Length];
for (int i = 0; i < arr.Length; i++)
{
r[i] = arr[i] as T;
}
return r;
}
private void CreateSceneObjects()
{
SceneObjects = new Dictionary<int, CutsceneObject>();
if (Objects == null) return;
var refCounts = new Dictionary<MetaHash, int>();
2019-11-25 17:44:16 +08:00
foreach (var obj in Objects.Values)
{
var sobj = new CutsceneObject();
2019-11-25 22:26:28 +08:00
sobj.Init(obj, GameFileCache);
2019-11-25 17:44:16 +08:00
SceneObjects[sobj.ObjectID] = sobj;
if (sobj.AnimHash != 0)
{
int refcount = 0;
var hash = sobj.AnimHash;
refCounts.TryGetValue(hash, out refcount);
if (refcount > 0)
{
var newstr = hash.ToString() + "^" + refcount.ToString();
sobj.AnimHash = JenkHash.GenHash(newstr);
}
refcount++;
refCounts[hash] = refcount;
}
2019-11-25 17:44:16 +08:00
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class CutsceneObject
{
public int ObjectID { get; set; }
public CutObject CutObject { get; set; }
public MetaHash Name { get; set; }
public Vector3 Position { get; set; }
public Quaternion Rotation { get; set; }
2019-11-25 22:26:28 +08:00
public Ped Ped { get; set; }
public YmapEntityDef Prop { get; set; }
2019-11-26 17:47:47 +08:00
public Vehicle Vehicle { get; set; }
2019-11-27 10:32:07 +08:00
public Weapon Weapon { get; set; }
public YmapEntityDef HideEntity { get; set; }
public MetaHash AnimHash { get; set; }
public ClipMapEntry AnimClip { get; set; }
2019-11-26 20:35:08 +08:00
public bool Enabled { get; set; } = false;
2019-11-26 17:47:47 +08:00
2019-11-25 22:26:28 +08:00
public void Init(CutObject obj, GameFileCache gfc)
2019-11-25 17:44:16 +08:00
{
CutObject = obj;
ObjectID = obj?.iObjectId ?? -1;
if (obj is CutNamedObject nobj)
{
Name = nobj.cName;
}
if (obj is CutAnimationManagerObject anim)
{
}
else if (obj is CutAssetManagerObject ass)
{
}
else if (obj is CutCameraObject cam)
{
}
else if (obj is CutPedModelObject ped)
{
2019-11-25 22:26:28 +08:00
InitPed(ped, gfc);
2019-11-25 17:44:16 +08:00
}
else if (obj is CutPropModelObject prop)
{
2019-11-25 22:26:28 +08:00
InitProp(prop, gfc);
2019-11-25 17:44:16 +08:00
}
else if (obj is CutVehicleModelObject veh)
{
2019-11-25 22:26:28 +08:00
InitVehicle(veh, gfc);
2019-11-25 17:44:16 +08:00
}
else if (obj is CutWeaponModelObject weap)
{
2019-11-25 22:26:28 +08:00
InitWeapon(weap, gfc);
2019-11-25 17:44:16 +08:00
}
else if (obj is CutHiddenModelObject hid)
{
2019-11-25 22:26:28 +08:00
InitHiddenModel(hid, gfc);
2019-11-25 17:44:16 +08:00
}
else if (obj is CutFixupModelObject fix)
{
}
else if (obj is CutRayfireObject rayf)
{
}
else if (obj is CutParticleEffectObject eff)
{
}
else if (obj is CutAnimatedParticleEffectObject aeff)
{
}
else if (obj is CutLightObject light)
{
}
else if (obj is CutAnimatedLightObject alight)
{
}
else if (obj is CutDecalObject dec)
{
}
else if (obj is CutOverlayObject ovr)
{
}
else if (obj is CutAudioObject aud)
{
}
else if (obj is CutSubtitleObject sub)
{
}
else if (obj is CutBlockingBoundsObject blk)
{
}
else if (obj is CutScreenFadeObject fad)
{
}
else
{ }
}
2019-11-25 22:26:28 +08:00
private void InitPed(CutPedModelObject ped, GameFileCache gfc)
{
Ped = new Ped();
Ped.Init(ped.StreamingName, gfc);
Ped.LoadDefaultComponents(gfc);
if (ped.StreamingName == JenkHash.GenHash("player_zero"))
{
//for michael, switch his outfit so it's not glitching everywhere (until it's fixed?)
Ped.SetComponentDrawable(3, 27, 0, 0, gfc);
Ped.SetComponentDrawable(4, 19, 0, 0, gfc);
Ped.SetComponentDrawable(6, null, null, gfc);
}
AnimHash = ped.StreamingName;
2019-11-25 22:26:28 +08:00
}
private void InitProp(CutPropModelObject prop, GameFileCache gfc)
{
Prop = new YmapEntityDef();
Prop.SetArchetype(gfc.GetArchetype(prop.StreamingName));
2019-11-25 22:26:28 +08:00
AnimHash = prop.StreamingName;
2019-11-25 22:26:28 +08:00
}
private void InitVehicle(CutVehicleModelObject veh, GameFileCache gfc)
{
2019-11-26 17:47:47 +08:00
var name = veh.StreamingName.ToString();
Vehicle = new Vehicle();
Vehicle.Init(name, gfc);
2019-11-25 22:26:28 +08:00
2019-11-26 17:47:47 +08:00
AnimHash = veh.StreamingName;
2019-11-25 22:26:28 +08:00
}
private void InitWeapon(CutWeaponModelObject weap, GameFileCache gfc)
{
2019-11-27 10:32:07 +08:00
var name = weap.StreamingName.ToString();
Weapon = new Weapon();
Weapon.Init(name, gfc);
2019-11-25 22:26:28 +08:00
2019-11-27 10:32:07 +08:00
AnimHash = weap.StreamingName;
2019-11-25 22:26:28 +08:00
}
private void InitHiddenModel(CutHiddenModelObject hid, GameFileCache gfc)
{
HideEntity = new YmapEntityDef();
HideEntity._CEntityDef.archetypeName = hid.cName;
HideEntity.SetPosition(hid.vPosition);
2019-11-25 22:26:28 +08:00
}
2019-11-25 17:44:16 +08:00
public override string ToString()
{
return CutObject?.ToString() ?? (ObjectID.ToString() + ": " + Name.ToString());
}
}
}