mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-26 00:43:00 +08:00
Add support for ScenarioTypeGroups in scenario files
This commit is contained in:
parent
4559312f1c
commit
d260a58ee6
@ -4714,7 +4714,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
public byte TypeId { get { return _Data.iType; } set { _Data.iType = value; } }
|
||||
public ScenarioType Type { get; set; }
|
||||
public ScenarioTypeRef? Type { get; set; }
|
||||
|
||||
public byte ModelSetId { get { return _Data.ModelSetId; } set { _Data.ModelSetId = value; } }
|
||||
public AmbientModelSet ModelSet { get; set; }
|
||||
@ -5298,7 +5298,7 @@ namespace CodeWalker.GameFiles
|
||||
public Vector3 Position { get { return _Data.Position; } set { _Data.Position = value; } }
|
||||
public MetaHash Unk1 { get { return _Data.Unk_2602393771; } set { _Data.Unk_2602393771 = value; } }
|
||||
public MetaHash TypeHash { get { return _Data.ScenarioType; } set { _Data.ScenarioType = value; } }
|
||||
public ScenarioType Type { get; set; }
|
||||
public ScenarioTypeRef? Type { get; set; }
|
||||
public bool NotFirst { get { return _Data.Unk_407126079_NotFirst == 1; } set { _Data.Unk_407126079_NotFirst = (byte)(value ? 1 : 0); } }
|
||||
public bool NotLast { get { return _Data.Unk_1308720135_NotLast == 1; } set { _Data.Unk_1308720135_NotLast = (byte)(value ? 1 : 0); } }
|
||||
|
||||
|
@ -208,13 +208,23 @@ namespace CodeWalker.World
|
||||
if (tpind < typhashes.Length)
|
||||
{
|
||||
var hash = typhashes[tpind];
|
||||
scp.Type = types.GetScenarioType(hash);
|
||||
if (scp.Type != null)
|
||||
var st = types.GetScenarioType(hash);
|
||||
if (st != null)
|
||||
{
|
||||
isveh = scp.Type.IsVehicle;
|
||||
scp.Type = new ScenarioTypeRef(st);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
{
|
||||
var stg = types.GetScenarioTypeGroup(hash);
|
||||
if (stg != null)
|
||||
{
|
||||
scp.Type = new ScenarioTypeRef(stg);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
|
||||
isveh = scp.Type.Value.IsVehicle;
|
||||
}
|
||||
else
|
||||
{ }
|
||||
@ -282,13 +292,23 @@ namespace CodeWalker.World
|
||||
if ((hash != 0) && (hash != 493038497))
|
||||
{
|
||||
bool isveh = false;
|
||||
spn.Type = types.GetScenarioType(hash);
|
||||
if (spn.Type != null)
|
||||
var st = types.GetScenarioType(hash);
|
||||
if (st != null)
|
||||
{
|
||||
isveh = spn.Type.IsVehicle;
|
||||
spn.Type = new ScenarioTypeRef(st);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
{
|
||||
var stg = types.GetScenarioTypeGroup(hash);
|
||||
if (stg != null)
|
||||
{
|
||||
spn.Type = new ScenarioTypeRef(stg);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
|
||||
isveh = spn.Type?.IsVehicle ?? false;
|
||||
if (isveh)
|
||||
{ }
|
||||
else
|
||||
@ -1067,10 +1087,10 @@ namespace CodeWalker.World
|
||||
int interiorid = 0;
|
||||
int groupid = 0;
|
||||
int imapid = 0;
|
||||
if ((mp.Type != null) && (!typeNames.TryGetValue(mp.Type.NameHash, out typeid)))
|
||||
if ((mp.Type != null) && (!typeNames.TryGetValue(mp.Type.Value.NameHash, out typeid)))
|
||||
{
|
||||
typeid = typeNames.Count;
|
||||
typeNames[mp.Type.NameHash] = typeid;
|
||||
typeNames[mp.Type.Value.NameHash] = typeid;
|
||||
}
|
||||
if (mp.ModelSet != null)
|
||||
{
|
||||
@ -1159,10 +1179,10 @@ namespace CodeWalker.World
|
||||
int interiorid = 0;
|
||||
int groupid = 0;
|
||||
int imapid = 0;
|
||||
if ((mp.Type != null) && (!typeNames.TryGetValue(mp.Type.NameHash, out typeid)))
|
||||
if ((mp.Type != null) && (!typeNames.TryGetValue(mp.Type.Value.NameHash, out typeid)))
|
||||
{
|
||||
typeid = typeNames.Count;
|
||||
typeNames[mp.Type.NameHash] = typeid;
|
||||
typeNames[mp.Type.Value.NameHash] = typeid;
|
||||
}
|
||||
if (mp.ModelSet != null)
|
||||
{
|
||||
@ -1502,6 +1522,7 @@ namespace CodeWalker.World
|
||||
private object SyncRoot = new object(); //keep this thread-safe.. technically shouldn't be necessary, but best to be safe
|
||||
|
||||
private Dictionary<uint, ScenarioType> Types { get; set; }
|
||||
private Dictionary<uint, ScenarioTypeGroup> TypeGroups { get; set; }
|
||||
private Dictionary<uint, AmbientModelSet> PropSets { get; set; }
|
||||
private Dictionary<uint, AmbientModelSet> PedModelSets { get; set; }
|
||||
private Dictionary<uint, AmbientModelSet> VehicleModelSets { get; set; }
|
||||
@ -1514,6 +1535,7 @@ namespace CodeWalker.World
|
||||
lock (SyncRoot)
|
||||
{
|
||||
Types = LoadTypes(gfc, "common:\\data\\ai\\scenarios.meta");
|
||||
TypeGroups = LoadTypeGroups(gfc, "common:\\data\\ai\\scenarios.meta");
|
||||
PropSets = LoadModelSets(gfc, "common:\\data\\ai\\propsets.meta");
|
||||
PedModelSets = LoadModelSets(gfc, "common:\\data\\ai\\ambientpedmodelsets.meta");
|
||||
VehicleModelSets = LoadModelSets(gfc, "common:\\data\\ai\\vehiclemodelsets.meta");
|
||||
@ -1594,6 +1616,40 @@ namespace CodeWalker.World
|
||||
return types;
|
||||
}
|
||||
|
||||
private Dictionary<uint, ScenarioTypeGroup> LoadTypeGroups(GameFileCache gfc, string filename)
|
||||
{
|
||||
Dictionary<uint, ScenarioTypeGroup> types = new Dictionary<uint, ScenarioTypeGroup>();
|
||||
|
||||
var xml = LoadXml(gfc, filename);
|
||||
|
||||
if ((xml == null) || (xml.DocumentElement == null))
|
||||
{
|
||||
return types;
|
||||
}
|
||||
|
||||
var typesxml = xml.DocumentElement;
|
||||
var items = typesxml.SelectNodes("ScenarioTypeGroups/Item");
|
||||
|
||||
foreach (XmlNode item in items)
|
||||
{
|
||||
ScenarioTypeGroup group = new ScenarioTypeGroup();
|
||||
|
||||
group.Load(item);
|
||||
if (!string.IsNullOrEmpty(group.NameLower))
|
||||
{
|
||||
JenkIndex.Ensure(group.NameLower);
|
||||
uint hash = JenkHash.GenHash(group.NameLower);
|
||||
types[hash] = group;
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
|
||||
JenkIndex.Ensure("none");
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
private Dictionary<uint, AmbientModelSet> LoadModelSets(GameFileCache gfc, string filename)
|
||||
{
|
||||
Dictionary<uint, AmbientModelSet> sets = new Dictionary<uint, AmbientModelSet>();
|
||||
@ -1666,6 +1722,16 @@ namespace CodeWalker.World
|
||||
return st;
|
||||
}
|
||||
}
|
||||
public ScenarioTypeGroup GetScenarioTypeGroup(uint hash)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (TypeGroups == null) return null;
|
||||
ScenarioTypeGroup tg;
|
||||
TypeGroups.TryGetValue(hash, out tg);
|
||||
return tg;
|
||||
}
|
||||
}
|
||||
public AmbientModelSet GetPropSet(uint hash)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
@ -1715,6 +1781,14 @@ namespace CodeWalker.World
|
||||
return Types.Values.ToArray();
|
||||
}
|
||||
}
|
||||
public ScenarioTypeGroup[] GetScenarioTypeGroups()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (TypeGroups == null) return null;
|
||||
return TypeGroups.Values.ToArray();
|
||||
}
|
||||
}
|
||||
public AmbientModelSet[] GetPropSets()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
@ -1750,6 +1824,69 @@ namespace CodeWalker.World
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a scenario type that may either be a <see cref="ScenarioType"/> or a <see cref="ScenarioTypeGroup"/>.
|
||||
/// Used with CScenarioChainingNode and CScenarioPoint.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public struct ScenarioTypeRef
|
||||
{
|
||||
public string Name => IsGroup ? Group.Name : Type.Name;
|
||||
public string NameLower => IsGroup ? Group.NameLower : Type.NameLower;
|
||||
public MetaHash NameHash => IsGroup ? Group.NameHash : Type.NameHash;
|
||||
public bool IsVehicle => IsGroup ? false : Type.IsVehicle; // groups don't support vehicle infos, so always false
|
||||
public string VehicleModelSet => IsGroup ? null : Type.VehicleModelSet;
|
||||
public MetaHash VehicleModelSetHash => IsGroup ? 0 : Type.VehicleModelSetHash;
|
||||
|
||||
public bool IsGroup { get; }
|
||||
public ScenarioType Type { get; }
|
||||
public ScenarioTypeGroup Group { get; }
|
||||
|
||||
public ScenarioTypeRef(ScenarioTypeRef typeRef)
|
||||
{
|
||||
IsGroup = typeRef.IsGroup;
|
||||
Type = typeRef.Type;
|
||||
Group = typeRef.Group;
|
||||
}
|
||||
|
||||
public ScenarioTypeRef(ScenarioType type)
|
||||
{
|
||||
IsGroup = false;
|
||||
Type = type;
|
||||
Group = null;
|
||||
}
|
||||
|
||||
public ScenarioTypeRef(ScenarioTypeGroup group)
|
||||
{
|
||||
IsGroup = true;
|
||||
Type = null;
|
||||
Group = group;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is ScenarioTypeRef other && other == this;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return NameHash.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(ScenarioTypeRef a, ScenarioTypeRef b)
|
||||
{
|
||||
return a.NameHash == b.NameHash;
|
||||
}
|
||||
|
||||
public static bool operator !=(ScenarioTypeRef a, ScenarioTypeRef b)
|
||||
{
|
||||
return a.NameHash != b.NameHash;
|
||||
}
|
||||
}
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class ScenarioType
|
||||
{
|
||||
@ -1795,6 +1932,29 @@ namespace CodeWalker.World
|
||||
}
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class ScenarioTypeGroup
|
||||
{
|
||||
public string OuterXml { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string NameLower { get; set; }
|
||||
public MetaHash NameHash { get; set; }
|
||||
|
||||
|
||||
public void Load(XmlNode node)
|
||||
{
|
||||
OuterXml = node.OuterXml;
|
||||
Name = Xml.GetChildInnerText(node, "Name");
|
||||
NameLower = Name.ToLowerInvariant();
|
||||
NameHash = JenkHash.GenHash(NameLower);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class AmbientModelSet
|
||||
{
|
||||
|
@ -133,6 +133,9 @@ namespace CodeWalker.Project.Panels
|
||||
var stypes = types.GetScenarioTypes();
|
||||
if (stypes == null) return;
|
||||
|
||||
var stgroups = types.GetScenarioTypeGroups();
|
||||
if (stgroups == null) return;
|
||||
|
||||
var pmsets = types.GetPedModelSets();
|
||||
if (pmsets == null) return;
|
||||
|
||||
@ -147,9 +150,17 @@ namespace CodeWalker.Project.Panels
|
||||
ScenarioChainNodeTypeComboBox.Items.Add("");
|
||||
foreach (var stype in stypes)
|
||||
{
|
||||
ScenarioPointTypeComboBox.Items.Add(stype);
|
||||
ScenarioClusterPointTypeComboBox.Items.Add(stype);
|
||||
ScenarioChainNodeTypeComboBox.Items.Add(stype);
|
||||
ScenarioTypeRef? typeRef = new ScenarioTypeRef(stype);
|
||||
ScenarioPointTypeComboBox.Items.Add(typeRef);
|
||||
ScenarioClusterPointTypeComboBox.Items.Add(typeRef);
|
||||
ScenarioChainNodeTypeComboBox.Items.Add(typeRef);
|
||||
}
|
||||
foreach (var stgroup in stgroups)
|
||||
{
|
||||
ScenarioTypeRef? typeRef = new ScenarioTypeRef(stgroup);
|
||||
ScenarioPointTypeComboBox.Items.Add(typeRef);
|
||||
ScenarioClusterPointTypeComboBox.Items.Add(typeRef);
|
||||
ScenarioChainNodeTypeComboBox.Items.Add(typeRef);
|
||||
}
|
||||
|
||||
ScenarioPointModelSetComboBox.Items.Clear();
|
||||
@ -827,7 +838,7 @@ namespace CodeWalker.Project.Panels
|
||||
if (populatingui) return;
|
||||
if (CurrentScenarioNode == null) return;
|
||||
if (CurrentScenarioNode.MyPoint == null) return;
|
||||
ScenarioType stype = ScenarioPointTypeComboBox.SelectedItem as ScenarioType;
|
||||
ScenarioTypeRef? stype = ScenarioPointTypeComboBox.SelectedItem as ScenarioTypeRef?;
|
||||
lock (ProjectForm.ProjectSyncRoot)
|
||||
{
|
||||
if (CurrentScenarioNode.MyPoint.Type != stype)
|
||||
@ -1711,7 +1722,7 @@ namespace CodeWalker.Project.Panels
|
||||
if (populatingui) return;
|
||||
if (CurrentScenarioNode == null) return;
|
||||
if (CurrentScenarioNode.ChainingNode == null) return;
|
||||
ScenarioType stype = ScenarioChainNodeTypeComboBox.SelectedItem as ScenarioType;
|
||||
ScenarioTypeRef? stype = ScenarioChainNodeTypeComboBox.SelectedItem as ScenarioTypeRef?;
|
||||
lock (ProjectForm.ProjectSyncRoot)
|
||||
{
|
||||
if (CurrentScenarioNode.ChainingNode.Type != stype)
|
||||
@ -2133,7 +2144,7 @@ namespace CodeWalker.Project.Panels
|
||||
if (populatingui) return;
|
||||
if (CurrentScenarioNode == null) return;
|
||||
if (CurrentScenarioNode.ClusterMyPoint == null) return;
|
||||
ScenarioType stype = ScenarioClusterPointTypeComboBox.SelectedItem as ScenarioType;
|
||||
ScenarioTypeRef? stype = ScenarioClusterPointTypeComboBox.SelectedItem as ScenarioTypeRef?;
|
||||
lock (ProjectForm.ProjectSyncRoot)
|
||||
{
|
||||
if (CurrentScenarioNode.ClusterMyPoint.Type != stype)
|
||||
|
@ -4266,7 +4266,7 @@ namespace CodeWalker.Project
|
||||
var action = Unk_3609807418.Move;
|
||||
var navMode = Unk_3971773454.Direct;
|
||||
var navSpeed = Unk_941086046.Unk_00_3279574318;
|
||||
var stype = defaulttype;
|
||||
var stype = new ScenarioTypeRef(defaulttype);
|
||||
var modelset = defaultmodelset;
|
||||
var flags = defaultflags;
|
||||
var ok = true;
|
||||
@ -4298,7 +4298,23 @@ namespace CodeWalker.Project
|
||||
if (vals.Length > 6)
|
||||
{
|
||||
var sthash = JenkHash.GenHash(vals[6].Trim().ToLowerInvariant());
|
||||
stype = stypes?.GetScenarioType(sthash) ?? defaulttype;
|
||||
var st = stypes?.GetScenarioType(sthash);
|
||||
if (st != null)
|
||||
{
|
||||
stype = new ScenarioTypeRef(st);
|
||||
}
|
||||
else
|
||||
{
|
||||
var stg = stypes?.GetScenarioTypeGroup(sthash);
|
||||
if (stg != null)
|
||||
{
|
||||
stype = new ScenarioTypeRef(stg);
|
||||
}
|
||||
else
|
||||
{
|
||||
stype = new ScenarioTypeRef(defaulttype);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vals.Length > 7)
|
||||
{
|
||||
@ -4326,7 +4342,7 @@ namespace CodeWalker.Project
|
||||
thisnode.ChainingNode.ScenarioNode = thisnode;
|
||||
thisnode.ChainingNode.Chain = chain;
|
||||
thisnode.ChainingNode.Type = stype;
|
||||
thisnode.ChainingNode.TypeHash = stype?.NameHash ?? 0;
|
||||
thisnode.ChainingNode.TypeHash = stype.NameHash;
|
||||
thisnode.ChainingNode.NotLast = (i < (lines.Length - 1));
|
||||
thisnode.ChainingNode.NotFirst = (lastnode != null);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user