diff --git a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs index 839e411..81b440b 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YmapFile.cs @@ -1165,6 +1165,41 @@ namespace CodeWalker.GameFiles if (change) physicsDictionaries = physDict.ToArray(); } + public void InitYmapEntityArchetypes(GameFileCache gfc) + { + if (AllEntities != null) + { + for (int i = 0; i < AllEntities.Length; i++) + { + var ent = AllEntities[i]; + var arch = gfc.GetArchetype(ent.CEntityDef.archetypeName); + ent.SetArchetype(arch); + if (ent.IsMlo) ent.MloInstance.InitYmapEntityArchetypes(gfc); + } + } + if (GrassInstanceBatches != null) + { + for (int i = 0; i < GrassInstanceBatches.Length; i++) + { + var batch = GrassInstanceBatches[i]; + batch.Archetype = gfc.GetArchetype(batch.Batch.archetypeName); + } + } + + if (TimeCycleModifiers != null) + { + for (int i = 0; i < TimeCycleModifiers.Length; i++) + { + var tcm = TimeCycleModifiers[i]; + World.TimecycleMod wtcm; + if (gfc.TimeCycleModsDict.TryGetValue(tcm.CTimeCycleModifier.name.Hash, out wtcm)) + { + tcm.TimeCycleModData = wtcm; + } + } + } + + } private static uint SetBit(uint value, int bit) { @@ -1194,7 +1229,7 @@ namespace CodeWalker.GameFiles public bool IsMlo { get; set; } public MloInstanceData MloInstance { get; set; } public YmapEntityDef MloParent { get; set; } - public MCMloEntitySet MloEntitySet { get; set; } + public MloInstanceEntitySet MloEntitySet { get; set; } public Vector3 MloRefPosition { get; set; } public Quaternion MloRefOrientation { get; set; } public MetaWrapper[] Extensions { get; set; } @@ -1297,56 +1332,57 @@ namespace CodeWalker.GameFiles { MloInstance = new MloInstanceData(); } - MloInstance.CreateYmapEntities(this, mloa); + if (mloa != null) + { + if (!IsMlo) + { + IsMlo = true; + MloInstance._Instance = new CMloInstanceDef { CEntityDef = _CEntityDef }; + + List mloEntities = Ymap.MloEntities?.ToList() ?? new List(); + mloEntities.Add(this); + Ymap.MloEntities = mloEntities.ToArray(); + } + + MloInstance.CreateYmapEntities(this, mloa); + } if (BSRadius == 0.0f) { BSRadius = CEntityDef.lodDist;//need something so it doesn't get culled... } } + else if (IsMlo) // archetype is no longer an mlo + { + IsMlo = false; + MloInstance = null; + if (Ymap.MloEntities != null) + { + List mloEntities = Ymap.MloEntities.ToList(); + if (mloEntities.Remove(this)) + { + Ymap.MloEntities = mloEntities.ToArray(); + } + } + } } - } public void SetPosition(Vector3 pos) { + Position = pos; if (MloParent != null) { - //TODO: SetPosition for interior entities! - Position = pos; - var inst = MloParent.MloInstance; - if (inst != null) - { - //transform world position into mlo space - //MloRefPosition = ... - //MloRefOrientation = ... - } + _CEntityDef.position = Quaternion.Normalize(Quaternion.Invert(MloParent.Orientation)).Multiply(pos - MloParent.Position); + MloRefPosition = _CEntityDef.position; + UpdateBB(); + UpdateMloArchetype(); } else { - Position = pos; _CEntityDef.position = pos; - - if (Archetype != null) - { - BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale; - } - if ((Archetype != null) && (Orientation == Quaternion.Identity)) - { - BBMin = (Archetype.BBMin * Scale) + Position; - BBMax = (Archetype.BBMax * Scale) + Position; - } - else - { - BBMin = Position - (BSRadius); - BBMax = Position + (BSRadius); - ////not ideal: should transform all 8 corners! - } - - - - UpdateWidgetPosition(); + UpdateBB(); } @@ -1356,40 +1392,51 @@ namespace CodeWalker.GameFiles MloInstance.UpdateEntities(); } + UpdateWidgetPosition(); } - public void SetOrientation(Quaternion ori) + private void UpdateBB() { - Quaternion inv = Quaternion.Normalize(Quaternion.Invert(ori)); - Orientation = ori; - _CEntityDef.rotation = new Vector4(inv.X, inv.Y, inv.Z, inv.W); - - if (MloInstance != null) - { - MloInstance.SetOrientation(ori); - } - - if (Archetype != null) { BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale; } - - UpdateWidgetPosition(); - UpdateWidgetOrientation(); + if ((Archetype != null) && (Orientation == Quaternion.Identity)) + { + BBMin = (Archetype.BBMin * Scale) + Position; + BBMax = (Archetype.BBMax * Scale) + Position; + } + else + { + BBMin = Position - (BSRadius); + BBMax = Position + (BSRadius); + ////not ideal: should transform all 8 corners! + } } - public void SetOrientationInv(Quaternion inv) + + public void SetOrientation(Quaternion ori, bool inverse = false) { - Quaternion ori = Quaternion.Normalize(Quaternion.Invert(inv)); - Orientation = ori; - _CEntityDef.rotation = new Vector4(inv.X, inv.Y, inv.Z, inv.W); + if (MloParent != null) + { + var mloInv = Quaternion.Normalize(Quaternion.Invert(MloParent.Orientation)); + Quaternion rel = Quaternion.Normalize(Quaternion.Multiply(mloInv, ori)); + Quaternion inv = Quaternion.Normalize(Quaternion.Invert(rel)); + Orientation = ori; + _CEntityDef.rotation = inv.ToVector4(); + } + else + { + Quaternion inv = inverse ? ori : Quaternion.Normalize(Quaternion.Invert(ori)); + ori = inverse ? Quaternion.Normalize(Quaternion.Invert(ori)) : ori; + Orientation = ori; + _CEntityDef.rotation = inv.ToVector4(); + } if (MloInstance != null) { MloInstance.SetOrientation(ori); } - if (Archetype != null) { BSCenter = Orientation.Multiply(Archetype.BSCenter) * Scale; @@ -1404,14 +1451,35 @@ namespace CodeWalker.GameFiles Scale = new Vector3(s.X, s.X, s.Z); _CEntityDef.scaleXY = s.X; _CEntityDef.scaleZ = s.Z; + + MloInstanceData mloInstance = MloParent?.MloInstance; + if (mloInstance != null) + { + var mcEntity = mloInstance.TryGetArchetypeEntity(this); + if (mcEntity != null) + { + mcEntity._Data.scaleXY = s.X; + mcEntity._Data.scaleZ = s.Z; + } + } if (Archetype != null) { float smax = Math.Max(Scale.X, Scale.Z); BSRadius = Archetype.BSRadius * smax; } + SetPosition(Position);//update the BB } + private void UpdateMloArchetype() + { + if (!(MloParent.Archetype is MloArchetype mloArchetype)) return; + if (Index >= mloArchetype.entities.Length) return; + + MCEntityDef entity = mloArchetype.entities[Index]; + entity._Data.position = _CEntityDef.position; + entity._Data.rotation = _CEntityDef.rotation; + } public void SetPivotPosition(Vector3 pos) @@ -1787,7 +1855,7 @@ namespace CodeWalker.GameFiles } private List[] SplitGrass( - IReadOnlyList points, + IReadOnlyList points, BoundingBox batchAABB) { var pointGroup = new List[2]; diff --git a/CodeWalker.Core/GameFiles/FileTypes/YtypFile.cs b/CodeWalker.Core/GameFiles/FileTypes/YtypFile.cs index 08a312c..7160363 100644 --- a/CodeWalker.Core/GameFiles/FileTypes/YtypFile.cs +++ b/CodeWalker.Core/GameFiles/FileTypes/YtypFile.cs @@ -21,8 +21,8 @@ namespace CodeWalker.GameFiles public uint NameHash { get; set; } public string[] Strings { get; set; } - - public CMapTypes CMapTypes { get; set; } + public CMapTypes _CMapTypes; + public CMapTypes CMapTypes { get { return _CMapTypes; } set { _CMapTypes = value; } } public Archetype[] AllArchetypes { get; set; } @@ -50,6 +50,111 @@ namespace CodeWalker.GameFiles return (RpfFileEntry != null) ? RpfFileEntry.Name : string.Empty; } + public byte[] Save() + { + MetaBuilder mb = new MetaBuilder(); + + var mdb = mb.EnsureBlock(MetaName.CMapTypes); + + CMapTypes mapTypes = _CMapTypes; + + if (Extensions == null || Extensions.Length <= 0) + mapTypes.extensions = new Array_StructurePointer(); + else + mapTypes.extensions = mb.AddWrapperArrayPtr(Extensions); + + if ((AllArchetypes != null) && (AllArchetypes.Length > 0)) + { + for (int i = 0; i < AllArchetypes.Length; i++) + { + var arch = AllArchetypes[i]; //save the extensions first.. + if (arch._BaseArchetypeDef.extensions.Count1 > 0) + { + arch._BaseArchetypeDef.extensions = mb.AddWrapperArrayPtr(arch.Extensions); + } + } + + MetaPOINTER[] ptrs = new MetaPOINTER[AllArchetypes.Length]; + for (int i = 0; i < AllArchetypes.Length; i++) + { + var arch = AllArchetypes[i]; + switch (arch) + { + case TimeArchetype t: + ptrs[i] = mb.AddItemPtr(MetaName.CTimeArchetypeDef, t._TimeArchetypeDef); + break; + case MloArchetype m: + try + { + m._MloArchetypeDef._MloArchetypeDef.entities = mb.AddWrapperArrayPtr(m.entities); + m._MloArchetypeDef._MloArchetypeDef.rooms = mb.AddWrapperArray(m.rooms); + m._MloArchetypeDef._MloArchetypeDef.portals = mb.AddWrapperArray(m.portals); + m._MloArchetypeDef._MloArchetypeDef.entitySets = mb.AddWrapperArray(m.entitySets); + m._MloArchetypeDef._MloArchetypeDef.timeCycleModifiers = mb.AddItemArrayPtr(MetaName.CTimeCycleModifier, m.timeCycleModifiers); + } + catch/* (Exception e)*/ + { + //todo: log save error. + } + ptrs[i] = mb.AddItemPtr(MetaName.CMloArchetypeDef, m._MloArchetypeDef); + break; + case Archetype a: + ptrs[i] = mb.AddItemPtr(MetaName.CBaseArchetypeDef, a._BaseArchetypeDef); + break; + } + } + mapTypes.archetypes = mb.AddPointerArray(ptrs); + } + else + { + mapTypes.archetypes = new Array_StructurePointer(); + } + + if (CompositeEntityTypes != null && CompositeEntityTypes.Length > 0) + { + var cptrs = new MetaPOINTER[CompositeEntityTypes.Length]; + + for (int i = 0; i < cptrs.Length; i++) + { + var cet = CompositeEntityTypes[i]; + cptrs[i] = mb.AddItemPtr(MetaName.CCompositeEntityType, cet); + } + mapTypes.compositeEntityTypes = mb.AddItemArrayPtr(MetaName.CCompositeEntityType, cptrs); + } + + mapTypes.name = NameHash; + mapTypes.dependencies = new Array_uint(); // is this never used? possibly a todo? + + mb.AddStructureInfo(MetaName.CMapTypes); + mb.AddStructureInfo(MetaName.CBaseArchetypeDef); + mb.AddStructureInfo(MetaName.CMloArchetypeDef); + mb.AddStructureInfo(MetaName.CTimeArchetypeDef); + mb.AddStructureInfo(MetaName.CCompositeEntityType); + mb.AddStructureInfo(MetaName.CMloRoomDef); + mb.AddStructureInfo(MetaName.CMloPortalDef); + mb.AddStructureInfo(MetaName.CMloEntitySet); + + if ((AllArchetypes != null && AllArchetypes.Length > 0)) + { + mb.AddEnumInfo((MetaName)1991964615); // ASSET_TYPE_ + } + + if ((AllArchetypes != null) && (AllArchetypes.Any(x => x is MloArchetype m && m.entities.Length > 0))) + { + mb.AddStructureInfo(MetaName.CEntityDef); + mb.AddEnumInfo((MetaName)1264241711); //LODTYPES_ + mb.AddEnumInfo((MetaName)648413703); //PRI_ + } + + mb.AddItem(MetaName.CMapTypes, mapTypes); + + Meta meta = mb.GetMeta(); + byte[] data = ResourceBuilder.Build(meta, 2); + + HasChanged = false; + + return data; + } public void Load(byte[] data) { @@ -94,12 +199,12 @@ namespace CodeWalker.GameFiles Meta = rd.ReadBlock(); - CMapTypes = MetaTypes.GetTypedData(Meta, MetaName.CMapTypes); + _CMapTypes = MetaTypes.GetTypedData(Meta, MetaName.CMapTypes); List allarchs = new List(); - var ptrs = MetaTypes.GetPointerArray(Meta, CMapTypes.archetypes); + var ptrs = MetaTypes.GetPointerArray(Meta, _CMapTypes.archetypes); if (ptrs != null) { for (int i = 0; i < ptrs.Length; i++) @@ -151,7 +256,8 @@ namespace CodeWalker.GameFiles AllArchetypes = allarchs.ToArray(); - Extensions = MetaTypes.GetExtensions(Meta, CMapTypes.extensions); + Extensions = MetaTypes.GetExtensions(Meta, _CMapTypes.extensions); + if (Extensions != null) { } @@ -163,11 +269,11 @@ namespace CodeWalker.GameFiles //CEntityDefs = MetaTypes.GetTypedDataArray(Meta, MetaName.CEntityDef); - CompositeEntityTypes = MetaTypes.ConvertDataArray(Meta, MetaName.CCompositeEntityType, CMapTypes.compositeEntityTypes); + CompositeEntityTypes = MetaTypes.ConvertDataArray(Meta, MetaName.CCompositeEntityType, _CMapTypes.compositeEntityTypes); if (CompositeEntityTypes != null) { } - NameHash = CMapTypes.name; + NameHash = _CMapTypes.name; if (NameHash == 0) { int ind = entry.NameLower.LastIndexOf('.'); @@ -241,122 +347,39 @@ namespace CodeWalker.GameFiles } - public void AddArchetype(Archetype arch) + + public void AddArchetype(Archetype archetype) { - List allArchs = new List(); + if (AllArchetypes == null) + AllArchetypes = new Archetype[0]; - if (AllArchetypes != null) - allArchs.AddRange(AllArchetypes); - - allArchs.Add(arch); - - AllArchetypes = allArchs.ToArray(); + List archetypes = AllArchetypes.ToList(); + archetype.Ytyp = this; + archetypes.Add(archetype); + AllArchetypes = archetypes.ToArray(); } - public void RemoveArchetype(Archetype arch) + public Archetype AddArchetype() { - List allArchs = new List(); - - if (AllArchetypes != null) - allArchs.AddRange(AllArchetypes); - - if (allArchs.Contains(arch)) - allArchs.Remove(arch); - - AllArchetypes = allArchs.ToArray(); + var a = new Archetype(); + a._BaseArchetypeDef.assetType = Unk_1991964615.ASSET_TYPE_DRAWABLE; + a._BaseArchetypeDef.lodDist = 60; + a._BaseArchetypeDef.hdTextureDist = 15; + a.Ytyp = this; + AddArchetype(a); + return a; } - public byte[] Save() + public bool RemoveArchetype(Archetype archetype) { - MetaBuilder mb = new MetaBuilder(); - - var mdb = mb.EnsureBlock(MetaName.CMapTypes); - - CMapTypes mapTypes = CMapTypes; - - if((AllArchetypes != null) && (AllArchetypes.Length > 0)) + List archetypes = AllArchetypes.ToList(); + if (archetypes.Remove(archetype)) { - MetaPOINTER[] archPtrs = new MetaPOINTER[AllArchetypes.Length]; - - for(int i=0; i 0)) - { - MetaPOINTER[] cetPtrs = new MetaPOINTER[CompositeEntityTypes.Length] ; - - for (int i = 0; i < cetPtrs.Length; i++) - { - var cet = CompositeEntityTypes[i]; - cetPtrs[i] = mb.AddItemPtr(MetaName.CCompositeEntityType, cet); - } - - mapTypes.compositeEntityTypes = mb.AddItemArrayPtr(MetaName.CCompositeEntityType, cetPtrs); - } - - mb.AddItem(MetaName.CMapTypes, mapTypes); - - mb.AddStructureInfo(MetaName.CMapTypes); - mb.AddStructureInfo(MetaName.CBaseArchetypeDef); - mb.AddStructureInfo(MetaName.CMloArchetypeDef); - mb.AddStructureInfo(MetaName.CTimeArchetypeDef); - mb.AddStructureInfo(MetaName.CMloRoomDef); - mb.AddStructureInfo(MetaName.CMloPortalDef); - mb.AddStructureInfo(MetaName.CMloEntitySet); - mb.AddStructureInfo(MetaName.CCompositeEntityType); - - mb.AddEnumInfo((MetaName)1991964615); - mb.AddEnumInfo((MetaName)1294270217); - mb.AddEnumInfo((MetaName)1264241711); - mb.AddEnumInfo((MetaName)648413703); - mb.AddEnumInfo((MetaName)3573596290); - mb.AddEnumInfo((MetaName)700327466); - mb.AddEnumInfo((MetaName)193194928); - mb.AddEnumInfo((MetaName)2266515059); - - Meta = mb.GetMeta(); - - byte[] data = ResourceBuilder.Build(Meta, 2); //ymap is version 2... - - return data; - + return false; } - } diff --git a/CodeWalker.Core/GameFiles/GameFileCache.cs b/CodeWalker.Core/GameFiles/GameFileCache.cs index 7e052ec..253f40f 100644 --- a/CodeWalker.Core/GameFiles/GameFileCache.cs +++ b/CodeWalker.Core/GameFiles/GameFileCache.cs @@ -1804,116 +1804,6 @@ namespace CodeWalker.GameFiles } - public void InitYmapEntityArchetypes(YmapFile file) - { - if (file == null) return; - if (file.AllEntities != null) - { - for (int i = 0; i < file.AllEntities.Length; i++) - { - var ent = file.AllEntities[i]; - var arch = GetArchetype(ent.CEntityDef.archetypeName); - ent.SetArchetype(arch); - - if (ent.MloInstance != null) - { - var entities = ent.MloInstance.Entities; - if (entities != null) - { - for (int j = 0; j < entities.Length; j++) - { - var ient = entities[j]; - var iarch = GetArchetype(ient.CEntityDef.archetypeName); - ient.SetArchetype(iarch); - if (iarch == null) - { } //can't find archetype - des stuff eg {des_prologue_door} - } - - - //update archetype room AABB's.. bad to have this here? where else to put it? - var mloa = arch as MloArchetype; - if (mloa != null) - { - Vector3 mlobbmin = Vector3.Zero; - Vector3 mlobbmax = Vector3.Zero; - Vector3[] c = new Vector3[8]; - var rooms = mloa.rooms; - if (rooms != null) - { - for (int j = 0; j < rooms.Length; j++) - { - var room = rooms[j]; - if ((room.AttachedObjects == null) || (room.AttachedObjects.Length == 0)) continue; - Vector3 min = new Vector3(float.MaxValue); - Vector3 max = new Vector3(float.MinValue); - for (int k = 0; k < room.AttachedObjects.Length; k++) - { - var objid = room.AttachedObjects[k]; - if (objid < entities.Length) - { - var rooment = entities[objid]; - if ((rooment != null) && (rooment.Archetype != null)) - { - var earch = rooment.Archetype; - var pos = rooment._CEntityDef.position; - var ori = rooment.Orientation; - Vector3 abmin = earch.BBMin * rooment.Scale; //entity box - Vector3 abmax = earch.BBMax * rooment.Scale; - c[0] = abmin; - c[1] = new Vector3(abmin.X, abmin.Y, abmax.Z); - c[2] = new Vector3(abmin.X, abmax.Y, abmin.Z); - c[3] = new Vector3(abmin.X, abmax.Y, abmax.Z); - c[4] = new Vector3(abmax.X, abmin.Y, abmin.Z); - c[5] = new Vector3(abmax.X, abmin.Y, abmax.Z); - c[6] = new Vector3(abmax.X, abmax.Y, abmin.Z); - c[7] = abmax; - for (int n = 0; n < 8; n++) - { - Vector3 corn = ori.Multiply(c[n]) + pos; - min = Vector3.Min(min, corn); - max = Vector3.Max(max, corn); - } - } - } - } - room.BBMin_CW = min; - room.BBMax_CW = max; - mlobbmin = Vector3.Min(mlobbmin, min); - mlobbmax = Vector3.Max(mlobbmax, max); - } - } - mloa.BBMin = mlobbmin; - mloa.BBMax = mlobbmax; - } - } - } - - - } - } - if (file.GrassInstanceBatches != null) - { - for (int i = 0; i < file.GrassInstanceBatches.Length; i++) - { - var batch = file.GrassInstanceBatches[i]; - batch.Archetype = GetArchetype(batch.Batch.archetypeName); - } - } - - if (file.TimeCycleModifiers != null) - { - for (int i = 0; i < file.TimeCycleModifiers.Length; i++) - { - var tcm = file.TimeCycleModifiers[i]; - World.TimecycleMod wtcm; - if (TimeCycleModsDict.TryGetValue(tcm.CTimeCycleModifier.name.Hash, out wtcm)) - { - tcm.TimeCycleModData = wtcm; - } - } - } - - } @@ -1955,8 +1845,9 @@ namespace CodeWalker.GameFiles if (req.Loaded) AddTextureLookups(req as YtdFile); break; case GameFileType.Ymap: - req.Loaded = LoadFile(req as YmapFile); - if (req.Loaded) InitYmapEntityArchetypes(req as YmapFile); + YmapFile y = req as YmapFile; + req.Loaded = LoadFile(y); + if (req.Loaded) y.InitYmapEntityArchetypes(this); break; case GameFileType.Yft: req.Loaded = LoadFile(req as YftFile); diff --git a/CodeWalker.Core/GameFiles/MetaTypes/Archetype.cs b/CodeWalker.Core/GameFiles/MetaTypes/Archetype.cs index f9392c7..ebd4de1 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/Archetype.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/Archetype.cs @@ -14,7 +14,7 @@ namespace CodeWalker.GameFiles public virtual MetaName Type => MetaName.CBaseArchetypeDef; public CBaseArchetypeDef _BaseArchetypeDef; - public CBaseArchetypeDef BaseArchetypeDef { get { return _BaseArchetypeDef; } set { _BaseArchetypeDef = value; } } + public CBaseArchetypeDef BaseArchetypeDef => _BaseArchetypeDef; // for browsing. public MetaHash Hash { get; set; } public YtypFile Ytyp { get; set; } @@ -31,16 +31,16 @@ namespace CodeWalker.GameFiles - public string Name + public string Name { - get + get { return _BaseArchetypeDef.name.ToString(); } } - public string AssetName + public string AssetName { - get + get { return _BaseArchetypeDef.assetName.ToString(); } @@ -49,7 +49,7 @@ namespace CodeWalker.GameFiles protected void InitVars(ref CBaseArchetypeDef arch) { - BaseArchetypeDef = arch; + _BaseArchetypeDef = arch; Hash = arch.assetName; if (Hash.Hash == 0) Hash = arch.name; DrawableDict = arch.drawableDictionary; @@ -83,10 +83,8 @@ namespace CodeWalker.GameFiles public class TimeArchetype : Archetype { public override MetaName Type => MetaName.CTimeArchetypeDef; - - public CTimeArchetypeDefData _TimeArchetypeDef; - public CTimeArchetypeDefData TimeArchetypeDef { get { return _TimeArchetypeDef; } set { _TimeArchetypeDef = value; } } - + public CTimeArchetypeDef _TimeArchetypeDef; + public CTimeArchetypeDef TimeArchetypeDef => _TimeArchetypeDef; // for browsing. public uint TimeFlags { get; set; } public bool[] ActiveHours { get; set; } @@ -98,9 +96,9 @@ namespace CodeWalker.GameFiles { Ytyp = ytyp; InitVars(ref arch._BaseArchetypeDef); - TimeArchetypeDef = arch.TimeArchetypeDef; + _TimeArchetypeDef = arch; - TimeFlags = _TimeArchetypeDef.timeFlags; + TimeFlags = arch.TimeArchetypeDef.timeFlags; ActiveHours = new bool[24]; ActiveHoursText = new string[24]; for (int i = 0; i < 24; i++) @@ -128,11 +126,10 @@ namespace CodeWalker.GameFiles { public override MetaName Type => MetaName.CMloArchetypeDef; - public CMloArchetypeDef _BaseMloArchetypeDef; - public CMloArchetypeDef BaseMloArchetypeDef { get { return _BaseMloArchetypeDef; } set { _BaseMloArchetypeDef = value; } } - public CMloArchetypeDefData _MloArchetypeDef; - public CMloArchetypeDefData MloArchetypeDef { get { return _MloArchetypeDef; } set { _MloArchetypeDef = value; } } + public CMloArchetypeDef MloArchetypeDef => _MloArchetypeDef; // for browsing. + public CMloArchetypeDef _MloArchetypeDef; + public CMloArchetypeDefData _MloArchetypeDefData; public MCEntityDef[] entities { get; set; } public MCMloRoomDef[] rooms { get; set; } @@ -140,37 +137,147 @@ namespace CodeWalker.GameFiles public MCMloEntitySet[] entitySets { get; set; } public CMloTimeCycleModifier[] timeCycleModifiers { get; set; } + public void Init(YtypFile ytyp, ref CMloArchetypeDef arch) { Ytyp = ytyp; InitVars(ref arch._BaseArchetypeDef); - BaseMloArchetypeDef = arch; - MloArchetypeDef = arch.MloArchetypeDef; + _MloArchetypeDef = arch; + _MloArchetypeDefData = arch.MloArchetypeDef; + } + + public bool AddEntity(YmapEntityDef ent, int roomIndex) + { + if (ent == null) return false; + + // entity already exists in our array. so we'll just add + // it to the instanced entities list and continue. + MloInstanceData mloInstance = ent.MloParent?.MloInstance; + MCEntityDef ymcent = mloInstance?.TryGetArchetypeEntity(ent); + if (ymcent != null) + { + return true; + } + + if (roomIndex > rooms.Length) + { + throw new ArgumentOutOfRangeException($"Room index {roomIndex} exceeds the amount of rooms in {Name}."); + } + + var mcEntityDef = new MCEntityDef(ref ent._CEntityDef, this); + + // Add the new entity def to the entities list. + AddEntity(ent, mcEntityDef); + + // Update the attached objects in the room index specified. + AttachEntityToRoom(ent, roomIndex); + return true; + } + + // attaches the specified ymap entity index to the room at roomIndex. + private void AttachEntityToRoom(YmapEntityDef ent, int roomIndex) + { + if (roomIndex > rooms.Length) + { + return; // the room index is bigger than the rooms we have... + } + var attachedObjs = rooms[roomIndex].AttachedObjects?.ToList() ?? new List(); + attachedObjs.Add((uint)ent.Index); + rooms[roomIndex].AttachedObjects = attachedObjs.ToArray(); + } + + // Adds an entity to the entities array and then set's the index of the + // ymap entity to the index of the new MCEntityDef. + private void AddEntity(YmapEntityDef ent, MCEntityDef mcEntityDef) + { + if (ent == null || mcEntityDef == null) return; // no entity?... + // initialize the array. + if (entities == null) entities = new MCEntityDef[0]; + + List entList = entities.ToList(); + entList.Add(mcEntityDef); + ent.Index = entList.IndexOf(mcEntityDef); + entities = entList.ToArray(); + } + + public bool RemoveEntity(YmapEntityDef ent) + { + if (ent.Index >= entities.Length) return false; + + MCEntityDef delent = entities[ent.Index]; + MloInstanceData inst = ent.MloParent?.MloInstance; + if (inst == null) return false; + + if (delent != null) + { + MCEntityDef[] newentities = new MCEntityDef[entities.Length - 1]; + bool didDel = false; + int index = 0; + int delIndex = 0; + for (int i = 0; i < entities.Length; i++) + { + if (entities[i] == delent) + { + delIndex = i; + didDel = true; + continue; + } + + newentities[index] = entities[i]; + YmapEntityDef ymapEntityDef = inst.TryGetYmapEntity(newentities[index]); + if (ymapEntityDef != null) ymapEntityDef.Index = index; + index++; + } + entities = newentities; + + if (didDel) FixRoomIndexes(delIndex); + return didDel; + } + + return false; + } + + private void FixRoomIndexes(int deletedIndex) + { + foreach (var room in rooms) + { + List newAttachedObjects = new List(); + if (room.AttachedObjects == null) + continue; + foreach (var objIndex in room.AttachedObjects) + { + if (objIndex == deletedIndex) continue; + if (objIndex > deletedIndex) + newAttachedObjects.Add(objIndex - 1); // move the index back so it matches the index in the entitiy array. + else newAttachedObjects.Add(objIndex); // else just add the index to the attached objects. + } + room.AttachedObjects = newAttachedObjects.ToArray(); + } } public void LoadChildren(Meta meta) { - var centities = MetaTypes.ConvertDataArray(meta, MetaName.CEntityDef, _MloArchetypeDef.entities); + var centities = MetaTypes.ConvertDataArray(meta, MetaName.CEntityDef, _MloArchetypeDefData.entities); if (centities != null) { entities = new MCEntityDef[centities.Length]; for (int i = 0; i < centities.Length; i++) { - entities[i] = new MCEntityDef(meta, centities[i]); + entities[i] = new MCEntityDef(meta, ref centities[i]) { Archetype = this }; } } - var crooms = MetaTypes.ConvertDataArray(meta, MetaName.CMloRoomDef, _MloArchetypeDef.rooms); + var crooms = MetaTypes.ConvertDataArray(meta, MetaName.CMloRoomDef, _MloArchetypeDefData.rooms); if (crooms != null) { rooms = new MCMloRoomDef[crooms.Length]; for (int i = 0; i < crooms.Length; i++) { - rooms[i] = new MCMloRoomDef(meta, crooms[i]); + rooms[i] = new MCMloRoomDef(meta, crooms[i]) { Archetype = this, Index = i }; } } - var cportals = MetaTypes.ConvertDataArray(meta, MetaName.CMloPortalDef, _MloArchetypeDef.portals); + var cportals = MetaTypes.ConvertDataArray(meta, MetaName.CMloPortalDef, _MloArchetypeDefData.portals); if (cportals != null) { portals = new MCMloPortalDef[cportals.Length]; @@ -180,7 +287,7 @@ namespace CodeWalker.GameFiles } } - var centitySets = MetaTypes.ConvertDataArray(meta, MetaName.CMloEntitySet, _MloArchetypeDef.entitySets); + var centitySets = MetaTypes.ConvertDataArray(meta, MetaName.CMloEntitySet, _MloArchetypeDefData.entitySets); if (centitySets != null) { entitySets = new MCMloEntitySet[centitySets.Length]; @@ -191,14 +298,44 @@ namespace CodeWalker.GameFiles } - timeCycleModifiers = MetaTypes.ConvertDataArray(meta, MetaName.CMloTimeCycleModifier, _MloArchetypeDef.timeCycleModifiers); + timeCycleModifiers = MetaTypes.ConvertDataArray(meta, MetaName.CMloTimeCycleModifier, _MloArchetypeDefData.timeCycleModifiers); } + public MCMloRoomDef GetEntityRoom(MCEntityDef ent) + { + int objectIndex = -1; + for (int i = 0; i < entities.Length; i++) + { + MCEntityDef e = entities[i]; + if (e == ent) + { + objectIndex = i; + break; + } + } + if (objectIndex == -1) return null; + + MCMloRoomDef room = null; + for (int i = 0; i < rooms.Length; i++) + { + MCMloRoomDef r = rooms[i]; + for (int j = 0; j < r.AttachedObjects.Length; j++) + { + uint ind = r.AttachedObjects[j]; + if (ind == objectIndex) + { + room = r; + break; + } + } + if (room != null) break; + } + + return room; + } } - - [TypeConverter(typeof(ExpandableObjectConverter))] public class MloInstanceData { @@ -208,7 +345,12 @@ namespace CodeWalker.GameFiles public uint[] defaultEntitySets { get; set; } public YmapEntityDef[] Entities { get; set; } + public Dictionary EntitySets { get; set; } + public MloInstanceData() + { + EntitySets = new Dictionary(); + } public void CreateYmapEntities(YmapEntityDef owner, MloArchetype mloa) { @@ -234,27 +376,182 @@ namespace CodeWalker.GameFiles var entitySet = entitySets[i]; if (entitySet.Entities != null) { + EntitySets[entitySet._Data.name] = new MloInstanceEntitySet(entitySet, this); + MloInstanceEntitySet instset = EntitySets[entitySet._Data.name]; for (int j = 0; j < entitySet.Entities.Length; j++) { YmapEntityDef e = CreateYmapEntity(owner, entitySet.Entities[j], lasti); - e.MloEntitySet = entitySet; - entlist.Add(e); + EntitySets[entitySet._Data.name].Entities.Add(e); + e.MloEntitySet = instset; lasti++; } } } } - if (defaultEntitySets != null) + if ((defaultEntitySets != null) && (entitySets != null)) { + for (var i = 0; i < defaultEntitySets.Length; i++) + { + uint index = defaultEntitySets[i]; + if (index >= entitySets.Length) continue; + MCMloEntitySet set = entitySets[index]; + MloInstanceEntitySet instset = EntitySets[set._Data.name]; + instset.Visible = true; + } } Entities = entlist.ToArray(); } - private YmapEntityDef CreateYmapEntity(YmapEntityDef owner, MCEntityDef ment, int i) + public void InitYmapEntityArchetypes(GameFileCache gfc) { - YmapEntityDef e = new YmapEntityDef(null, i, ref ment._Data); + if (Owner == null) return; + var arch = Owner.Archetype; + + if (Entities != null) + { + for (int j = 0; j < Entities.Length; j++) + { + var ient = Entities[j]; + var iarch = gfc.GetArchetype(ient.CEntityDef.archetypeName); + ient.SetArchetype(iarch); + + if (iarch == null) + { } //can't find archetype - des stuff eg {des_prologue_door} + } + + UpdateBBs(arch); + } + + if (EntitySets != null) + { + foreach (var entitySet in EntitySets) + { + var entities = entitySet.Value.Entities; + if (entities == null) continue; + + for (int i = 0; i < entities.Count; i++) + { + var ient = entities[i]; + var iarch = gfc.GetArchetype(ient.CEntityDef.archetypeName); + ient.SetArchetype(iarch); + + if (iarch == null) + { } //can't find archetype - des stuff eg {des_prologue_door} + } + } + } + } + + public void UpdateBBs(Archetype arch) + { + //update archetype room AABB's.. bad to have this here? where else to put it? + var mloa = arch as MloArchetype; + if (mloa != null) + { + Vector3 mlobbmin = Vector3.Zero; + Vector3 mlobbmax = Vector3.Zero; + Vector3[] c = new Vector3[8]; + var rooms = mloa.rooms; + if (rooms != null) + { + for (int j = 0; j < rooms.Length; j++) + { + var room = rooms[j]; + if ((room.AttachedObjects == null) || (room.AttachedObjects.Length == 0)) continue; + Vector3 min = new Vector3(float.MaxValue); + Vector3 max = new Vector3(float.MinValue); + for (int k = 0; k < room.AttachedObjects.Length; k++) + { + var objid = room.AttachedObjects[k]; + if (objid < Entities.Length) + { + var rooment = Entities[objid]; + if ((rooment != null) && (rooment.Archetype != null)) + { + var earch = rooment.Archetype; + var pos = rooment._CEntityDef.position; + var ori = rooment.Orientation; + Vector3 abmin = earch.BBMin * rooment.Scale; //entity box + Vector3 abmax = earch.BBMax * rooment.Scale; + c[0] = abmin; + c[1] = new Vector3(abmin.X, abmin.Y, abmax.Z); + c[2] = new Vector3(abmin.X, abmax.Y, abmin.Z); + c[3] = new Vector3(abmin.X, abmax.Y, abmax.Z); + c[4] = new Vector3(abmax.X, abmin.Y, abmin.Z); + c[5] = new Vector3(abmax.X, abmin.Y, abmax.Z); + c[6] = new Vector3(abmax.X, abmax.Y, abmin.Z); + c[7] = abmax; + for (int n = 0; n < 8; n++) + { + Vector3 corn = ori.Multiply(c[n]) + pos; + min = Vector3.Min(min, corn); + max = Vector3.Max(max, corn); + } + } + } + } + room.BBMin_CW = min; + room.BBMax_CW = max; + mlobbmin = Vector3.Min(mlobbmin, min); + mlobbmax = Vector3.Max(mlobbmax, max); + } + } + mloa.BBMin = mlobbmin; + mloa.BBMax = mlobbmax; + } + } + + public bool DeleteEntity(YmapEntityDef ent) + { + if (Entities == null) + { + throw new NullReferenceException("The Entities list returned null in our MloInstanceData. This could be an issue with initialization. The MloInstance probably doesn't exist."); + } + + if (ent.Index >= Entities.Length) + { + throw new ArgumentOutOfRangeException("The index of the entity was greater than the amount of entities that exist in this MloInstance. Likely an issue with initializion."); + } + + int index = 0; + YmapEntityDef[] newentities = new YmapEntityDef[Entities.Length - 1]; + YmapEntityDef delentity = Entities[ent.Index]; + bool del = false; + + for (int i = 0; i < Entities.Length; i++) + { + if (Entities[i] == delentity) + { + del = true; + continue; + } + newentities[index] = Entities[i]; + newentities[index].Index = index; + index++; + } + if (!del) + throw new ArgumentException("The entity specified was not found in this MloInstance. It cannot be deleted."); + + if (Owner.Archetype is MloArchetype arch) + { + if (arch.RemoveEntity(ent)) + { + if (ent.MloEntitySet != null) + if (!ent.MloEntitySet.Entities.Remove(ent)) + return false; + // Delete was successful... + Entities = newentities; + return true; + } + } + throw new InvalidCastException("The owner of this archetype's archetype definition is not an MloArchetype."); + } + + public YmapEntityDef CreateYmapEntity(YmapEntityDef owner, MCEntityDef ment, int index) + { + YmapEntityDef e = new YmapEntityDef(null, index, ref ment._Data); e.Extensions = ment.Extensions; e.MloRefPosition = e.Position; e.MloRefOrientation = e.Orientation; @@ -263,9 +560,31 @@ namespace CodeWalker.GameFiles e.Orientation = Quaternion.Multiply(owner.Orientation, e.MloRefOrientation); e.UpdateWidgetPosition(); e.UpdateWidgetOrientation(); + return e; } + public MCEntityDef TryGetArchetypeEntity(YmapEntityDef ymapEntity) + { + if (ymapEntity == null) return null; + if (Owner?.Archetype == null) return null; + if (!(Owner.Archetype is MloArchetype mloa)) return null; + if (ymapEntity.Index >= mloa.entities.Length) return null; + + var entity = mloa.entities[ymapEntity.Index]; + return entity; + } + + public YmapEntityDef TryGetYmapEntity(MCEntityDef mcEntity) + { + if (mcEntity == null) return null; + if (Owner?.Archetype == null) return null; + if (!(Owner.Archetype is MloArchetype mloa)) return null; + + var index = Array.FindIndex(mloa.entities, x => x == mcEntity); + if (index == -1 || index >= Entities.Length) return null; + return Entities[index]; + } public void SetPosition(Vector3 pos) { @@ -289,17 +608,52 @@ namespace CodeWalker.GameFiles for (int i = 0; i < Entities.Length; i++) { YmapEntityDef e = Entities[i]; - e.Position = Owner.Position + Owner.Orientation.Multiply(e.MloRefPosition); - e.Orientation = Quaternion.Multiply(Owner.Orientation, e.MloRefOrientation); - e.UpdateWidgetPosition(); - e.UpdateWidgetOrientation(); + UpdateEntity(e); } } + public void UpdateEntity(YmapEntityDef e) + { + e.Position = Owner.Position + Owner.Orientation.Multiply(e.MloRefPosition); + e.Orientation = Quaternion.Multiply(Owner.Orientation, e.MloRefOrientation); + e.UpdateWidgetPosition(); + e.UpdateWidgetOrientation(); + } + public void AddEntity(YmapEntityDef e) + { + if (e == null) return; + if (Entities == null) Entities = new YmapEntityDef[0]; + var entities = Entities.ToList(); + entities.Add(e); + Entities = entities.ToArray(); + } } + [TypeConverter(typeof(ExpandableObjectConverter))] + public class MloInstanceEntitySet + { + public MloInstanceEntitySet(MCMloEntitySet entSet, MloInstanceData instance) + { + EntitySet = entSet; + Entities = new List(); + Instance = instance; + } + + public MCMloEntitySet EntitySet { get; set; } + public List Entities { get; set; } + public MloInstanceData Instance { get; set; } + + public uint[] Locations + { + get { return EntitySet?.Locations; } + set { if (EntitySet != null) EntitySet.Locations = value; } + } + + public bool Visible { get; set; } + } + } diff --git a/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs b/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs index 3013d08..0d407b1 100644 --- a/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs +++ b/CodeWalker.Core/GameFiles/MetaTypes/MetaTypes.cs @@ -2428,7 +2428,9 @@ namespace CodeWalker.GameFiles public Vector3 BBMax { get { return (_Data.bbMax); } } public Vector3 BBMin_CW { get; set; } public Vector3 BBMax_CW { get; set; } - + + public MloArchetype Archetype { get; set; } + public int Index { get; set; } public MCMloRoomDef() { } public MCMloRoomDef(Meta meta, CMloRoomDef data) @@ -2610,7 +2612,7 @@ namespace CodeWalker.GameFiles Entities = new MCEntityDef[ents.Length]; for (int i = 0; i < ents.Length; i++) { - Entities[i] = new MCEntityDef(meta, ents[i]); + Entities[i] = new MCEntityDef(meta, ref ents[i]); } } } @@ -2750,23 +2752,26 @@ namespace CodeWalker.GameFiles [TC(typeof(EXP))] public class MCEntityDef : MetaWrapper { public CEntityDef _Data; - public CEntityDef Data { get { return _Data; } } + public CEntityDef Data { get { return _Data; } set { _Data = value; } } public MetaWrapper[] Extensions { get; set; } - public MCEntityDef() { } + public MloArchetype Archetype { get; set; } // for browsing/reference purposes + public MCEntityDef(MCEntityDef copy) { - if (copy != null) - { - _Data = copy.Data; - } + if (copy != null) _Data = copy.Data; } - public MCEntityDef(Meta meta, CEntityDef d) + public MCEntityDef(Meta meta, ref CEntityDef d) { _Data = d; Extensions = MetaTypes.GetExtensions(meta, _Data.extensions); } + public MCEntityDef(ref CEntityDef d, MloArchetype arch) + { + _Data = d; + Archetype = arch; + } public override void Load(Meta meta, MetaPOINTER ptr) { diff --git a/CodeWalker.Core/Utils/Vectors.cs b/CodeWalker.Core/Utils/Vectors.cs index 19b354e..1e748d7 100644 --- a/CodeWalker.Core/Utils/Vectors.cs +++ b/CodeWalker.Core/Utils/Vectors.cs @@ -24,6 +24,11 @@ namespace CodeWalker { return new Vector4((float)Math.Floor(v.X), (float)Math.Floor(v.Y), (float)Math.Floor(v.Z), (float)Math.Floor(v.W)); } + + public static Quaternion ToQuaternion(this Vector4 v) + { + return new Quaternion(v); + } } diff --git a/CodeWalker.csproj b/CodeWalker.csproj index 6d2938e..fa9fd96 100644 --- a/CodeWalker.csproj +++ b/CodeWalker.csproj @@ -328,6 +328,12 @@ EditYmapCarGenPanel.cs + + Form + + + EditYtypArchetypeMloRoomPanel.cs + Form @@ -382,6 +388,12 @@ EditYnvPortalPanel.cs + + Form + + + EditYtypArchetypePanel.cs + Form @@ -596,6 +608,9 @@ EditYmapCarGenPanel.cs + + EditYtypArchetypeMloRoomPanel.cs + EditYmapEntityPanel.cs @@ -623,6 +638,9 @@ EditYnvPortalPanel.cs + + EditYtypArchetypePanel.cs + EditYtypPanel.cs diff --git a/Project/Panels/EditYmapEntityPanel.Designer.cs b/Project/Panels/EditYmapEntityPanel.Designer.cs index f33c0e7..6d1b070 100644 --- a/Project/Panels/EditYmapEntityPanel.Designer.cs +++ b/Project/Panels/EditYmapEntityPanel.Designer.cs @@ -71,6 +71,7 @@ this.EntityNumChildrenTextBox = new System.Windows.Forms.TextBox(); this.label25 = new System.Windows.Forms.Label(); this.EntityExtensionsTabPage = new System.Windows.Forms.TabPage(); + this.label1 = new System.Windows.Forms.Label(); this.EntityPivotTabPage = new System.Windows.Forms.TabPage(); this.label95 = new System.Windows.Forms.Label(); this.EntityPivotEditCheckBox = new System.Windows.Forms.CheckBox(); @@ -79,7 +80,6 @@ this.EntityPivotRotationNormalizeButton = new System.Windows.Forms.Button(); this.label94 = new System.Windows.Forms.Label(); this.EntityPivotRotationTextBox = new System.Windows.Forms.TextBox(); - this.label1 = new System.Windows.Forms.Label(); this.EntityTabControl.SuspendLayout(); this.EntityGeneralTabPage.SuspendLayout(); this.EntityLodTabPage.SuspendLayout(); @@ -575,6 +575,15 @@ this.EntityExtensionsTabPage.Text = "Extensions"; this.EntityExtensionsTabPage.UseVisualStyleBackColor = true; // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(27, 27); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(157, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Entity extensions editing TODO!"; + // // EntityPivotTabPage // this.EntityPivotTabPage.Controls.Add(this.label95); @@ -660,15 +669,6 @@ this.EntityPivotRotationTextBox.TabIndex = 25; this.EntityPivotRotationTextBox.TextChanged += new System.EventHandler(this.EntityPivotRotationTextBox_TextChanged); // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(27, 27); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(157, 13); - this.label1.TabIndex = 0; - this.label1.Text = "Entity extensions editing TODO!"; - // // EditYmapEntityPanel // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); diff --git a/Project/Panels/EditYmapEntityPanel.cs b/Project/Panels/EditYmapEntityPanel.cs index 30f351b..b286963 100644 --- a/Project/Panels/EditYmapEntityPanel.cs +++ b/Project/Panels/EditYmapEntityPanel.cs @@ -1,13 +1,6 @@ using CodeWalker.GameFiles; 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.Tasks; using System.Windows.Forms; namespace CodeWalker.Project.Panels @@ -16,6 +9,7 @@ namespace CodeWalker.Project.Panels { public ProjectForm ProjectForm; public YmapEntityDef CurrentEntity { get; set; } + public MCEntityDef CurrentMCEntity { get; set; } private bool populatingui = false; @@ -29,6 +23,8 @@ namespace CodeWalker.Project.Panels public void SetEntity(YmapEntityDef entity) { CurrentEntity = entity; + MloInstanceData instance = entity?.MloParent?.MloInstance; + CurrentMCEntity = instance?.TryGetArchetypeEntity(entity); Tag = entity; LoadEntity(); UpdateFormTitle(); @@ -94,10 +90,10 @@ namespace CodeWalker.Project.Panels else { populatingui = true; - var e = CurrentEntity.CEntityDef; + var e = CurrentEntity._CEntityDef; var po = CurrentEntity.PivotOrientation; //EntityPanel.Enabled = true; - EntityAddToProjectButton.Enabled = !ProjectForm.YmapExistsInProject(CurrentEntity.Ymap); + EntityAddToProjectButton.Enabled = CurrentEntity.Ymap != null ? !ProjectForm.YmapExistsInProject(CurrentEntity.Ymap) : !ProjectForm.YtypExistsInProject(CurrentEntity.MloParent?.Archetype?.Ytyp); EntityDeleteButton.Enabled = !EntityAddToProjectButton.Enabled; EntityArchetypeTextBox.Text = e.archetypeName.ToString(); EntityArchetypeHashLabel.Text = "Hash: " + e.archetypeName.Hash.ToString(); @@ -176,21 +172,53 @@ namespace CodeWalker.Project.Panels { 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); - ProjectForm.SetYmapHasChanged(true); + + if (CurrentEntity.IsMlo) + { + CurrentEntity.MloInstance.InitYmapEntityArchetypes(ProjectForm.GameFileCache); + } + + ProjectItemChanged(); } } } } + private void ProjectItemChanged() + { + if (CurrentEntity.Ymap != null) + { + ProjectForm.SetYmapHasChanged(true); + } + else if (CurrentEntity.MloParent?.Archetype?.Ytyp != null) + { + ProjectForm.SetYtypHasChanged(true); + } + } + private void EntityFlagsTextBox_TextChanged(object sender, EventArgs e) { if (populatingui) return; @@ -209,7 +237,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.flags != flags) { CurrentEntity._CEntityDef.flags = flags; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.flags = flags; + ProjectItemChanged(); } } } @@ -244,7 +274,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.flags != flags) { CurrentEntity._CEntityDef.flags = flags; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.flags = flags; + ProjectItemChanged(); } } } @@ -260,7 +292,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.guid != guid) { CurrentEntity._CEntityDef.guid = guid; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.guid = guid; + ProjectItemChanged(); } } } @@ -274,14 +308,16 @@ namespace CodeWalker.Project.Panels { if (CurrentEntity.MloParent != null) { - //TODO: positioning for interior entities! + v = CurrentEntity.MloParent.Position + CurrentEntity.MloParent.Orientation.Multiply(v); + CurrentEntity.SetPosition(v); + ProjectItemChanged(); } else { if (CurrentEntity.Position != v) { CurrentEntity.SetPosition(v); - ProjectForm.SetYmapHasChanged(true); + ProjectItemChanged(); var wf = ProjectForm.WorldForm; if (wf != null) { @@ -304,17 +340,24 @@ namespace CodeWalker.Project.Panels { if (CurrentEntity._CEntityDef.rotation != v) { - Quaternion q = new Quaternion(v); - CurrentEntity.SetOrientationInv(q); - ProjectForm.SetYmapHasChanged(true); + Quaternion q = v.ToQuaternion(); var wf = ProjectForm.WorldForm; - if (wf != null) + + if (CurrentEntity.MloParent != null) { - wf.BeginInvoke(new Action(() => - { - wf.SetWidgetRotation(CurrentEntity.WidgetOrientation, true); - })); + var world = Quaternion.Normalize(Quaternion.Multiply(q, CurrentEntity.MloParent.Orientation)); + CurrentEntity.SetOrientation(world); } + else + { + CurrentEntity.SetOrientation(q, true); + } + + ProjectItemChanged(); + wf?.BeginInvoke(new Action(() => + { + wf.SetWidgetRotation(CurrentEntity.WidgetOrientation, true); + })); } } } @@ -331,7 +374,7 @@ namespace CodeWalker.Project.Panels { Vector3 newscale = new Vector3(sxy, sxy, CurrentEntity.Scale.Z); CurrentEntity.SetScale(newscale); - ProjectForm.SetYmapHasChanged(true); + ProjectItemChanged(); var wf = ProjectForm.WorldForm; if (wf != null) { @@ -356,7 +399,7 @@ namespace CodeWalker.Project.Panels { Vector3 newscale = new Vector3(CurrentEntity.Scale.X, CurrentEntity.Scale.Y, sz); CurrentEntity.SetScale(newscale); - ProjectForm.SetYmapHasChanged(true); + ProjectItemChanged(); var wf = ProjectForm.WorldForm; if (wf != null) { @@ -380,7 +423,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.parentIndex != pind) { CurrentEntity._CEntityDef.parentIndex = pind; //Needs more work for LOD linking! - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.parentIndex = pind; + ProjectItemChanged(); } } } @@ -396,7 +441,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.lodDist != lodDist) { CurrentEntity._CEntityDef.lodDist = lodDist; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.lodDist = lodDist; + ProjectItemChanged(); } } } @@ -412,7 +459,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.childLodDist != childLodDist) { CurrentEntity._CEntityDef.childLodDist = childLodDist; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.childLodDist = childLodDist; + ProjectItemChanged(); } } } @@ -427,7 +476,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.lodLevel != lodLevel) { CurrentEntity._CEntityDef.lodLevel = lodLevel; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.lodLevel = lodLevel; + ProjectItemChanged(); } } } @@ -443,7 +494,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.numChildren != numChildren) { CurrentEntity._CEntityDef.numChildren = numChildren; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.numChildren = numChildren; + ProjectItemChanged(); } } } @@ -458,7 +511,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.priorityLevel != priorityLevel) { CurrentEntity._CEntityDef.priorityLevel = priorityLevel; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.priorityLevel = priorityLevel; + ProjectItemChanged(); } } } @@ -474,7 +529,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.ambientOcclusionMultiplier != aomult) { CurrentEntity._CEntityDef.ambientOcclusionMultiplier = aomult; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.ambientOcclusionMultiplier = aomult; + ProjectItemChanged(); } } } @@ -490,7 +547,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.artificialAmbientOcclusion != artao) { CurrentEntity._CEntityDef.artificialAmbientOcclusion = artao; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.artificialAmbientOcclusion = artao; + ProjectItemChanged(); } } } @@ -506,7 +565,9 @@ namespace CodeWalker.Project.Panels if (CurrentEntity._CEntityDef.tintValue != tintValue) { CurrentEntity._CEntityDef.tintValue = tintValue; - ProjectForm.SetYmapHasChanged(true); + if (CurrentMCEntity != null) + CurrentMCEntity._Data.tintValue = tintValue; + ProjectItemChanged(); } } } @@ -515,7 +576,7 @@ namespace CodeWalker.Project.Panels { if (CurrentEntity == null) return; if (ProjectForm.WorldForm == null) return; - ProjectForm.WorldForm.GoToPosition(CurrentEntity.Position); + ProjectForm.WorldForm.GoToPosition(CurrentEntity.Position, Vector3.One * CurrentEntity.BSRadius); } private void EntityNormalizeRotationButton_Click(object sender, EventArgs e) diff --git a/Project/Panels/EditYmapGrassPanel.cs b/Project/Panels/EditYmapGrassPanel.cs index dedd9d1..5e7f558 100644 --- a/Project/Panels/EditYmapGrassPanel.cs +++ b/Project/Panels/EditYmapGrassPanel.cs @@ -42,6 +42,7 @@ namespace CodeWalker.Project.Panels Tag = batch; UpdateFormTitle(); UpdateControls(); + ProjectForm.WorldForm?.SelectGrassBatch(batch); } private void UpdateControls() @@ -197,6 +198,13 @@ namespace CodeWalker.Project.Panels private void OptimizeBatchButton_Click(object sender, EventArgs e) { if (CurrentBatch.Instances == null || CurrentBatch.Instances.Length <= 0) return; + var d = MessageBox.Show( + @"You are about to split the selected batch into multiple parts. Are you sure you want to do this?", + @"Instance Optimizer", MessageBoxButtons.YesNo); + + if (d == DialogResult.No) + return; + lock (ProjectForm.WorldForm.RenderSyncRoot) { var newBatches = CurrentBatch?.OptimizeInstances(CurrentBatch, (float)OptmizationThresholdNumericUpDown.Value); diff --git a/Project/Panels/EditYtypArchetypeMloRoomPanel.Designer.cs b/Project/Panels/EditYtypArchetypeMloRoomPanel.Designer.cs new file mode 100644 index 0000000..0d30f09 --- /dev/null +++ b/Project/Panels/EditYtypArchetypeMloRoomPanel.Designer.cs @@ -0,0 +1,173 @@ +namespace CodeWalker.Project.Panels +{ + partial class EditYtypArchetypeMloRoomPanel + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditYtypArchetypeMloRoomPanel)); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.MinBoundsTextBox = new CodeWalker.WinForms.TextBoxFix(); + this.MaxBoundsTextBox = new CodeWalker.WinForms.TextBoxFix(); + this.label3 = new System.Windows.Forms.Label(); + this.RoomNameTextBox = new CodeWalker.WinForms.TextBoxFix(); + this.RoomFlagsCheckedListBox = new System.Windows.Forms.CheckedListBox(); + this.RoomFlagsTextBox = new System.Windows.Forms.TextBox(); + this.label14 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(33, 69); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(27, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Min:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(30, 95); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(30, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Max:"; + // + // MinBoundsTextBox + // + this.MinBoundsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.MinBoundsTextBox.Location = new System.Drawing.Point(66, 66); + this.MinBoundsTextBox.Name = "MinBoundsTextBox"; + this.MinBoundsTextBox.Size = new System.Drawing.Size(275, 20); + this.MinBoundsTextBox.TabIndex = 2; + this.MinBoundsTextBox.TextChanged += new System.EventHandler(this.MinBoundsTextBox_TextChanged); + // + // MaxBoundsTextBox + // + this.MaxBoundsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.MaxBoundsTextBox.Location = new System.Drawing.Point(66, 92); + this.MaxBoundsTextBox.Name = "MaxBoundsTextBox"; + this.MaxBoundsTextBox.Size = new System.Drawing.Size(275, 20); + this.MaxBoundsTextBox.TabIndex = 3; + this.MaxBoundsTextBox.TextChanged += new System.EventHandler(this.MaxBoundsTextBox_TextChanged); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(19, 43); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(41, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Name: "; + // + // RoomNameTextBox + // + this.RoomNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.RoomNameTextBox.Location = new System.Drawing.Point(66, 40); + this.RoomNameTextBox.Name = "RoomNameTextBox"; + this.RoomNameTextBox.Size = new System.Drawing.Size(275, 20); + this.RoomNameTextBox.TabIndex = 5; + this.RoomNameTextBox.TextChanged += new System.EventHandler(this.RoomNameTextBox_TextChanged); + // + // RoomFlagsCheckedListBox + // + this.RoomFlagsCheckedListBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.RoomFlagsCheckedListBox.CheckOnClick = true; + this.RoomFlagsCheckedListBox.FormattingEnabled = true; + this.RoomFlagsCheckedListBox.Items.AddRange(new object[] { + "1 - Unk01", + "2 - Unk02", + "4 - Unk03", + "8 - Unk04", + "16 - Unk05", + "32 - Unk06", + "64 - Unk07"}); + this.RoomFlagsCheckedListBox.Location = new System.Drawing.Point(352, 62); + this.RoomFlagsCheckedListBox.Name = "RoomFlagsCheckedListBox"; + this.RoomFlagsCheckedListBox.Size = new System.Drawing.Size(201, 244); + this.RoomFlagsCheckedListBox.TabIndex = 35; + this.RoomFlagsCheckedListBox.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.RoomFlagsCheckedListBox_ItemCheck); + // + // RoomFlagsTextBox + // + this.RoomFlagsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.RoomFlagsTextBox.Location = new System.Drawing.Point(406, 36); + this.RoomFlagsTextBox.Name = "RoomFlagsTextBox"; + this.RoomFlagsTextBox.Size = new System.Drawing.Size(147, 20); + this.RoomFlagsTextBox.TabIndex = 34; + this.RoomFlagsTextBox.TextChanged += new System.EventHandler(this.RoomFlagsTextBox_TextChanged); + // + // label14 + // + this.label14.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(365, 39); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(35, 13); + this.label14.TabIndex = 33; + this.label14.Text = "Flags:"; + // + // EditYtypArchetypeMloRoomPanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(565, 505); + this.Controls.Add(this.RoomFlagsCheckedListBox); + this.Controls.Add(this.RoomFlagsTextBox); + this.Controls.Add(this.label14); + this.Controls.Add(this.RoomNameTextBox); + this.Controls.Add(this.label3); + this.Controls.Add(this.MaxBoundsTextBox); + this.Controls.Add(this.MinBoundsTextBox); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "EditYtypArchetypeMloRoomPanel"; + this.Text = "Room"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private WinForms.TextBoxFix MinBoundsTextBox; + private WinForms.TextBoxFix MaxBoundsTextBox; + private System.Windows.Forms.Label label3; + private WinForms.TextBoxFix RoomNameTextBox; + private System.Windows.Forms.CheckedListBox RoomFlagsCheckedListBox; + private System.Windows.Forms.TextBox RoomFlagsTextBox; + private System.Windows.Forms.Label label14; + } +} \ No newline at end of file diff --git a/Project/Panels/EditYtypArchetypeMloRoomPanel.cs b/Project/Panels/EditYtypArchetypeMloRoomPanel.cs new file mode 100644 index 0000000..a7547c4 --- /dev/null +++ b/Project/Panels/EditYtypArchetypeMloRoomPanel.cs @@ -0,0 +1,137 @@ +using System; +using System.Windows.Forms; +using CodeWalker.GameFiles; +using SharpDX; + +namespace CodeWalker.Project.Panels +{ + public partial class EditYtypArchetypeMloRoomPanel : ProjectPanel + { + public ProjectForm ProjectForm; + public MCMloRoomDef CurrentRoom { get; set; } + + public EditYtypArchetypeMloRoomPanel(ProjectForm owner) + { + ProjectForm = owner; + InitializeComponent(); + } + + public void SetRoom(MCMloRoomDef room) + { + CurrentRoom = room; + Tag = room; + UpdateFormTitle(); + MloInstanceData instance = ProjectForm.TryGetMloInstance(room?.Archetype); + ProjectForm.WorldForm?.SelectMloRoom(room, instance); + UpdateControls(); + } + + private void UpdateControls() + { + if (CurrentRoom != null) + { + RoomNameTextBox.Text = CurrentRoom.RoomName; + MinBoundsTextBox.Text = FloatUtil.GetVector3String(CurrentRoom.BBMin); + MaxBoundsTextBox.Text = FloatUtil.GetVector3String(CurrentRoom.BBMax); + RoomFlagsTextBox.Text = CurrentRoom._Data.flags.ToString(); + } + } + + private void UpdateFormTitle() + { + Text = CurrentRoom?.RoomName ?? "Room"; + } + + private void RoomNameTextBox_TextChanged(object sender, EventArgs e) + { + if (CurrentRoom == null) return; + + if (CurrentRoom.RoomName != RoomNameTextBox.Text) + { + CurrentRoom.RoomName = RoomNameTextBox.Text; + + TreeNode tn = ProjectForm.ProjectExplorer?.FindMloRoomTreeNode(CurrentRoom); + if (tn != null) + { + tn.Text = CurrentRoom.RoomName; + } + + UpdateFormTitle(); + ProjectForm.SetYtypHasChanged(true); + } + } + + private void MinBoundsTextBox_TextChanged(object sender, EventArgs e) + { + if (CurrentRoom == null) return; + Vector3 bb = FloatUtil.ParseVector3String(MinBoundsTextBox.Text); + if (CurrentRoom._Data.bbMin != bb) + { + CurrentRoom._Data.bbMin = bb; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void MaxBoundsTextBox_TextChanged(object sender, EventArgs e) + { + if (CurrentRoom == null) return; + Vector3 bb = FloatUtil.ParseVector3String(MaxBoundsTextBox.Text); + if (CurrentRoom._Data.bbMax != bb) + { + CurrentRoom._Data.bbMax = bb; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void RoomFlagsTextBox_TextChanged(object sender, EventArgs e) + { + if (CurrentRoom == null) return; + uint.TryParse(RoomFlagsTextBox.Text, out uint flags); + for (int i = 0; i < RoomFlagsCheckedListBox.Items.Count; i++) + { + var c = ((flags & (1u << i)) > 0); + RoomFlagsCheckedListBox.SetItemCheckState(i, c ? CheckState.Checked : CheckState.Unchecked); + } + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentRoom._Data.flags != flags) + { + CurrentRoom._Data.flags = flags; + ProjectForm.SetYtypHasChanged(true); + } + } + } + + private void RoomFlagsCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e) + { + if (CurrentRoom == null) return; + uint flags = 0; + for (int i = 0; i < RoomFlagsCheckedListBox.Items.Count; i++) + { + if (e.Index == i) + { + if (e.NewValue == CheckState.Checked) + { + flags += (uint)(1 << i); + } + } + else + { + if (RoomFlagsCheckedListBox.GetItemChecked(i)) + { + flags += (uint)(1 << i); + } + } + } + RoomFlagsTextBox.Text = flags.ToString(); + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentRoom._Data.flags != flags) + { + CurrentRoom._Data.flags = flags; + ProjectForm.SetYtypHasChanged(true); + } + } + } + } +} diff --git a/Project/Panels/EditYtypArchetypeMloRoomPanel.resx b/Project/Panels/EditYtypArchetypeMloRoomPanel.resx new file mode 100644 index 0000000..1431f6b --- /dev/null +++ b/Project/Panels/EditYtypArchetypeMloRoomPanel.resx @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + 6P///ysvjWVqtP///////wAAAAAAAAAAAP////D0/0hPpsDG6////////6y02d7k8////3qAx+/z/f// + /wAAAAAAAAAAAAAAAAAAAP///////////////8zT8V5ns1Rcrdzh9f///////////wAAAAAAAAAAAAAA + AAAAAP////////7+/6ix3nmBxFthtmdwu09WqbC54/v9//r8//j6//39/wAAAAAAAAAAAOjt/H6I0FJc + skpSqHF+wRMahFZhs4iT1AsNc1pgrm52v2RsuO/z/gAAAP////////L2/cLJ7rrD64+V4DY+ozU+mYmU + 0X2Hy1hfss7V8urv/PP2/v///wAAAP///+Pp+d/k9////////+Pp/4uR3ysymW14xYOM0fD0/P///+Xq + +ri/6Pj6/wAAAOrv/j5DnbS75P////////////X4/+/0/ubr+/r7/////////9rh+hgZhKGo2QAAAPDz + /eLn+f////j6/2Nqttrg9////+Hn+P3+//3+/1hescLJ6/////L2/eru/AAAAAAAAAAAAP///8rR70tR + p/3+//v8/zY6jNPY7////09WqWpwu////wAAAAAAAAAAAAAAAAAAAAAAAPb4/vr7//////v8/5Wd1eHm + +P////v8//T3/wAAAAAAAAAAAAAAAP//AAD8PwAA/D8AAPwDAACAAwAAgAMAAIAHAADABwAAwAEAAMAB + AAAAAQAAAAEAAAABAAAAAQAAwAcAAOAPAAAoAAAAQAAAAIAAAAABABgAAAAAAAAwAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//P3//P3//P3/ + /f7//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/ + +fv/+fv/+Pr/+fv/+vv//P3//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA/f7/+fr/8/b/7PL/5+3/6e/+9Pf/+vv//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA/P3/9/r/6O7/cXe1UVaet7z17fL/+Pr//f3/AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+/z/9Pj/4Oj/NzyCUlOd2dz/6O//9Pf//P3/AAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/2+P9X2OmREGLnqPd + 4+v/8vb/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/ + 1N35bXK1JSRtbHGz5O7/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA+vv/8PX/3Ob/U1eaDwtXjZLT4+z/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/2eP+MjR6AAA+c3i34Or/8fX/+/z/AAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/1d/7MS91AAA1UFSS4On/8vb/+/z/AAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + /v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+vz/+fv/+Pr/+Pr/+vv//f3//v//AAAAAAAAAAAAAAAA + /v//+fv/9Pf/2+L/SVGtAABsLTaZytL58fX/9/n//f7/AAAAAAAAAAAAAAAA/v7/+/z/9/n/9fj/9vn/ + 9fj/9vj/+vz//f7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//f3//f3//f3//v7//v//AAAA + AAAAAAAAAAAAAAAAAAAA+/z/9vn/6e//mZ7gTVarr7bp6/H/9fj/+vv//v7/AAAAAAAAAAAAAAAAAAAA + /v7//f7/+/z/+/z/+/z//P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/f3/+Pr/9fj/6e7/4+n/8fb/9Pf/+Pr//f3/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+fv/+fv/+vv/+Pr/+vv/ + /P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7/ + /f3//P3//f7//v7//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//////// + ///////4D/////////AH////////8Af////////wB/////////AH////////8Af////////wB/////// + //AH////////8Af////////wB/////////AH////////8AfwP//////wB8Af//+Af/AHgB///wA/8AcA + H///AB/wBgAf//8AD/AGAB///wAH8AYAH///AAPwBAAf//8AA/AEAD///wAD8AQAP///AAPwBAB///+A + A/AEAP///8AD4AAA////4AcAAAH////wDgAAAf/////8AAAH//////gAAAf/////4AAAAf/////gAAAA + /f//+AAAAAAAD//AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+A + AAAAAAAP/4AAAAAAAB//wAAAAABAf/4HwAAAAYAf8APAAAADgA/gA+AAAAMAA8AD8AAABwADgAP8AAAf + AAOAA/4AAB8AA4ADAAAAAQADgAIAcA4AgAOABgBwDgBAA4AMAGAMADADwDwAYAwAOAfg+ABgBAAeH//4 + AEAEAB////gAwAYAH///+ADABgAf///4AcAGAB////gBwAcAH///+APAB4A////8B+AHwH//////4A// + ///////gD/////////Af//////////////8= + + + \ No newline at end of file diff --git a/Project/Panels/EditYtypArchetypePanel.Designer.cs b/Project/Panels/EditYtypArchetypePanel.Designer.cs new file mode 100644 index 0000000..6fbd3ff --- /dev/null +++ b/Project/Panels/EditYtypArchetypePanel.Designer.cs @@ -0,0 +1,632 @@ +namespace CodeWalker.Project.Panels +{ + partial class EditYtypArchetypePanel + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditYtypArchetypePanel)); + this.BaseArchetypeTabPage = new System.Windows.Forms.TabPage(); + this.ArchetypeDeleteButton = new System.Windows.Forms.Button(); + this.label13 = new System.Windows.Forms.Label(); + this.BSRadiusTextBox = new System.Windows.Forms.TextBox(); + this.BSCenterTextBox = new System.Windows.Forms.TextBox(); + this.BBMaxTextBox = new System.Windows.Forms.TextBox(); + this.BBMinTextBox = new System.Windows.Forms.TextBox(); + this.ArchetypeNameTextBox = new System.Windows.Forms.TextBox(); + this.ArchetypeFlagsTextBox = new System.Windows.Forms.TextBox(); + this.PhysicsDictionaryTextBox = new System.Windows.Forms.TextBox(); + this.ClipDictionaryTextBox = new System.Windows.Forms.TextBox(); + this.AssetNameTextBox = new System.Windows.Forms.TextBox(); + this.TextureDictTextBox = new System.Windows.Forms.TextBox(); + this.label12 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.PhysicsDictHashLabel = new System.Windows.Forms.Label(); + this.TextureDictHashLabel = new System.Windows.Forms.Label(); + this.EntityFlagsCheckedListBox = new System.Windows.Forms.CheckedListBox(); + this.label14 = new System.Windows.Forms.Label(); + this.SpecialAttributeNumericUpDown = new System.Windows.Forms.NumericUpDown(); + this.label10 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.AssetTypeComboBox = new System.Windows.Forms.ComboBox(); + this.label8 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.HDTextureDistNumericUpDown = new System.Windows.Forms.NumericUpDown(); + this.label3 = new System.Windows.Forms.Label(); + this.LodDistNumericUpDown = new System.Windows.Forms.NumericUpDown(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.TabControl = new System.Windows.Forms.TabControl(); + this.MloArchetypeTabPage = new System.Windows.Forms.TabPage(); + this.EntitySetsListBox = new System.Windows.Forms.CheckedListBox(); + this.label15 = new System.Windows.Forms.Label(); + this.BaseArchetypeTabPage.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.SpecialAttributeNumericUpDown)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.HDTextureDistNumericUpDown)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.LodDistNumericUpDown)).BeginInit(); + this.TabControl.SuspendLayout(); + this.MloArchetypeTabPage.SuspendLayout(); + this.SuspendLayout(); + // + // BaseArchetypeTabPage + // + this.BaseArchetypeTabPage.Controls.Add(this.ArchetypeDeleteButton); + this.BaseArchetypeTabPage.Controls.Add(this.label13); + this.BaseArchetypeTabPage.Controls.Add(this.BSRadiusTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.BSCenterTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.BBMaxTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.BBMinTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.ArchetypeNameTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.ArchetypeFlagsTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.PhysicsDictionaryTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.ClipDictionaryTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.AssetNameTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.TextureDictTextBox); + this.BaseArchetypeTabPage.Controls.Add(this.label12); + this.BaseArchetypeTabPage.Controls.Add(this.label11); + this.BaseArchetypeTabPage.Controls.Add(this.label5); + this.BaseArchetypeTabPage.Controls.Add(this.PhysicsDictHashLabel); + this.BaseArchetypeTabPage.Controls.Add(this.TextureDictHashLabel); + this.BaseArchetypeTabPage.Controls.Add(this.EntityFlagsCheckedListBox); + this.BaseArchetypeTabPage.Controls.Add(this.label14); + this.BaseArchetypeTabPage.Controls.Add(this.SpecialAttributeNumericUpDown); + this.BaseArchetypeTabPage.Controls.Add(this.label10); + this.BaseArchetypeTabPage.Controls.Add(this.label9); + this.BaseArchetypeTabPage.Controls.Add(this.AssetTypeComboBox); + this.BaseArchetypeTabPage.Controls.Add(this.label8); + this.BaseArchetypeTabPage.Controls.Add(this.label7); + this.BaseArchetypeTabPage.Controls.Add(this.label6); + this.BaseArchetypeTabPage.Controls.Add(this.label4); + this.BaseArchetypeTabPage.Controls.Add(this.HDTextureDistNumericUpDown); + this.BaseArchetypeTabPage.Controls.Add(this.label3); + this.BaseArchetypeTabPage.Controls.Add(this.LodDistNumericUpDown); + this.BaseArchetypeTabPage.Controls.Add(this.label2); + this.BaseArchetypeTabPage.Controls.Add(this.label1); + this.BaseArchetypeTabPage.Location = new System.Drawing.Point(4, 22); + this.BaseArchetypeTabPage.Name = "BaseArchetypeTabPage"; + this.BaseArchetypeTabPage.Padding = new System.Windows.Forms.Padding(3); + this.BaseArchetypeTabPage.Size = new System.Drawing.Size(631, 479); + this.BaseArchetypeTabPage.TabIndex = 0; + this.BaseArchetypeTabPage.Text = "Base Archetype Def"; + this.BaseArchetypeTabPage.UseVisualStyleBackColor = true; + // + // ArchetypeDeleteButton + // + this.ArchetypeDeleteButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; + this.ArchetypeDeleteButton.Location = new System.Drawing.Point(270, 450); + this.ArchetypeDeleteButton.Name = "ArchetypeDeleteButton"; + this.ArchetypeDeleteButton.Size = new System.Drawing.Size(126, 23); + this.ArchetypeDeleteButton.TabIndex = 79; + this.ArchetypeDeleteButton.Text = "Delete Archetype"; + this.ArchetypeDeleteButton.UseVisualStyleBackColor = true; + this.ArchetypeDeleteButton.Click += new System.EventHandler(this.DeleteArchetypeButton_Click); + // + // label13 + // + this.label13.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(8, 411); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(57, 13); + this.label13.TabIndex = 78; + this.label13.Text = "BSRadius:"; + // + // BSRadiusTextBox + // + this.BSRadiusTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BSRadiusTextBox.Location = new System.Drawing.Point(71, 408); + this.BSRadiusTextBox.Name = "BSRadiusTextBox"; + this.BSRadiusTextBox.Size = new System.Drawing.Size(552, 20); + this.BSRadiusTextBox.TabIndex = 77; + this.BSRadiusTextBox.TextChanged += new System.EventHandler(this.BSRadiusTextBox_TextChanged); + // + // BSCenterTextBox + // + this.BSCenterTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BSCenterTextBox.Location = new System.Drawing.Point(71, 382); + this.BSCenterTextBox.Name = "BSCenterTextBox"; + this.BSCenterTextBox.Size = new System.Drawing.Size(552, 20); + this.BSCenterTextBox.TabIndex = 75; + this.BSCenterTextBox.TextChanged += new System.EventHandler(this.BSCenterTextBox_TextChanged); + // + // BBMaxTextBox + // + this.BBMaxTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BBMaxTextBox.Location = new System.Drawing.Point(71, 356); + this.BBMaxTextBox.Name = "BBMaxTextBox"; + this.BBMaxTextBox.Size = new System.Drawing.Size(552, 20); + this.BBMaxTextBox.TabIndex = 73; + this.BBMaxTextBox.TextChanged += new System.EventHandler(this.BBMaxTextBox_TextChanged); + // + // BBMinTextBox + // + this.BBMinTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.BBMinTextBox.Location = new System.Drawing.Point(71, 330); + this.BBMinTextBox.Name = "BBMinTextBox"; + this.BBMinTextBox.Size = new System.Drawing.Size(552, 20); + this.BBMinTextBox.TabIndex = 71; + this.BBMinTextBox.TextChanged += new System.EventHandler(this.BBMinTextBox_TextChanged); + // + // ArchetypeNameTextBox + // + this.ArchetypeNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ArchetypeNameTextBox.Location = new System.Drawing.Point(110, 9); + this.ArchetypeNameTextBox.Name = "ArchetypeNameTextBox"; + this.ArchetypeNameTextBox.Size = new System.Drawing.Size(247, 20); + this.ArchetypeNameTextBox.TabIndex = 70; + this.ArchetypeNameTextBox.TextChanged += new System.EventHandler(this.ArchetypeNameTextBox_TextChanged); + // + // ArchetypeFlagsTextBox + // + this.ArchetypeFlagsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.ArchetypeFlagsTextBox.Location = new System.Drawing.Point(476, 12); + this.ArchetypeFlagsTextBox.Name = "ArchetypeFlagsTextBox"; + this.ArchetypeFlagsTextBox.Size = new System.Drawing.Size(147, 20); + this.ArchetypeFlagsTextBox.TabIndex = 66; + this.ArchetypeFlagsTextBox.TextChanged += new System.EventHandler(this.ArchetypeFlagsTextBox_TextChanged); + // + // PhysicsDictionaryTextBox + // + this.PhysicsDictionaryTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.PhysicsDictionaryTextBox.Location = new System.Drawing.Point(110, 191); + this.PhysicsDictionaryTextBox.Name = "PhysicsDictionaryTextBox"; + this.PhysicsDictionaryTextBox.Size = new System.Drawing.Size(206, 20); + this.PhysicsDictionaryTextBox.TabIndex = 60; + this.PhysicsDictionaryTextBox.TextChanged += new System.EventHandler(this.PhysicsDictionaryTextBox_TextChanged); + // + // ClipDictionaryTextBox + // + this.ClipDictionaryTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.ClipDictionaryTextBox.Location = new System.Drawing.Point(110, 165); + this.ClipDictionaryTextBox.Name = "ClipDictionaryTextBox"; + this.ClipDictionaryTextBox.Size = new System.Drawing.Size(247, 20); + this.ClipDictionaryTextBox.TabIndex = 58; + this.ClipDictionaryTextBox.TextChanged += new System.EventHandler(this.ClipDictionaryTextBox_TextChanged); + // + // AssetNameTextBox + // + this.AssetNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AssetNameTextBox.Location = new System.Drawing.Point(110, 35); + this.AssetNameTextBox.Name = "AssetNameTextBox"; + this.AssetNameTextBox.Size = new System.Drawing.Size(247, 20); + this.AssetNameTextBox.TabIndex = 56; + this.AssetNameTextBox.TextChanged += new System.EventHandler(this.AssetNameTextBox_TextChanged); + // + // TextureDictTextBox + // + this.TextureDictTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.TextureDictTextBox.Location = new System.Drawing.Point(110, 139); + this.TextureDictTextBox.Name = "TextureDictTextBox"; + this.TextureDictTextBox.Size = new System.Drawing.Size(206, 20); + this.TextureDictTextBox.TabIndex = 54; + this.TextureDictTextBox.TextChanged += new System.EventHandler(this.TextureDictTextBox_TextChanged); + // + // label12 + // + this.label12.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(8, 385); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(55, 13); + this.label12.TabIndex = 76; + this.label12.Text = "BSCenter:"; + // + // label11 + // + this.label11.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(19, 359); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(44, 13); + this.label11.TabIndex = 74; + this.label11.Text = "BBMax:"; + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(24, 333); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(41, 13); + this.label5.TabIndex = 72; + this.label5.Text = "BBMin:"; + // + // PhysicsDictHashLabel + // + this.PhysicsDictHashLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.PhysicsDictHashLabel.AutoSize = true; + this.PhysicsDictHashLabel.Location = new System.Drawing.Point(322, 194); + this.PhysicsDictHashLabel.Name = "PhysicsDictHashLabel"; + this.PhysicsDictHashLabel.Size = new System.Drawing.Size(35, 13); + this.PhysicsDictHashLabel.TabIndex = 69; + this.PhysicsDictHashLabel.Text = "Hash:"; + // + // TextureDictHashLabel + // + this.TextureDictHashLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.TextureDictHashLabel.AutoSize = true; + this.TextureDictHashLabel.Location = new System.Drawing.Point(322, 142); + this.TextureDictHashLabel.Name = "TextureDictHashLabel"; + this.TextureDictHashLabel.Size = new System.Drawing.Size(35, 13); + this.TextureDictHashLabel.TabIndex = 68; + this.TextureDictHashLabel.Text = "Hash:"; + // + // EntityFlagsCheckedListBox + // + this.EntityFlagsCheckedListBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.EntityFlagsCheckedListBox.CheckOnClick = true; + this.EntityFlagsCheckedListBox.FormattingEnabled = true; + this.EntityFlagsCheckedListBox.Items.AddRange(new object[] { + "1 - Unk01", + "2 - Unk02", + "4 - Unk03", + "8 - Unk04", + "16 - Unk05", + "32 - Static", + "64 - Unk07", + "128 - Unk08", + "256 - Unk09", + "512 - Unk10", + "1024 - Unk11", + "2048 - Unk12", + "4096 - Unk13", + "8192 - Unk14", + "16384 - Unk15", + "32768 - Unk16", + "65536 - Unk17", + "131072 - Unk18", + "262144 - Unk19", + "524288 - Unk20", + "1048576 - Unk21", + "2097152 - Unk22", + "4194304 - Unk23", + "8388608 - Unk24", + "16777216 - Unk25", + "33554432 - Unk26", + "67108864 - Unk27", + "134217728 - Unk28", + "268435456 - Unk29", + "536870912 - Unk30", + "1073741824 - Unk31", + "2147483648 - Unk32"}); + this.EntityFlagsCheckedListBox.Location = new System.Drawing.Point(422, 38); + this.EntityFlagsCheckedListBox.Name = "EntityFlagsCheckedListBox"; + this.EntityFlagsCheckedListBox.Size = new System.Drawing.Size(201, 274); + this.EntityFlagsCheckedListBox.TabIndex = 67; + this.EntityFlagsCheckedListBox.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.ArchetypeFlagsCheckedListBox_ItemCheck); + // + // label14 + // + this.label14.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(419, 15); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(35, 13); + this.label14.TabIndex = 65; + this.label14.Text = "Flags:"; + // + // SpecialAttributeNumericUpDown + // + this.SpecialAttributeNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.SpecialAttributeNumericUpDown.Location = new System.Drawing.Point(110, 113); + this.SpecialAttributeNumericUpDown.Maximum = new decimal(new int[] { + 9999999, + 0, + 0, + 0}); + this.SpecialAttributeNumericUpDown.Name = "SpecialAttributeNumericUpDown"; + this.SpecialAttributeNumericUpDown.Size = new System.Drawing.Size(247, 20); + this.SpecialAttributeNumericUpDown.TabIndex = 64; + this.SpecialAttributeNumericUpDown.ValueChanged += new System.EventHandler(this.SpecialAttributeNumericUpDown_ValueChanged); + // + // label10 + // + this.label10.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(17, 115); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(87, 13); + this.label10.TabIndex = 63; + this.label10.Text = "Special Attribute:"; + // + // label9 + // + this.label9.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(41, 220); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(63, 13); + this.label9.TabIndex = 62; + this.label9.Text = "Asset Type:"; + // + // AssetTypeComboBox + // + this.AssetTypeComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.AssetTypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.AssetTypeComboBox.FormattingEnabled = true; + this.AssetTypeComboBox.Location = new System.Drawing.Point(110, 217); + this.AssetTypeComboBox.Name = "AssetTypeComboBox"; + this.AssetTypeComboBox.Size = new System.Drawing.Size(247, 21); + this.AssetTypeComboBox.TabIndex = 61; + // + // label8 + // + this.label8.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(8, 194); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(96, 13); + this.label8.TabIndex = 59; + this.label8.Text = "Physics Dictionary:"; + // + // label7 + // + this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(27, 168); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(77, 13); + this.label7.TabIndex = 57; + this.label7.Text = "Clip Dictionary:"; + // + // label6 + // + this.label6.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(37, 38); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(67, 13); + this.label6.TabIndex = 55; + this.label6.Text = "Asset Name:"; + // + // label4 + // + this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(8, 142); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(96, 13); + this.label4.TabIndex = 53; + this.label4.Text = "Texture Dictionary:"; + // + // HDTextureDistNumericUpDown + // + this.HDTextureDistNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.HDTextureDistNumericUpDown.DecimalPlaces = 8; + this.HDTextureDistNumericUpDown.Location = new System.Drawing.Point(110, 87); + this.HDTextureDistNumericUpDown.Maximum = new decimal(new int[] { + 9999999, + 0, + 0, + 0}); + this.HDTextureDistNumericUpDown.Name = "HDTextureDistNumericUpDown"; + this.HDTextureDistNumericUpDown.Size = new System.Drawing.Size(247, 20); + this.HDTextureDistNumericUpDown.TabIndex = 52; + this.HDTextureDistNumericUpDown.ValueChanged += new System.EventHandler(this.HDTextureDistNumericUpDown_ValueChanged); + // + // label3 + // + this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(18, 89); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(86, 13); + this.label3.TabIndex = 51; + this.label3.Text = "HD Texture Dist:"; + // + // LodDistNumericUpDown + // + this.LodDistNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.LodDistNumericUpDown.DecimalPlaces = 8; + this.LodDistNumericUpDown.Location = new System.Drawing.Point(110, 61); + this.LodDistNumericUpDown.Maximum = new decimal(new int[] { + 9999999, + 0, + 0, + 0}); + this.LodDistNumericUpDown.Name = "LodDistNumericUpDown"; + this.LodDistNumericUpDown.Size = new System.Drawing.Size(247, 20); + this.LodDistNumericUpDown.TabIndex = 50; + this.LodDistNumericUpDown.ValueChanged += new System.EventHandler(this.LodDistNumericUpDown_ValueChanged); + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(55, 63); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(49, 13); + this.label2.TabIndex = 49; + this.label2.Text = "Lod Dist:"; + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(66, 12); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 48; + this.label1.Text = "Name:"; + // + // TabControl + // + this.TabControl.Controls.Add(this.BaseArchetypeTabPage); + this.TabControl.Controls.Add(this.MloArchetypeTabPage); + this.TabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.TabControl.Location = new System.Drawing.Point(0, 0); + this.TabControl.Name = "TabControl"; + this.TabControl.SelectedIndex = 0; + this.TabControl.Size = new System.Drawing.Size(639, 505); + this.TabControl.TabIndex = 48; + // + // MloArchetypeTabPage + // + this.MloArchetypeTabPage.Controls.Add(this.EntitySetsListBox); + this.MloArchetypeTabPage.Controls.Add(this.label15); + this.MloArchetypeTabPage.Location = new System.Drawing.Point(4, 22); + this.MloArchetypeTabPage.Name = "MloArchetypeTabPage"; + this.MloArchetypeTabPage.Padding = new System.Windows.Forms.Padding(3); + this.MloArchetypeTabPage.Size = new System.Drawing.Size(631, 479); + this.MloArchetypeTabPage.TabIndex = 1; + this.MloArchetypeTabPage.Text = "Mlo Archetype Def"; + this.MloArchetypeTabPage.UseVisualStyleBackColor = true; + // + // EntitySetsListBox + // + this.EntitySetsListBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.EntitySetsListBox.CheckOnClick = true; + this.EntitySetsListBox.FormattingEnabled = true; + this.EntitySetsListBox.Location = new System.Drawing.Point(11, 42); + this.EntitySetsListBox.Name = "EntitySetsListBox"; + this.EntitySetsListBox.Size = new System.Drawing.Size(603, 214); + this.EntitySetsListBox.TabIndex = 2; + this.EntitySetsListBox.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.EntitySetsListBox_ItemCheck); + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(8, 26); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(57, 13); + this.label15.TabIndex = 1; + this.label15.Text = "EntitySets:"; + // + // EditYtypArchetypePanel + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(639, 505); + this.Controls.Add(this.TabControl); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(531, 458); + this.Name = "EditYtypArchetypePanel"; + this.Text = "Edit Archetype"; + this.Load += new System.EventHandler(this.EditYtypArchetypePanel_Load); + this.BaseArchetypeTabPage.ResumeLayout(false); + this.BaseArchetypeTabPage.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.SpecialAttributeNumericUpDown)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.HDTextureDistNumericUpDown)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.LodDistNumericUpDown)).EndInit(); + this.TabControl.ResumeLayout(false); + this.MloArchetypeTabPage.ResumeLayout(false); + this.MloArchetypeTabPage.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabPage BaseArchetypeTabPage; + private System.Windows.Forms.Button ArchetypeDeleteButton; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.TextBox BSRadiusTextBox; + private System.Windows.Forms.TextBox BSCenterTextBox; + private System.Windows.Forms.TextBox BBMaxTextBox; + private System.Windows.Forms.TextBox BBMinTextBox; + private System.Windows.Forms.TextBox ArchetypeNameTextBox; + private System.Windows.Forms.TextBox ArchetypeFlagsTextBox; + private System.Windows.Forms.TextBox PhysicsDictionaryTextBox; + private System.Windows.Forms.TextBox ClipDictionaryTextBox; + private System.Windows.Forms.TextBox AssetNameTextBox; + private System.Windows.Forms.TextBox TextureDictTextBox; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label PhysicsDictHashLabel; + private System.Windows.Forms.Label TextureDictHashLabel; + private System.Windows.Forms.CheckedListBox EntityFlagsCheckedListBox; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.NumericUpDown SpecialAttributeNumericUpDown; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.ComboBox AssetTypeComboBox; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.NumericUpDown HDTextureDistNumericUpDown; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.NumericUpDown LodDistNumericUpDown; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TabControl TabControl; + private System.Windows.Forms.TabPage MloArchetypeTabPage; + private System.Windows.Forms.CheckedListBox EntitySetsListBox; + private System.Windows.Forms.Label label15; + } +} \ No newline at end of file diff --git a/Project/Panels/EditYtypArchetypePanel.cs b/Project/Panels/EditYtypArchetypePanel.cs new file mode 100644 index 0000000..79fc5a6 --- /dev/null +++ b/Project/Panels/EditYtypArchetypePanel.cs @@ -0,0 +1,353 @@ +using System; +using System.Globalization; +using System.Windows.Forms; +using CodeWalker.GameFiles; +using SharpDX; + +namespace CodeWalker.Project.Panels +{ + public partial class EditYtypArchetypePanel : ProjectPanel + { + public ProjectForm ProjectForm; + + private bool populatingui; + + public EditYtypArchetypePanel(ProjectForm owner) + { + InitializeComponent(); + + ProjectForm = owner; + } + + public Archetype CurrentArchetype { get; set; } + + private void EditYtypArchetypePanel_Load(object sender, EventArgs e) + { + AssetTypeComboBox.Items.AddRange(Enum.GetNames(typeof(Unk_1991964615))); + } + + public void SetArchetype(Archetype archetype) + { + CurrentArchetype = archetype; + Tag = archetype; + UpdateFormTitle(); + UpdateControls(); + } + + private void UpdateFormTitle() + { + Text = CurrentArchetype?.Name ?? "Edit Archetype"; + } + + private void UpdateControls() + { + if (CurrentArchetype != null) + { + ArchetypeDeleteButton.Enabled = ProjectForm.YtypExistsInProject(CurrentArchetype.Ytyp); + ArchetypeNameTextBox.Text = CurrentArchetype.Name; + AssetNameTextBox.Text = CurrentArchetype.AssetName; + LodDistNumericUpDown.Value = (decimal)CurrentArchetype._BaseArchetypeDef.lodDist; + HDTextureDistNumericUpDown.Value = (decimal)CurrentArchetype._BaseArchetypeDef.hdTextureDist; + SpecialAttributeNumericUpDown.Value = CurrentArchetype._BaseArchetypeDef.specialAttribute; + ArchetypeFlagsTextBox.Text = CurrentArchetype._BaseArchetypeDef.flags.ToString(); + TextureDictTextBox.Text = CurrentArchetype._BaseArchetypeDef.textureDictionary.ToCleanString(); + ClipDictionaryTextBox.Text = CurrentArchetype._BaseArchetypeDef.clipDictionary.ToCleanString(); + PhysicsDictionaryTextBox.Text = CurrentArchetype._BaseArchetypeDef.physicsDictionary.ToCleanString(); + AssetTypeComboBox.Text = CurrentArchetype._BaseArchetypeDef.assetType.ToString(); + BBMinTextBox.Text = FloatUtil.GetVector3String(CurrentArchetype._BaseArchetypeDef.bbMin); + BBMaxTextBox.Text = FloatUtil.GetVector3String(CurrentArchetype._BaseArchetypeDef.bbMax); + BSCenterTextBox.Text = FloatUtil.GetVector3String(CurrentArchetype._BaseArchetypeDef.bsCentre); + BSRadiusTextBox.Text = CurrentArchetype._BaseArchetypeDef.bsRadius.ToString(CultureInfo.InvariantCulture); + + EntitySetsListBox.Items.Clear(); + if (CurrentArchetype is MloArchetype MloArchetype) + { + if (!TabControl.TabPages.Contains(MloArchetypeTabPage)) + { + TabControl.TabPages.Add(MloArchetypeTabPage); + } + + MloInstanceData mloinstance = ProjectForm.TryGetMloInstance(MloArchetype); + if (mloinstance != null) + { + EntitySetsListBox.Enabled = true; + foreach (var sets in mloinstance.EntitySets) + { + MloInstanceEntitySet set = sets.Value; + EntitySetsListBox.Items.Add(set.EntitySet.ToString(), set.Visible); + } + } + else EntitySetsListBox.Enabled = false; + } + else TabControl.TabPages.Remove(MloArchetypeTabPage); + } + } + + private void ArchetypeFlagsTextBox_TextChanged(object sender, EventArgs e) + { + if (populatingui) return; + if (CurrentArchetype == null) return; + uint flags = 0; + uint.TryParse(ArchetypeFlagsTextBox.Text, out flags); + populatingui = true; + for (int i = 0; i < EntityFlagsCheckedListBox.Items.Count; i++) + { + var c = ((flags & (1u << i)) > 0); + EntityFlagsCheckedListBox.SetItemCheckState(i, c ? CheckState.Checked : CheckState.Unchecked); + } + populatingui = false; + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentArchetype._BaseArchetypeDef.flags != flags) + { + CurrentArchetype._BaseArchetypeDef.flags = flags; + ProjectForm.SetYtypHasChanged(true); + } + } + } + + private void ArchetypeFlagsCheckedListBox_ItemCheck(object sender, ItemCheckEventArgs e) + { + if (populatingui) return; + if (CurrentArchetype == null) return; + uint flags = 0; + for (int i = 0; i < EntityFlagsCheckedListBox.Items.Count; i++) + { + if (e.Index == i) + { + if (e.NewValue == CheckState.Checked) + { + flags += (uint)(1 << i); + } + } + else + { + if (EntityFlagsCheckedListBox.GetItemChecked(i)) + { + flags += (uint)(1 << i); + } + } + } + populatingui = true; + ArchetypeFlagsTextBox.Text = flags.ToString(); + populatingui = false; + lock (ProjectForm.ProjectSyncRoot) + { + if (CurrentArchetype._BaseArchetypeDef.flags != flags) + { + CurrentArchetype._BaseArchetypeDef.flags = flags; + ProjectForm.SetYtypHasChanged(true); + } + } + } + + 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 = 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; + } + TextureDictHashLabel.Text = "Hash: " + hash.ToString(); + CurrentArchetype._BaseArchetypeDef.textureDictionary = hash; + ProjectForm.SetYtypHasChanged(true); + } + } + } + + 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 = 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; + } + PhysicsDictHashLabel.Text = "Hash: " + hash.ToString(); + + CurrentArchetype._BaseArchetypeDef.physicsDictionary = hash; + ProjectForm.SetYtypHasChanged(true); + } + } + } + + private void ArchetypeNameTextBox_TextChanged(object sender, EventArgs e) + { + var 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 AssetNameTextBox_TextChanged(object sender, EventArgs e) + { + var hash = JenkHash.GenHash(AssetNameTextBox.Text); + + if (CurrentArchetype._BaseArchetypeDef.assetName != hash) + { + CurrentArchetype._BaseArchetypeDef.assetName = hash; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void ClipDictionaryTextBox_TextChanged(object sender, EventArgs e) + { + var hash = JenkHash.GenHash(ClipDictionaryTextBox.Text); + + if (CurrentArchetype._BaseArchetypeDef.clipDictionary != hash) + { + CurrentArchetype._BaseArchetypeDef.clipDictionary = hash; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void LodDistNumericUpDown_ValueChanged(object sender, EventArgs e) + { + var loddist = (float)LodDistNumericUpDown.Value; + if (!MathUtil.NearEqual(loddist, CurrentArchetype._BaseArchetypeDef.lodDist)) + { + CurrentArchetype._BaseArchetypeDef.lodDist = loddist; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void HDTextureDistNumericUpDown_ValueChanged(object sender, EventArgs e) + { + var hddist = (float)HDTextureDistNumericUpDown.Value; + if (!MathUtil.NearEqual(hddist, CurrentArchetype._BaseArchetypeDef.hdTextureDist)) + { + CurrentArchetype._BaseArchetypeDef.hdTextureDist = hddist; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void SpecialAttributeNumericUpDown_ValueChanged(object sender, EventArgs e) + { + var att = (uint)SpecialAttributeNumericUpDown.Value; + if (CurrentArchetype._BaseArchetypeDef.specialAttribute != att) + { + CurrentArchetype._BaseArchetypeDef.specialAttribute = att; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void BBMinTextBox_TextChanged(object sender, EventArgs e) + { + Vector3 min = FloatUtil.ParseVector3String(BBMinTextBox.Text); + if (CurrentArchetype._BaseArchetypeDef.bbMin != min) + { + CurrentArchetype._BaseArchetypeDef.bbMin = min; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void BBMaxTextBox_TextChanged(object sender, EventArgs e) + { + Vector3 max = FloatUtil.ParseVector3String(BBMaxTextBox.Text); + + if (CurrentArchetype._BaseArchetypeDef.bbMax != max) + { + CurrentArchetype._BaseArchetypeDef.bbMax = max; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void BSCenterTextBox_TextChanged(object sender, EventArgs e) + { + Vector3 c = FloatUtil.ParseVector3String(BSCenterTextBox.Text); + + if (CurrentArchetype._BaseArchetypeDef.bsCentre != c) + { + CurrentArchetype._BaseArchetypeDef.bsCentre = c; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void BSRadiusTextBox_TextChanged(object sender, EventArgs e) + { + if (float.TryParse(BSRadiusTextBox.Text, out float f)) + { + if (!MathUtil.NearEqual(CurrentArchetype._BaseArchetypeDef.bsRadius, f)) + { + CurrentArchetype._BaseArchetypeDef.bsRadius = f; + ProjectForm.SetYtypHasChanged(true); + } + } + else + { + CurrentArchetype._BaseArchetypeDef.bsRadius = 0f; + ProjectForm.SetYtypHasChanged(true); + } + } + + private void DeleteArchetypeButton_Click(object sender, EventArgs e) + { + ProjectForm.SetProjectItem(CurrentArchetype); + ProjectForm.DeleteArchetype(); + } + + private void EntitySetsListBox_ItemCheck(object sender, ItemCheckEventArgs e) + { + if (CurrentArchetype is MloArchetype MloArchetype) + { + var inst = ProjectForm.TryGetMloInstance(MloArchetype); + if (inst != null) + { + MloInstanceEntitySet mloInstanceEntitySet = inst.EntitySets[MloArchetype.entitySets[e.Index]._Data.name]; + mloInstanceEntitySet.Visible = e.NewValue == CheckState.Checked; + return; + } + } + e.NewValue = CheckState.Unchecked; + } + } +} diff --git a/Project/Panels/EditYtypArchetypePanel.resx b/Project/Panels/EditYtypArchetypePanel.resx new file mode 100644 index 0000000..2d9a79e --- /dev/null +++ b/Project/Panels/EditYtypArchetypePanel.resx @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAEBAAAAAAGABoAwAAFgAAACgAAAAQAAAAIAAAAAEAGAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAD////r7/3y9f7///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///+P + lce/xeb///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///+Ah7a0utv///////// + //////////8AAAAAAAAAAAD////x9P73+v7///////////+Mk8K6weH////s8Pu6wOj9/f////8AAAAA + AAAAAAD///+epdgZHILl6/z///////+NlMPIzuj///8rL41larT///////8AAAAAAAAAAAD////w9P9I + T6bAxuv///////+stNne5PP///96gMfv8/3///8AAAAAAAAAAAAAAAAAAAD////////////////M0/Fe + Z7NUXK3c4fX///////////8AAAAAAAAAAAAAAAAAAAD////////+/v+osd55gcRbYbZncLtPVqmwueP7 + /f/6/P/4+v/9/f8AAAAAAAAAAADo7fx+iNBSXLJKUqhxfsETGoRWYbOIk9QLDXNaYK5udr9kbLjv8/4A + AAD////////y9v3Cye66w+uPleA2PqM1PpmJlNF9h8tYX7LO1fLq7/zz9v7///8AAAD////j6fnf5Pf/ + ///////j6f+Lkd8rMplteMWDjNHw9Pz////l6vq4v+j4+v8AAADq7/4+Q520u+T////////////1+P/v + 9P7m6/v6+//////////a4foYGYShqNkAAADw8/3i5/n////4+v9jarba4Pf////h5/j9/v/9/v9YXrHC + yev////y9v3q7vwAAAAAAAAAAAD////K0e9LUaf9/v/7/P82OozT2O////9PVqlqcLv///8AAAAAAAAA + AAAAAAAAAAAAAAD2+P76+//////7/P+VndXh5vj////7/P/09/8AAAAAAAAAAAAAAAD//wAA/D8AAPw/ + AAD8AwAAgAMAAIADAACABwAAwAcAAMABAADAAQAAAAEAAAABAAAAAQAAAAEAAMAHAADgDwAA + + + \ No newline at end of file diff --git a/Project/Panels/EditYtypPanel.Designer.cs b/Project/Panels/EditYtypPanel.Designer.cs index 8b545b4..ac6c8c5 100644 --- a/Project/Panels/EditYtypPanel.Designer.cs +++ b/Project/Panels/EditYtypPanel.Designer.cs @@ -29,34 +29,20 @@ private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(EditYtypPanel)); - this.label1 = new System.Windows.Forms.Label(); this.SuspendLayout(); // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(58, 52); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(99, 13); - this.label1.TabIndex = 0; - this.label1.Text = "Ytyp editing TODO!"; - // // EditYtypPanel // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(469, 292); - this.Controls.Add(this.label1); + this.ClientSize = new System.Drawing.Size(599, 406); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "EditYtypPanel"; this.Text = "Edit Ytyp"; this.ResumeLayout(false); - this.PerformLayout(); } #endregion - - private System.Windows.Forms.Label label1; } } \ No newline at end of file diff --git a/Project/Panels/ProjectExplorerPanel.cs b/Project/Panels/ProjectExplorerPanel.cs index 027b2e4..9fff95b 100644 --- a/Project/Panels/ProjectExplorerPanel.cs +++ b/Project/Panels/ProjectExplorerPanel.cs @@ -248,8 +248,53 @@ namespace CodeWalker.Project.Panels } } - private void LoadYtypTreeNodes(YtypFile ytyp, TreeNode node)//TODO! + private void LoadYtypTreeNodes(YtypFile ytyp, TreeNode node) { + if (ytyp == null) return; + + if (!string.IsNullOrEmpty(node.Name)) return; + + node.Nodes.Clear(); + + if ((ytyp.AllArchetypes != null) && (ytyp.AllArchetypes.Length > 0)) + { + var archetypesnode = node.Nodes.Add("Archetypes (" + ytyp.AllArchetypes.Length.ToString() + ")"); + archetypesnode.Name = "Archetypes"; + archetypesnode.Tag = ytyp; + var archetypes = ytyp.AllArchetypes; + for (int i = 0; i < archetypes.Length; i++) + { + var yarch = archetypes[i]; + var tarch = archetypesnode.Nodes.Add(yarch.Name); + tarch.Tag = yarch; + + if (yarch is MloArchetype mlo) + { + if ((mlo.entities.Length) > 0 && (mlo.rooms.Length > 0)) + { + MCEntityDef[] entities = mlo.entities; + var roomsnode = tarch.Nodes.Add("Rooms (" + mlo.rooms.Length.ToString() + ")"); + roomsnode.Name = "Rooms"; + for (int j = 0; j < mlo.rooms.Length; j++) + { + MCMloRoomDef room = mlo.rooms[j]; + var roomnode = roomsnode.Nodes.Add(room.RoomName); + roomnode.Tag = room; + var entitiesnode = roomnode.Nodes.Add("Attached Objects (" + room.AttachedObjects.Length + ")"); + entitiesnode.Name = "Attached Objects"; + + for (int k = 0; k < room.AttachedObjects.Length; k++) + { + uint attachedObject = room.AttachedObjects[k]; + MCEntityDef ent = entities[attachedObject]; + TreeNode entnode = entitiesnode.Nodes.Add(ent.ToString()); + entnode.Tag = ent; + } + } + } + } + } + } } private void LoadYndTreeNodes(YndFile ynd, TreeNode node) { @@ -726,7 +771,101 @@ namespace CodeWalker.Project.Panels } return null; } + public TreeNode FindYtypTreeNode(YtypFile ytyp) + { + if (ProjectTreeView.Nodes.Count <= 0) return null; + var projnode = ProjectTreeView.Nodes[0]; + var ytypsnode = GetChildTreeNode(projnode, "Ytyp"); + if (ytypsnode == null) return null; + for (int i = 0; i < ytypsnode.Nodes.Count; i++) + { + var ytypnode = ytypsnode.Nodes[i]; + if (ytypnode.Tag == ytyp) return ytypnode; + } + return null; + } + public TreeNode FindArchetypeTreeNode(Archetype archetype) + { + if (archetype == null) return null; + TreeNode ytypnode = FindYtypTreeNode(archetype.Ytyp); + if (ytypnode == null) return null; + var archetypenode = GetChildTreeNode(ytypnode, "Archetypes"); + if (archetypenode == null) return null; + for (int i = 0; i < archetypenode.Nodes.Count; i++) + { + TreeNode archnode = archetypenode.Nodes[i]; + if (archnode.Tag == archetype) return archnode; + } + return null; + } + public TreeNode FindMloRoomTreeNode(MCMloRoomDef room) + { + if (room == null) return null; + TreeNode ytypnode = FindYtypTreeNode(room.Archetype.Ytyp); + if (ytypnode == null) return null; + + TreeNode archetypesnode = GetChildTreeNode(ytypnode, "Archetypes"); + if (archetypesnode == null) return null; + + for (int i = 0; i < archetypesnode.Nodes.Count; i++) + { + TreeNode mloarchetypenode = archetypesnode.Nodes[i]; + if (mloarchetypenode.Tag == room.Archetype) + { + TreeNode roomsnode = GetChildTreeNode(mloarchetypenode, "Rooms"); + if (roomsnode == null) return null; + + for (int j = 0; j < roomsnode.Nodes.Count; j++) + { + TreeNode roomnode = roomsnode.Nodes[j]; + if (roomnode.Tag == room) return roomnode; + } + break; + } + } + return null; + } + public TreeNode FindMloEntityTreeNode(MCEntityDef ent) + { + MCMloRoomDef entityroom = ent?.Archetype?.GetEntityRoom(ent); + if (entityroom == null) return null; + + TreeNode ytypnode = FindYtypTreeNode(ent.Archetype.Ytyp); + if (ytypnode == null) return null; + + var archetypesnode = GetChildTreeNode(ytypnode, "Archetypes"); + if (archetypesnode == null) return null; + + for (int i = 0; i < archetypesnode.Nodes.Count; i++) + { + TreeNode mloarchetypenode = archetypesnode.Nodes[i]; + if (mloarchetypenode.Tag == ent.Archetype) + { + TreeNode roomsnode = GetChildTreeNode(mloarchetypenode, "Rooms"); + if (roomsnode == null) return null; + + for (int j = 0; j < roomsnode.Nodes.Count; j++) + { + TreeNode roomnode = roomsnode.Nodes[j]; + if (roomnode.Tag == entityroom) + { + TreeNode entitiesnode = GetChildTreeNode(roomnode, "Attached Objects"); + if (entitiesnode == null) return null; + + for (var k = 0; k < entitiesnode.Nodes.Count; k++) + { + TreeNode entitynode = entitiesnode.Nodes[k]; + if (entitynode.Tag == ent) return entitynode; + } + break; + } + } + break; + } + } + return null; + } public TreeNode FindYndTreeNode(YndFile ynd) { if (ProjectTreeView.Nodes.Count <= 0) return null; @@ -974,6 +1113,51 @@ namespace CodeWalker.Project.Panels } } } + public void TrySelectMloEntityTreeNode(MCEntityDef ent) + { + TreeNode entnode = FindMloEntityTreeNode(ent); + if (entnode != null) + { + if (ProjectTreeView.SelectedNode == entnode) + { + OnItemSelected?.Invoke(ent); + } + else + { + ProjectTreeView.SelectedNode = entnode; + } + } + } + public void TrySelectMloRoomTreeNode(MCMloRoomDef room) + { + TreeNode roomnode = FindMloRoomTreeNode(room); + if (roomnode != null) + { + if (ProjectTreeView.SelectedNode == roomnode) + { + OnItemSelected?.Invoke(room); + } + else + { + ProjectTreeView.SelectedNode = roomnode; + } + } + } + public void TrySelectArchetypeTreeNode(Archetype archetype) + { + TreeNode archetypenode = FindArchetypeTreeNode(archetype); + if (archetypenode != null) + { + if (ProjectTreeView.SelectedNode == archetypenode) + { + OnItemSelected?.Invoke(archetype); + } + else + { + ProjectTreeView.SelectedNode = archetypenode; + } + } + } public void TrySelectPathNodeTreeNode(YndNode node) { TreeNode tnode = FindPathNodeTreeNode(node); @@ -1195,6 +1379,16 @@ namespace CodeWalker.Project.Panels } } + + + public void UpdateArchetypeTreeNode(Archetype archetype) + { + var tn = FindArchetypeTreeNode(archetype); + if (tn != null) + { + tn.Text = archetype._BaseArchetypeDef.ToString(); + } + } public void UpdateCarGenTreeNode(YmapCarGen cargen) { var tn = FindCarGenTreeNode(cargen); @@ -1266,6 +1460,7 @@ namespace CodeWalker.Project.Panels } + public void RemoveEntityTreeNode(YmapEntityDef ent) { var tn = FindEntityTreeNode(ent); @@ -1275,6 +1470,7 @@ namespace CodeWalker.Project.Panels tn.Parent.Nodes.Remove(tn); } } + public void RemoveCarGenTreeNode(YmapCarGen cargen) { var tn = FindCarGenTreeNode(cargen); @@ -1294,6 +1490,28 @@ namespace CodeWalker.Project.Panels tn.Parent.Nodes.Remove(tn); } } + public void RemoveArchetypeTreeNode(Archetype archetype) + { + var tn = FindArchetypeTreeNode(archetype); + if ((tn != null) && (tn.Parent != null)) + { + tn.Parent.Text = "Archetypes (" + archetype.Ytyp.AllArchetypes.Length.ToString() + ")"; + tn.Parent.Nodes.Remove(tn); + } + } + public void RemoveMloEntityTreeNode(MCEntityDef ent) + { + var tn = FindMloEntityTreeNode(ent); + if ((tn != null) && (tn.Parent != null)) + { + var tnp = tn.Parent.Parent; + MCMloRoomDef room = null; + if (tnp != null) room = tnp.Tag as MCMloRoomDef; + + tn.Parent.Text = "Attached Objects (" + (room?.AttachedObjects.Length - 1 ?? 0) + ")"; + tn.Parent.Nodes.Remove(tn); + } + } public void RemovePathNodeTreeNode(YndNode node) { var tn = FindPathNodeTreeNode(node); diff --git a/Project/ProjectFile.cs b/Project/ProjectFile.cs index af5451e..9906b9f 100644 --- a/Project/ProjectFile.cs +++ b/Project/ProjectFile.cs @@ -59,10 +59,11 @@ namespace CodeWalker.Project Xml.AddChildWithInnerText(doc, ytypselem, "Item", ytypfilename); } + var yndselem = Xml.AddChild(doc, projelem, "YndFilenames"); foreach (string yndfilename in YndFilenames) { - Xml.AddChildWithInnerText(doc, yndselem, "Item", yndfilename); + Xml.AddChildWithInnerText(doc, ytypselem, "Item", yndfilename); } var ynvselem = Xml.AddChild(doc, projelem, "YnvFilenames"); diff --git a/Project/ProjectForm.Designer.cs b/Project/ProjectForm.Designer.cs index 00e8469..3faf152 100644 --- a/Project/ProjectForm.Designer.cs +++ b/Project/ProjectForm.Designer.cs @@ -155,6 +155,8 @@ this.ToolbarSaveButton = new System.Windows.Forms.ToolStripButton(); this.ToolbarSaveAllButton = new System.Windows.Forms.ToolStripButton(); this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); + this.YtypMloToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.YtypMloNewEntityToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MainMenu.SuspendLayout(); this.MainToolbar.SuspendLayout(); this.SuspendLayout(); @@ -282,54 +284,54 @@ // FileOpenProjectMenu // this.FileOpenProjectMenu.Name = "FileOpenProjectMenu"; - this.FileOpenProjectMenu.Size = new System.Drawing.Size(149, 22); + this.FileOpenProjectMenu.Size = new System.Drawing.Size(152, 22); this.FileOpenProjectMenu.Text = "Project..."; this.FileOpenProjectMenu.Click += new System.EventHandler(this.FileOpenProjectMenu_Click); // // toolStripSeparator9 // this.toolStripSeparator9.Name = "toolStripSeparator9"; - this.toolStripSeparator9.Size = new System.Drawing.Size(146, 6); + this.toolStripSeparator9.Size = new System.Drawing.Size(149, 6); // // FileOpenYmapMenu // this.FileOpenYmapMenu.Name = "FileOpenYmapMenu"; - this.FileOpenYmapMenu.Size = new System.Drawing.Size(149, 22); + this.FileOpenYmapMenu.Size = new System.Drawing.Size(152, 22); this.FileOpenYmapMenu.Text = "Ymap File..."; this.FileOpenYmapMenu.Click += new System.EventHandler(this.FileOpenYmapMenu_Click); // // FileOpenYtypMenu // this.FileOpenYtypMenu.Name = "FileOpenYtypMenu"; - this.FileOpenYtypMenu.Size = new System.Drawing.Size(149, 22); + this.FileOpenYtypMenu.Size = new System.Drawing.Size(152, 22); this.FileOpenYtypMenu.Text = "Ytyp File..."; this.FileOpenYtypMenu.Click += new System.EventHandler(this.FileOpenYtypMenu_Click); // // FileOpenYndMenu // this.FileOpenYndMenu.Name = "FileOpenYndMenu"; - this.FileOpenYndMenu.Size = new System.Drawing.Size(149, 22); + this.FileOpenYndMenu.Size = new System.Drawing.Size(152, 22); this.FileOpenYndMenu.Text = "Ynd File..."; this.FileOpenYndMenu.Click += new System.EventHandler(this.FileOpenYndMenu_Click); // // FileOpenYnvMenu // this.FileOpenYnvMenu.Name = "FileOpenYnvMenu"; - this.FileOpenYnvMenu.Size = new System.Drawing.Size(149, 22); + this.FileOpenYnvMenu.Size = new System.Drawing.Size(152, 22); this.FileOpenYnvMenu.Text = "Ynv File..."; this.FileOpenYnvMenu.Click += new System.EventHandler(this.FileOpenYnvMenu_Click); // // FileOpenTrainsMenu // this.FileOpenTrainsMenu.Name = "FileOpenTrainsMenu"; - this.FileOpenTrainsMenu.Size = new System.Drawing.Size(149, 22); + this.FileOpenTrainsMenu.Size = new System.Drawing.Size(152, 22); this.FileOpenTrainsMenu.Text = "Trains File..."; this.FileOpenTrainsMenu.Click += new System.EventHandler(this.FileOpenTrainsMenu_Click); // // FileOpenScenarioMenu // this.FileOpenScenarioMenu.Name = "FileOpenScenarioMenu"; - this.FileOpenScenarioMenu.Size = new System.Drawing.Size(149, 22); + this.FileOpenScenarioMenu.Size = new System.Drawing.Size(152, 22); this.FileOpenScenarioMenu.Text = "Scenario File..."; this.FileOpenScenarioMenu.Click += new System.EventHandler(this.FileOpenScenarioMenu_Click); // @@ -594,6 +596,7 @@ this.YtypNameMenu, this.toolStripSeparator13, this.YtypNewArchetypeMenu, + this.YtypMloToolStripMenuItem, this.toolStripSeparator15, this.YtypAddToProjectMenu, this.YtypRemoveFromProjectMenu}); @@ -1174,6 +1177,22 @@ this.toolStripSeparator5.Name = "toolStripSeparator5"; this.toolStripSeparator5.Size = new System.Drawing.Size(6, 25); // + // YtypMloToolStripMenuItem + // + this.YtypMloToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.YtypMloNewEntityToolStripMenuItem}); + this.YtypMloToolStripMenuItem.Enabled = false; + this.YtypMloToolStripMenuItem.Name = "YtypMloToolStripMenuItem"; + this.YtypMloToolStripMenuItem.Size = new System.Drawing.Size(192, 22); + this.YtypMloToolStripMenuItem.Text = "Mlo"; + // + // YtypMloNewEntityToolStripMenuItem + // + this.YtypMloNewEntityToolStripMenuItem.Name = "YtypMloNewEntityToolStripMenuItem"; + this.YtypMloNewEntityToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.YtypMloNewEntityToolStripMenuItem.Text = "New Entity"; + this.YtypMloNewEntityToolStripMenuItem.Click += new System.EventHandler(this.YtypMloNewEntityToolStripMenuItem_Click); + // // ProjectForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1325,5 +1344,7 @@ private System.Windows.Forms.ToolStripMenuItem ScenarioAddToProjectMenu; private System.Windows.Forms.ToolStripMenuItem ScenarioRemoveFromProjectMenu; private System.Windows.Forms.ToolStripMenuItem YmapNewGrassBatchMenu; + private System.Windows.Forms.ToolStripMenuItem YtypMloToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem YtypMloNewEntityToolStripMenuItem; } } \ No newline at end of file diff --git a/Project/ProjectForm.cs b/Project/ProjectForm.cs index 3a9b906..5c3bdb2 100644 --- a/Project/ProjectForm.cs +++ b/Project/ProjectForm.cs @@ -42,7 +42,9 @@ namespace CodeWalker.Project private YmapGrassInstanceBatch CurrentGrassBatch; private YtypFile CurrentYtypFile; - //private Archetype CurrentArchetype; + private Archetype CurrentArchetype; + private MCEntityDef CurrentMloEntity; + private MCMloRoomDef CurrentMloRoom; private YndFile CurrentYndFile; private YndNode CurrentPathNode; @@ -76,6 +78,7 @@ namespace CodeWalker.Project private Dictionary visibleynvs = new Dictionary(); private Dictionary visibletrains = new Dictionary(); private Dictionary visiblescenarios = new Dictionary(); + private Dictionary visiblemloentities = new Dictionary(); private bool ShowProjectItemInProcess = false; @@ -352,6 +355,13 @@ namespace CodeWalker.Project (panel) => { panel.SetYtyp(CurrentYtypFile); }, //updateFunc (panel) => { return panel.Ytyp == CurrentYtypFile; }); //findFunc } + private void ShowEditArchetypePanel(bool promote) + { + ShowPanel(promote, + () => { return new EditYtypArchetypePanel(this); }, //createFunc + (panel) => { panel.SetArchetype(CurrentArchetype); }, //updateFunc + (panel) => { return panel.CurrentArchetype == CurrentArchetype; }); //findFunc + } private void ShowEditYndPanel(bool promote) { ShowPanel(promote, @@ -422,6 +432,13 @@ namespace CodeWalker.Project (panel) => { panel.SetScenarioNode(CurrentScenarioNode); }, //updateFunc (panel) => { return panel.CurrentScenarioNode == CurrentScenarioNode; }); //findFunc } + private void ShowEditYtypArchetypeMloRoomPanel(bool promote) + { + ShowPanel(promote, + () => { return new EditYtypArchetypeMloRoomPanel(this); }, //createFunc + (panel) => { panel.SetRoom(CurrentMloRoom); }, //updateFunc + (panel) => { return panel.CurrentRoom == CurrentMloRoom; }); //findFunc + } private void ShowEditAudioFilePanel(bool promote) //TODO { } @@ -440,10 +457,22 @@ namespace CodeWalker.Project private void ShowCurrentProjectItem(bool promote) { - if (CurrentEntity != null) + if (CurrentMloEntity != null) { ShowEditYmapEntityPanel(promote); } + else if (CurrentMloRoom != null) + { + ShowEditYtypArchetypeMloRoomPanel(promote); + } + else if (CurrentEntity != null) + { + ShowEditYmapEntityPanel(promote); + } + else if (CurrentArchetype != null) + { + ShowEditArchetypePanel(promote); + } else if (CurrentCarGen != null) { ShowEditYmapCarGenPanel(promote); @@ -456,7 +485,7 @@ namespace CodeWalker.Project { ShowEditYmapPanel(promote); } - if (CurrentYtypFile != null) + else if (CurrentYtypFile != null) { ShowEditYtypPanel(promote); } @@ -542,10 +571,12 @@ namespace CodeWalker.Project public void SetProjectItem(object item) { CurrentYmapFile = item as YmapFile; + CurrentMloEntity = item as MCEntityDef; CurrentEntity = item as YmapEntityDef; CurrentCarGen = item as YmapCarGen; CurrentGrassBatch = item as YmapGrassInstanceBatch; CurrentYtypFile = item as YtypFile; + CurrentArchetype = item as Archetype; CurrentYndFile = item as YndFile; CurrentPathNode = item as YndNode; CurrentYnvFile = item as YnvFile; @@ -562,10 +593,33 @@ namespace CodeWalker.Project CurrentAudioEmitter = item as AudioPlacement; if (CurrentAudioEmitter?.AudioEmitter == null) CurrentAudioEmitter = null; CurrentAudioZoneList = item as Dat151AmbientZoneList; CurrentAudioEmitterList = item as Dat151AmbientEmitterList; + CurrentMloRoom = item as MCMloRoomDef; - if (CurrentEntity != null) + if (CurrentMloEntity != null) { - CurrentYmapFile = CurrentEntity.Ymap; + MloInstanceData instance = TryGetMloInstance(CurrentMloEntity.Archetype); + + if (instance != null) + { + CurrentEntity = instance.TryGetYmapEntity(CurrentMloEntity); + + CurrentYmapFile = instance.Owner?.Ymap; + } + + CurrentArchetype = CurrentEntity?.MloParent?.Archetype; + } + else if (CurrentEntity != null) + { + if (CurrentEntity.MloParent != null) + { + CurrentArchetype = CurrentEntity?.MloParent?.Archetype; + } + else + { + CurrentArchetype = CurrentEntity.Archetype; + + CurrentYmapFile = CurrentEntity.Ymap; + } } else if (CurrentCarGen != null) { @@ -575,6 +629,10 @@ namespace CodeWalker.Project { CurrentYmapFile = CurrentGrassBatch.Ymap; } + if (CurrentArchetype != null) + { + CurrentYtypFile = CurrentEntity?.MloParent?.Archetype?.Ytyp ?? CurrentArchetype?.Ytyp; + } if (CurrentPathNode != null) { CurrentYndFile = CurrentPathNode.Ynd; @@ -1372,30 +1430,56 @@ namespace CodeWalker.Project } public void AddEntityToProject() { - if (CurrentEntity == null) return; - - if (CurrentEntity.Ymap == null) + try { - MessageBox.Show("Sorry, interior entities cannot currently be added to the project."); - return; - } + if (CurrentEntity == null) return; + if (CurrentEntity.Ymap == null) + { + CurrentYtypFile = CurrentEntity.MloParent?.Archetype?.Ytyp; - CurrentYmapFile = CurrentEntity.Ymap; - if (!YmapExistsInProject(CurrentYmapFile)) - { - var ent = CurrentEntity; - CurrentYmapFile.HasChanged = true; - AddYmapToProject(CurrentYmapFile); + if (!YtypExistsInProject(CurrentYtypFile)) + { + if (CurrentEntity.MloParent?.MloInstance != null) + { + var inst = CurrentEntity.MloParent.MloInstance; + var mcEntity = inst.TryGetArchetypeEntity(CurrentEntity); + if (mcEntity != null) + { + YmapEntityDef ent = CurrentEntity; + CurrentYtypFile.HasChanged = true; + AddYtypToProject(CurrentYtypFile); + CurrentEntity = ent; + CurrentYtypFile = ent.MloParent.Archetype.Ytyp; + ProjectExplorer?.TrySelectMloEntityTreeNode(mcEntity); + } + } + } + return; + } - CurrentEntity = ent; //bug fix for some reason the treeview selects the project node here. - CurrentYmapFile = ent.Ymap; - ProjectExplorer?.TrySelectEntityTreeNode(ent); + CurrentYmapFile = CurrentEntity.Ymap; + if (!YmapExistsInProject(CurrentYmapFile)) + { + YmapEntityDef ent = CurrentEntity; + CurrentYmapFile.HasChanged = true; + AddYmapToProject(CurrentYmapFile); + + CurrentEntity = ent; //bug fix for some reason the treeview selects the project node here. + CurrentYmapFile = ent.Ymap; + ProjectExplorer?.TrySelectEntityTreeNode(ent); + } } + catch + { } } public bool DeleteEntity() { - if (CurrentYmapFile == null) return false; if (CurrentEntity == null) return false; + return CurrentYmapFile != null ? DeleteYmapEntity() : DeleteMloArchetypeEntity(); + } + + private bool DeleteYmapEntity() + { if (CurrentEntity.Ymap != CurrentYmapFile) return false; if (CurrentYmapFile.AllEntities == null) return false; //nothing to delete.. if (CurrentYmapFile.RootEntities == null) return false; //nothing to delete.. @@ -1932,8 +2016,73 @@ namespace CodeWalker.Project } } - public void SaveYtyp(bool saveas = false) //TODO! + public void SaveYtyp(bool saveas = false) { + if (CurrentYtypFile == null) return; + string ytypname = CurrentYtypFile.Name; + string filepath = CurrentYtypFile.FilePath; + if (string.IsNullOrEmpty(filepath)) + { + filepath = ytypname; + } + string origfile = filepath; + if (!File.Exists(filepath)) + { + saveas = true; + } + + + byte[] data; + lock (projectsyncroot) //need to sync writes to ytyp objects... + { + saveas = saveas || string.IsNullOrEmpty(filepath); + if (saveas) + { + filepath = ShowSaveDialog("Ytyp files|*.ytyp", filepath); + if (string.IsNullOrEmpty(filepath)) + { return; } + + string newname = Path.GetFileNameWithoutExtension(filepath); + JenkIndex.Ensure(newname); + CurrentYtypFile.FilePath = filepath; + CurrentYtypFile.RpfFileEntry.Name = new FileInfo(filepath).Name; + CurrentYtypFile.Name = CurrentYtypFile.RpfFileEntry.Name; + CurrentYtypFile._CMapTypes.name = new MetaHash(JenkHash.GenHash(newname)); + } + + data = CurrentYtypFile.Save(); + } + + + if (data != null) + { + File.WriteAllBytes(filepath, data); + } + + SetYtypHasChanged(false); + + if (saveas) + { + if (CurrentProjectFile != null) + { + string origpath = CurrentProjectFile.GetRelativePath(origfile); + string newpath = CurrentProjectFile.GetRelativePath(CurrentYtypFile.FilePath); + + if (!CurrentProjectFile.RenameYtyp(origpath, newpath)) + { //couldn't rename it in the project? + MessageBox.Show("Couldn't rename ytyp in project! This shouldn't happen - check the project file XML."); + } + } + SetProjectHasChanged(true); + SetCurrentSaveItem(); + } + + if (CurrentYtypFile.SaveWarnings != null) + { + string w = string.Join("\n", CurrentYtypFile.SaveWarnings); + MessageBox.Show(CurrentYtypFile.SaveWarnings.Count.ToString() + " warnings were generated while saving the ytyp:\n" + w); + CurrentYtypFile.SaveWarnings = null;//clear it out for next time.. + } } public void AddYtypToProject(YtypFile ytyp) { @@ -1968,6 +2117,241 @@ namespace CodeWalker.Project return CurrentProjectFile.ContainsYtyp(ytyp); } + public void NewArchetype(Archetype copy = null, bool copyPosition = false) + { + if (CurrentYtypFile == null) return; + var archetype = CurrentYtypFile.AddArchetype(); + var archetypeDef = archetype._BaseArchetypeDef; + if (copy == null) + { + copy = CurrentArchetype; + archetype._BaseArchetypeDef.name = JenkHash.GenHash("prop_alien_egg_01"); + } + if (copy != null) + { + archetype.Init(CurrentYtypFile, ref copy._BaseArchetypeDef); + } + archetype._BaseArchetypeDef = archetypeDef; + + LoadProjectTree(); + ProjectExplorer?.TrySelectArchetypeTreeNode(archetype); + CurrentArchetype = archetype; + } + public void NewMloEntity(YmapEntityDef copy = null, bool copyTransform = false) + { + if ((CurrentArchetype == null) || !(CurrentArchetype is MloArchetype mloArch)) + { + var arch = CurrentEntity?.MloParent.Archetype ?? CurrentMloRoom?.Archetype; + if (arch == null) + return; + + mloArch = arch as MloArchetype; + if (mloArch == null) + return; + + CurrentArchetype = mloArch; + } + + if (CurrentMloRoom == null) CurrentMloRoom = mloArch?.GetEntityRoom(CurrentMloEntity); + if (CurrentMloRoom == null) + { + return; + } + + MloInstanceData mloInstance = TryGetMloInstance(mloArch); + if (mloInstance == null) return; + + if (mloArch.rooms.Length <= 0) + { + MessageBox.Show($@"Mlo {mloArch.Name} has no rooms! Cannot create entity."); + return; + } + + int roomIndex = CurrentMloRoom.Index; + if (roomIndex < 0) + { + MessageBox.Show(@"Invalid room index."); + return; + } + if (roomIndex >= mloArch.rooms.Length) + { + MessageBox.Show( + $@"Room at index {roomIndex} does not exist in {mloArch.Name}! {mloArch.Name} only has { + mloArch.rooms.Length + } rooms."); + return; + } + + float spawndist = 5.0f; //use archetype BSradius if starting with a copy... + if (copy != null) + { + spawndist = copy.BSRadius * 2.5f; + } + + bool cp = copyTransform && (copy != null); + Vector3 pos = cp ? copy.CEntityDef.position : GetSpawnPosRel(spawndist, mloInstance.Owner.Position, mloInstance.Owner.Orientation); + Quaternion rot = cp ? copy.CEntityDef.rotation.ToQuaternion() : Quaternion.Identity; + + + CEntityDef cent = new CEntityDef(); + + if (copy != null) + { + cent = copy.CEntityDef; + //TODO: copy entity extensions! + } + else + { + cent.archetypeName = new MetaHash(JenkHash.GenHash("prop_alien_egg_01")); + cent.rotation = new Vector4(0, 0, 0, 1); + cent.scaleXY = 1.0f; + cent.scaleZ = 1.0f; + cent.flags = 1572872; + cent.parentIndex = -1; + cent.lodDist = 200.0f; + cent.lodLevel = Unk_1264241711.LODTYPES_DEPTH_ORPHANHD; + cent.priorityLevel = Unk_648413703.PRI_REQUIRED; + cent.ambientOcclusionMultiplier = 255; + cent.artificialAmbientOcclusion = 255; + } + + cent.position = pos; + cent.rotation = rot.ToVector4(); + + var createindex = mloArch.entities.Length; + MCEntityDef ment = new MCEntityDef(ref cent, mloArch); + + YmapEntityDef outEnt; + try + { + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + // Add the entity to the mlo instance and archetype. + outEnt = mloInstance.CreateYmapEntity(mloInstance.Owner, ment, createindex); + mloArch.AddEntity(outEnt, roomIndex); + } + } + else + { + outEnt = mloInstance.CreateYmapEntity(mloInstance.Owner, ment, createindex); + mloArch.AddEntity(outEnt, roomIndex); + } + } + catch(Exception e) + { + MessageBox.Show(this, e.Message, "Create MLO Entity Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + + mloInstance.AddEntity(outEnt); + outEnt.SetArchetype(GameFileCache.GetArchetype(cent.archetypeName)); + + LoadProjectTree(); + ProjectExplorer?.TrySelectMloEntityTreeNode(mloInstance.TryGetArchetypeEntity(outEnt)); + CurrentEntity = outEnt; + CurrentYtypFile = CurrentEntity.MloParent?.Archetype?.Ytyp; + } + private bool DeleteMloArchetypeEntity() + { + if (CurrentEntity?.MloParent?.Archetype?.Ytyp == null) return false; + if (CurrentEntity.MloParent.Archetype.Ytyp != CurrentYtypFile) return false; + if (!(CurrentEntity.MloParent.Archetype is MloArchetype mloArchetype)) return false; + if (mloArchetype.entities == null) return false; //nothing to delete.. + //if (mloArchetype.InstancedEntities == null) return false; //nothing to delete.. + + if (CurrentEntity._CEntityDef.numChildren != 0) + { + MessageBox.Show("This entity's numChildren is not 0 - deleting entities with children is not currently supported by CodeWalker."); + return true; + } + + if (MessageBox.Show("Are you sure you want to delete this entity?\n" + CurrentEntity._CEntityDef.archetypeName.ToString() + "\n" + CurrentEntity.Position.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) + { + return true; + } + MloInstanceData mloInstance = CurrentEntity.MloParent.MloInstance; + if (mloInstance == null) return false; + + var ent = CurrentEntity; + var mcEnt = mloInstance.TryGetArchetypeEntity(ent); + ProjectExplorer?.RemoveMloEntityTreeNode(mcEnt); + + try + { + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + mloInstance.DeleteEntity(ent); + //WorldForm.SelectItem(null, null, null); + } + } + else + { + mloInstance.DeleteEntity(ent); + } + } + catch (Exception e) // various failures could happen so we'll use a trycatch for when an exception is thrown. + { + MessageBox.Show(this, "Cannot delete entity: " + Environment.NewLine + e.Message); + return false; + } + + var delent = ent; + var delytyp = delent.MloParent.Archetype.Ytyp; + + ProjectExplorer?.SetYtypHasChanged(delytyp, true); + + ClosePanel((EditYmapEntityPanel p) => { return p.Tag == delent; }); + CurrentEntity = null; + WorldForm.SelectItem(null); + + return true; + } + public bool DeleteArchetype() + { + if (CurrentArchetype == null) return false; + if (CurrentArchetype.Ytyp != CurrentYtypFile) return false; + + if (MessageBox.Show("Are you sure you want to delete this archetype?\n" + CurrentArchetype._BaseArchetypeDef.name.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) + { + return true; + } + + bool res = false; + if (WorldForm != null) + { + lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... + { + res = CurrentArchetype.Ytyp.RemoveArchetype(CurrentArchetype); + //WorldForm.SelectItem(null, null, null); + } + } + else + { + res = CurrentArchetype.Ytyp.RemoveArchetype(CurrentArchetype); + } + if (!res) + { + MessageBox.Show("Archetype couldn't be removed!"); + return false; + } + + var delarch = CurrentArchetype; + var delytyp = delarch.Ytyp; + + ProjectExplorer?.RemoveArchetypeTreeNode(delarch); + ProjectExplorer?.SetYtypHasChanged(delytyp, true); + + ClosePanel((EditYtypArchetypePanel p) => { return p.Tag == delarch; }); + + CurrentArchetype = null; + + return true; + } public void NewYnd() { @@ -3998,6 +4382,18 @@ namespace CodeWalker.Project ymaps[isnew ? JenkHash.GenHash(ymap.Name) : ymap.RpfFileEntry.ShortNameHash] = ymap; } } + + visiblemloentities.Clear(); + foreach (var kvp in ymaps) + { + var ymap = kvp.Value; + if (ymap.MloEntities == null) continue; + foreach (var mloDef in ymap.MloEntities) + { + if (mloDef.Archetype == null) continue; // archetype was changed from an mlo to a regular archetype + visiblemloentities[mloDef.Archetype._BaseArchetypeDef.name] = mloDef; + } + } } } } @@ -4158,6 +4554,18 @@ namespace CodeWalker.Project } + public MloInstanceData TryGetMloInstance(MloArchetype arch) + { + lock (projectsyncroot) + { + if (arch == null) return null; + MetaHash name = arch._BaseArchetypeDef.name; + if (name == 0) return null; + if (!visiblemloentities.ContainsKey(name)) return null; + return visiblemloentities[name]?.MloInstance; + } + } + public void OnWorldSelectionChanged(MapSelection sel) { @@ -4169,6 +4577,8 @@ namespace CodeWalker.Project } else { + var mlo = sel.MloEntityDef; + var room = sel.MloRoomDef; var ent = sel.EntityDef; var cargen = sel.CarGenerator; var grassbatch = sel.GrassBatch; @@ -4181,7 +4591,9 @@ namespace CodeWalker.Project var scenariond = sel.ScenarioNode; var scenarioedge = sel.ScenarioEdge; var audiopl = sel.Audio; - YmapFile ymap = ent?.Ymap ?? cargen?.Ymap ?? grassbatch?.Ymap; + Archetype arch = mlo?.Archetype ?? ent?.MloParent?.Archetype ?? ent?.Archetype; + YtypFile ytyp = mlo?.Archetype?.Ytyp ?? ent?.MloParent?.Archetype?.Ytyp ?? ent?.Archetype?.Ytyp ?? room?.Archetype?.Ytyp; + YmapFile ymap = ent?.Ymap ?? cargen?.Ymap ?? grassbatch?.Ymap ?? mlo?.Ymap; YndFile ynd = pathnode?.Ynd; YnvFile ynv = navpoly?.Ynv ?? navpoint?.Ynv ?? navportal?.Ynv; TrainTrack traintrack = trainnode?.Track; @@ -4205,6 +4617,26 @@ namespace CodeWalker.Project } } + else if (YtypExistsInProject(ytyp)) + { + if (arch != CurrentArchetype) + { + ProjectExplorer?.TrySelectArchetypeTreeNode(mlo?.Archetype); + } + if (ent != CurrentEntity) + { + MloInstanceData mloInstance = ent.MloParent?.MloInstance; + if (mloInstance != null) + { + MCEntityDef entityDef = mloInstance.TryGetArchetypeEntity(ent); + ProjectExplorer?.TrySelectMloEntityTreeNode(entityDef); + } + } + if (room != CurrentMloRoom) + { + ProjectExplorer?.TrySelectMloRoomTreeNode(room); + } + } else if (YndExistsInProject(ynd)) { if (pathnode != CurrentPathNode) @@ -4259,9 +4691,11 @@ namespace CodeWalker.Project showcurrent = true; } + CurrentMloRoom = room; CurrentYmapFile = ymap; - CurrentYtypFile = null;//TODO: interiors! - CurrentEntity = ent; + CurrentYtypFile = ytyp; + CurrentArchetype = arch; + CurrentEntity = ent ?? mlo; CurrentCarGen = cargen; CurrentGrassBatch = grassbatch; CurrentYndFile = ynd; @@ -4335,7 +4769,6 @@ namespace CodeWalker.Project OnWorldAudioPlacementModified(sel.Audio); } } - private void OnWorldEntityModified(YmapEntityDef ent) { try @@ -4346,7 +4779,7 @@ namespace CodeWalker.Project } else { - if ((ent.Ymap == null) || (ent.MloParent != null)) + if ((ent.Ymap == null) && (ent.MloParent == null)) { return;//TODO: properly handle interior entities! } @@ -4356,26 +4789,62 @@ namespace CodeWalker.Project NewProject(); } - if (!YmapExistsInProject(ent.Ymap)) + if (ent.MloParent == null && ent.Ymap != null) { - ent.Ymap.HasChanged = true; - AddYmapToProject(ent.Ymap); - ProjectExplorer?.TrySelectEntityTreeNode(ent); - } - - if (ent != CurrentEntity) - { - CurrentEntity = ent; - ProjectExplorer?.TrySelectEntityTreeNode(ent); - } - - if (ent == CurrentEntity) - { - ShowEditYmapEntityPanel(false); - - if (ent.Ymap != null) + if (!YmapExistsInProject(ent.Ymap)) { - SetYmapHasChanged(true); + ent.Ymap.HasChanged = true; + AddYmapToProject(ent.Ymap); + ProjectExplorer?.TrySelectEntityTreeNode(ent); + } + + if (ent != CurrentEntity) + { + CurrentEntity = ent; + ProjectExplorer?.TrySelectEntityTreeNode(ent); + } + + if (ent == CurrentEntity) + { + ShowEditYmapEntityPanel(false); + + if (ent.Ymap != null) + { + SetYmapHasChanged(true); + } + } + } + else if (ent.MloParent != null && ent.Ymap == null) + { + MloInstanceData mloInstance = ent.MloParent?.MloInstance; + if (mloInstance != null) + { + var mcEntity = mloInstance.TryGetArchetypeEntity(ent); + if (mcEntity != null) + { + if (!YtypExistsInProject(ent.MloParent.Archetype.Ytyp)) + { + ent.MloParent.Archetype.Ytyp.HasChanged = true; + AddYtypToProject(ent.MloParent.Archetype.Ytyp); + ProjectExplorer?.TrySelectMloEntityTreeNode(mcEntity); + } + + if (ent != CurrentEntity) + { + CurrentEntity = ent; + ProjectExplorer?.TrySelectMloEntityTreeNode(mcEntity); + } + } + } + + if (ent == CurrentEntity) + { + ShowEditYmapEntityPanel(false); + + if (ent.MloParent.Archetype.Ytyp != null) + { + SetYtypHasChanged(true); + } } } } @@ -4909,6 +5378,23 @@ namespace CodeWalker.Project return pos; } + public Vector3 GetSpawnPosRel(float dist, Vector3 relPos, Quaternion relRot) + { + Vector3 pos = Vector3.Zero; + if (WorldForm != null) + { + Vector3 campos = WorldForm.GetCameraPosition(); + Vector3 camdir = WorldForm.GetCameraViewDir(); + pos = campos + camdir * dist; + + Quaternion rot = Quaternion.Invert(relRot); + Vector3 delta = pos - relPos; + Vector3 relativePos = rot.Multiply(delta); + pos = relativePos; + } + return pos; + } + public RpfFileEntry FindParentYmapEntry(uint hash) { if (CurrentProjectFile != null) @@ -4944,7 +5430,7 @@ namespace CodeWalker.Project ymap.Load(data); - GameFileCache.InitYmapEntityArchetypes(ymap); //this needs to be done after calling YmapFile.Load() + ymap.InitYmapEntityArchetypes(GameFileCache); //this needs to be done after calling YmapFile.Load() } private void LoadYtypFromFile(YtypFile ytyp, string filename) { @@ -5117,8 +5603,11 @@ namespace CodeWalker.Project { bool enable = (CurrentYtypFile != null); bool inproj = YtypExistsInProject(CurrentYtypFile); + bool ismlo = ((CurrentEntity != null) && (CurrentEntity.MloParent != null) || (CurrentMloRoom != null)) || (CurrentArchetype is MloArchetype); YtypNewArchetypeMenu.Enabled = enable && inproj; + YtypMloToolStripMenuItem.Enabled = enable && inproj && ismlo; + YtypMloNewEntityToolStripMenuItem.Enabled = YtypMloToolStripMenuItem.Enabled; if (CurrentYtypFile != null) { @@ -5516,10 +6005,6 @@ namespace CodeWalker.Project RemoveYmapFromProject(); } - private void YtypNewArchetypeMenu_Click(object sender, EventArgs e) - { - //NewArchetype(); - } private void YtypAddToProjectMenu_Click(object sender, EventArgs e) { AddYtypToProject(CurrentYtypFile); @@ -5528,6 +6013,14 @@ namespace CodeWalker.Project { RemoveYtypFromProject(); } + private void YtypNewArchetypeMenu_Click(object sender, EventArgs e) + { + NewArchetype(); + } + private void YtypMloNewEntityToolStripMenuItem_Click(object sender, EventArgs e) + { + NewMloEntity(); + } private void YndNewNodeMenu_Click(object sender, EventArgs e) { diff --git a/Project/ProjectFormOLD.cs b/Project/ProjectFormOLD.cs index f244a99..aa95737 100644 --- a/Project/ProjectFormOLD.cs +++ b/Project/ProjectFormOLD.cs @@ -1262,7 +1262,7 @@ namespace CodeWalker ymap.Load(data); - GameFileCache.InitYmapEntityArchetypes(ymap); //this needs to be done after calling YmapFile.Load() + ymap.InitYmapEntityArchetypes(GameFileCache); //this needs to be done after calling YmapFile.Load() } private void LoadYmapTreeNodes(YmapFile ymap, TreeNode node) @@ -1282,7 +1282,7 @@ namespace CodeWalker for (int i = 0; i < ents.Length; i++) { var ent = ents[i]; - var edef = ent.CEntityDef; + var edef = ent._CEntityDef; var enode = entsnode.Nodes.Add(edef.archetypeName.ToString()); enode.Tag = ent; } @@ -7542,7 +7542,7 @@ namespace CodeWalker if (CurrentEntity._CEntityDef.rotation != v) { Quaternion q = new Quaternion(v); - CurrentEntity.SetOrientationInv(q); + CurrentEntity.SetOrientation(q, true); SetYmapHasChanged(true); if (WorldForm != null) { diff --git a/Rendering/Renderer.cs b/Rendering/Renderer.cs index e5a1d7e..c677095 100644 --- a/Rendering/Renderer.cs +++ b/Rendering/Renderer.cs @@ -1745,24 +1745,55 @@ namespace CodeWalker.Rendering if (renderinteriors && ent.IsMlo) //render Mlo child entities... { - if ((ent.MloInstance != null) && (ent.MloInstance.Entities != null)) + if ((ent.MloInstance != null)) { - for (int j = 0; j < ent.MloInstance.Entities.Length; j++) + if (ent.MloInstance.Entities != null) { - var intent = ent.MloInstance.Entities[j]; - if (intent.Archetype == null) continue; //missing archetype... - if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something.. - - intent.IsVisible = true; - - var iebscent = intent.Position + intent.BSCenter - camera.Position; - float iebsrad = intent.BSRadius; - if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref iebscent, iebsrad)) + for (int j = 0; j < ent.MloInstance.Entities.Length; j++) { - continue; //frustum cull interior ents - } + var intent = ent.MloInstance.Entities[j]; + if (intent.Archetype == null) continue; //missing archetype... + if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something.. - renderworldentities.Add(intent); + intent.IsVisible = true; + + var iebscent = intent.Position + intent.BSCenter - camera.Position; + float iebsrad = intent.BSRadius; + if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref iebscent, iebsrad)) + { + continue; //frustum cull interior ents + } + + renderworldentities.Add(intent); + } + } + if (ent.MloInstance.EntitySets != null) + { + foreach (var entitysets in ent.MloInstance.EntitySets) + { + var entityset = entitysets.Value; + if (!entityset.Visible) continue; + + var entities = entityset.Entities; + for (int i = 0; i < entities.Count; i++) + { + var intent = entities[i]; + if (intent.Archetype == null) continue; //missing archetype... + if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something.. + + intent.IsVisible = true; + + var iebscent = intent.Position + intent.BSCenter - camera.Position; + float iebsrad = intent.BSRadius; + if (!camera.ViewFrustum.ContainsSphereNoClipNoOpt(ref iebscent, iebsrad)) + { + continue; //frustum cull interior ents + } + + renderworldentities.Add(intent); + + } + } } } } diff --git a/Utils/MapUtils.cs b/Utils/MapUtils.cs index fdadbca..196bf0a 100644 --- a/Utils/MapUtils.cs +++ b/Utils/MapUtils.cs @@ -182,6 +182,7 @@ namespace CodeWalker public YmapGrassInstanceBatch GrassBatch { get; set; } public YmapDistantLODLights DistantLodLights { get; set; } public YmapEntityDef MloEntityDef { get; set; } + public MCMloRoomDef MloRoomDef { get; set; } public WaterQuad WaterQuad { get; set; } public Bounds CollisionBounds { get; set; } public YnvPoly NavPoly { get; set; } @@ -227,7 +228,8 @@ namespace CodeWalker (DistantLodLights != null) || (MloEntityDef != null) || (ScenarioNode != null) || - (Audio != null); + (Audio != null) || + (MloRoomDef != null); } } @@ -257,7 +259,8 @@ namespace CodeWalker || (PathNode != mhit.PathNode) || (TrainTrackNode != mhit.TrainTrackNode) || (ScenarioNode != mhit.ScenarioNode) - || (Audio != mhit.Audio); + || (Audio != mhit.Audio) + || (MloRoomDef != mhit.MloRoomDef); } public bool CheckForChanges() { @@ -280,7 +283,8 @@ namespace CodeWalker || (PathLink != null) || (TrainTrackNode != null) || (ScenarioNode != null) - || (Audio != null); + || (Audio != null) + || (MloRoomDef != null); } @@ -386,6 +390,10 @@ namespace CodeWalker { name = Audio.ShortTypeName + " " + Audio.GetNameString();// FloatUtil.GetVector3String(Audio.InnerPos); } + if (MloRoomDef != null) + { + name = "MloRoomDef " + MloRoomDef.RoomName; + } return name; } @@ -460,6 +468,10 @@ namespace CodeWalker { name = Audio.ShortTypeName + " " + Audio.GetNameString();// + FloatUtil.GetVector3String(Audio.InnerPos); } + if (MloRoomDef != null) + { + name = "MloRoomDef " + MloRoomDef.RoomName; + } return name; } diff --git a/WorldForm.cs b/WorldForm.cs index 2cc588a..3e92106 100644 --- a/WorldForm.cs +++ b/WorldForm.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; @@ -3368,6 +3367,37 @@ namespace CodeWalker SelectItem(ms); } } + + public void SelectGrassBatch(YmapGrassInstanceBatch batch) + { + if (batch == null) + { + SelectItem(null); + } + else + { + MapSelection ms = new MapSelection(); + ms.GrassBatch = batch; + ms.AABB = new BoundingBox(batch.AABBMin, batch.AABBMax); + SelectItem(ms); + } + } + public void SelectMloRoom(MCMloRoomDef room, MloInstanceData instance) + { + if (room == null) + { + SelectItem(null); + } + else if (instance != null) + { + MapSelection ms = new MapSelection(); + ms.MloRoomDef = room; + Vector3 min = instance.Owner.Position + instance.Owner.Orientation.Multiply(room.BBMin_CW); + Vector3 max = instance.Owner.Position + instance.Owner.Orientation.Multiply(room.BBMax_CW); + ms.AABB = new BoundingBox(min, max); + SelectItem(ms); + } + } public void SelectNavPoly(YnvPoly poly) { if (poly == null) @@ -3915,6 +3945,7 @@ namespace CodeWalker { ProjectForm = new ProjectForm(this); ProjectForm.Show(this); + ProjectForm.OnWorldSelectionChanged(SelectedItem); // so that the project form isn't stuck on the welcome window. } else { @@ -5063,11 +5094,25 @@ namespace CodeWalker } else { - //project not open, or entity not selected there, just remove the entity from the ymap... + //project not open, or entity not selected there, just remove the entity from the ymap/nlo... var ymap = ent.Ymap; + var instance = ent.MloParent?.MloInstance; if (ymap == null) { - MessageBox.Show("Sorry, deleting interior entities is not currently supported."); + if (instance != null) + { + try + { + if (!instance.DeleteEntity(ent)) + { + SelectItem(null); + } + } + catch (Exception e) // various failures can happen here. + { + MessageBox.Show("Unable to remove entity..." + Environment.NewLine + e.Message); + } + } } else if (!ymap.RemoveEntity(ent)) { @@ -5088,7 +5133,16 @@ namespace CodeWalker { if (CopiedEntity == null) return; if (ProjectForm == null) return; - ProjectForm.NewEntity(CopiedEntity); + MloInstanceData instance = CopiedEntity.MloParent?.MloInstance; + MCEntityDef entdef = instance?.TryGetArchetypeEntity(CopiedEntity); + if (entdef != null) + { + ProjectForm.NewMloEntity(CopiedEntity, true); + } + else + { + ProjectForm.NewEntity(CopiedEntity, true); + } } private void CloneEntity() {