mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2026-05-14 16:04:49 +08:00
Ability to edit YTYP files and MLO Entity Defintions + Revisions to grass brush (#33)
* - Add ability to edit/add ytyp files to project. - Add ability to edit/add ytyp archetype files to ytyp. - Add ability to add/remove entities from mlo archetype defs. - Add ability to save ytyp files. - Add dialog popup before optimizing grass batches. - Fix grass batches not being selected when chaning selection in project explorer. - Merged with upstream/master. - Squashed last 4 commits for PR cleanliness. * Fixed windows forms reference error. * - Added error checking to deleting mlo entities. - Fixed various bugs with deleting mlo entities. - Fixed edit archetype panel Asset Type box. - Removed redundant/unnecessary. - Removed backwards references between MCEntityDef and YmapEntityDef. All ymap entity to mcentity references are grabbed using indecies in the MloInstanceData class. - Fixed "YmapMenu" not showing when selecting entities/mlo entities in project form. Current bugs: - Loading a ytyp file -- mlo entities are not editiable, and are created in the world. - entitysets are not editable (properly). - Removing an mloinstancedef from a ymap does not delete the mlo instance's gizmo from the world, and it's still selectable. (Although all references are lost, and I believe collected by the GC?) * - Moved archetype initialization methods YmapFile.InitYmapEntityArchetypes(GameFileCache gfc) and MloInstanceData.InitYmapEntityArchetypes(GameFileCache gfc) - Added ability to load mlo instance defs through ymap files. - Fixed add method for mlo archetypes. * - Removed SetOrientationInv. - Removed unreachable code + updated comment. - Renamed CreateEntity to CreateYmapEntity, and renamed params for consistency. * Split calls to CreateYmapEntity() and MloArchetype.AddEntity(). * Fixed redundant rotation inversions. * - Added ability to select rooms. - Changed tree view grouping for mlo entities. - Fixed projectexplorer selection bugs. - Added ability to toggle mlo entity sets. - Fixed some change events when editing archetypes.
This commit is contained in:
committed by
dexyfex
Unverified
parent
4da1e3d8c7
commit
462e464c2f
+543
-50
@@ -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<int, YnvFile> visibleynvs = new Dictionary<int, YnvFile>();
|
||||
private Dictionary<string, TrainTrack> visibletrains = new Dictionary<string, TrainTrack>();
|
||||
private Dictionary<string, YmtFile> visiblescenarios = new Dictionary<string, YmtFile>();
|
||||
private Dictionary<uint, YmapEntityDef> visiblemloentities = new Dictionary<uint, YmapEntityDef>();
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user