CodeWalker/CodeWalker.Core/World/Ped.cs

307 lines
11 KiB
C#
Raw Normal View History

2019-11-25 17:44:16 +08:00
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace CodeWalker.World
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class Ped
{
public string Name { get; set; } = string.Empty;
public MetaHash NameHash { get; set; } = 0;//ped name hash
public CPedModelInfo__InitData InitData { get; set; } = null; //ped init data
public YddFile Ydd { get; set; } = null; //ped drawables
public YtdFile Ytd { get; set; } = null; //ped textures
2019-11-29 17:47:11 +08:00
public YldFile Yld { get; set; } = null; //ped clothes
2019-11-25 17:44:16 +08:00
public YcdFile Ycd { get; set; } = null; //ped animations
2020-03-06 00:02:40 +08:00
public YedFile Yed { get; set; } = null; //ped expressions
2019-11-25 17:44:16 +08:00
public YftFile Yft { get; set; } = null; //ped skeleton YFT
public PedFile Ymt { get; set; } = null; //ped variation info
public Dictionary<MetaHash, RpfFileEntry> DrawableFilesDict { get; set; } = null;
public Dictionary<MetaHash, RpfFileEntry> TextureFilesDict { get; set; } = null;
2019-11-29 17:47:11 +08:00
public Dictionary<MetaHash, RpfFileEntry> ClothFilesDict { get; set; } = null;
2019-11-25 17:44:16 +08:00
public RpfFileEntry[] DrawableFiles { get; set; } = null;
public RpfFileEntry[] TextureFiles { get; set; } = null;
2019-11-29 17:47:11 +08:00
public RpfFileEntry[] ClothFiles { get; set; } = null;
2019-11-25 17:44:16 +08:00
public ClipMapEntry AnimClip { get; set; } = null;
2020-03-06 00:02:40 +08:00
public Expression Expression { get; set; } = null;
2019-11-25 17:44:16 +08:00
public string[] DrawableNames { get; set; } = new string[12];
public Drawable[] Drawables { get; set; } = new Drawable[12];
public Texture[] Textures { get; set; } = new Texture[12];
2020-03-06 00:02:40 +08:00
public Expression[] Expressions { get; set; } = new Expression[12];
2019-11-29 17:47:11 +08:00
public ClothInstance[] Clothes { get; set; } = new ClothInstance[12];
2019-11-25 17:44:16 +08:00
public bool EnableRootMotion { get; set; } = false; //used to toggle whether or not to include root motion when playing animations
public Skeleton Skeleton { get; set; } = null;
2019-11-25 17:44:16 +08:00
public Vector3 Position { get; set; } = Vector3.Zero;
public Quaternion Rotation { get; set; } = Quaternion.Identity;
public YmapEntityDef RenderEntity = new YmapEntityDef(); //placeholder entity object for rendering
2019-11-25 17:44:16 +08:00
public async ValueTask InitAsync(string name, GameFileCache gfc)
2019-11-25 17:44:16 +08:00
{
var hash = JenkHash.GenHash(name.ToLowerInvariant());
await InitAsync(hash, gfc);
2019-11-25 17:44:16 +08:00
Name = name;
}
public async ValueTask InitAsync(MetaHash pedhash, GameFileCache gfc)
2019-11-25 17:44:16 +08:00
{
Name = string.Empty;
NameHash = 0;
InitData = null;
Ydd = null;
Ytd = null;
2020-03-06 00:02:40 +08:00
Yld = null;
2019-11-25 17:44:16 +08:00
Ycd = null;
2020-03-06 00:02:40 +08:00
Yed = null;
2019-11-25 17:44:16 +08:00
Yft = null;
Ymt = null;
AnimClip = null;
for (int i = 0; i < 12; i++)
{
Drawables[i] = null;
Textures[i] = null;
2020-03-06 00:02:40 +08:00
Expressions[i] = null;
2019-11-25 17:44:16 +08:00
}
CPedModelInfo__InitData initdata = null;
if (!gfc.PedsInitDict.TryGetValue(pedhash, out initdata)) return;
var ycdhash = JenkHash.GenHash(initdata.ClipDictionaryName.ToLowerInvariant());
2020-03-06 00:02:40 +08:00
var yedhash = JenkHash.GenHash(initdata.ExpressionDictionaryName.ToLowerInvariant());
2019-11-25 17:44:16 +08:00
//bool pedchange = NameHash != pedhash;
//Name = pedname;
NameHash = pedhash;
InitData = initdata;
Ydd = gfc.GetYdd(pedhash);
Ytd = gfc.GetYtd(pedhash);
Ycd = gfc.GetYcd(ycdhash);
2020-03-06 00:02:40 +08:00
Yed = gfc.GetYed(yedhash);
2019-11-25 17:44:16 +08:00
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();
2019-11-29 17:47:11 +08:00
gfc.PedClothDicts.TryGetValue(NameHash, out peddict);
ClothFilesDict = peddict;
ClothFiles = ClothFilesDict?.Values.ToArray();
RpfFileEntry clothFile = null;
if (ClothFilesDict?.TryGetValue(pedhash, out clothFile) ?? false)
{
Yld = await gfc.GetFileUncachedAsync<YldFile>(clothFile);
2019-11-29 17:47:11 +08:00
while ((Yld != null) && (!Yld.Loaded))
{
await Task.Delay(1);//kinda hacky
await gfc.TryLoadEnqueue(Yld);
2019-11-29 17:47:11 +08:00
}
}
2019-11-25 17:44:16 +08:00
while ((Ydd != null) && (!Ydd.Loaded))
{
await Task.Delay(1);//kinda hacky
2019-11-25 17:44:16 +08:00
Ydd = gfc.GetYdd(pedhash);
}
while ((Ytd != null) && (!Ytd.Loaded))
{
await Task.Delay(1);//kinda hacky
2019-11-25 17:44:16 +08:00
Ytd = gfc.GetYtd(pedhash);
}
while ((Ycd != null) && (!Ycd.Loaded))
{
await Task.Delay(1);//kinda hacky
2019-11-25 17:44:16 +08:00
Ycd = gfc.GetYcd(ycdhash);
}
2020-03-06 00:02:40 +08:00
while ((Yed != null) && (!Yed.Loaded))
{
await Task.Delay(1);//kinda hacky
2020-03-06 00:02:40 +08:00
Yed = gfc.GetYed(yedhash);
}
2019-11-25 17:44:16 +08:00
while ((Yft != null) && (!Yft.Loaded))
{
await Task.Delay(1);//kinda hacky
2019-11-25 17:44:16 +08:00
Yft = gfc.GetYft(pedhash);
}
Skeleton = Yft?.Fragment?.Drawable?.Skeleton?.Clone();
2019-11-25 17:44:16 +08:00
MetaHash cliphash = JenkHash.GenHash("idle");
ClipMapEntry cme = null;
Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
AnimClip = cme;
var exprhash = JenkHash.GenHashLower(initdata.ExpressionName);
2020-03-06 00:02:40 +08:00
Expression expr = null;
Yed?.ExprMap?.TryGetValue(exprhash, out expr);
Expression = expr;
UpdateEntity();
2019-11-25 17:44:16 +08:00
}
2019-11-25 22:26:28 +08:00
public async ValueTask SetComponentDrawableAsync(int index, string name, string tex, GameFileCache gfc)
2019-11-25 22:26:28 +08:00
{
if (string.IsNullOrEmpty(name))
{
DrawableNames[index] = null;
Drawables[index] = null;
Textures[index] = null;
2020-03-06 00:02:40 +08:00
Expressions[index] = null;
2019-11-25 22:26:28 +08:00
return;
}
MetaHash namehash = JenkHash.GenHashLower(name);
2019-11-25 22:26:28 +08:00
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 = await gfc.GetFileUncachedAsync<YddFile>(file);
2019-11-25 22:26:28 +08:00
while ((ydd != null) && (!ydd.Loaded))
{
await Task.Delay(1);//kinda hacky
await gfc.TryLoadEnqueue(ydd);
2019-11-25 22:26:28 +08:00
}
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 = await gfc.GetFileUncachedAsync<YtdFile>(file);
2019-11-25 22:26:28 +08:00
while ((ytd != null) && (!ytd.Loaded))
{
await Task.Delay(1);//kinda hacky
await gfc.TryLoadEnqueue(ytd);
2019-11-25 22:26:28 +08:00
}
if (ytd?.TextureDict?.Textures?.data_items.Length > 0)
{
t = ytd.TextureDict.Textures.data_items[0];//should only be one in this dict
}
}
}
2019-11-29 17:47:11 +08:00
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 = await gfc.GetFileUncachedAsync<YldFile>(file);
2019-11-29 17:47:11 +08:00
while ((yld != null) && (!yld.Loaded))
{
await Task.Delay(1);//kinda hacky
await gfc.TryLoadEnqueue(yld);
2019-11-29 17:47:11 +08:00
}
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);
}
2020-03-06 00:02:40 +08:00
Expression e = null;
if (Yed?.ExprMap != null)
{
Yed.ExprMap.TryGetValue(namehash, out e);
}
2019-11-25 22:26:28 +08:00
if (d != null) Drawables[index] = d.ShallowCopy() as Drawable;
2019-11-25 22:26:28 +08:00
if (t != null) Textures[index] = t;
2019-11-29 17:47:11 +08:00
if (c != null) Clothes[index] = c;
2020-03-06 00:02:40 +08:00
if (e != null) Expressions[index] = e;
2019-11-25 22:26:28 +08:00
DrawableNames[index] = name;
}
public async ValueTask SetComponentDrawableAsync(int index, int drawbl, int alt, int tex, GameFileCache gfc)
2019-11-25 22:26:28 +08:00
{
var vi = Ymt?.VariationInfo;
if (vi != null)
{
var compData = vi.GetComponentData(index);
if (compData?.DrawblData3 != null)
{
var item = (drawbl < (compData.DrawblData3?.Length ?? 0)) ? compData.DrawblData3[drawbl] : null;
if (item != null)
{
var name = item?.GetDrawableName(alt);
var texn = item?.GetTextureName(tex);
await SetComponentDrawableAsync(index, name, texn, gfc);
2019-11-25 22:26:28 +08:00
}
}
}
}
public async ValueTask LoadDefaultComponentsAsync(GameFileCache gfc)
2019-11-25 22:26:28 +08:00
{
for (int i = 0; i < 12; i++)
{
await SetComponentDrawableAsync(i, 0, 0, 0, gfc);
2019-11-25 22:26:28 +08:00
}
}
public void UpdateEntity()
{
RenderEntity.SetPosition(Position);
RenderEntity.SetOrientation(Rotation);
}
2019-11-25 17:44:16 +08:00
}
}