using CodeWalker.GameFiles; using CodeWalker.Project.Panels; using CodeWalker.Properties; using CodeWalker.World; using SharpDX; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using WeifenLuo.WinFormsUI.Docking; namespace CodeWalker.Project { public partial class ProjectForm : Form { public WorldForm WorldForm { get; private set; } public ThemeBase Theme { get; private set; } public ProjectExplorerPanel ProjectExplorer { get; set; } public ProjectPanel PreviewPanel { get; set; } public GameFileCache GameFileCache { get; private set; } public RpfManager RpfMan { get; private set; } public bool IsProjectLoaded { get { return CurrentProjectFile != null; } } public ProjectFile CurrentProjectFile; private MapSelection[] CurrentMulti; private YmapFile CurrentYmapFile; private YmapEntityDef CurrentEntity; private YmapCarGen CurrentCarGen; private YmapGrassInstanceBatch CurrentGrassBatch; private YtypFile CurrentYtypFile; private Archetype CurrentArchetype; private MCEntityDef CurrentMloEntity; private MCMloRoomDef CurrentMloRoom; private MCMloPortalDef CurrentMloPortal; private MCMloEntitySet CurrentMloEntitySet; private YndFile CurrentYndFile; private YndNode CurrentPathNode; private YndLink CurrentPathLink; private YnvFile CurrentYnvFile; private YnvPoly CurrentNavPoly; private YnvPoint CurrentNavPoint; private YnvPortal CurrentNavPortal; private TrainTrack CurrentTrainTrack; private TrainTrackNode CurrentTrainNode; private YmtFile CurrentScenario; private ScenarioNode CurrentScenarioNode; private MCScenarioChainingEdge CurrentScenarioChainEdge; private RelFile CurrentAudioFile; private AudioPlacement CurrentAudioZone; private AudioPlacement CurrentAudioEmitter; private Dat151AmbientZoneList CurrentAudioZoneList; private Dat151AmbientEmitterList CurrentAudioEmitterList; private Dat151Interior CurrentAudioInterior; private Dat151InteriorRoom CurrentAudioInteriorRoom; private YbnFile CurrentYbnFile; private Bounds CurrentCollisionBounds; private BoundPolygon CurrentCollisionPoly; private BoundVertex CurrentCollisionVertex; private bool renderitems = true; private bool hidegtavmap = false; private object projectsyncroot = new object(); public object ProjectSyncRoot { get { return projectsyncroot; } } private Dictionary visibleybns = new Dictionary(); private Dictionary visibleynds = new Dictionary(); private Dictionary visibleynvs = new Dictionary(); private Dictionary visibletrains = new Dictionary(); private Dictionary visiblescenarios = new Dictionary(); private Dictionary visiblemloentities = new Dictionary(); private Dictionary visibleaudiofiles = new Dictionary(); private Dictionary projectarchetypes = new Dictionary();//used to override archetypes in world view private Dictionary projectybns = new Dictionary();//used for handling interior ybns private List interiorslist = new List(); //used for handling interiors ybns private bool ShowProjectItemInProcess = false; public ProjectForm(WorldForm worldForm = null) { WorldForm = worldForm; InitializeComponent(); SetTheme(Settings.Default.ProjectWindowTheme, false); ShowDefaultPanels(); if ((WorldForm != null) && (WorldForm.GameFileCache != null)) { GameFileCache = WorldForm.GameFileCache; RpfMan = GameFileCache.RpfMan; } else { GameFileCache = GameFileCacheFactory.Create(); new Thread(new ThreadStart(() => { GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key); GameFileCache.Init(UpdateStatus, UpdateError); RpfMan = GameFileCache.RpfMan; })).Start(); } } private void UpdateStatus(string text) { try { if (InvokeRequired) { BeginInvoke(new Action(() => { UpdateStatus(text); })); } else { //TODO: status text //StatusLabel.Text = text; } } catch { } } private void UpdateError(string text) { try { if (InvokeRequired) { BeginInvoke(new Action(() => { UpdateError(text); })); } else { //TODO: error text //ErrorLabel.Text = text; } } catch { } } private void SetTheme(string themestr, bool changing = true) { if (changing && (CurrentProjectFile != null)) { if (MessageBox.Show("Project will be closed before changing the theme. Are you sure you want to continue?", "Theme change", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; } } CloseProject(); //string configFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "DockPanel.temp.config"); //MainDockPanel.SaveAsXml(configFile); CloseAllContents(); ProjectExplorer = null; PreviewPanel = null; foreach (ToolStripMenuItem menu in ViewThemeMenu.DropDownItems) { menu.Checked = false; } Theme = null; switch (themestr) { default: case "Blue": Theme = new VS2015BlueTheme(); ViewThemeBlueMenu.Checked = true; break; case "Light": Theme = new VS2015LightTheme(); ViewThemeLightMenu.Checked = true; break; case "Dark": Theme = new VS2015DarkTheme(); ViewThemeDarkMenu.Checked = true; break; } if (changing) { Settings.Default.ProjectWindowTheme = themestr; Settings.Default.Save(); } Theme.Extender.FloatWindowFactory = new ProjectFloatWindowFactory(); MainDockPanel.Theme = Theme; var version = VisualStudioToolStripExtender.VsVersion.Vs2015; VSExtender.SetStyle(MainMenu, version, Theme); VSExtender.SetStyle(MainToolbar, version, Theme); //VSExtender.SetStyle(MainStatusBar, version, theme); //if (File.Exists(configFile)) MainDockPanel.LoadFromXml(configFile, m_deserializeDockContent); if (changing) { ShowDefaultPanels(); } } private T FindPanel(Func findFunc) where T : ProjectPanel { foreach (var pane in MainDockPanel.Panes) { foreach (var content in pane.Contents) { var test = content as T; if ((test != null) && findFunc(test)) { return test; } } } return null; } public void ShowDefaultPanels() { ShowProjectExplorer(); ShowWelcomePanel(); } public void ShowProjectExplorer() { if ((ProjectExplorer == null) || (ProjectExplorer.IsDisposed) || (ProjectExplorer.Disposing)) { ProjectExplorer = new ProjectExplorerPanel(this); ProjectExplorer.OnItemSelected += ProjectExplorer_OnItemSelected; ProjectExplorer.OnItemActivated += ProjectExplorer_OnItemActivated; ProjectExplorer.SetTheme(Theme); ProjectExplorer.Show(MainDockPanel, DockState.DockLeft); } else { ProjectExplorer.Show(); } } public void ShowWelcomePanel() { ShowPreviewPanel(() => { return new WelcomePanel(); }); } public void ShowPreviewPanel(Func createFunc, Action updateAction = null) where T : ProjectPanel { if ((PreviewPanel != null) && (PreviewPanel is T)) { PreviewPanel.BringToFront();//.Show(); updateAction?.Invoke(PreviewPanel as T); } else { var panel = createFunc(); panel.HideOnClose = true; panel.SetTheme(Theme); panel.Show(MainDockPanel, DockState.Document); updateAction?.Invoke(panel); if (PreviewPanel != null) { PreviewPanel.Close(); } PreviewPanel = panel; } } public void ShowPanel(bool promote, Func createFunc, Action updateAction, Func findFunc) where T : ProjectPanel { T found = FindPanel(findFunc); if ((found != null) && (found != PreviewPanel)) { if (found.IsHidden) { found.Show(); } found.BringToFront();//.Show(); updateAction?.Invoke(found); } else { if (promote) { PromoteIfPreviewPanel(PreviewPanel); if (found != null) { found.BringToFront();//.Show(); updateAction?.Invoke(found); } else { ShowPreviewPanel(createFunc, updateAction); PreviewPanel = null; } } else { ShowPreviewPanel(createFunc, updateAction); } } } public void ShowEditProjectPanel(bool promote) { ShowPanel(promote, () => { return new EditProjectPanel(this); }, //createFunc (panel) => { panel.SetProject(CurrentProjectFile); }, //updateFunc (panel) => { return true; }); //findFunc } public void ShowEditProjectManifestPanel(bool promote) { ShowPanel(promote, () => { return new EditProjectManifestPanel(this); }, //createFunc (panel) => { panel.SetProject(CurrentProjectFile); }, //updateFunc (panel) => { return true; }); //findFunc } public void ShowGenerateLODLightsPanel(bool promote) { ShowPanel(promote, () => { return new GenerateLODLightsPanel(this); }, //createFunc (panel) => { panel.SetProject(CurrentProjectFile); }, //updateFunc (panel) => { return true; }); //findFunc } public void ShowGenerateNavMeshPanel(bool promote) { ShowPanel(promote, () => { return new GenerateNavMeshPanel(this); }, //createFunc (panel) => { panel.SetProject(CurrentProjectFile); }, //updateFunc (panel) => { return true; }); //findFunc } public void ShowEditMultiPanel(bool promote) { ShowPanel(promote, () => { return new EditMultiPanel(this); }, //createFunc (panel) => { panel.SetItems(CurrentMulti); }, //updateFunc (panel) => { return panel.Items == CurrentMulti; }); //findFunc } public void ShowEditYmapPanel(bool promote) { ShowPanel(promote, () => { return new EditYmapPanel(this); }, //createFunc (panel) => { panel.SetYmap(CurrentYmapFile); }, //updateFunc (panel) => { return panel.Ymap == CurrentYmapFile; }); //findFunc } public void ShowEditYmapEntityPanel(bool promote) { ShowPanel(promote, () => { return new EditYmapEntityPanel(this); }, //createFunc (panel) => { panel.SetEntity(CurrentEntity); }, //updateFunc (panel) => { return panel.CurrentEntity == CurrentEntity; }); //findFunc } public void ShowEditYmapCarGenPanel(bool promote) { ShowPanel(promote, () => { return new EditYmapCarGenPanel(this); }, //createFunc (panel) => { panel.SetCarGen(CurrentCarGen); }, //updateFunc (panel) => { return panel.CurrentCarGen == CurrentCarGen; }); //findFunc } public void ShowEditYmapGrassBatchPanel(bool promote) { ShowPanel(promote, () => { return new EditYmapGrassPanel(this); }, //createFunc (panel) => { panel.SetBatch(CurrentGrassBatch); }, //updateFunc (panel) => { return panel.CurrentBatch == CurrentGrassBatch; }); //findFunc } public void ShowEditYtypPanel(bool promote) { ShowPanel(promote, () => { return new EditYtypPanel(this); }, //createFunc (panel) => { panel.SetYtyp(CurrentYtypFile); }, //updateFunc (panel) => { return panel.Ytyp == CurrentYtypFile; }); //findFunc } public void ShowEditArchetypePanel(bool promote) { ShowPanel(promote, () => { return new EditYtypArchetypePanel(this); }, //createFunc (panel) => { panel.SetArchetype(CurrentArchetype); }, //updateFunc (panel) => { return panel.CurrentArchetype == CurrentArchetype; }); //findFunc } public void ShowEditYbnPanel(bool promote) { ShowPanel(promote, () => { return new EditYbnPanel(this); }, //createFunc (panel) => { panel.SetYbn(CurrentYbnFile); }, //updateFunc (panel) => { return panel.Ybn == CurrentYbnFile; }); //findFunc } public void ShowEditYbnBoundsPanel(bool promote) { ShowPanel(promote, () => { return new EditYbnBoundsPanel(this); }, //createFunc (panel) => { panel.SetCollisionBounds(CurrentCollisionBounds); }, //updateFunc (panel) => { return panel.CollisionBounds == CurrentCollisionBounds; }); //findFunc } public void ShowEditYbnBoundPolyPanel(bool promote) { ShowPanel(promote, () => { return new EditYbnBoundPolyPanel(this); }, //createFunc (panel) => { panel.SetCollisionPoly(CurrentCollisionPoly); }, //updateFunc (panel) => { return panel.CollisionPoly == CurrentCollisionPoly; }); //findFunc } public void ShowEditYbnBoundVertexPanel(bool promote) { ShowPanel(promote, () => { return new EditYbnBoundVertexPanel(this); }, //createFunc (panel) => { panel.SetCollisionVertex(CurrentCollisionVertex); }, //updateFunc (panel) => { return panel.CollisionVertex == CurrentCollisionVertex; }); //findFunc } public void ShowEditYndPanel(bool promote) { ShowPanel(promote, () => { return new EditYndPanel(this); }, //createFunc (panel) => { panel.SetYnd(CurrentYndFile); }, //updateFunc (panel) => { return panel.Ynd == CurrentYndFile; }); //findFunc } public void ShowEditYndNodePanel(bool promote) { ShowPanel(promote, () => { return new EditYndNodePanel(this); }, //createFunc (panel) => { panel.SetPathNode(CurrentPathNode); }, //updateFunc (panel) => { return panel.CurrentPathNode == CurrentPathNode; }); //findFunc } public void ShowEditYnvPanel(bool promote) { ShowPanel(promote, () => { return new EditYnvPanel(this); }, //createFunc (panel) => { panel.SetYnv(CurrentYnvFile); }, //updateFunc (panel) => { return panel.Ynv == CurrentYnvFile; }); //findFunc } public void ShowEditYnvPolyPanel(bool promote) { ShowPanel(promote, () => { return new EditYnvPolyPanel(this); }, //createFunc (panel) => { panel.SetYnvPoly(CurrentNavPoly); }, //updateFunc (panel) => { return panel.YnvPoly == CurrentNavPoly; }); //findFunc } public void ShowEditYnvPointPanel(bool promote) { ShowPanel(promote, () => { return new EditYnvPointPanel(this); }, //createFunc (panel) => { panel.SetYnvPoint(CurrentNavPoint); }, //updateFunc (panel) => { return panel.YnvPoint == CurrentNavPoint; }); //findFunc } public void ShowEditYnvPortalPanel(bool promote) { ShowPanel(promote, () => { return new EditYnvPortalPanel(this); }, //createFunc (panel) => { panel.SetYnvPortal(CurrentNavPortal); }, //updateFunc (panel) => { return panel.YnvPortal == CurrentNavPortal; }); //findFunc } public void ShowEditTrainTrackPanel(bool promote) { ShowPanel(promote, () => { return new EditTrainTrackPanel(this); }, //createFunc (panel) => { panel.SetTrainTrack(CurrentTrainTrack); }, //updateFunc (panel) => { return panel.Track == CurrentTrainTrack; }); //findFunc } public void ShowEditTrainNodePanel(bool promote) { ShowPanel(promote, () => { return new EditTrainNodePanel(this); }, //createFunc (panel) => { panel.SetTrainNode(CurrentTrainNode); }, //updateFunc (panel) => { return panel.TrainNode == CurrentTrainNode; }); //findFunc } public void ShowEditScenarioYmtPanel(bool promote) { ShowPanel(promote, () => { return new EditScenarioYmtPanel(this); }, //createFunc (panel) => { panel.SetScenarioYmt(CurrentScenario); }, //updateFunc (panel) => { return panel.CurrentScenario == CurrentScenario; }); //findFunc } public void ShowEditScenarioNodePanel(bool promote) { ShowPanel(promote, () => { return new EditScenarioNodePanel(this); }, //createFunc (panel) => { panel.SetScenarioNode(CurrentScenarioNode); }, //updateFunc (panel) => { return panel.CurrentScenarioNode == CurrentScenarioNode; }); //findFunc } public void ShowEditYtypMloRoomPanel(bool promote) { ShowPanel(promote, () => { return new EditYtypMloRoomPanel(this); }, //createFunc (panel) => { panel.SetRoom(CurrentMloRoom); }, //updateFunc (panel) => { return panel.CurrentRoom == CurrentMloRoom; }); //findFunc } public void ShowEditYtypMloPortalPanel(bool promote) { ShowPanel(promote, () => { return new EditYtypMloPortalPanel(this); }, //createFunc (panel) => { panel.SetPortal(CurrentMloPortal); }, //updateFunc (panel) => { return panel.CurrentPortal == CurrentMloPortal; }); //findFunc } public void ShowEditYtypMloEntSetPanel(bool promote) { ShowPanel(promote, () => { return new EditYtypMloEntSetPanel(this); }, //createFunc (panel) => { panel.SetEntitySet(CurrentMloEntitySet); }, //updateFunc (panel) => { return panel.CurrentEntitySet == CurrentMloEntitySet; }); //findFunc } public void ShowEditAudioFilePanel(bool promote) { ShowPanel(promote, () => { return new EditAudioFilePanel(this); }, //createFunc (panel) => { panel.SetFile(CurrentAudioFile); }, //updateFunc (panel) => { return panel.CurrentFile == CurrentAudioFile; }); //findFunc } public void ShowEditAudioZonePanel(bool promote) { ShowPanel(promote, () => { return new EditAudioZonePanel(this); }, //createFunc (panel) => { panel.SetZone(CurrentAudioZone); }, //updateFunc (panel) => { return panel.CurrentZone?.AudioZone == CurrentAudioZone?.AudioZone; }); //findFunc } public void ShowEditAudioEmitterPanel(bool promote) { ShowPanel(promote, () => { return new EditAudioEmitterPanel(this); }, //createFunc (panel) => { panel.SetEmitter(CurrentAudioEmitter); }, //updateFunc (panel) => { return panel.CurrentEmitter?.AudioEmitter == CurrentAudioEmitter?.AudioEmitter; }); //findFunc } public void ShowEditAudioZoneListPanel(bool promote) { ShowPanel(promote, () => { return new EditAudioZoneListPanel(this); }, //createFunc (panel) => { panel.SetZoneList(CurrentAudioZoneList); }, //updateFunc (panel) => { return panel.CurrentZoneList == CurrentAudioZoneList; }); //findFunc } public void ShowEditAudioEmitterListPanel(bool promote) { ShowPanel(promote, () => { return new EditAudioEmitterListPanel(this); }, //createFunc (panel) => { panel.SetEmitterList(CurrentAudioEmitterList); }, //updateFunc (panel) => { return panel.CurrentEmitterList == CurrentAudioEmitterList; }); //findFunc } public void ShowEditAudioInteriorPanel(bool promote) { ShowPanel(promote, () => { return new EditAudioInteriorPanel(this); }, //createFunc (panel) => { panel.SetInterior(CurrentAudioInterior); }, //updateFunc (panel) => { return panel.CurrentInterior == CurrentAudioInterior; }); //findFunc } public void ShowEditAudioInteriorRoomPanel(bool promote) { ShowPanel(promote, () => { return new EditAudioInteriorRoomPanel(this); }, //createFunc (panel) => { panel.SetRoom(CurrentAudioInteriorRoom); }, //updateFunc (panel) => { return panel.CurrentRoom == CurrentAudioInteriorRoom; }); //findFunc } private void ShowCurrentProjectItem(bool promote) { if (CurrentMulti != null) { ShowEditMultiPanel(promote); } else if (CurrentMloEntity != null) { ShowEditYmapEntityPanel(promote); } else if (CurrentMloRoom != null) { ShowEditYtypMloRoomPanel(promote); } else if (CurrentMloPortal != null) { ShowEditYtypMloPortalPanel(promote); } else if (CurrentMloEntitySet != null) { ShowEditYtypMloEntSetPanel(promote); } else if (CurrentYbnFile != null) { if (CurrentCollisionVertex != null) { ShowEditYbnBoundVertexPanel(promote); } else if (CurrentCollisionPoly != null) { ShowEditYbnBoundPolyPanel(promote); } else if (CurrentCollisionBounds != null) { ShowEditYbnBoundsPanel(promote); } else { ShowEditYbnPanel(promote); } } else if (CurrentEntity != null) { ShowEditYmapEntityPanel(promote); } else if (CurrentArchetype != null) { ShowEditArchetypePanel(promote); } else if (CurrentCarGen != null) { ShowEditYmapCarGenPanel(promote); } else if (CurrentGrassBatch != null) { ShowEditYmapGrassBatchPanel(promote); } else if (CurrentYmapFile != null) { ShowEditYmapPanel(promote); } else if (CurrentYtypFile != null) { ShowEditYtypPanel(promote); } if (CurrentPathNode != null) { ShowEditYndNodePanel(promote); } else if (CurrentYndFile != null) { ShowEditYndPanel(promote); } if (CurrentNavPoly != null) { ShowEditYnvPolyPanel(promote); } else if (CurrentNavPoint != null) { ShowEditYnvPointPanel(promote); } else if (CurrentNavPortal != null) { ShowEditYnvPortalPanel(promote); } else if (CurrentYnvFile != null) { ShowEditYnvPanel(promote); } if (CurrentTrainNode != null) { ShowEditTrainNodePanel(promote); } else if (CurrentTrainTrack != null) { ShowEditTrainTrackPanel(promote); } if (CurrentScenarioNode != null) { ShowEditScenarioNodePanel(promote); } else if (CurrentScenario != null) { ShowEditScenarioYmtPanel(promote); } if (CurrentAudioZone != null) { ShowEditAudioZonePanel(promote); } else if (CurrentAudioEmitter != null) { ShowEditAudioEmitterPanel(promote); } else if (CurrentAudioZoneList != null) { ShowEditAudioZoneListPanel(promote); } else if (CurrentAudioEmitterList != null) { ShowEditAudioEmitterListPanel(promote); } else if (CurrentAudioInterior != null) { ShowEditAudioInteriorPanel(promote); } else if (CurrentAudioInteriorRoom != null) { ShowEditAudioInteriorRoomPanel(promote); } else if (CurrentAudioFile != null) { ShowEditAudioFilePanel(promote); } } public void ShowProjectItem(object item, bool promote) { if (item is object[] arr) { var multisel = MapSelection.FromProjectObject(arr); //convert to MapSelection array item = multisel.MultipleSelectionItems; } ShowProjectItemInProcess = true; SetProjectItem(item); if (item == CurrentProjectFile) { ShowEditProjectPanel(promote); } else { ShowCurrentProjectItem(promote); } if (item is MapSelection[] multi) { WorldForm?.SelectMulti(multi, false, false); } ShowProjectItemInProcess = false; } public void SetProjectItem(object item, bool refreshUI = true) { if (item is MapSelection[] multi) { CurrentMulti = multi; return; } else { CurrentMulti = null; } 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; CurrentYbnFile = item as YbnFile; CurrentCollisionBounds = item as Bounds; CurrentCollisionPoly = item as BoundPolygon; CurrentCollisionVertex = item as BoundVertex; CurrentYndFile = item as YndFile; CurrentPathNode = item as YndNode; CurrentYnvFile = item as YnvFile; CurrentNavPoly = item as YnvPoly; CurrentNavPoint = item as YnvPoint; CurrentNavPortal = item as YnvPortal; CurrentTrainTrack = item as TrainTrack; CurrentTrainNode = item as TrainTrackNode; CurrentScenario = item as YmtFile; CurrentScenarioNode = item as ScenarioNode; CurrentScenarioChainEdge = item as MCScenarioChainingEdge; CurrentAudioFile = item as RelFile; CurrentAudioZone = item as AudioPlacement; CurrentAudioEmitter = item as AudioPlacement; CurrentAudioZoneList = item as Dat151AmbientZoneList; CurrentAudioEmitterList = item as Dat151AmbientEmitterList; CurrentAudioInterior = item as Dat151Interior; CurrentAudioInteriorRoom = item as Dat151InteriorRoom; CurrentMloRoom = item as MCMloRoomDef; CurrentMloPortal = item as MCMloPortalDef; CurrentMloEntitySet = item as MCMloEntitySet; if (CurrentAudioZone?.AudioZone == null) CurrentAudioZone = null; if (CurrentAudioEmitter?.AudioEmitter == null) CurrentAudioEmitter = null; //need to create a temporary AudioPlacement wrapper for these, since AudioPlacements usually come from WorldForm var daz = item as Dat151AmbientZone; var dae = item as Dat151AmbientEmitter; if (daz != null) CurrentAudioZone = new AudioPlacement(daz.Rel, daz); if (dae != null) CurrentAudioEmitter = new AudioPlacement(dae.Rel, dae); if (CurrentMloEntity != null) { MloInstanceData instance = TryGetMloInstance(CurrentMloEntity.OwnerMlo); 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) { CurrentYmapFile = CurrentCarGen.Ymap; } else if (CurrentGrassBatch != null) { CurrentYmapFile = CurrentGrassBatch.Ymap; } if (CurrentMloRoom != null) { CurrentArchetype = CurrentMloRoom.OwnerMlo; } if (CurrentMloPortal != null) { CurrentArchetype = CurrentMloPortal.OwnerMlo; } if (CurrentMloEntitySet != null) { CurrentArchetype = CurrentMloEntitySet.OwnerMlo; } if (CurrentArchetype != null) { CurrentYtypFile = CurrentEntity?.MloParent?.Archetype?.Ytyp ?? CurrentArchetype?.Ytyp; } if (CurrentCollisionVertex != null) { CurrentCollisionBounds = CurrentCollisionVertex.Owner; } if (CurrentCollisionPoly != null) { CurrentCollisionBounds = CurrentCollisionPoly.Owner; } if (CurrentCollisionBounds != null) { CurrentYbnFile = CurrentCollisionBounds.GetRootYbn(); } if (CurrentPathNode != null) { CurrentYndFile = CurrentPathNode.Ynd; } if (CurrentNavPoly != null) { CurrentYnvFile = CurrentNavPoly.Ynv; } if (CurrentNavPoint != null) { CurrentYnvFile = CurrentNavPoint.Ynv; } if (CurrentNavPortal != null) { CurrentYnvFile = CurrentNavPortal.Ynv; } if (CurrentTrainNode != null) { CurrentTrainTrack = CurrentTrainNode.Track; } if ((CurrentScenario != null) && (CurrentScenario.ScenarioRegion == null)) { CurrentScenario = null;//incase other types of ymt files make it into the project... } if (CurrentScenarioNode != null) { CurrentScenario = CurrentScenarioNode.Ymt; } if (CurrentScenarioChainEdge != null) { CurrentScenario = CurrentScenarioChainEdge.Region?.Ymt; } if (CurrentAudioZone != null) { CurrentAudioFile = CurrentAudioZone.RelFile; } if (CurrentAudioEmitter != null) { CurrentAudioFile = CurrentAudioEmitter.RelFile; } if (CurrentAudioZoneList != null) { CurrentAudioFile = CurrentAudioZoneList.Rel; } if (CurrentAudioEmitterList != null) { CurrentAudioFile = CurrentAudioEmitterList.Rel; } if (CurrentAudioInterior != null) { CurrentAudioFile = CurrentAudioInterior.Rel; } if (CurrentAudioInteriorRoom != null) { CurrentAudioFile = CurrentAudioInteriorRoom.Rel; } if (refreshUI) { RefreshUI(); } } public void SetCurrentArchetype(Archetype arch) { CurrentArchetype = arch; if (CurrentArchetype != null) { CurrentYtypFile = CurrentEntity?.MloParent?.Archetype?.Ytyp ?? CurrentArchetype?.Ytyp; } } private void ClosePanel(Func findFunc) where T : ProjectPanel { var panel = FindPanel(findFunc); if (PreviewPanel == panel) { PreviewPanel = null; } panel?.Close(); } private void CloseAllDocuments() { if (MainDockPanel.DocumentStyle == DocumentStyle.SystemMdi) { foreach (Form form in MdiChildren) form.Close(); } else { foreach (IDockContent document in MainDockPanel.DocumentsToArray()) { // IMPORANT: dispose all panes. document.DockHandler.DockPanel = null; document.DockHandler.Close(); } } } private void CloseAllContents() { // we don't want to create another instance of tool window, set DockPanel to null if (ProjectExplorer != null) ProjectExplorer.DockPanel = null; if (PreviewPanel != null) PreviewPanel.DockPanel = null; // Close all other document windows CloseAllDocuments(); // IMPORTANT: dispose all float windows. foreach (var window in MainDockPanel.FloatWindows.ToList()) window.Dispose(); System.Diagnostics.Debug.Assert(MainDockPanel.Panes.Count == 0); System.Diagnostics.Debug.Assert(MainDockPanel.Contents.Count == 0); System.Diagnostics.Debug.Assert(MainDockPanel.FloatWindows.Count == 0); } private void CloseAllProjectItems() { foreach (var pane in MainDockPanel.Panes.ToArray()) { foreach (var content in pane.Contents.ToArray()) { var panel = content as ProjectPanel; if (panel?.Tag != null) { panel.Close(); } } } } private void PromoteIfPreviewPanel(IDockContent panel) { if (panel == PreviewPanel) { if (PreviewPanel != null) { PreviewPanel.HideOnClose = false; } PreviewPanel = null; } } private void PromoteIfPreviewPanelActive() { PromoteIfPreviewPanel(MainDockPanel.ActiveContent); } //######## Public methods public bool CanPaintInstances() { // Possibly future proofing for procedural prop instances if (CurrentGrassBatch != null) { if (CurrentGrassBatch.BrushEnabled) return true; } return false; } public float GetInstanceBrushRadius() { if (CurrentGrassBatch != null) return CurrentGrassBatch.BrushRadius; return 0f; } public void NewProject() { if (CurrentProjectFile != null) { ////unload current project first CloseProject(); } CurrentProjectFile = new ProjectFile(); CurrentProjectFile.Name = "New CodeWalker Project"; CurrentProjectFile.Version = 1; CurrentProjectFile.HasChanged = true; LoadProjectUI(); } public void OpenProject() { string file = ShowOpenDialog("CodeWalker Projects|*.cwproj", string.Empty); if (string.IsNullOrEmpty(file)) { return; } CloseProject(); CurrentProjectFile = new ProjectFile(); CurrentProjectFile.Load(file); string cpath = new FileInfo(CurrentProjectFile.Filepath).Directory.FullName; foreach (var ymap in CurrentProjectFile.YmapFiles) { string filename = ymap.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadYmapFromFile(ymap, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } foreach (var ytyp in CurrentProjectFile.YtypFiles) { string filename = ytyp.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadYtypFromFile(ytyp, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } foreach (var ybn in CurrentProjectFile.YbnFiles) { string filename = ybn.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadYbnFromFile(ybn, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } foreach (var ynd in CurrentProjectFile.YndFiles) { string filename = ynd.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadYndFromFile(ynd, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } foreach (var ynv in CurrentProjectFile.YnvFiles) { string filename = ynv.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadYnvFromFile(ynv, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } foreach (var track in CurrentProjectFile.TrainsFiles) { string filename = track.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadTrainTrackFromFile(track, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } foreach (var scenario in CurrentProjectFile.ScenarioFiles) { string filename = scenario.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadScenarioFromFile(scenario, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } foreach (var datrel in CurrentProjectFile.AudioRelFiles) { string filename = datrel.FilePath; if (!File.Exists(filename)) { filename = cpath + "\\" + filename; } if (File.Exists(filename)) { LoadAudioRelFromFile(datrel, filename); } else { MessageBox.Show("Couldn't find file: " + filename); } } LoadProjectUI(); } public void CloseProject() { if (CurrentProjectFile == null) return; foreach (var ymap in CurrentProjectFile.YmapFiles) { if ((ymap != null) && (ymap.HasChanged)) { //save the current ymap first? if (MessageBox.Show("Would you like to save " + ymap.Name + " before closing?", "Save .ymap before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentYmapFile = ymap; SaveYmap(); } } } foreach (var ytyp in CurrentProjectFile.YtypFiles) { if ((ytyp != null) && (ytyp.HasChanged)) { //save the current ytyp first? if (MessageBox.Show("Would you like to save " + ytyp.Name + " before closing?", "Save .ytyp before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentYtypFile = ytyp; SaveYtyp(); } } } foreach (var ybn in CurrentProjectFile.YbnFiles) { if ((ybn != null) && (ybn.HasChanged)) { //save the current ybn first? if (MessageBox.Show("Would you like to save " + ybn.Name + " before closing?", "Save .ybn before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentYbnFile = ybn; SaveYbn(); } } } foreach (var ynd in CurrentProjectFile.YndFiles) { if ((ynd != null) && (ynd.HasChanged)) { //save the current ynd first? if (MessageBox.Show("Would you like to save " + ynd.Name + " before closing?", "Save .ynd before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentYndFile = ynd; SaveYnd(); } } } foreach (var ynv in CurrentProjectFile.YnvFiles) { if ((ynv != null) && (ynv.HasChanged)) { //save the current ynv first? if (MessageBox.Show("Would you like to save " + ynv.Name + " before closing?", "Save .ynv before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentYnvFile = ynv; SaveYnv(); } } } foreach (var trains in CurrentProjectFile.TrainsFiles) { if ((trains != null) && (trains.HasChanged)) { //save the current trains file first? if (MessageBox.Show("Would you like to save " + trains.Name + " before closing?", "Save trains file before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentTrainTrack = trains; SaveTrainTrack(); } } } foreach (var scenario in CurrentProjectFile.ScenarioFiles) { if ((scenario != null) && (scenario.HasChanged)) { //save the current scenario file first? if (MessageBox.Show("Would you like to save " + scenario.Name + " before closing?", "Save scenario file before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentScenario = scenario; SaveScenario(); } } } foreach (var datrel in CurrentProjectFile.AudioRelFiles) { if ((datrel != null) && (datrel.HasChanged)) { //save the current scenario file first? if (MessageBox.Show("Would you like to save " + datrel.Name + " before closing?", "Save scenario file before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { CurrentAudioFile = datrel; SaveAudioFile(); } } } if (CurrentProjectFile.HasChanged) { //save the current project first? if (MessageBox.Show("Would you like to save the current project before closing?", "Save project before closing?", MessageBoxButtons.YesNo) == DialogResult.Yes) { SaveProject(); } } lock (projectsyncroot) { CloseAllProjectItems(); CurrentProjectFile = null; CurrentYmapFile = null; CurrentYtypFile = null; CurrentYbnFile = null; CurrentYndFile = null; CurrentYnvFile = null; CurrentTrainTrack = null; CurrentScenario = null; LoadProjectUI(); } if (WorldForm != null) { WorldForm.SelectItem(null);//make sure current selected item isn't still selected... } } public void SaveProject(bool saveas = false) { if (CurrentProjectFile == null) return; if (string.IsNullOrEmpty(CurrentProjectFile.Filepath) || saveas) { string fileName = ShowSaveDialog("CodeWalker Projects|*.cwproj", CurrentProjectFile.Filepath); if (string.IsNullOrEmpty(fileName)) { return; } //user cancelled string oldpath = CurrentProjectFile.Filepath; CurrentProjectFile.Filepath = fileName; CurrentProjectFile.Filename = new FileInfo(fileName).Name; CurrentProjectFile.UpdateFilenames(oldpath); } CurrentProjectFile.Save(); SetProjectHasChanged(false); } public void Save() { if (CurrentYmapFile != null) { SaveYmap(); } else if (CurrentYtypFile != null) { SaveYtyp(); } else if (CurrentYbnFile != null) { SaveYbn(); } else if (CurrentYndFile != null) { SaveYnd(); } else if (CurrentYnvFile != null) { SaveYnv(); } else if (CurrentTrainTrack != null) { SaveTrainTrack(); } else if (CurrentScenario != null) { SaveScenario(); } else if (CurrentAudioFile != null) { SaveAudioFile(); } else if (CurrentProjectFile != null) { SaveProject(); } } public void SaveAll() { if (CurrentProjectFile != null) { if (CurrentProjectFile.YmapFiles != null) { var cymap = CurrentYmapFile; foreach (var ymap in CurrentProjectFile.YmapFiles) { CurrentYmapFile = ymap; SaveYmap(); } CurrentYmapFile = cymap; //ShowEditYmapPanel(false); } if (CurrentProjectFile.YtypFiles != null) { var cytyp = CurrentYtypFile; foreach (var ytyp in CurrentProjectFile.YtypFiles) { CurrentYtypFile = ytyp; SaveYtyp(); } CurrentYtypFile = cytyp; //ShowEditYtypPanel(false); } if (CurrentProjectFile.YbnFiles != null) { var cybn = CurrentYbnFile; foreach (var ybn in CurrentProjectFile.YbnFiles) { CurrentYbnFile = ybn; SaveYbn(); } CurrentYbnFile = cybn; //ShowEditYbnPanel(false); } if (CurrentProjectFile.YndFiles != null) { var cynd = CurrentYndFile; foreach (var ynd in CurrentProjectFile.YndFiles) { CurrentYndFile = ynd; SaveYnd(); } CurrentYndFile = cynd; //ShowEditYndPanel(false); } if (CurrentProjectFile.YnvFiles != null) { var cynv = CurrentYnvFile; foreach (var ynv in CurrentProjectFile.YnvFiles) { CurrentYnvFile = ynv; SaveYnv(); } CurrentYnvFile = cynv; //ShowEditYnvPanel(false); } if (CurrentProjectFile.TrainsFiles != null) { var ctrack = CurrentTrainTrack; foreach (var track in CurrentProjectFile.TrainsFiles) { CurrentTrainTrack = track; SaveYnd(); } CurrentTrainTrack = ctrack; //ShowEditTrainTrackPanel(false); } if (CurrentProjectFile.ScenarioFiles != null) { var cscen = CurrentScenario; foreach (var scen in CurrentProjectFile.ScenarioFiles) { CurrentScenario = scen; SaveScenario(); } CurrentScenario = cscen; //ShowEditScenarioPanel(false); } if (CurrentProjectFile.AudioRelFiles != null) { var caudf = CurrentAudioFile; foreach (var audf in CurrentProjectFile.AudioRelFiles) { CurrentAudioFile = audf; SaveAudioFile(); } CurrentAudioFile = caudf; //ShowEditAudioFilePanel(false); } SaveProject(); } } public void SaveCurrentItem(bool saveas = false) { if (CurrentYmapFile != null) { SaveYmap(saveas); } else if (CurrentYtypFile != null) { SaveYtyp(saveas); } else if (CurrentYbnFile != null) { SaveYbn(saveas); } else if (CurrentYndFile != null) { SaveYnd(saveas); } else if (CurrentYnvFile != null) { SaveYnv(saveas); } else if (CurrentTrainTrack != null) { SaveTrainTrack(saveas); } else if (CurrentScenario != null) { SaveScenario(saveas); } else if (CurrentAudioFile != null) { SaveAudioFile(saveas); } } public object NewObject(MapSelection sel, bool copyPosition = false, bool selectNew = true) { //general method to add a new object, given a map selection if (sel.MultipleSelectionItems != null) { var objs = new List(); for (int i = 0; i < sel.MultipleSelectionItems.Length; i++) { objs.Add(NewObject(sel.MultipleSelectionItems[i], copyPosition, false)); } LoadProjectTree(); CurrentMulti = sel.MultipleSelectionItems; return objs.ToArray(); } else if (sel.CollisionPoly != null) return NewCollisionPoly(sel.CollisionPoly.Type, sel.CollisionPoly, copyPosition, selectNew); else if (sel.CollisionBounds != null) return NewCollisionBounds(sel.CollisionBounds.Type, sel.CollisionBounds, copyPosition, selectNew); else if (sel.EntityDef != null) return NewEntity(sel.EntityDef, copyPosition, selectNew); else if (sel.CarGenerator != null) return NewCarGen(sel.CarGenerator, copyPosition, selectNew); else if (sel.PathNode != null) return NewPathNode(sel.PathNode, copyPosition, selectNew); else if (sel.NavPoly != null) return NewNavPoly(sel.NavPoly, copyPosition, selectNew); else if (sel.NavPoint != null) return NewNavPoint(sel.NavPoint, copyPosition, selectNew); else if (sel.NavPortal != null) return NewNavPortal(sel.NavPortal, copyPosition, selectNew); else if (sel.TrainTrackNode != null) return NewTrainNode(sel.TrainTrackNode, copyPosition, selectNew); else if (sel.ScenarioNode != null) return NewScenarioNode(sel.ScenarioNode, copyPosition, selectNew); else if (sel.Audio?.AudioZone != null) return NewAudioZone(sel.Audio, copyPosition, selectNew); else if (sel.Audio?.AudioEmitter != null) return NewAudioEmitter(sel.Audio, copyPosition, selectNew); return null; } public void DeleteObject(MapSelection sel) { SetObject(ref sel); if (sel.MultipleSelectionItems != null) { for (int i = 0; i < sel.MultipleSelectionItems.Length; i++) { DeleteObject(sel.MultipleSelectionItems[i]); } } else if (sel.CollisionVertex != null) DeleteCollisionVertex(); else if (sel.CollisionPoly != null) DeleteCollisionPoly(); else if (sel.CollisionBounds != null) DeleteCollisionBounds(); else if (sel.EntityDef != null) DeleteEntity(); else if (sel.CarGenerator != null) DeleteCarGen(); else if (sel.PathNode != null) DeletePathNode(); else if (sel.NavPoly != null) DeleteNavPoly(); else if (sel.NavPoint != null) DeleteNavPoint(); else if (sel.NavPortal != null) DeleteNavPortal(); else if (sel.TrainTrackNode != null) DeleteTrainNode(); else if (sel.ScenarioNode != null) DeleteScenarioNode(); else if (sel.Audio?.AudioZone != null) DeleteAudioZone(); else if (sel.Audio?.AudioEmitter != null) DeleteAudioEmitter(); } private void SetObject(ref MapSelection sel) { if (sel.MultipleSelectionItems != null) SetProjectItem(sel.MultipleSelectionItems, false); else if (sel.CollisionVertex != null) SetProjectItem(sel.CollisionVertex, false); else if (sel.CollisionPoly != null) SetProjectItem(sel.CollisionPoly, false); else if (sel.CollisionBounds != null) SetProjectItem(sel.CollisionBounds, false); else if (sel.EntityDef != null) SetProjectItem(sel.EntityDef, false); else if (sel.CarGenerator != null) SetProjectItem(sel.CarGenerator, false); else if (sel.PathNode != null) SetProjectItem(sel.PathNode, false); else if (sel.NavPoly != null) SetProjectItem(sel.NavPoly, false); else if (sel.NavPoint != null) SetProjectItem(sel.NavPoint, false); else if (sel.NavPortal != null) SetProjectItem(sel.NavPortal, false); else if (sel.TrainTrackNode != null) SetProjectItem(sel.TrainTrackNode, false); else if (sel.ScenarioNode != null) SetProjectItem(sel.ScenarioNode, false); else if (sel.Audio?.AudioZone != null) SetProjectItem(sel.Audio, false); else if (sel.Audio?.AudioEmitter != null) SetProjectItem(sel.Audio, false); } public void NewYmap() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 1; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "map" + testi.ToString() + ".ymap"; filenameok = !CurrentProjectFile.ContainsYmap(fname); testi++; } lock (projectsyncroot) { YmapFile ymap = CurrentProjectFile.AddYmapFile(fname); if (ymap != null) { ymap.Loaded = true; ymap.HasChanged = true; //new ymap, flag as not saved ymap._CMapData.contentFlags = 65; //stream flags value } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenYmap() { string[] files = ShowOpenDialogMulti("Ymap files|*.ymap", string.Empty); if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var ymap = CurrentProjectFile.AddYmapFile(file); if (ymap != null) { SetProjectHasChanged(true); LoadYmapFromFile(ymap, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } public void SaveYmap(bool saveas = false) { if (CurrentYmapFile == null) return; string ymapname = CurrentYmapFile.Name; string filepath = CurrentYmapFile.FilePath; if (string.IsNullOrEmpty(filepath)) { filepath = ymapname; } string origfile = filepath; if (!File.Exists(filepath)) { saveas = true; } byte[] data; lock (projectsyncroot) //need to sync writes to ymap objects... { saveas = saveas || string.IsNullOrEmpty(filepath); if (saveas) { filepath = ShowSaveDialog("Ymap files|*.ymap", filepath); if (string.IsNullOrEmpty(filepath)) { return; } string newname = Path.GetFileNameWithoutExtension(filepath); JenkIndex.Ensure(newname); CurrentYmapFile.FilePath = filepath; CurrentYmapFile.RpfFileEntry.Name = new FileInfo(filepath).Name; CurrentYmapFile.Name = CurrentYmapFile.RpfFileEntry.Name; CurrentYmapFile._CMapData.name = new MetaHash(JenkHash.GenHash(newname)); } data = CurrentYmapFile.Save(); } if (data != null) { File.WriteAllBytes(filepath, data); } SetYmapHasChanged(false); if (saveas) { //ShowEditYmapPanel(false); if (CurrentProjectFile != null) { string origpath = CurrentProjectFile.GetRelativePath(origfile); string newpath = CurrentProjectFile.GetRelativePath(CurrentYmapFile.FilePath); if (!CurrentProjectFile.RenameYmap(origpath, newpath)) { //couldn't rename it in the project? //MessageBox.Show("Couldn't rename ymap in project! This shouldn't happen - check the project file XML."); } ProjectExplorer?.UpdateYmapTreeNode(CurrentYmapFile); } SetProjectHasChanged(true); SetCurrentSaveItem(); } if (CurrentYmapFile.SaveWarnings != null) { string w = string.Join("\n", CurrentYmapFile.SaveWarnings); MessageBox.Show(CurrentYmapFile.SaveWarnings.Count.ToString() + " warnings were generated while saving the ymap:\n" + w); CurrentYmapFile.SaveWarnings = null;//clear it out for next time.. } } public void AddYmapToProject(YmapFile ymap) { if (ymap == null) return; if (CurrentProjectFile == null) { NewProject(); } if (YmapExistsInProject(ymap)) return; if (CurrentProjectFile.AddYmapFile(ymap)) { ymap.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentYmapFile = ymap; RefreshUI(); if (CurrentEntity != null) { ProjectExplorer?.TrySelectEntityTreeNode(CurrentEntity); } else if (CurrentCarGen != null) { ProjectExplorer?.TrySelectCarGenTreeNode(CurrentCarGen); } else if (CurrentGrassBatch != null) { ProjectExplorer?.TrySelectGrassBatchTreeNode(CurrentGrassBatch); } } public void RemoveYmapFromProject() { if (CurrentYmapFile == null) return; if (CurrentProjectFile == null) return; CurrentProjectFile.RemoveYmapFile(CurrentYmapFile); CurrentYmapFile = null; LoadProjectTree(); RefreshUI(); } public bool YmapExistsInProject(YmapFile ymap) { if (ymap == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsYmap(ymap); } public YmapEntityDef NewEntity(YmapEntityDef copy = null, bool copyPosition = false, bool selectNew = true) { if (copy != null) { //create the entity in MLO instead of a ymap, if the copy is in an MLO var instance = copy.MloParent?.MloInstance; var entdef = instance?.TryGetArchetypeEntity(copy); if (entdef != null) { return NewMloEntity(copy, copyPosition, selectNew); } } if (CurrentYmapFile == null) return null; float spawndist = 5.0f; //use archetype BSradius if starting with a copy... if (copy != null) { spawndist = copy.BSRadius * 2.5f; } bool cp = copyPosition && (copy != null); Vector3 pos = cp ? copy.Position : GetSpawnPos(spawndist); 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 = 32; //1572872; cent.parentIndex = -1; cent.lodDist = 200.0f; cent.lodLevel = rage__eLodType.LODTYPES_DEPTH_ORPHANHD; cent.priorityLevel = rage__ePriorityLevel.PRI_REQUIRED; cent.ambientOcclusionMultiplier = 255; cent.artificialAmbientOcclusion = 255; } cent.position = pos; YmapEntityDef ent = new YmapEntityDef(CurrentYmapFile, 0, ref cent); ent.SetArchetype(GameFileCache.GetArchetype(cent.archetypeName)); if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { CurrentYmapFile.AddEntity(ent); } } else { CurrentYmapFile.AddEntity(ent); } if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectEntityTreeNode(ent); CurrentEntity = ent; ShowEditYmapEntityPanel(false); } return ent; } public void AddEntityToProject() { try { if (CurrentEntity == null) return; if (CurrentEntity.Ymap == null) { CurrentYtypFile = CurrentEntity.MloParent?.Archetype?.Ytyp; 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; } 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 (CurrentEntity == null) return false; return CurrentYmapFile != null ? DeleteYmapEntity() : DeleteMloEntity(); } 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.. 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; } int idx = CurrentEntity.Index; for (int i = idx + 1; i < CurrentYmapFile.AllEntities.Length; i++) { var ent = CurrentYmapFile.AllEntities[i]; if (ent._CEntityDef.numChildren != 0) { MessageBox.Show("There are other entities present in this .ymap that have children. Deleting this entity 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; //} bool res = false; if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { res = CurrentYmapFile.RemoveEntity(CurrentEntity); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentYmapFile.RemoveEntity(CurrentEntity); } if (!res) { MessageBox.Show("Entity.Index didn't match the index of the entity in the ymap. This shouldn't happen, check LOD linkages!"); } var delent = CurrentEntity; var delymap = CurrentYmapFile; ProjectExplorer?.RemoveEntityTreeNode(delent); ProjectExplorer?.SetYmapHasChanged(delymap, true); ClosePanel((EditYmapEntityPanel p) => { return p.Tag == delent; }); CurrentEntity = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool IsCurrentEntity(YmapEntityDef ent) { return CurrentEntity == ent; } public YmapGrassInstanceBatch NewGrassBatch(YmapGrassInstanceBatch copy = null) { if (CurrentYmapFile == null) return null; rage__fwGrassInstanceListDef fwBatch = new rage__fwGrassInstanceListDef(); rage__fwGrassInstanceListDef__InstanceData[] instances = new rage__fwGrassInstanceListDef__InstanceData[0]; if (copy != null) { fwBatch = copy.Batch; instances = copy.Instances; } else { fwBatch.archetypeName = new MetaHash(JenkHash.GenHash("proc_grasses01")); fwBatch.lodDist = 120; fwBatch.LodFadeStartDist = 15; fwBatch.LodInstFadeRange = 0.75f; fwBatch.OrientToTerrain = 1.0f; fwBatch.ScaleRange = new Vector3(0.3f, 0.2f, 0.7f); } YmapGrassInstanceBatch batch = new YmapGrassInstanceBatch { AABBMin = fwBatch.BatchAABB.min.XYZ(), AABBMax = fwBatch.BatchAABB.max.XYZ(), Archetype = GameFileCache.GetArchetype(fwBatch.archetypeName), Batch = fwBatch, Instances = instances }; batch.Position = (batch.AABBMin + batch.AABBMax) * 0.5f; batch.Radius = (batch.AABBMax - batch.AABBMin).Length() * 0.5f; batch.Ymap = CurrentYmapFile; if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { CurrentYmapFile.AddGrassBatch(batch); } } else { CurrentYmapFile.AddGrassBatch(batch); } LoadProjectTree(); ProjectExplorer?.TrySelectGrassBatchTreeNode(batch); CurrentGrassBatch = batch; ShowEditYmapGrassBatchPanel(false); return batch; } public void AddGrassBatchToProject() { if (CurrentGrassBatch == null) return; CurrentYmapFile = CurrentGrassBatch.Ymap; if (!YmapExistsInProject(CurrentYmapFile)) { var grassBatch = CurrentGrassBatch; CurrentYmapFile.HasChanged = true; AddYmapToProject(CurrentYmapFile); CurrentGrassBatch = grassBatch; //bug fix for some reason the treeview selects the project node here. CurrentYmapFile = grassBatch.Ymap; ProjectExplorer?.TrySelectGrassBatchTreeNode(grassBatch); } } public bool DeleteGrassBatch() { if (CurrentYmapFile == null) return false; if (CurrentGrassBatch == null) return false; if (CurrentGrassBatch.Ymap != CurrentYmapFile) return false; if (CurrentYmapFile.GrassInstanceBatches == null) return false; //nothing to delete.. if (MessageBox.Show("Are you sure you want to delete this grass batch?\n" + CurrentGrassBatch.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 = CurrentYmapFile.RemoveGrassBatch(CurrentGrassBatch); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentYmapFile.RemoveGrassBatch(CurrentGrassBatch); } if (!res) { MessageBox.Show("Unable to delete the grass batch. This shouldn't happen!"); } var delbatch = CurrentGrassBatch; ProjectExplorer?.RemoveGrassBatchTreeNode(CurrentGrassBatch); ProjectExplorer?.SetYmapHasChanged(CurrentYmapFile, true); ClosePanel((EditYmapGrassPanel p) => { return p.Tag == delbatch; }); CurrentGrassBatch = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public void PaintGrass(SpaceRayIntersectResult mouseRay, bool erase) { try { if (InvokeRequired) { Invoke(new Action(() => { PaintGrass(mouseRay, erase); })); return; } if (!mouseRay.Hit || !mouseRay.TestComplete) return; if (CurrentGrassBatch == null || (!CurrentGrassBatch.BrushEnabled)) return; // brush isn't enabled right now EditYmapGrassPanel panel = FindPanel(x => x.CurrentBatch == CurrentGrassBatch); if (panel == null) return; // no panels with this batch // TODO: Maybe move these functions into the batch instead of the grass panel? // although, the panel does have the brush settings. if (!erase) panel.CreateInstancesAtMouse(mouseRay); else panel.EraseInstancesAtMouse(mouseRay); } catch { } } public bool GrassBatchExistsInProject(YmapGrassInstanceBatch batch) { if (CurrentProjectFile?.YmapFiles == null) return false; if (CurrentProjectFile.YmapFiles.Count <= 0) return false; foreach (var ymapFile in CurrentProjectFile.YmapFiles) { if (ymapFile.GrassInstanceBatches == null) continue; foreach (var b in ymapFile.GrassInstanceBatches) { if (batch == b) return true; } } return false; } public YmapCarGen NewCarGen(YmapCarGen copy = null, bool copyPosition = false, bool selectNew = true) { if (CurrentYmapFile == null) return null; Vector3 pos = GetSpawnPos(10.0f); CCarGen ccg = new CCarGen(); if (copy != null) { ccg = copy.CCarGen; } else { ccg.flags = 3680; ccg.orientX = 5.0f; ccg.perpendicularLength = 2.6f; ccg.bodyColorRemap1 = -1; ccg.bodyColorRemap2 = -1; ccg.bodyColorRemap3 = -1; ccg.bodyColorRemap4 = -1; ccg.livery = -1; } if (!copyPosition || (copy == null)) { ccg.position = pos; } YmapCarGen cg = new YmapCarGen(CurrentYmapFile, ccg); if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { CurrentYmapFile.AddCarGen(cg); } } else { CurrentYmapFile.AddCarGen(cg); } if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectCarGenTreeNode(cg); CurrentCarGen = cg; ShowEditYmapCarGenPanel(false); } return cg; } public void AddCarGenToProject() { if (CurrentCarGen == null) return; CurrentYmapFile = CurrentCarGen.Ymap; if (!YmapExistsInProject(CurrentYmapFile)) { var cargen = CurrentCarGen; CurrentYmapFile.HasChanged = true; AddYmapToProject(CurrentYmapFile); CurrentCarGen = cargen; //bug fix for some reason the treeview selects the project node here. CurrentYmapFile = cargen.Ymap; ProjectExplorer?.TrySelectCarGenTreeNode(cargen); } } public bool DeleteCarGen() { if (CurrentYmapFile == null) return false; if (CurrentCarGen == null) return false; if (CurrentCarGen.Ymap != CurrentYmapFile) return false; if (CurrentYmapFile.CarGenerators == null) return false; //nothing to delete.. //if (MessageBox.Show("Are you sure you want to delete this car generator?\n" + CurrentCarGen.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 = CurrentYmapFile.RemoveCarGen(CurrentCarGen); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentYmapFile.RemoveCarGen(CurrentCarGen); } if (!res) { MessageBox.Show("Unable to delete the car generator. This shouldn't happen!"); } var delgen = CurrentCarGen; ProjectExplorer?.RemoveCarGenTreeNode(CurrentCarGen); ProjectExplorer?.SetYmapHasChanged(CurrentYmapFile, true); ClosePanel((EditYmapCarGenPanel p) => { return p.Tag == delgen; }); CurrentCarGen = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool IsCurrentCarGen(YmapCarGen cargen) { return CurrentCarGen == cargen; } private void ImportMenyooXml() { if (CurrentProjectFile == null) { NewProject(); } var xmlpath = ShowOpenDialog("XML Files|*.xml", string.Empty); if (string.IsNullOrEmpty(xmlpath)) return; var xmlstr = string.Empty; try { xmlstr = File.ReadAllText(xmlpath); } catch (Exception ex) { MessageBox.Show("Error loading file!\n" + ex.ToString()); } if (string.IsNullOrEmpty(xmlstr)) return; var finf = new FileInfo(xmlpath); MenyooXml menyooXml = new MenyooXml(); menyooXml.FilePath = xmlpath; menyooXml.FileName = finf.Name; menyooXml.Name = Path.GetFileNameWithoutExtension(finf.Name); menyooXml.Init(xmlstr); string fname = menyooXml.Name + ".ymap"; lock (ProjectSyncRoot) { YmapFile ymap = CurrentProjectFile.AddYmapFile(fname); if (ymap != null) { ymap.Loaded = true; ymap.HasChanged = true; //new ymap, flag as not saved ymap._CMapData.contentFlags = 65; //stream flags value } CurrentYmapFile = ymap; } CurrentProjectFile.HasChanged = true; int pedcount = 0; int carcount = 0; int entcount = 0; int unkcount = 0; foreach (var placement in menyooXml.Placements) { if (placement.Type == 1) { pedcount++; } else if (placement.Type == 2) { CCarGen ccg = new CCarGen(); var rotq = Quaternion.Invert(new Quaternion(placement.Rotation)); Vector3 cdir = rotq.Multiply(new Vector3(0, 5, 0)); ccg.flags = 3680; ccg.orientX = cdir.X; ccg.orientY = cdir.Y; ccg.perpendicularLength = 2.6f; ccg.position = placement.Position; ccg.carModel = placement.ModelHash; YmapCarGen cg = new YmapCarGen(CurrentYmapFile, ccg); if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { CurrentYmapFile.AddCarGen(cg); } } else { CurrentYmapFile.AddCarGen(cg); } carcount++; } else if (placement.Type == 3) //standard entity { CEntityDef cent = new CEntityDef(); cent.archetypeName = placement.ModelHash; cent.position = placement.Position; cent.rotation = placement.Rotation; cent.scaleXY = 1.0f; cent.scaleZ = 1.0f; cent.flags = placement.Dynamic ? 0 : 32u;// 1572872; //32 = static cent.parentIndex = -1; cent.lodDist = placement.LodDistance; cent.lodLevel = rage__eLodType.LODTYPES_DEPTH_ORPHANHD; cent.priorityLevel = rage__ePriorityLevel.PRI_REQUIRED; cent.ambientOcclusionMultiplier = 255; cent.artificialAmbientOcclusion = 255; YmapEntityDef ent = new YmapEntityDef(CurrentYmapFile, 0, ref cent); ent.SetArchetype(GameFileCache.GetArchetype(cent.archetypeName)); if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { CurrentYmapFile.AddEntity(ent); } } else { CurrentYmapFile.AddEntity(ent); } entcount++; } else { unkcount++; } } lock (ProjectSyncRoot) { CurrentYmapFile.CalcFlags(); CurrentYmapFile.CalcExtents(); } LoadProjectTree(); ShowProjectItem(CurrentYmapFile, false); MessageBox.Show(entcount.ToString() + " entities imported. \n" + carcount.ToString() + " car generators imported. \n" + pedcount.ToString() + " peds ignored. \n" + unkcount.ToString() + " others ignored."); } public void NewYtyp() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 1; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "types" + testi.ToString() + ".ytyp"; filenameok = !CurrentProjectFile.ContainsYtyp(fname); testi++; } lock (projectsyncroot) { YtypFile ytyp = CurrentProjectFile.AddYtypFile(fname); if (ytyp != null) { //ytyp.Loaded = true; ytyp.HasChanged = true; //new ytyp, flag as not saved } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenYtyp() { string[] files = ShowOpenDialogMulti("Ytyp files|*.ytyp", string.Empty); if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var ytyp = CurrentProjectFile.AddYtypFile(file); if (ytyp != null) { SetProjectHasChanged(true); LoadYtypFromFile(ytyp, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } 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."); } ProjectExplorer?.UpdateYtypTreeNode(CurrentYtypFile); } 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) { if (ytyp == null) return; if (CurrentProjectFile == null) { NewProject(); } if (YtypExistsInProject(ytyp)) return; if (CurrentProjectFile.AddYtypFile(ytyp)) { ytyp.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentYtypFile = ytyp; RefreshUI(); AddProjectArchetypes(ytyp); } public void RemoveYtypFromProject() { if (CurrentYtypFile == null) return; if (CurrentProjectFile == null) return; RemoveProjectArchetypes(CurrentYtypFile); CurrentProjectFile.RemoveYtypFile(CurrentYtypFile); CurrentYtypFile = null; LoadProjectTree(); RefreshUI(); } public bool YtypExistsInProject(YtypFile ytyp) { if (ytyp == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsYtyp(ytyp); } public Archetype NewArchetype(Archetype copy = null) { if (CurrentYtypFile == null) return null; 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; AddProjectArchetype(archetype); return archetype; } public YmapEntityDef NewMloEntity(YmapEntityDef copy = null, bool copyTransform = false, bool selectNew = true) { if ((CurrentArchetype == null) || !(CurrentArchetype is MloArchetype mloArch)) { mloArch = (CurrentEntity?.MloParent.Archetype as MloArchetype) ?? CurrentMloRoom?.OwnerMlo ?? CurrentMloPortal?.OwnerMlo ?? CurrentMloEntitySet?.OwnerMlo; if (mloArch == null) return null; CurrentArchetype = mloArch; } var mloInstance = TryGetMloInstance(mloArch); if (mloInstance == null) { MessageBox.Show("Unable to find MLO instance for this interior! Try adding an MLO instance ymap to the project."); return null; } if ((CurrentMloEntity == null) && (CurrentEntity != null)) { CurrentMloEntity = mloInstance.TryGetArchetypeEntity(CurrentEntity); } if ((CurrentMloRoom == null) && (CurrentMloPortal == null) && (CurrentMloEntitySet == null)) { if (CurrentMloEntity != null) { CurrentMloRoom = mloArch.GetEntityRoom(CurrentMloEntity); CurrentMloPortal = mloArch.GetEntityPortal(CurrentMloEntity); CurrentMloEntitySet = mloArch.GetEntitySet(CurrentMloEntity); } else { if ((mloArch.rooms?.Length??0) <= 0) { MessageBox.Show($@"Mlo {mloArch.Name} has no rooms! Cannot create entity."); return null; } CurrentMloRoom = mloArch.rooms[0]; } } int roomIndex = CurrentMloRoom?.Index ?? -1; if (roomIndex >= (mloArch.rooms?.Length ?? 0)) { MessageBox.Show($@"Room at index {roomIndex} does not exist in {mloArch.Name}! {mloArch.Name} only has {(mloArch.rooms?.Length ?? 0)} rooms."); return null; } int portalIndex = CurrentMloPortal?.Index ?? -1; if (portalIndex >= (mloArch.portals?.Length ?? 0)) { MessageBox.Show($@"Portal at index {portalIndex} does not exist in {mloArch.Name}! {mloArch.Name} only has {(mloArch.portals?.Length ?? 0)} portals."); return null; } int entsetIndex = CurrentMloEntitySet?.Index ?? -1; if (entsetIndex >= (mloArch.entitySets?.Length ?? 0)) { MessageBox.Show($@"EntitySet at index {entsetIndex} does not exist in {mloArch.Name}! {mloArch.Name} only has {(mloArch.entitySets?.Length ?? 0)} entitySets."); return null; } 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 = rage__eLodType.LODTYPES_DEPTH_ORPHANHD; cent.priorityLevel = rage__ePriorityLevel.PRI_REQUIRED; cent.ambientOcclusionMultiplier = 255; cent.artificialAmbientOcclusion = 255; } cent.position = pos; cent.rotation = rot.ToVector4(); var createindex = mloArch.entities.Length; var ment = new MCEntityDef(ref cent, mloArch); var outEnt = mloInstance.CreateYmapEntity(mloInstance.Owner, ment, createindex); try { if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { mloArch.AddEntity(outEnt, roomIndex, portalIndex, entsetIndex); mloInstance.AddEntity(outEnt); outEnt.SetArchetype(GameFileCache.GetArchetype(cent.archetypeName)); } } else { mloArch.AddEntity(outEnt, roomIndex, portalIndex, entsetIndex); mloInstance.AddEntity(outEnt); outEnt.SetArchetype(GameFileCache.GetArchetype(cent.archetypeName)); } } catch(Exception e) { MessageBox.Show(this, e.Message, "Create MLO Entity Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return null; } ment = mloInstance.TryGetArchetypeEntity(outEnt); if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectMloEntityTreeNode(ment); CurrentEntity = outEnt; CurrentMloEntity = ment; CurrentYtypFile = CurrentEntity.MloParent?.Archetype?.Ytyp; } return outEnt; } public MCMloRoomDef NewMloRoom(MCMloRoomDef copy = null) { var mlo = CurrentMloRoom?.OwnerMlo ?? CurrentMloPortal?.OwnerMlo ?? CurrentMloEntitySet?.OwnerMlo ?? (CurrentEntity?.MloParent.Archetype as MloArchetype) ?? (CurrentArchetype as MloArchetype); if (mlo == null) return null; if (copy == null) { copy = CurrentMloRoom; } var room = new MCMloRoomDef(); if (copy != null) { room._Data = copy._Data; room.RoomName = copy.RoomName; } else { room._Data.flags = 96; room._Data.blend = 1.0f; room._Data.exteriorVisibiltyDepth = -1; room.RoomName = "NewRoom"; } mlo.AddRoom(room); var mloInstance = TryGetMloInstance(mlo); if (mloInstance != null) { } LoadProjectTree(); ProjectExplorer?.TrySelectMloRoomTreeNode(room); CurrentMloRoom = room; CurrentYtypFile = room?.OwnerMlo?.Ytyp; return room; } public MCMloPortalDef NewMloPortal(MCMloPortalDef copy = null) { var mlo = CurrentMloRoom?.OwnerMlo ?? CurrentMloPortal?.OwnerMlo ?? CurrentMloEntitySet?.OwnerMlo ?? (CurrentEntity?.MloParent.Archetype as MloArchetype) ?? (CurrentArchetype as MloArchetype); if (mlo == null) return null; if (copy == null) { copy = CurrentMloPortal; } var portal = new MCMloPortalDef(); if (copy != null) { portal._Data = copy._Data; portal.Corners = (Vector4[])copy.Corners?.Clone(); } else { portal._Data.roomFrom = 1; portal._Data.roomTo = 0; } if (portal.Corners == null) { portal.Corners = new[] { new Vector4(0, 0, 0, float.NaN), new Vector4(0, 0, 1, float.NaN), new Vector4(0, 1, 1, float.NaN), new Vector4(0, 1, 0, float.NaN) }; } mlo.AddPortal(portal); var mloInstance = TryGetMloInstance(mlo); if (mloInstance != null) { } LoadProjectTree(); ProjectExplorer?.TrySelectMloPortalTreeNode(portal); CurrentMloPortal = portal; CurrentYtypFile = portal?.OwnerMlo?.Ytyp; return portal; } public MCMloEntitySet NewMloEntitySet(MCMloEntitySet copy = null) { var mlo = CurrentMloRoom?.OwnerMlo ?? CurrentMloPortal?.OwnerMlo ?? CurrentMloEntitySet?.OwnerMlo ?? (CurrentEntity?.MloParent.Archetype as MloArchetype) ?? (CurrentArchetype as MloArchetype); if (mlo == null) return null; if (copy == null) { copy = CurrentMloEntitySet; } var set = new MCMloEntitySet(); if (copy != null) { set._Data.name = copy._Data.name; } else { JenkIndex.Ensure("NewEntitySet");//why is this here though set._Data.name = JenkHash.GenHash("NewEntitySet"); } mlo.AddEntitySet(set); var mloInstance = TryGetMloInstance(mlo); if (mloInstance != null) { mloInstance.AddEntitySet(set); } LoadProjectTree(); ProjectExplorer?.TrySelectMloEntitySetTreeNode(set); CurrentMloEntitySet = set; CurrentYtypFile = set?.OwnerMlo?.Ytyp; return set; } 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; RemoveProjectArchetype(delarch); ProjectExplorer?.RemoveArchetypeTreeNode(delarch); ProjectExplorer?.SetYtypHasChanged(delytyp, true); ClosePanel((EditYtypArchetypePanel p) => { return p.Tag == delarch; }); CurrentArchetype = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool DeleteMloEntity() { 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 delent = CurrentEntity; //CurrentEntity could get changed when we remove the tree node.. var delytyp = CurrentEntity.MloParent.Archetype.Ytyp; var mcEnt = mloInstance.TryGetArchetypeEntity(CurrentEntity); ProjectExplorer?.RemoveMloEntityTreeNode(mcEnt); ProjectExplorer?.SetYtypHasChanged(delytyp, true); try { if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { mloArchetype.RemoveEntity(delent); mloInstance.DeleteEntity(delent); //WorldForm.SelectItem(null, null, null); } } else { mloArchetype.RemoveEntity(delent); mloInstance.DeleteEntity(delent); } } 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; } ClosePanel((EditYmapEntityPanel p) => { return p.Tag == delent; }); CurrentEntity = null; CurrentMloEntity = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool DeleteMloRoom() { var mlo = CurrentMloRoom?.OwnerMlo; if (mlo == null) return false; if (MessageBox.Show("Are you sure you want to delete this room?\n" + CurrentMloRoom.Name + "\n\nDeleting existing rooms is generally not recommended, as it will mess up all the room IDs.\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) { return true; } mlo.RemoveRoom(CurrentMloRoom); var mloInstance = TryGetMloInstance(mlo); if (mloInstance != null) { } ProjectExplorer?.RemoveMloRoomTreeNode(CurrentMloRoom); ProjectExplorer?.SetYtypHasChanged(mlo.Ytyp, true); ClosePanel((EditYtypMloRoomPanel p) => { return p.Tag == CurrentMloRoom; }); CurrentMloRoom = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool DeleteMloPortal() { var mlo = CurrentMloPortal?.OwnerMlo; if (mlo == null) return false; if (MessageBox.Show("Are you sure you want to delete this portal?\n" + CurrentMloPortal.Name + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) { return true; } mlo.RemovePortal(CurrentMloPortal); var mloInstance = TryGetMloInstance(mlo); if (mloInstance != null) { } ProjectExplorer?.RemoveMloPortalTreeNode(CurrentMloPortal); ProjectExplorer?.SetYtypHasChanged(mlo.Ytyp, true); ClosePanel((EditYtypMloPortalPanel p) => { return p.Tag == CurrentMloPortal; }); CurrentMloPortal = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool DeleteMloEntitySet() { var mlo = CurrentMloEntitySet?.OwnerMlo; if (mlo == null) return false; if (MessageBox.Show("Are you sure you want to delete this entity set?\n" + CurrentMloEntitySet.Name + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) { return true; } mlo.RemoveEntitySet(CurrentMloEntitySet); var mloInstance = TryGetMloInstance(mlo); if (mloInstance != null) { mloInstance.DeleteEntitySet(CurrentMloEntitySet); } ProjectExplorer?.RemoveMloEntitySetTreeNode(CurrentMloEntitySet); ProjectExplorer?.SetYtypHasChanged(mlo.Ytyp, true); ClosePanel((EditYtypMloEntSetPanel p) => { return p.Tag == CurrentMloEntitySet; }); CurrentMloEntitySet = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } private void AddProjectArchetypes(YtypFile ytyp) { if (ytyp?.AllArchetypes == null) return; foreach (var arch in ytyp.AllArchetypes) { AddProjectArchetype(arch); } } private void AddProjectArchetype(Archetype arch) { if ((arch?.Hash ?? 0) == 0) return; lock (projectsyncroot) { projectarchetypes[arch.Hash] = arch; } } private void RemoveProjectArchetypes(YtypFile ytyp) { if (ytyp?.AllArchetypes == null) return; foreach (var arch in ytyp.AllArchetypes) { RemoveProjectArchetype(arch); } } private void RemoveProjectArchetype(Archetype arch) { if ((arch?.Hash ?? 0) == 0) return; Archetype tarch = null; lock (projectsyncroot) { projectarchetypes.TryGetValue(arch.Hash, out tarch); if (tarch == arch) { projectarchetypes.Remove(arch.Hash); } } } public void NewYbn() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 1; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "bounds" + testi.ToString() + ".ybn"; filenameok = !CurrentProjectFile.ContainsYbn(fname); testi++; } lock (projectsyncroot) { YbnFile ybn = CurrentProjectFile.AddYbnFile(fname); if (ybn != null) { ybn.Loaded = true; ybn.HasChanged = true; //new ynd, flag as not saved } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenYbn() { string[] files = ShowOpenDialogMulti("Ybn files|*.ybn", string.Empty); if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var ybn = CurrentProjectFile.AddYbnFile(file); if (ybn != null) { SetProjectHasChanged(true); LoadYbnFromFile(ybn, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } public void SaveYbn(bool saveas = false) { if ((CurrentYbnFile == null) && (CurrentCollisionBounds != null)) CurrentYbnFile = CurrentCollisionBounds.GetRootYbn(); if (CurrentYbnFile == null) return; string ybnname = CurrentYbnFile.Name; string filepath = CurrentYbnFile.FilePath; if (string.IsNullOrEmpty(filepath)) { filepath = ybnname; } string origfile = filepath; if (!File.Exists(filepath)) { saveas = true; } byte[] data; lock (projectsyncroot) //need to sync writes to ybn objects... { saveas = saveas || string.IsNullOrEmpty(filepath); if (saveas) { filepath = ShowSaveDialog("Ybn files|*.ybn", filepath); if (string.IsNullOrEmpty(filepath)) { return; } string newname = Path.GetFileNameWithoutExtension(filepath); JenkIndex.Ensure(newname); CurrentYbnFile.FilePath = filepath; CurrentYbnFile.RpfFileEntry.Name = new FileInfo(filepath).Name; CurrentYbnFile.Name = CurrentYbnFile.RpfFileEntry.Name; } data = CurrentYbnFile.Save(); } if (data != null) { File.WriteAllBytes(filepath, data); } SetYbnHasChanged(false); if (saveas) { //ShowEditYbnPanel(false); if (CurrentProjectFile != null) { string origpath = CurrentProjectFile.GetRelativePath(origfile); string newpath = CurrentProjectFile.GetRelativePath(CurrentYbnFile.FilePath); if (!CurrentProjectFile.RenameYbn(origpath, newpath)) { //couldn't rename it in the project? happens when project not saved yet... //MessageBox.Show("Couldn't rename ybn in project! This shouldn't happen - check the project file XML."); } ProjectExplorer?.UpdateYbnTreeNode(CurrentYbnFile); } SetProjectHasChanged(true); SetCurrentSaveItem(); } } public void AddYbnToProject(YbnFile ybn) { if (ybn == null) return; if (CurrentProjectFile == null) { NewProject(); } if (YbnExistsInProject(ybn)) return; if (CurrentProjectFile.AddYbnFile(ybn)) { ybn.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentYbnFile = ybn; RefreshUI(); if (CurrentCollisionVertex != null) { ProjectExplorer?.TrySelectCollisionVertexTreeNode(CurrentCollisionVertex); } else if (CurrentCollisionPoly != null) { ProjectExplorer?.TrySelectCollisionPolyTreeNode(CurrentCollisionPoly); } else if (CurrentCollisionBounds != null) { ProjectExplorer?.TrySelectCollisionBoundsTreeNode(CurrentCollisionBounds); } } public void RemoveYbnFromProject() { if (CurrentYbnFile == null) return; if (CurrentProjectFile == null) return; CurrentProjectFile.RemoveYbnFile(CurrentYbnFile); CurrentYbnFile = null; LoadProjectTree(); RefreshUI(); } public bool YbnExistsInProject(YbnFile ybn) { if (ybn == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsYbn(ybn); } public Bounds NewCollisionBounds(BoundsType type, Bounds copy = null, bool copyPosition = false, bool selectNew = true) { if (CurrentYbnFile == null) return null; Bounds b = null; switch (type) { case BoundsType.Sphere: b = new BoundSphere(); break; case BoundsType.Capsule: b = new BoundCapsule(); break; case BoundsType.Box: b = new BoundBox(); break; case BoundsType.Geometry: b = new BoundGeometry(); break; case BoundsType.GeometryBVH: b = new BoundBVH(); break; case BoundsType.Composite: b = new BoundComposite(); break; case BoundsType.Disc: b = new BoundDisc(); break; case BoundsType.Cylinder: b = new BoundCylinder(); break; case BoundsType.Cloth: b = new BoundCloth(); break; } if (b == null) return null; if ((copy != null) && (copy.Type == type)) { b.CopyFrom(copy); } else { var pos = GetSpawnPos(10.0f); b.Type = type; b.Margin = 0.005f; b.Volume = 1.0f; b.Unknown_60h = Vector3.One; b.Unknown_3Ch = 1; b.SphereCenter = Vector3.Zero; b.SphereRadius = 1.0f; b.BoxCenter = Vector3.Zero; b.BoxMin = -Vector3.One; b.BoxMax = Vector3.One; b.Position = pos; if (b is BoundBVH bbvh) { } if (b is BoundGeometry bgeo) { bgeo.CenterGeom = Vector3.Zero; bgeo.Quantum = Vector3.Zero; bgeo.Unknown_9Ch = 7.629627e-8f; bgeo.Unknown_ACh = 0.0025f; bgeo.Position = Vector3.Zero;//start geometry transform at 0 } if (b is BoundComposite bcmp) { bcmp.Position = Vector3.Zero;//start composite transform at 0 } } var bcomp = (CurrentCollisionBounds as BoundComposite) ?? CurrentCollisionBounds?.Parent; if (bcomp != null) { bcomp.AddChild(b); } else { CurrentYbnFile.AddBounds(b); } if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectCollisionBoundsTreeNode(b); CurrentCollisionBounds = b; //ShowEditYbnPanel(false);; ShowEditYbnBoundsPanel(false); } if (bcomp != null) { if (WorldForm != null) { WorldForm.UpdateCollisionBoundsGraphics(bcomp); } } return b; } public void AddCollisionBoundsToProject() { try { if (CurrentCollisionBounds == null) return; CurrentYbnFile = CurrentCollisionBounds.GetRootYbn(); if (CurrentYbnFile == null) { MessageBox.Show("Sorry, only YBN collisions can currently be added to the project. Embedded collisions TODO!"); return; } if (!YbnExistsInProject(CurrentYbnFile)) { var b = CurrentCollisionBounds; CurrentYbnFile.HasChanged = true; AddYbnToProject(CurrentYbnFile); CurrentCollisionBounds = b; //bug fix for some reason the treeview selects the project node here. CurrentYbnFile = b.GetRootYbn(); ProjectExplorer?.TrySelectCollisionBoundsTreeNode(b); } } catch { } } public bool DeleteCollisionBounds() { if (CurrentCollisionBounds == null) return false; if (CurrentYbnFile == null) return false; if (CurrentCollisionBounds.GetRootYbn() != CurrentYbnFile) return false; if (MessageBox.Show("Are you sure you want to delete this collision bounds?\n" + CurrentCollisionBounds.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) { return true; } var parent = CurrentCollisionBounds.Parent; bool res = false; if (WorldForm != null) { lock (WorldForm.RenderSyncRoot) //don't try to do this while rendering... { if (parent != null) { res = parent.DeleteChild(CurrentCollisionBounds); } else { res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); } //WorldForm.SelectItem(null, null, null); } } else { if (parent != null) { res = parent.DeleteChild(CurrentCollisionBounds); } else { res = CurrentYbnFile.RemoveBounds(CurrentCollisionBounds); } } if (!res) { MessageBox.Show("Unable to delete the collision bounds. This shouldn't happen!"); } var delb = CurrentCollisionBounds; ProjectExplorer?.RemoveCollisionBoundsTreeNode(CurrentCollisionBounds); ProjectExplorer?.SetYbnHasChanged(CurrentYbnFile, true); ClosePanel((EditYbnBoundsPanel p) => { return p.Tag == delb; }); CurrentCollisionBounds = null; if (WorldForm != null) { if (parent != null) { WorldForm.UpdateCollisionBoundsGraphics(parent); } WorldForm.SelectItem(null); } return true; } public bool IsCurrentCollisionBounds(Bounds bounds) { return bounds == CurrentCollisionBounds; } public BoundPolygon NewCollisionPoly(BoundPolygonType type, BoundPolygon copy = null, bool copyPosition = false, bool selectNew = true) { var bgeom = CurrentCollisionBounds as BoundGeometry; if (bgeom == null) return null; var poly = bgeom.AddPolygon(type); var ptri = poly as BoundPolygonTriangle; var psph = poly as BoundPolygonSphere; var pcap = poly as BoundPolygonCapsule; var pbox = poly as BoundPolygonBox; var pcyl = poly as BoundPolygonCylinder; var ctri = copy as BoundPolygonTriangle; var csph = copy as BoundPolygonSphere; var ccap = copy as BoundPolygonCapsule; var cbox = copy as BoundPolygonBox; var ccyl = copy as BoundPolygonCylinder; if (ptri != null) { ptri.edgeIndex1 = -1; ptri.edgeIndex2 = -1; ptri.edgeIndex3 = -1; } if (copy != null) { poly.VertexPositions = copy.VertexPositions; poly.Material = copy.Material; switch (type) { case BoundPolygonType.Triangle: if ((ptri != null) && (ctri != null)) { ptri.vertFlag1 = ctri.vertFlag1; ptri.vertFlag2 = ctri.vertFlag2; ptri.vertFlag3 = ctri.vertFlag3; } break; case BoundPolygonType.Sphere: if ((psph != null) && (csph != null)) { psph.sphereRadius = csph.sphereRadius; } break; case BoundPolygonType.Capsule: if ((pcap != null) && (ccap != null)) { pcap.capsuleRadius = ccap.capsuleRadius; } break; case BoundPolygonType.Box: if ((pbox != null) && (cbox != null)) { } break; case BoundPolygonType.Cylinder: if ((pcyl != null) && (ccyl != null)) { pcyl.cylinderRadius = ccyl.cylinderRadius; } break; default: break; } } else { var pos = GetSpawnPos(10.0f); var x = Vector3.UnitX; var y = Vector3.UnitY; var z = Vector3.UnitZ; if (ptri != null) { ptri.VertexPositions = new[] { pos, pos + x, pos + y }; } if (psph != null) { psph.VertexPositions = new[] { pos }; psph.sphereRadius = 1.0f; } if (pcap != null) { pcap.VertexPositions = new[] { pos - x, pos + x }; pcap.capsuleRadius = 1.0f; } if (pbox != null) { pbox.VertexPositions = new[] { pos - x + y - z, pos - x - y + z, pos + x + y + z, pos + x - y - z }; } if (pcyl != null) { pcyl.VertexPositions = new[] { pos - x, pos + x }; pcyl.cylinderRadius = 1.0f; } } if (selectNew) { //LoadProjectTree();//is this necessary? ProjectExplorer?.TrySelectCollisionPolyTreeNode(poly); CurrentCollisionPoly = poly; //ShowEditYbnPanel(false);; ShowEditYbnBoundPolyPanel(false); } if (WorldForm != null) { WorldForm.UpdateCollisionBoundsGraphics(bgeom); } return poly; } public void AddCollisionPolyToProject() { try { if (CurrentCollisionPoly == null) return; CurrentYbnFile = CurrentCollisionPoly.Owner?.GetRootYbn(); if (CurrentYbnFile == null) { MessageBox.Show("Sorry, only YBN collisions can currently be added to the project. Embedded collisions TODO!"); return; } if (!YbnExistsInProject(CurrentYbnFile)) { var p = CurrentCollisionPoly; CurrentYbnFile.HasChanged = true; AddYbnToProject(CurrentYbnFile); CurrentCollisionPoly = p; //bug fix for some reason the treeview selects the project node here. CurrentCollisionBounds = p.Owner; CurrentYbnFile = p.Owner?.GetRootYbn(); ProjectExplorer?.TrySelectCollisionPolyTreeNode(p); } } catch { } } public bool DeleteCollisionPoly() { if (CurrentCollisionBounds == null) return false; if (CurrentCollisionPoly == null) return false; if (CurrentYbnFile == null) return false; if (CurrentCollisionPoly.Owner != CurrentCollisionBounds) return false; //if (MessageBox.Show("Are you sure you want to delete this collision poly?\n" + CurrentCollisionPoly.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 = CurrentCollisionPoly.Owner.DeletePolygon(CurrentCollisionPoly); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentCollisionPoly.Owner.DeletePolygon(CurrentCollisionPoly); } if (!res) { MessageBox.Show("Unable to delete the collision poly. This shouldn't happen!"); } var delp = CurrentCollisionPoly; //ProjectExplorer?.RemoveCollisionPolyTreeNode(CurrentCollisionPoly); ProjectExplorer?.SetYbnHasChanged(CurrentYbnFile, true); ClosePanel((EditYbnBoundPolyPanel p) => { return p.Tag == delp; }); CurrentCollisionPoly = null; if (WorldForm != null) { WorldForm.UpdateCollisionBoundsGraphics(CurrentCollisionBounds); WorldForm.SelectItem(null); } return true; } public bool IsCurrentCollisionPoly(BoundPolygon poly) { return poly == CurrentCollisionPoly; } public void AddCollisionVertexToProject() { try { if (CurrentCollisionVertex == null) return; CurrentYbnFile = CurrentCollisionVertex.Owner?.GetRootYbn(); if (CurrentYbnFile == null) { MessageBox.Show("Sorry, only YBN collisions can currently be added to the project. Embedded collisions TODO!"); return; } if (!YbnExistsInProject(CurrentYbnFile)) { var v = CurrentCollisionVertex; CurrentYbnFile.HasChanged = true; AddYbnToProject(CurrentYbnFile); CurrentCollisionVertex = v; //bug fix for some reason the treeview selects the project node here. CurrentCollisionBounds = v.Owner; CurrentYbnFile = v.Owner?.GetRootYbn(); ProjectExplorer?.TrySelectCollisionVertexTreeNode(v); } } catch { } } public bool DeleteCollisionVertex() { if (CurrentCollisionBounds == null) return false; if (CurrentCollisionVertex == null) return false; if (CurrentYbnFile == null) return false; if (CurrentCollisionVertex.Owner != CurrentCollisionBounds) return false; //if (MessageBox.Show("Are you sure you want to delete this collision vertex, and all attached polygons?\n" + CurrentCollisionVertex.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 = CurrentCollisionVertex.Owner.DeleteVertex(CurrentCollisionVertex.Index); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentCollisionVertex.Owner.DeleteVertex(CurrentCollisionVertex.Index); } if (!res) { MessageBox.Show("Unable to delete the collision vertex. This shouldn't happen!"); } var delv = CurrentCollisionVertex; //ProjectExplorer?.RemoveCollisionVertexTreeNode(CurrentCollisionVertex); ProjectExplorer?.SetYbnHasChanged(CurrentYbnFile, true); ClosePanel((EditYbnBoundVertexPanel p) => { return p.Tag == delv; }); CurrentCollisionVertex = null; if (WorldForm != null) { WorldForm.UpdateCollisionBoundsGraphics(CurrentCollisionBounds); WorldForm.SelectItem(null); } return true; } public bool IsCurrentCollisionVertex(BoundVertex vertex) { return vertex == CurrentCollisionVertex; } public void NewYnd() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 1; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "nodes" + testi.ToString() + ".ynd"; filenameok = !CurrentProjectFile.ContainsYnd(fname); testi++; } lock (projectsyncroot) { YndFile ynd = CurrentProjectFile.AddYndFile(fname); if (ynd != null) { ynd.Loaded = true; ynd.HasChanged = true; //new ynd, flag as not saved //TODO: set new ynd default values... ynd.NodeDictionary = new NodeDictionary(); } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenYnd() { string[] files = ShowOpenDialogMulti("Ynd files|*.ynd", string.Empty); if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var ynd = CurrentProjectFile.AddYndFile(file); if (ynd != null) { SetProjectHasChanged(true); LoadYndFromFile(ynd, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } public void SaveYnd(bool saveas = false) { if ((CurrentYndFile == null) && (CurrentPathNode != null)) CurrentYndFile = CurrentPathNode.Ynd; if (CurrentYndFile == null) return; // Check that vehicle nodes and ped nodes add up to total nodes if(CurrentYndFile.NodeDictionary != null && (CurrentYndFile.NodeDictionary.NodesCountPed + CurrentYndFile.NodeDictionary.NodesCountVehicle != CurrentYndFile.NodeDictionary.NodesCount)) { var result = MessageBox.Show($"YND Area {CurrentYndFile.AreaID}: The total number of nodes ({CurrentYndFile.NodeDictionary.NodesCount}) does not match the total number of ped ({CurrentYndFile.NodeDictionary.NodesCountPed}) and vehicle ({CurrentYndFile.NodeDictionary.NodesCountVehicle}) nodes. You should manually adjust the number of nodes on the YND screen.\n\nDo you want to continue saving the YND file? Some of your nodes may not work in game.", $"Node count mismatch in Area {CurrentYndFile.AreaID}", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2); if(result == DialogResult.Cancel) { return; } } string yndname = CurrentYndFile.Name; string filepath = CurrentYndFile.FilePath; if (string.IsNullOrEmpty(filepath)) { filepath = yndname; } string origfile = filepath; if (!File.Exists(filepath)) { saveas = true; } byte[] data; lock (projectsyncroot) //need to sync writes to ynd objects... { saveas = saveas || string.IsNullOrEmpty(filepath); if (saveas) { filepath = ShowSaveDialog("Ynd files|*.ynd", filepath); if (string.IsNullOrEmpty(filepath)) { return; } string newname = Path.GetFileNameWithoutExtension(filepath); JenkIndex.Ensure(newname); CurrentYndFile.FilePath = filepath; CurrentYndFile.RpfFileEntry.Name = new FileInfo(filepath).Name; CurrentYndFile.Name = CurrentYndFile.RpfFileEntry.Name; } data = CurrentYndFile.Save(); } if (data != null) { File.WriteAllBytes(filepath, data); } SetYndHasChanged(false); if (saveas) { //ShowEditYndPanel(false); if (CurrentProjectFile != null) { string origpath = CurrentProjectFile.GetRelativePath(origfile); string newpath = CurrentProjectFile.GetRelativePath(CurrentYndFile.FilePath); if (!CurrentProjectFile.RenameYnd(origpath, newpath)) { //couldn't rename it in the project? happens when project not saved yet... //MessageBox.Show("Couldn't rename ynd in project! This shouldn't happen - check the project file XML."); } ProjectExplorer?.UpdateYndTreeNode(CurrentYndFile); } SetProjectHasChanged(true); SetCurrentSaveItem(); } } public void AddYndToProject(YndFile ynd) { if (ynd == null) return; if (CurrentProjectFile == null) { NewProject(); } if (YndExistsInProject(ynd)) return; if (CurrentProjectFile.AddYndFile(ynd)) { ynd.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentYndFile = ynd; RefreshUI(); if (CurrentPathNode != null) { ProjectExplorer?.TrySelectPathNodeTreeNode(CurrentPathNode); } } public void RemoveYndFromProject() { if (CurrentYndFile == null) return; if (CurrentProjectFile == null) return; CurrentProjectFile.RemoveYndFile(CurrentYndFile); CurrentYndFile = null; LoadProjectTree(); RefreshUI(); } public bool YndExistsInProject(YndFile ynd) { if (ynd == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsYnd(ynd); } public YndNode NewPathNode(YndNode copy = null, bool copyPosition = false, bool selectNew = true) { if (CurrentYndFile == null) return null; var n = CurrentYndFile.AddNode(); var areaid = n.AreaID; var nodeid = n.NodeID; if (copy == null) { copy = CurrentPathNode; } if (copy != null) { n.Init(CurrentYndFile, copy.RawData); n.LinkCountUnk = copy.LinkCountUnk; } n.AreaID = areaid; n.NodeID = nodeid; bool cp = copyPosition && (copy != null); Vector3 pos = cp ? copy.Position : GetSpawnPos(10.0f); n.SetPosition(pos); if (copy != null) { var link1 = n.AddLink(copy); var link2 = copy.AddLink(n); if ((copy.Links != null) && (copy.Links.Length > 0)) { var clink = copy.Links[0]; link1.CopyFlags(clink); var clnode = clink.Node2; if (clnode.Links != null) { for (int i = 0; i < clnode.Links.Length; i++) { var clnlink = clnode.Links[i]; if (clnlink.Node2 == copy) { link2.CopyFlags(clnlink); break; } } } } } CurrentYndFile.UpdateAllNodePositions(); //for the graphics... CurrentYndFile.BuildBVH(); if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectPathNodeTreeNode(n); CurrentPathNode = n; //ShowEditYndPanel(false);; ShowEditYndNodePanel(false); } if (WorldForm != null) { WorldForm.UpdatePathYndGraphics(CurrentYndFile, false); } return n; } public bool DeletePathNode() { if (CurrentYndFile == null) return false; if (CurrentPathNode == null) return false; if (CurrentPathNode.Ynd != CurrentYndFile) return false; if (CurrentYndFile.Nodes == null) return false; //nothing to delete.. //if (MessageBox.Show("Are you sure you want to delete this path node?\n" + CurrentPathNode.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 = CurrentYndFile.RemoveNode(CurrentPathNode); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentYndFile.RemoveNode(CurrentPathNode); } if (!res) { MessageBox.Show("Unable to delete the path node. This shouldn't happen!"); } var delnode = CurrentPathNode; ProjectExplorer?.RemovePathNodeTreeNode(CurrentPathNode); ProjectExplorer?.SetYndHasChanged(CurrentYndFile, true); ClosePanel((EditYndNodePanel p) => { return p.Tag == delnode; }); CurrentPathNode = null; if (WorldForm != null) { WorldForm.UpdatePathYndGraphics(CurrentYndFile, false); WorldForm.SelectItem(null); } return true; } public bool IsCurrentPathNode(YndNode pathnode) { return CurrentPathNode == pathnode; } public void NewYnv() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 1; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "navmesh" + testi.ToString() + ".ynv"; filenameok = !CurrentProjectFile.ContainsYnv(fname); testi++; } lock (projectsyncroot) { YnvFile ynv = CurrentProjectFile.AddYnvFile(fname); if (ynv != null) { ynv.Loaded = true; ynv.HasChanged = true; //new ynd, flag as not saved //TODO: set new ynv default values... ynv.Nav = new NavMesh(); } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenYnv() { string[] files = ShowOpenDialogMulti("Ynv files|*.ynv", string.Empty); if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var ynv = CurrentProjectFile.AddYnvFile(file); if (ynv != null) { SetProjectHasChanged(true); LoadYnvFromFile(ynv, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } public void SaveYnv(bool saveas = false) { if ((CurrentYnvFile == null) && (CurrentNavPoly != null)) CurrentYnvFile = CurrentNavPoly.Ynv; if (CurrentYnvFile == null) return; string ynvname = CurrentYnvFile.Name; string filepath = CurrentYnvFile.FilePath; if (string.IsNullOrEmpty(filepath)) { filepath = ynvname; } string origfile = filepath; if (!File.Exists(filepath)) { saveas = true; } byte[] data; lock (projectsyncroot) //need to sync writes to ynv objects... { saveas = saveas || string.IsNullOrEmpty(filepath); if (saveas) { filepath = ShowSaveDialog("Ynv files|*.ynv", filepath); if (string.IsNullOrEmpty(filepath)) { return; } string newname = Path.GetFileNameWithoutExtension(filepath); JenkIndex.Ensure(newname); CurrentYnvFile.FilePath = filepath; CurrentYnvFile.RpfFileEntry.Name = new FileInfo(filepath).Name; CurrentYnvFile.Name = CurrentYnvFile.RpfFileEntry.Name; } data = CurrentYnvFile.Save(); } if (data != null) { File.WriteAllBytes(filepath, data); } SetYnvHasChanged(false); if (saveas) { //ShowEditYnvPanel(false); if (CurrentProjectFile != null) { string origpath = CurrentProjectFile.GetRelativePath(origfile); string newpath = CurrentProjectFile.GetRelativePath(CurrentYnvFile.FilePath); if (!CurrentProjectFile.RenameYnv(origpath, newpath)) { //couldn't rename it in the project? happens when project not saved yet... //MessageBox.Show("Couldn't rename ynv in project! This shouldn't happen - check the project file XML."); } ProjectExplorer?.UpdateYnvTreeNode(CurrentYnvFile); } SetProjectHasChanged(true); SetCurrentSaveItem(); } } public void AddYnvToProject(YnvFile ynv) { if (ynv == null) return; if (CurrentProjectFile == null) { NewProject(); } if (YnvExistsInProject(ynv)) return; if (CurrentProjectFile.AddYnvFile(ynv)) { ynv.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentYnvFile = ynv; RefreshUI(); if (CurrentNavPoly != null) { ProjectExplorer?.TrySelectNavPolyTreeNode(CurrentNavPoly); } } public void RemoveYnvFromProject() { if (CurrentYnvFile == null) return; if (CurrentProjectFile == null) return; CurrentProjectFile.RemoveYnvFile(CurrentYnvFile); CurrentYnvFile = null; LoadProjectTree(); RefreshUI(); } public bool YnvExistsInProject(YnvFile ynv) { if (ynv == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsYnv(ynv); } public YnvPoly NewNavPoly(YnvPoly copy = null, bool copyposition = false, bool selectNew = true)//TODO! { return null; } public bool DeleteNavPoly()//TODO! { return false; } public bool IsCurrentNavPoly(YnvPoly poly) { return poly == CurrentNavPoly; } public YnvPoint NewNavPoint(YnvPoint copy = null, bool copyposition = false, bool selectNew = true)//TODO! { return null; } public bool DeleteNavPoint()//TODO! { return false; } public bool IsCurrentNavPoint(YnvPoint point) { return point == CurrentNavPoint; } public YnvPortal NewNavPortal(YnvPortal copy = null, bool copyposition = false, bool selectNew = true)//TODO! { return null; } public bool DeleteNavPortal()//TODO! { return false; } public bool IsCurrentNavPortal(YnvPortal portal) { return portal == CurrentNavPortal; } public void NewTrainTrack() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 13; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "trains" + testi.ToString() + ".dat"; filenameok = !CurrentProjectFile.ContainsTrainTrack(fname); testi++; } lock (projectsyncroot) { TrainTrack track = CurrentProjectFile.AddTrainsFile(fname); if (track != null) { track.Loaded = true; track.HasChanged = true; //new track, flag as not saved //TODO: set new train track default values... } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenTrainTrack() { string[] files = ShowOpenDialogMulti("Dat files|*.dat", string.Empty); if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var track = CurrentProjectFile.AddTrainsFile(file); if (track != null) { SetProjectHasChanged(true); LoadTrainTrackFromFile(track, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } public void SaveTrainTrack(bool saveas = false) { if ((CurrentTrainTrack == null) && (CurrentTrainNode != null)) CurrentTrainTrack = CurrentTrainNode.Track; if (CurrentTrainTrack == null) return; string trackname = CurrentTrainTrack.Name; string filepath = CurrentTrainTrack.FilePath; if (string.IsNullOrEmpty(filepath)) { filepath = trackname; } string origfile = filepath; if (!File.Exists(filepath)) { saveas = true; } byte[] data; lock (projectsyncroot) //need to sync writes to objects... { saveas = saveas || string.IsNullOrEmpty(filepath); if (saveas) { filepath = ShowSaveDialog("Dat files|*.dat", filepath); if (string.IsNullOrEmpty(filepath)) { return; } string newname = Path.GetFileNameWithoutExtension(filepath); //////JenkIndex.Ensure(newname); CurrentTrainTrack.FilePath = filepath; CurrentTrainTrack.RpfFileEntry.Name = new FileInfo(filepath).Name; CurrentTrainTrack.Name = CurrentTrainTrack.RpfFileEntry.Name; } data = CurrentTrainTrack.Save(); } if (data != null) { File.WriteAllBytes(filepath, data); } SetTrainTrackHasChanged(false); if (saveas) { //ShowEditTrainTrackPanel(false); if (CurrentProjectFile != null) { string origpath = CurrentProjectFile.GetRelativePath(origfile); string newpath = CurrentProjectFile.GetRelativePath(CurrentTrainTrack.FilePath); if (!CurrentProjectFile.RenameTrainTrack(origpath, newpath)) { //couldn't rename it in the project? happens when project not saved yet... //MessageBox.Show("Couldn't rename train track in project! This shouldn't happen - check the project file XML."); } ProjectExplorer?.UpdateTrainTrackTreeNode(CurrentTrainTrack); } SetProjectHasChanged(true); SetCurrentSaveItem(); } } public void AddTrainTrackToProject(TrainTrack track) { if (track == null) return; if (CurrentProjectFile == null) { NewProject(); } if (TrainTrackExistsInProject(track)) return; if (CurrentProjectFile.AddTrainsFile(track)) { track.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentTrainTrack = track; RefreshUI(); if (CurrentTrainNode != null) { ProjectExplorer?.TrySelectTrainNodeTreeNode(CurrentTrainNode); } } public void RemoveTrainTrackFromProject() { if (CurrentTrainTrack == null) return; if (CurrentProjectFile == null) return; CurrentProjectFile.RemoveTrainsFile(CurrentTrainTrack); CurrentTrainTrack = null; LoadProjectTree(); RefreshUI(); } public bool TrainTrackExistsInProject(TrainTrack track) { if (track == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsTrainTrack(track); } public TrainTrackNode NewTrainNode(TrainTrackNode copy = null, bool copyPosition = false, bool selectNew = true) { if (CurrentTrainTrack == null) return null; var afternode = copyPosition ? copy : null; var n = CurrentTrainTrack.AddNode(afternode); if (copy == null) { copy = CurrentTrainNode; } if (copy != null) { n.NodeType = copy.NodeType; } bool cp = copyPosition && (copy != null); Vector3 pos = cp ? copy.Position : GetSpawnPos(10.0f); n.SetPosition(pos); //CurrentTrainTrack.BuildVertices(); //for the graphics... CurrentTrainTrack.BuildBVH(); if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectTrainNodeTreeNode(n); CurrentTrainNode = n; ShowEditTrainNodePanel(false); } if (WorldForm != null) { WorldForm.UpdateTrainTrackGraphics(CurrentTrainTrack, false); } return n; } public bool DeleteTrainNode() { if (CurrentTrainTrack == null) return false; if (CurrentTrainNode == null) return false; if (CurrentTrainNode.Track != CurrentTrainTrack) return false; if (CurrentTrainTrack.Nodes == null) return false; //nothing to delete.. //if (MessageBox.Show("Are you sure you want to delete this train track node?\n" + CurrentTrainNode.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 = CurrentTrainTrack.RemoveNode(CurrentTrainNode); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentTrainTrack.RemoveNode(CurrentTrainNode); } if (!res) { MessageBox.Show("Unable to delete the train track node. This shouldn't happen!"); } var delnode = CurrentTrainNode; ProjectExplorer?.RemoveTrainNodeTreeNode(CurrentTrainNode); ProjectExplorer?.SetTrainTrackHasChanged(CurrentTrainTrack, true); ClosePanel((EditTrainNodePanel p) => { return p.Tag == delnode; }); CurrentTrainNode = null; if (WorldForm != null) { WorldForm.UpdateTrainTrackGraphics(CurrentTrainTrack, false); WorldForm.SelectItem(null); } return true; } public bool IsCurrentTrainNode(TrainTrackNode node) { return node == CurrentTrainNode; } public void NewScenario() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 1; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "scenario" + testi.ToString() + ".ymt"; filenameok = !CurrentProjectFile.ContainsScenario(fname); testi++; } lock (projectsyncroot) { YmtFile ymt = CurrentProjectFile.AddScenarioFile(fname); if (ymt != null) { ymt.CScenarioPointRegion = new MCScenarioPointRegion(); ymt.CScenarioPointRegion.Ymt = ymt; ymt.CScenarioPointRegion.Points = new MCScenarioPointContainer(ymt.CScenarioPointRegion); ymt.CScenarioPointRegion.Paths = new MUnk_4023740759(ymt.CScenarioPointRegion); ymt.CScenarioPointRegion.LookUps = new MCScenarioPointLookUps(ymt.CScenarioPointRegion); ymt.ScenarioRegion = new ScenarioRegion(); ymt.ScenarioRegion.Region = ymt.CScenarioPointRegion; ymt.ScenarioRegion.Ymt = ymt; ymt.ScenarioRegion.BuildNodes(); //should be empty ymt.ScenarioRegion.BuildBVH(); //should be empty ymt.ScenarioRegion.BuildVertices(); //should be empty ymt.HasChanged = true; //new ymt, flag as not saved ymt.Loaded = true; } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenScenario() { string[] files = ShowOpenDialogMulti("Ymt files|*.ymt", string.Empty); if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var ymt = CurrentProjectFile.AddScenarioFile(file); if (ymt != null) { SetProjectHasChanged(true); LoadScenarioFromFile(ymt, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } public void SaveScenario(bool saveas = false) { if ((CurrentScenario == null) && (CurrentScenarioNode != null)) CurrentScenario = CurrentScenarioNode.Ymt; if (CurrentScenario == null) return; string ymtname = CurrentScenario.Name; string filepath = CurrentScenario.FilePath; if (string.IsNullOrEmpty(filepath)) { filepath = ymtname; } string origfile = filepath; if (!File.Exists(filepath)) { saveas = true; } byte[] data; lock (projectsyncroot) //need to sync writes to scenario... { saveas = saveas || string.IsNullOrEmpty(filepath); if (saveas) { filepath = ShowSaveDialog("Ymt files|*.ymt", filepath); if (string.IsNullOrEmpty(filepath)) { return; } string newname = Path.GetFileNameWithoutExtension(filepath); JenkIndex.Ensure(newname); CurrentScenario.FilePath = filepath; CurrentScenario.RpfFileEntry.Name = new FileInfo(filepath).Name; CurrentScenario.Name = CurrentScenario.RpfFileEntry.Name; } CurrentScenario.ContentType = YmtFileContentType.ScenarioPointRegion;//just to be sure.. data = CurrentScenario.Save(); } if (data != null) { File.WriteAllBytes(filepath, data); } SetScenarioHasChanged(false); if (saveas) { //ShowEditScenarioPanel(false); if (CurrentProjectFile != null) { string origpath = CurrentProjectFile.GetRelativePath(origfile); string newpath = CurrentProjectFile.GetRelativePath(CurrentScenario.FilePath); if (!CurrentProjectFile.RenameScenario(origpath, newpath)) { //couldn't rename it in the project? happens when project not saved yet... //MessageBox.Show("Couldn't rename scenario in project! This shouldn't happen - check the project file XML."); } ProjectExplorer?.UpdateScenarioTreeNode(CurrentScenario); } SetProjectHasChanged(true); SetCurrentSaveItem(); } } public void AddScenarioToProject(YmtFile ymt) { if (ymt == null) return; if (CurrentProjectFile == null) { NewProject(); } if (ScenarioExistsInProject(ymt)) return; if (CurrentProjectFile.AddScenarioFile(ymt)) { ymt.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentScenario = ymt; RefreshUI(); if (CurrentScenarioNode != null) { ProjectExplorer?.TrySelectScenarioNodeTreeNode(CurrentScenarioNode); } } public void RemoveScenarioFromProject() { if (CurrentScenario == null) return; if (CurrentProjectFile == null) return; CurrentProjectFile.RemoveScenarioFile(CurrentScenario); CurrentScenario = null; LoadProjectTree(); RefreshUI(); } public bool ScenarioExistsInProject(YmtFile ymt) { if (ymt == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsScenario(ymt); } public ScenarioNode NewScenarioNode(ScenarioNode copy = null, bool copyPosition = false, bool selectNew = true) { if (CurrentScenario == null) return null; if (CurrentScenario.ScenarioRegion == null) return null; if (copy == null) { copy = CurrentScenarioNode; } var n = CurrentScenario.ScenarioRegion.AddNode(copy); bool cp = copyPosition && (copy != null); Vector3 pos = cp ? copy.Position : GetSpawnPos(10.0f); Quaternion ori = cp ? copy.Orientation : Quaternion.Identity; n.SetPosition(pos); n.SetOrientation(ori); if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectScenarioNodeTreeNode(n); CurrentScenarioNode = n; //ShowEditScenarioPanel(false); ShowEditScenarioNodePanel(false); } if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); } else { CurrentScenario.ScenarioRegion.BuildBVH(); CurrentScenario.ScenarioRegion.BuildVertices(); //for the graphics... } return n; } public bool DeleteScenarioNode() { if (CurrentScenario == null) return false; if (CurrentScenario.ScenarioRegion == null) return false; if (CurrentScenarioNode == null) return false; //if (MessageBox.Show("Are you sure you want to delete this scenario node?\n" + CurrentScenarioNode.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 = CurrentScenario.ScenarioRegion.RemoveNode(CurrentScenarioNode); } } else { res = CurrentScenario.ScenarioRegion.RemoveNode(CurrentScenarioNode); } if (!res) { MessageBox.Show("Unable to delete the scenario node. This shouldn't happen!"); } var delnode = CurrentScenarioNode; ProjectExplorer?.RemoveScenarioNodeTreeNode(CurrentScenarioNode); ProjectExplorer?.SetScenarioHasChanged(CurrentScenario, true); ClosePanel((EditScenarioNodePanel p) => { return p.Tag == delnode; }); CurrentScenarioNode = null; if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); WorldForm.SelectItem(null); } return true; } public bool IsCurrentScenarioNode(ScenarioNode node) { return node == CurrentScenarioNode; } public void SetScenarioChainEdge(MCScenarioChainingEdge e) { CurrentScenarioChainEdge = e; } public void AddScenarioChain() { if (CurrentScenario.ScenarioRegion == null) return; var paths = CurrentScenario?.CScenarioPointRegion?.Paths; if (paths == null) return; var copy = CurrentScenarioNode?.ChainingNode?.Chain; var copyn = CurrentScenarioNode?.ChainingNode; var copyp = CurrentScenarioNode?.MyPoint; var copye = CurrentScenarioChainEdge; var copycl = CurrentScenarioNode?.Cluster; MCScenarioChain chain = new MCScenarioChain(); chain.Unk1 = 1; //default value if (copy != null) { chain.Data = copy.Data; chain._Data.EdgeIds = new Array_ushort(); //start empty.. not really necessary } paths.AddChain(chain); //add 2 new nodes to the new chain. var pos1 = GetSpawnPos(10.0f); var pos2 = pos1 + Vector3.UnitX; ScenarioNode n1 = null;// CurrentScenario.ScenarioRegion.AddNode(); if (copycl != null) { ScenarioNode copyclnode = new ScenarioNode(CurrentScenario); copyclnode.Cluster = copycl; copyclnode.ClusterMyPoint = new MCScenarioPoint(CurrentScenario.CScenarioPointRegion); copyclnode.ClusterMyPoint.InteriorName = 493038497; //JenkHash.GenHash("none"); copyclnode.ClusterMyPoint.GroupName = 493038497; copyclnode.ClusterMyPoint.IMapName = 493038497; copyclnode.ClusterMyPoint.TimeStart = 0; copyclnode.ClusterMyPoint.TimeEnd = 24; n1 = CurrentScenario.ScenarioRegion.AddNode(copyclnode); } else { n1 = CurrentScenario.ScenarioRegion.AddNode(); } ScenarioNode n2 = CurrentScenario.ScenarioRegion.AddNode(); if (copyp != null) { n1.MyPoint.CopyFrom(copyp); n2.MyPoint.CopyFrom(copyp); } n1.ChainingNode = new MCScenarioChainingNode(); n2.ChainingNode = new MCScenarioChainingNode(); if (copyn != null) { n1.ChainingNode.CopyFrom(copyn); n2.ChainingNode.CopyFrom(copyn); } n1.ChainingNode.NotLast = true; n2.ChainingNode.NotFirst = true; n1.ChainingNode.ScenarioNode = n1; n2.ChainingNode.ScenarioNode = n2; paths.AddNode(n1.ChainingNode); paths.AddNode(n2.ChainingNode); n1.ChainingNode.Chain = chain; n2.ChainingNode.Chain = chain; var ed = new MCScenarioChainingEdge(); if (copye != null) { ed.Data = copye.Data; } ed.NodeFrom = n1.ChainingNode; ed.NodeTo = n2.ChainingNode; ed.NodeIndexFrom = (ushort)n1.ChainingNode.NodeIndex; ed.NodeIndexTo = (ushort)n2.ChainingNode.NodeIndex; paths.AddEdge(ed); chain.AddEdge(ed); n1.SetPosition(pos1); n2.SetPosition(pos2); ProjectExplorer?.LoadProjectTree(CurrentProjectFile); ProjectExplorer?.TrySelectScenarioNodeTreeNode(n1); CurrentScenarioNode = n1; CurrentScenarioChainEdge = ed; //LoadScenarioChainTabPage(); ////LoadScenarioTabPage(); ////LoadScenarioNodeTabPages(); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); } else { CurrentScenario.ScenarioRegion.BuildBVH(); CurrentScenario.ScenarioRegion.BuildVertices(); //for the graphics... } } public void AddScenarioCluster()//TODO: add defualt cluster points to new cluster { if (CurrentScenario == null) return; var sr = CurrentScenario.ScenarioRegion; if (sr == null) return; var rgn = CurrentScenario.CScenarioPointRegion; if (rgn == null) return; var copy = CurrentScenarioNode?.Cluster; MCScenarioPointCluster cluster = new MCScenarioPointCluster(rgn, copy); List clusterpoints = new List(); if (copy != null) { if (copy.Points?.MyPoints != null) { clusterpoints.AddRange(copy.Points.MyPoints); } } rgn.AddCluster(cluster); //add the base cluster to the region. var pos1 = GetSpawnPos(10.0f); var ncopy = new ScenarioNode(CurrentScenario);//copy an empty node to start with, to avoid creating default MyPoint var nc = sr.AddNode(ncopy); //add the base cluster's display node. nc.Cluster = cluster; nc.SetPosition(pos1); if (cluster.Points != null) { foreach (var cpt in clusterpoints) { //TODO: copy cluster points.... //or create some default points! } } ProjectExplorer?.LoadProjectTree(CurrentProjectFile); ProjectExplorer?.TrySelectScenarioNodeTreeNode(nc); CurrentScenarioNode = nc; //LoadScenarioClusterTabPage(); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); } else { CurrentScenario.ScenarioRegion.BuildBVH(); CurrentScenario.ScenarioRegion.BuildVertices(); //for the graphics... } } public void AddScenarioClusterPoint() { if (CurrentScenario == null) return; var sr = CurrentScenario.ScenarioRegion; if (sr == null) return; var rgn = CurrentScenario.CScenarioPointRegion; if (rgn == null) return; var cluster = CurrentScenarioNode?.Cluster; if (cluster == null) return; if (cluster.Points == null) { cluster.Points = new MCScenarioPointContainer(rgn); cluster.Points.Parent = cluster; } var copy = CurrentScenarioNode?.ClusterMyPoint; var pos1 = GetSpawnPos(10.0f); var ori1 = copy?.Orientation ?? Quaternion.Identity; var cn = new ScenarioNode(CurrentScenario);//copy a blank node var n = sr.AddNode(cn); var np = new MCScenarioPoint(rgn, copy); cluster.Points.AddMyPoint(np); n.ClusterMyPoint = np; n.Cluster = cluster; n.SetPosition(pos1); n.SetOrientation(ori1); ProjectExplorer?.LoadProjectTree(CurrentProjectFile); ProjectExplorer?.TrySelectScenarioNodeTreeNode(n); CurrentScenarioNode = n; //LoadScenarioClusterTabPage(); //LoadScenarioClusterPointTabPage(); ////LoadScenarioTabPage(); ////LoadScenarioNodeTabPages(); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); } else { CurrentScenario.ScenarioRegion.BuildBVH(); CurrentScenario.ScenarioRegion.BuildVertices(); //for the graphics... } } public void AddScenarioEntity()//TODO: add default entity point(s) to entity { if (CurrentScenario == null) return; var sr = CurrentScenario.ScenarioRegion; if (sr == null) return; var rgn = CurrentScenario.CScenarioPointRegion; if (rgn == null) return; var copy = CurrentScenarioNode?.Entity; MCScenarioEntityOverride entity = new MCScenarioEntityOverride(rgn, copy); List entpoints = new List(); if (copy != null) { if (copy.ScenarioPoints != null) { entpoints.AddRange(copy.ScenarioPoints); } } rgn.AddEntity(entity); //add the base entity to the region. var pos1 = GetSpawnPos(10.0f); var ncopy = new ScenarioNode(CurrentScenario);//copy an empty node to start with, to avoid creating default MyPoint var ne = sr.AddNode(ncopy); //add the base entity's display node. ne.Entity = entity; ne.SetPosition(pos1); if (entity.ScenarioPoints != null) { foreach (var cpt in entpoints) { //TODO: copy entity points.... //or create some default points! } } ProjectExplorer?.LoadProjectTree(CurrentProjectFile); ProjectExplorer?.TrySelectScenarioNodeTreeNode(ne); CurrentScenarioNode = ne; //LoadScenarioEntityTabPage(); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); } else { CurrentScenario.ScenarioRegion.BuildBVH(); CurrentScenario.ScenarioRegion.BuildVertices(); //for the graphics... } } public void AddScenarioEntityPoint() { if (CurrentScenario == null) return; var sr = CurrentScenario.ScenarioRegion; if (sr == null) return; var rgn = CurrentScenario.CScenarioPointRegion; if (rgn == null) return; var entity = CurrentScenarioNode?.Entity; if (entity == null) return; var copy = CurrentScenarioNode?.EntityPoint; var pos1 = GetSpawnPos(10.0f); var ori1 = copy?.Orientation ?? Quaternion.Identity; var cn = new ScenarioNode(CurrentScenario);//copy a blank node var n = sr.AddNode(cn); var np = new MCExtensionDefSpawnPoint(rgn, copy); entity.AddScenarioPoint(np); n.EntityPoint = np; n.Entity = entity; n.SetPosition(pos1); n.SetOrientation(ori1); ProjectExplorer?.LoadProjectTree(CurrentProjectFile); ProjectExplorer?.TrySelectScenarioNodeTreeNode(n); CurrentScenarioNode = n; //LoadScenarioEntityTabPage(); //LoadScenarioEntityPointTabPage(); ////LoadScenarioTabPage(); ////LoadScenarioNodeTabPages(); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); } else { CurrentScenario.ScenarioRegion.BuildBVH(); CurrentScenario.ScenarioRegion.BuildVertices(); //for the graphics... } } public void DeleteScenarioChain() { if (CurrentScenario == null) return; if (CurrentScenarioNode == null) return; if (CurrentScenarioNode.ChainingNode == null) return; if (CurrentScenarioNode.ChainingNode.Chain == null) return; var chain = CurrentScenarioNode.ChainingNode.Chain; var paths = CurrentScenario.CScenarioPointRegion?.Paths; if (paths == null) return; var rgn = CurrentScenario.ScenarioRegion; if (rgn == null) return; if (MessageBox.Show("Are you sure you want to delete this scenario chain?\n" + chain.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; } bool delpoints = false; if (MessageBox.Show("Delete all Scenario Points for this chain as well?", "Confirm delete points", MessageBoxButtons.YesNo) == DialogResult.Yes) { delpoints = true; } Dictionary ndict = new Dictionary(); var edges = chain.Edges; if (edges != null) { foreach (var edge in edges) { //paths.RemoveEdge(edge); //removing nodes also removes edges! paths.RemoveNode(edge.NodeFrom); paths.RemoveNode(edge.NodeTo); ndict[edge.NodeFrom] = 1; ndict[edge.NodeTo] = 1; } } paths.RemoveChain(chain); List delnodes = new List(); foreach (var node in rgn.Nodes) { if ((node.ChainingNode != null) && (ndict.ContainsKey(node.ChainingNode))) { delnodes.Add(node); } } foreach (var delnode in delnodes) { delnode.ChainingNode = null;//this chaining node has been removed from the region. remove this association. if (delpoints) { rgn.RemoveNode(delnode); } } var cn = CurrentScenarioNode; var cs = CurrentScenario; ProjectExplorer?.LoadProjectTree(CurrentProjectFile); if (!delpoints && (cn != null)) { ProjectExplorer?.TrySelectScenarioNodeTreeNode(cn); } else { ProjectExplorer?.TrySelectScenarioTreeNode(cs); } ClosePanel((EditScenarioNodePanel p) => { return p.Tag == cn; }); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(cs, false); if (delpoints) { WorldForm.SelectItem(null); } } else if (cs?.ScenarioRegion != null) { cs.ScenarioRegion.BuildBVH(); cs.ScenarioRegion.BuildVertices(); //for the graphics... } } public void DeleteScenarioCluster() { if (CurrentScenario == null) return; if (CurrentScenarioNode == null) return; if (CurrentScenarioNode.Cluster == null) return; var cluster = CurrentScenarioNode.Cluster; var rgn = CurrentScenario.ScenarioRegion; if (rgn == null) return; var crgn = CurrentScenario.CScenarioPointRegion; if (crgn == null) return; if (MessageBox.Show("Are you sure you want to delete this scenario cluster?\n" + cluster.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; } bool delpoints = false; if (MessageBox.Show("Delete all Scenario Points for this cluster as well?", "Confirm delete points", MessageBoxButtons.YesNo) == DialogResult.Yes) { delpoints = true; } crgn.RemoveCluster(cluster); Dictionary ndict = new Dictionary(); if (cluster?.Points?.MyPoints != null) { foreach (var point in cluster.Points.MyPoints) { ndict[point] = 1; } } List delnodes = new List(); foreach (var node in rgn.Nodes) { if ((node.ClusterMyPoint != null) && (ndict.ContainsKey(node.ClusterMyPoint))) { delnodes.Add(node); } else if (node.Cluster == cluster) { delnodes.Add(node); } } foreach (var delnode in delnodes) { if (!delpoints && (crgn.Points != null) && (delnode.ClusterMyPoint != null)) { var copypt = new MCScenarioPoint(crgn, delnode.ClusterMyPoint); crgn.Points.AddMyPoint(copypt); delnode.MyPoint = copypt; } bool iscl = false; if ((delnode.Cluster != null) && (delnode.ClusterMyPoint == null) && (delnode.ClusterLoadSavePoint == null)) { iscl = true; } delnode.Cluster = null; delnode.ClusterMyPoint = null;//this cluster point has been removed from the region. remove this association. delnode.ClusterLoadSavePoint = null; if (delpoints) { //if ((delnode.ChainingNode == null) && (delnode.EntityPoint == null)) { rgn.RemoveNode(delnode); } } else if (iscl) { rgn.RemoveNode(delnode); //remove the cluster node itself. } } var cn = CurrentScenarioNode; var cs = CurrentScenario; ProjectExplorer?.LoadProjectTree(CurrentProjectFile); if (!delpoints && (cn != null)) { ProjectExplorer?.TrySelectScenarioNodeTreeNode(cn); } else { ProjectExplorer?.TrySelectScenarioTreeNode(cs); } ClosePanel((EditScenarioNodePanel p) => { return p.Tag == cn; }); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(cs, false); if (delpoints || ((cn != null) && (cn.MyPoint == null))) { WorldForm.SelectItem(null); } } else if (cs?.ScenarioRegion != null) { cs.ScenarioRegion.BuildBVH(); cs.ScenarioRegion.BuildVertices(); //for the graphics... } } public void DeleteScenarioEntity() { if (CurrentScenario == null) return; if (CurrentScenarioNode == null) return; if (CurrentScenarioNode.Entity == null) return; var entity = CurrentScenarioNode.Entity; var rgn = CurrentScenario.ScenarioRegion; if (rgn == null) return; var crgn = CurrentScenario.CScenarioPointRegion; if (crgn == null) return; if (MessageBox.Show("Are you sure you want to delete this scenario entity override, and all its override points?\n" + entity.ToString() + "\n\nThis operation cannot be undone. Continue?", "Confirm delete", MessageBoxButtons.YesNo) != DialogResult.Yes) { return; } //bool delpoints = false; //if (MessageBox.Show("Delete all Scenario Points for this entity override as well?", "Confirm delete points", MessageBoxButtons.YesNo) == DialogResult.Yes) //{ // delpoints = true; //} crgn.RemoveEntity(entity); Dictionary ndict = new Dictionary(); if (entity.ScenarioPoints != null) { foreach (var point in entity.ScenarioPoints) { ndict[point] = 1; } } List delnodes = new List(); foreach (var node in rgn.Nodes) { if ((node.EntityPoint != null) && (ndict.ContainsKey(node.EntityPoint))) { delnodes.Add(node); } else if (node.Entity == entity) { delnodes.Add(node); } } foreach (var delnode in delnodes) { delnode.Entity = null; delnode.EntityPoint = null;//this entity point has been removed from the region. remove this association. rgn.RemoveNode(delnode); } var cn = CurrentScenarioNode; var cs = CurrentScenario; ProjectExplorer?.LoadProjectTree(CurrentProjectFile); ProjectExplorer?.TrySelectScenarioTreeNode(cs); ClosePanel((EditScenarioNodePanel p) => { return p.Tag == cn; }); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(cs, false); WorldForm.SelectItem(null); } else if (cs?.ScenarioRegion != null) { cs.ScenarioRegion.BuildBVH(); cs.ScenarioRegion.BuildVertices(); //for the graphics... } } public void ImportScenarioChain() { var paths = CurrentScenario?.CScenarioPointRegion?.Paths; if (paths == null) return; var rgn = CurrentScenario.ScenarioRegion; if (rgn == null) return; TextInputForm f = new TextInputForm(); f.TitleText = "Import scenario chain points"; f.PromptText = "Input chain points in CSV (or TSV) format. Direction is in radians. NavSpeed is from 0 to 15. NavMode can be either Direct, NavMesh, or Roads. ScenarioType is the name of the scenario type to use."; f.MainText = "X, Y, Z, Direction, NavSpeed, NavMode, ScenarioType, ModelSet, Flags"; if (f.ShowDialog() == DialogResult.Cancel) return; var stypes = Scenarios.ScenarioTypes; //these are loaded by Scenarios.Init ScenarioType defaulttype = null; if (stypes != null) { defaulttype = stypes.GetScenarioType(1194480618); //"drive"; } AmbientModelSet defaultmodelset = null; uint defaultflags = 0; ScenarioNode thisnode = null; ScenarioNode lastnode = null; MCScenarioChainingEdge lastedge = null; var str = f.MainText; var lines = str.Split('\n'); if (lines.Length < 2) { return;//need at least 2 lines (1 point) to work with... } MCScenarioChain chain = new MCScenarioChain(); paths.AddChain(chain); for (int i = 0; i < lines.Length; i++) { var line = lines[i]; var delim = line.Contains(",") ? "," : " "; var vals = line.Split(new[] { delim }, StringSplitOptions.RemoveEmptyEntries); if (vals.Length < 3) continue; if (vals[0].StartsWith("X")) continue; Vector3 pos = Vector3.Zero; float dir = 0; var action = CScenarioChainingEdge__eAction.Move; var navMode = CScenarioChainingEdge__eNavMode.Direct; var navSpeed = CScenarioChainingEdge__eNavSpeed.Unk_00_3279574318; var stype = new ScenarioTypeRef(defaulttype); var modelset = defaultmodelset; var flags = defaultflags; var ok = true; ok = ok && FloatUtil.TryParse(vals[0].Trim(), out pos.X); ok = ok && FloatUtil.TryParse(vals[1].Trim(), out pos.Y); ok = ok && FloatUtil.TryParse(vals[2].Trim(), out pos.Z); if (vals.Length > 3) { ok = ok && FloatUtil.TryParse(vals[3].Trim(), out dir); while (dir > Math.PI) dir -= 2.0f * (float)Math.PI; while (dir < -Math.PI) dir += 2.0f * (float)Math.PI; } if (vals.Length > 4) { byte nsb = 0; byte.TryParse(vals[4].Trim(), out nsb); if (nsb > 15) nsb = 15; navSpeed = (CScenarioChainingEdge__eNavSpeed)nsb; } if (vals.Length > 5) { switch (vals[5].Trim()) { case "Direct": navMode = CScenarioChainingEdge__eNavMode.Direct; break; case "NavMesh": navMode = CScenarioChainingEdge__eNavMode.NavMesh; break; case "Roads": navMode = CScenarioChainingEdge__eNavMode.Roads; break; } } if (vals.Length > 6) { var sthash = JenkHash.GenHash(vals[6].Trim().ToLowerInvariant()); var st = stypes?.GetScenarioType(sthash); if (st != null) { stype = new ScenarioTypeRef(st); } else { var stg = stypes?.GetScenarioTypeGroup(sthash); if (stg != null) { stype = new ScenarioTypeRef(stg); } else { stype = new ScenarioTypeRef(defaulttype); } } } if (vals.Length > 7) { var mshash = JenkHash.GenHash(vals[7].Trim().ToLowerInvariant()); modelset = stypes?.GetPedModelSet(mshash) ?? null; if (modelset == null) modelset = stypes?.GetVehicleModelSet(mshash) ?? null; } if (vals.Length > 8) { if (!uint.TryParse(vals[8].Trim(), out flags)) flags = defaultflags; } if (!ok) continue; thisnode = rgn.AddNode(); thisnode.MyPoint.Direction = dir; thisnode.MyPoint.Type = stype; thisnode.MyPoint.ModelSet = modelset; thisnode.MyPoint.Flags = (CScenarioPointFlags__Flags)flags; thisnode.ChainingNode = new MCScenarioChainingNode(); thisnode.ChainingNode.ScenarioNode = thisnode; thisnode.ChainingNode.Chain = chain; thisnode.ChainingNode.Type = stype; thisnode.ChainingNode.TypeHash = stype.NameHash; thisnode.ChainingNode.NotLast = (i < (lines.Length - 1)); thisnode.ChainingNode.NotFirst = (lastnode != null); thisnode.SetPosition(pos); thisnode.Orientation = thisnode.MyPoint.Orientation; paths.AddNode(thisnode.ChainingNode); if (lastnode != null) { var edge = new MCScenarioChainingEdge(); edge.NodeFrom = lastnode.ChainingNode; edge.NodeTo = thisnode.ChainingNode; edge.NodeIndexFrom = (ushort)lastnode.ChainingNode.NodeIndex; edge.NodeIndexTo = (ushort)thisnode.ChainingNode.NodeIndex; edge.Action = action; edge.NavMode = navMode; edge.NavSpeed = navSpeed; paths.AddEdge(edge); chain.AddEdge(edge); lastedge = edge; } lastnode = thisnode; } LoadProjectTree(); if (lastnode != null) { ProjectExplorer?.TrySelectScenarioNodeTreeNode(lastnode); CurrentScenarioNode = lastnode; } //CurrentScenarioChainEdge = lastedge; //LoadScenarioChainTabPage(); //LoadScenarioTabPage(); //LoadScenarioNodeTabPages(); if (WorldForm != null) { WorldForm.UpdateScenarioGraphics(CurrentScenario, false); } else { CurrentScenario.ScenarioRegion.BuildBVH(); CurrentScenario.ScenarioRegion.BuildVertices(); //for the graphics... } } public void NewAudioFile() { if (CurrentProjectFile == null) { NewProject(); } if (CurrentProjectFile == null) return; int testi = 1; string fname = string.Empty; bool filenameok = false; while (!filenameok) { fname = "dlc" + testi.ToString() + "_game.dat151.rel"; filenameok = !CurrentProjectFile.ContainsAudioRel(fname); testi++; } lock (projectsyncroot) { RelFile rel = CurrentProjectFile.AddAudioRelFile(fname); if (rel != null) { rel.RelType = RelDatFileType.Dat151; //TODO: different types } } CurrentProjectFile.HasChanged = true; LoadProjectTree(); } public void OpenAudioFile() { string[] files = ShowOpenDialogMulti("DatRel files|*.rel", string.Empty); //TODO: better filter? if (files == null) { return; } if (CurrentProjectFile == null) { NewProject(); } foreach (string file in files) { if (!File.Exists(file)) continue; var rel = CurrentProjectFile.AddAudioRelFile(file); if (rel != null) { SetProjectHasChanged(true); LoadAudioRelFromFile(rel, file); LoadProjectTree(); } else { MessageBox.Show("Couldn't add\n" + file + "\n - the file already exists in the project."); } } } public void SaveAudioFile(bool saveas = false) { if (CurrentAudioFile == null) return; string relname = CurrentAudioFile.Name; string filepath = CurrentAudioFile.FilePath; if (string.IsNullOrEmpty(filepath)) { filepath = relname; } string origfile = filepath; if (!File.Exists(filepath)) { saveas = true; } byte[] data; lock (projectsyncroot) //need to sync writes to scenario... { saveas = saveas || string.IsNullOrEmpty(filepath); if (saveas) { filepath = ShowSaveDialog("DatRel files|*.rel", filepath); if (string.IsNullOrEmpty(filepath)) { return; } string newname = Path.GetFileNameWithoutExtension(filepath); JenkIndex.Ensure(newname); CurrentAudioFile.FilePath = filepath; CurrentAudioFile.RpfFileEntry.Name = new FileInfo(filepath).Name; CurrentAudioFile.Name = CurrentAudioFile.RpfFileEntry.Name; } data = CurrentAudioFile.Save(); } if (data != null) { File.WriteAllBytes(filepath, data); } SetAudioFileHasChanged(false); if (saveas) { //ShowEditAudioFilePanel(false); if (CurrentProjectFile != null) { string origpath = CurrentProjectFile.GetRelativePath(origfile); string newpath = CurrentProjectFile.GetRelativePath(CurrentAudioFile.FilePath); if (!CurrentProjectFile.RenameAudioRel(origpath, newpath)) { //couldn't rename it in the project? happens when project not saved yet... //MessageBox.Show("Couldn't rename audio rel in project! This shouldn't happen - check the project file XML."); } ProjectExplorer?.UpdateAudioRelTreeNode(CurrentAudioFile); } SetProjectHasChanged(true); SetCurrentSaveItem(); } } public void AddAudioFileToProject(RelFile rel) { if (rel == null) return; if (CurrentProjectFile == null) { NewProject(); } if (AudioFileExistsInProject(rel)) return; if (CurrentProjectFile.AddAudioRelFile(rel)) { rel.HasChanged = true; CurrentProjectFile.HasChanged = true; LoadProjectTree(); } CurrentAudioFile = rel; RefreshUI(); if (CurrentAudioZone != null) { ProjectExplorer?.TrySelectAudioZoneTreeNode(CurrentAudioZone); } else if (CurrentAudioEmitter != null) { ProjectExplorer?.TrySelectAudioEmitterTreeNode(CurrentAudioEmitter); } } public void RemoveAudioFileFromProject() { if (CurrentAudioFile == null) return; if (CurrentProjectFile == null) return; CurrentProjectFile.RemoveAudioRelFile(CurrentAudioFile); CurrentAudioFile = null; LoadProjectTree(); RefreshUI(); } public bool AudioFileExistsInProject(RelFile rel) { if (rel == null) return false; if (CurrentProjectFile == null) return false; return CurrentProjectFile.ContainsAudioRel(rel); } public AudioPlacement NewAudioZone(AudioPlacement copy = null, bool copyPosition = false, bool selectNew = true) { if (CurrentAudioFile == null) return null; if (copy == null) { copy = CurrentAudioZone; } bool cp = copyPosition && (copy != null); var zone = new Dat151AmbientZone(CurrentAudioFile); //AA800424 box, line //AA800420 sphere zone.Flags0 = cp ? copy.AudioZone.Flags0.Value : 0xAA800424; zone.Flags1 = cp ? copy.AudioZone.Flags1 : 0; zone.Flags2 = cp ? copy.AudioZone.Flags2 : 0; zone.Shape = cp ? copy.AudioZone.Shape : Dat151ZoneShape.Box; zone.InnerSize = cp ? copy.AudioZone.InnerSize : Vector3.One * 10.0f; zone.InnerAngle = cp ? copy.AudioZone.InnerAngle : 0; zone.InnerVec1 = cp ? copy.AudioZone.InnerVec1 : Vector4.Zero; zone.InnerVec2 = cp ? copy.AudioZone.InnerVec2 : new Vector4(1, 1, 1, 0); zone.InnerVec3 = cp ? copy.AudioZone.InnerVec3 : Vector3.Zero; zone.OuterSize = cp ? copy.AudioZone.OuterSize : Vector3.One * 15.0f; zone.OuterAngle = cp ? copy.AudioZone.OuterAngle : 0; zone.OuterVec1 = cp ? copy.AudioZone.OuterVec1 : Vector4.Zero; zone.OuterVec2 = cp ? copy.AudioZone.OuterVec2 : new Vector4(1, 1, 1, 0); zone.OuterVec3 = cp ? copy.AudioZone.OuterVec3 : Vector3.Zero; zone.UnkVec1 = cp ? copy.AudioZone.UnkVec1 : new Vector4(0, 0, 1, 0); zone.UnkVec2 = cp ? copy.AudioZone.UnkVec2 : new Vector4(1, -1, -1, 0); zone.UnkHash0 = cp ? copy.AudioZone.UnkHash0 : 0; zone.UnkHash1 = cp ? copy.AudioZone.UnkHash1 : 0; zone.UnkVec3 = cp ? copy.AudioZone.UnkVec3 : new Vector2(-1, 0); zone.Unk14 = cp ? copy.AudioZone.Unk14 : (byte)4; zone.Unk15 = cp ? copy.AudioZone.Unk15 : (byte)1; zone.Unk16 = cp ? copy.AudioZone.Unk16 : (byte)0; zone.HashesCount = cp ? copy.AudioZone.HashesCount: (byte)0; zone.Hashes = cp ? copy.AudioZone.Hashes : null; zone.ExtParamsCount = cp ? copy.AudioZone.ExtParamsCount : 0; zone.ExtParams = cp ? copy.AudioZone.ExtParams : null; zone.Name = "zone1"; zone.NameHash = JenkHash.GenHash(zone.Name); var ap = new AudioPlacement(CurrentAudioFile, zone); ap.Name = zone.Name; ap.NameHash = zone.NameHash; Vector3 pos = cp ? copy.Position : GetSpawnPos(20.0f); Quaternion ori = cp ? copy.Orientation : Quaternion.Identity; ap.SetPosition(pos); ap.SetOrientation(ori); CurrentAudioFile.AddRelData(zone); if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectAudioZoneTreeNode(ap); CurrentAudioZone = ap; ShowEditAudioZonePanel(false); } if (WorldForm != null) { WorldForm.UpdateAudioPlacementGraphics(CurrentAudioFile); } return ap; } public bool DeleteAudioZone() { if (CurrentAudioZone?.RelFile != CurrentAudioFile) return false; if (CurrentAudioFile?.RelDatas == null) return false; //nothing to delete.. if (CurrentAudioFile?.RelDatasSorted == null) return false; //nothing to delete.. if (CurrentAudioZone?.AudioZone == null) return false; //if (MessageBox.Show("Are you sure you want to delete this audio zone?\n" + CurrentAudioZone.GetNameString() + "\n" + CurrentAudioZone.Position.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 = CurrentAudioFile.RemoveRelData(CurrentAudioZone.AudioZone); WorldForm.UpdateAudioPlacementGraphics(CurrentAudioFile); } } else { res = CurrentAudioFile.RemoveRelData(CurrentAudioZone.AudioZone); } if (!res) { MessageBox.Show("Unspecified error occurred when removing the audio zone from the file!"); } var delzone = CurrentAudioZone; var delrel = CurrentAudioFile; ProjectExplorer?.RemoveAudioZoneTreeNode(delzone); ProjectExplorer?.SetAudioRelHasChanged(delrel, true); ClosePanel((EditAudioZonePanel p) => { return p.CurrentZone.AudioZone == delzone.AudioZone; }); CurrentAudioZone = null; if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool IsCurrentAudioZone(AudioPlacement zone) { return zone == CurrentAudioZone; } public AudioPlacement NewAudioEmitter(AudioPlacement copy = null, bool copyPosition = false, bool selectNew = true) { if (CurrentAudioFile == null) return null; if (copy == null) { copy = CurrentAudioEmitter; } bool cp = copyPosition && (copy != null); var emitter = new Dat151AmbientEmitter(CurrentAudioFile); emitter.Flags0 = cp ? copy.AudioEmitter.Flags0.Value : 0xAA001100; emitter.Flags5 = cp ? copy.AudioEmitter.Flags5.Value : 0xFFFFFFFF; emitter.InnerRad = cp ? copy.AudioEmitter.InnerRad : 0.0f; emitter.OuterRad = cp ? copy.AudioEmitter.OuterRad : 20.0f; emitter.Unk01 = cp ? copy.AudioEmitter.Unk01 : 1.0f; emitter.Unk02 = cp ? copy.AudioEmitter.Unk02.Value : (byte)0; emitter.Unk03 = cp ? copy.AudioEmitter.Unk03.Value : (byte)0; emitter.Unk04 = cp ? copy.AudioEmitter.Unk04.Value : (byte)160; emitter.Unk05 = cp ? copy.AudioEmitter.Unk05.Value : (byte)5; emitter.Unk06 = cp ? copy.AudioEmitter.Unk06.Value : (ushort)0; emitter.Unk07 = cp ? copy.AudioEmitter.Unk07.Value : (ushort)0; emitter.Unk08 = cp ? copy.AudioEmitter.Unk08.Value : (byte)0; emitter.Unk09 = cp ? copy.AudioEmitter.Unk09.Value : (byte)1; emitter.Unk10 = cp ? copy.AudioEmitter.Unk10.Value : (byte)1; emitter.Unk11 = cp ? copy.AudioEmitter.Unk11.Value : (byte)1; emitter.Unk12 = cp ? copy.AudioEmitter.Unk12.Value : (byte)100; emitter.Unk13 = cp ? copy.AudioEmitter.Unk13.Value : (byte)3; emitter.Name = "emitter1"; emitter.NameHash = JenkHash.GenHash(emitter.Name); var ap = new AudioPlacement(CurrentAudioFile, emitter); ap.Name = emitter.Name; ap.NameHash = emitter.NameHash; Vector3 pos = cp ? copy.Position : GetSpawnPos(20.0f); Quaternion ori = cp ? copy.Orientation : Quaternion.Identity; ap.SetPosition(pos); ap.SetOrientation(ori); CurrentAudioFile.AddRelData(emitter); if (selectNew) { LoadProjectTree(); ProjectExplorer?.TrySelectAudioEmitterTreeNode(ap); CurrentAudioEmitter = ap; ShowEditAudioEmitterPanel(false); } if (WorldForm != null) { WorldForm.UpdateAudioPlacementGraphics(CurrentAudioFile); } return ap; } public bool DeleteAudioEmitter() { if (CurrentAudioEmitter?.RelFile != CurrentAudioFile) return false; if (CurrentAudioFile?.RelDatas == null) return false; //nothing to delete.. if (CurrentAudioFile?.RelDatasSorted == null) return false; //nothing to delete.. if (CurrentAudioEmitter?.AudioEmitter == null) return false; //if (MessageBox.Show("Are you sure you want to delete this audio emitter?\n" + CurrentAudioEmitter.GetNameString() + "\n" + CurrentAudioEmitter.Position.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 = CurrentAudioFile.RemoveRelData(CurrentAudioEmitter.AudioEmitter); WorldForm.UpdateAudioPlacementGraphics(CurrentAudioFile); } } else { res = CurrentAudioFile.RemoveRelData(CurrentAudioEmitter.AudioEmitter); } if (!res) { MessageBox.Show("Unspecified error occurred when removing the audio emitter from the file!"); } var delem = CurrentAudioEmitter; var delrel = CurrentAudioFile; ProjectExplorer?.RemoveAudioEmitterTreeNode(delem); ProjectExplorer?.SetAudioRelHasChanged(delrel, true); CurrentAudioEmitter = null; ClosePanel((EditAudioEmitterPanel p) => { return p.CurrentEmitter.AudioEmitter == delem.AudioEmitter; }); if (WorldForm != null) { WorldForm.SelectItem(null); } return true; } public bool IsCurrentAudioEmitter(AudioPlacement emitter) { return emitter == CurrentAudioEmitter; } public void NewAudioZoneList() { if (CurrentAudioFile == null) return; var zonelist = new Dat151AmbientZoneList(CurrentAudioFile); zonelist.Name = "zonelist1"; zonelist.NameHash = JenkHash.GenHash(zonelist.Name); CurrentAudioFile.AddRelData(zonelist); LoadProjectTree(); ProjectExplorer?.TrySelectAudioZoneListTreeNode(zonelist); CurrentAudioZoneList = zonelist; ShowEditAudioZoneListPanel(false); } public bool DeleteAudioZoneList() { if (CurrentAudioZoneList?.Rel != CurrentAudioFile) return false; if (CurrentAudioFile?.RelDatas == null) return false; //nothing to delete.. if (CurrentAudioFile?.RelDatasSorted == null) return false; //nothing to delete.. //if (MessageBox.Show("Are you sure you want to delete this audio zone list?\n" + CurrentAudioZoneList.GetNameString() + "\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 = CurrentAudioFile.RemoveRelData(CurrentAudioZoneList); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentAudioFile.RemoveRelData(CurrentAudioZoneList); } if (!res) { MessageBox.Show("Unspecified error occurred when removing the audio zone list from the file!"); } var delzl = CurrentAudioZoneList; var delrel = CurrentAudioFile; ProjectExplorer?.RemoveAudioZoneListTreeNode(delzl); ProjectExplorer?.SetAudioRelHasChanged(delrel, true); ClosePanel((EditAudioZoneListPanel p) => { return p.Tag == delzl; }); CurrentAudioZoneList = null; return true; } public bool IsCurrentAudioZoneList(Dat151AmbientZoneList list) { return list == CurrentAudioZoneList; } public void NewAudioEmitterList() { if (CurrentAudioFile == null) return; var emlist = new Dat151AmbientEmitterList(CurrentAudioFile); emlist.Name = "emitterlist1"; emlist.NameHash = JenkHash.GenHash(emlist.Name); CurrentAudioFile.AddRelData(emlist); LoadProjectTree(); ProjectExplorer?.TrySelectAudioEmitterListTreeNode(emlist); CurrentAudioEmitterList = emlist; ShowEditAudioEmitterListPanel(false); } public bool DeleteAudioEmitterList() { if (CurrentAudioEmitterList?.Rel != CurrentAudioFile) return false; if (CurrentAudioFile?.RelDatas == null) return false; //nothing to delete.. if (CurrentAudioFile?.RelDatasSorted == null) return false; //nothing to delete.. //if (MessageBox.Show("Are you sure you want to delete this audio emitter list?\n" + CurrentAudioEmitterList.GetNameString() + "\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 = CurrentAudioFile.RemoveRelData(CurrentAudioEmitterList); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentAudioFile.RemoveRelData(CurrentAudioEmitterList); } if (!res) { MessageBox.Show("Unspecified error occurred when removing the audio emitter list from the file!"); } var delel = CurrentAudioEmitterList; var delrel = CurrentAudioFile; ProjectExplorer?.RemoveAudioEmitterListTreeNode(delel); ProjectExplorer?.SetAudioRelHasChanged(delrel, true); ClosePanel((EditAudioEmitterListPanel p) => { return p.Tag == delel; }); CurrentAudioEmitterList = null; return true; } public bool IsCurrentAudioEmitterList(Dat151AmbientEmitterList list) { return list == CurrentAudioEmitterList; } public void NewAudioInterior() { if (CurrentAudioFile == null) return; var interior = new Dat151Interior(CurrentAudioFile); interior.Name = "interior1"; interior.NameHash = JenkHash.GenHash(interior.Name); interior.Unk0 = 0xAAAAA844; interior.Unk1 = 0xD4855127; CurrentAudioFile.AddRelData(interior); LoadProjectTree(); ProjectExplorer?.TrySelectAudioInteriorTreeNode(interior); CurrentAudioInterior = interior; ShowEditAudioInteriorPanel(false); } public bool DeleteAudioInterior() { if (CurrentAudioInterior?.Rel != CurrentAudioFile) return false; if (CurrentAudioFile?.RelDatas == null) return false; //nothing to delete.. if (CurrentAudioFile?.RelDatasSorted == null) return false; //nothing to delete.. if (MessageBox.Show("Are you sure you want to delete this audio interior?\n" + CurrentAudioInterior.GetNameString() + "\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 = CurrentAudioFile.RemoveRelData(CurrentAudioInterior); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentAudioFile.RemoveRelData(CurrentAudioInterior); } if (!res) { MessageBox.Show("Unspecified error occurred when removing the audio interior from the file!"); } var delel = CurrentAudioInterior; var delrel = CurrentAudioFile; ProjectExplorer?.RemoveAudioInteriorTreeNode(delel); ProjectExplorer?.SetAudioRelHasChanged(delrel, true); ClosePanel((EditAudioInteriorPanel p) => { return p.Tag == delel; }); CurrentAudioInterior = null; return true; } public bool IsCurrentAudioInterior(Dat151Interior interior) { return interior == CurrentAudioInterior; } public void NewAudioInteriorRoom() { if (CurrentAudioFile == null) return; var room = new Dat151InteriorRoom(CurrentAudioFile); room.Name = "room1"; room.NameHash = JenkHash.GenHash(room.Name); room.Flags0 = 0xAAAAAAAA; room.Unk06 = (uint)MetaName.null_sound; room.Unk14 = 3565506855;//? CurrentAudioFile.AddRelData(room); LoadProjectTree(); ProjectExplorer?.TrySelectAudioInteriorRoomTreeNode(room); CurrentAudioInteriorRoom = room; ShowEditAudioInteriorRoomPanel(false); } public bool DeleteAudioInteriorRoom() { if (CurrentAudioInteriorRoom?.Rel != CurrentAudioFile) return false; if (CurrentAudioFile?.RelDatas == null) return false; //nothing to delete.. if (CurrentAudioFile?.RelDatasSorted == null) return false; //nothing to delete.. if (MessageBox.Show("Are you sure you want to delete this audio interior room?\n" + CurrentAudioInteriorRoom.GetNameString() + "\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 = CurrentAudioFile.RemoveRelData(CurrentAudioInteriorRoom); //WorldForm.SelectItem(null, null, null); } } else { res = CurrentAudioFile.RemoveRelData(CurrentAudioInteriorRoom); } if (!res) { MessageBox.Show("Unspecified error occurred when removing the audio interior from the file!"); } var delel = CurrentAudioInteriorRoom; var delrel = CurrentAudioFile; ProjectExplorer?.RemoveAudioInteriorRoomTreeNode(delel); ProjectExplorer?.SetAudioRelHasChanged(delrel, true); ClosePanel((EditAudioInteriorRoomPanel p) => { return p.Tag == delel; }); CurrentAudioInteriorRoom = null; return true; } public bool IsCurrentAudioInteriorRoom(Dat151InteriorRoom room) { return room == CurrentAudioInteriorRoom; } public void GetVisibleYmaps(Camera camera, Dictionary ymaps) { if (hidegtavmap) { ymaps.Clear(); //remove all the gtav ymaps. } lock (projectsyncroot) { if (renderitems && (CurrentProjectFile != null)) { for (int i = 0; i < CurrentProjectFile.YmapFiles.Count; i++) { var ymap = CurrentProjectFile.YmapFiles[i]; if (ymap.Loaded) { // make sure we're replacing ymaps that have been added by the end-user. if (ymap.RpfFileEntry.ShortNameHash == 0) { ymap.RpfFileEntry.ShortNameHash = JenkHash.GenHash(ymap.RpfFileEntry.GetShortNameLower()); } ymaps[ymap.RpfFileEntry.ShortNameHash] = ymap; } } visiblemloentities.Clear(); foreach (var kvp in ymaps) { var ymap = kvp.Value; if (ymap.AllEntities != null) { foreach (var ent in ymap.AllEntities) { if (ent.Archetype == null) continue; Archetype parch = null; projectarchetypes.TryGetValue(ent.Archetype.Hash, out parch); if ((parch != null) && (ent.Archetype != parch)) { ent.SetArchetype(parch); //swap archetype to project one... if (ent.IsMlo) { ent.MloInstance.InitYmapEntityArchetypes(GameFileCache); } } } } if (ymap.MloEntities != null) { 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; } } } } } } public void GetVisibleYbns(Camera camera, List ybns, Dictionary interiors) { if (hidegtavmap) { ybns.Clear(); } lock (projectsyncroot) { if (CurrentProjectFile == null) return; visibleybns.Clear(); for (int i = 0; i < ybns.Count; i++) { var ybn = ybns[i]; visibleybns[ybn.Name] = ybn; } for (int i = 0; i < CurrentProjectFile.YbnFiles.Count; i++) { var ybn = CurrentProjectFile.YbnFiles[i]; if (ybn.Loaded) { if (!visiblemloentities.ContainsKey((ybn.RpfFileEntry != null) ? ybn.RpfFileEntry.ShortNameHash : 0)) { visibleybns[ybn.Name] = ybn; } } } ybns.Clear(); foreach (var ybn in visibleybns.Values) { ybns.Add(ybn); } //messy way to gather the interior ybns! projectybns.Clear(); for (int i = 0; i < CurrentProjectFile.YbnFiles.Count; i++) { var ybn = CurrentProjectFile.YbnFiles[i]; if (ybn.Loaded) { projectybns[ybn.RpfFileEntry?.ShortNameHash ?? JenkHash.GenHash(ybn.Name)] = ybn; } } interiorslist.Clear(); interiorslist.AddRange(interiors.Keys); for (int i = 0; i < interiorslist.Count; i++) { var mlo = interiorslist[i]; var hash = mlo._CEntityDef.archetypeName; if (projectybns.TryGetValue(hash, out YbnFile ybn)) { if ((ybn != null) && (ybn.Loaded)) { interiors[mlo] = ybn; } } } } } public void GetVisibleYnds(Camera camera, List ynds) { if (hidegtavmap) { ynds.Clear(); } lock (projectsyncroot) { if (CurrentProjectFile == null) return; visibleynds.Clear(); for (int i = 0; i < ynds.Count; i++) { var ynd = ynds[i]; visibleynds[ynd.AreaID] = ynd; } for (int i = 0; i < CurrentProjectFile.YndFiles.Count; i++) { var ynd = CurrentProjectFile.YndFiles[i]; if (ynd.Loaded) { visibleynds[ynd.AreaID] = ynd; } } ynds.Clear(); foreach (var ynd in visibleynds.Values) { ynds.Add(ynd); } } } public void GetVisibleYnvs(Camera camera, List ynvs) { if (hidegtavmap) { ynvs.Clear(); } lock (projectsyncroot) { if (CurrentProjectFile == null) return; visibleynvs.Clear(); for (int i = 0; i < ynvs.Count; i++) { var ynv = ynvs[i]; visibleynvs[ynv.AreaID] = ynv; } for (int i = 0; i < CurrentProjectFile.YnvFiles.Count; i++) { var ynv = CurrentProjectFile.YnvFiles[i]; if (ynv.Loaded) { visibleynvs[ynv.AreaID] = ynv; } } ynvs.Clear(); foreach (var ynv in visibleynvs.Values) { ynvs.Add(ynv); } } } public void GetVisibleTrainTracks(Camera camera, List tracks) { if (hidegtavmap) { tracks.Clear(); } lock (projectsyncroot) { if (CurrentProjectFile == null) return; visibletrains.Clear(); for (int i = 0; i < tracks.Count; i++) { var track = tracks[i]; visibletrains[track.Name] = track; } for (int i = 0; i < CurrentProjectFile.TrainsFiles.Count; i++) { var track = CurrentProjectFile.TrainsFiles[i]; if (track.Loaded) { visibletrains[track.Name] = track; } } tracks.Clear(); foreach (var track in visibletrains.Values) { tracks.Add(track); } } } public void GetVisibleScenarios(Camera camera, List ymts) { if (hidegtavmap) { ymts.Clear(); } lock (projectsyncroot) { if (CurrentProjectFile == null) return; visiblescenarios.Clear(); for (int i = 0; i < ymts.Count; i++) { var ymt = ymts[i]; visiblescenarios[ymt.Name] = ymt; } for (int i = 0; i < CurrentProjectFile.ScenarioFiles.Count; i++) { var scenario = CurrentProjectFile.ScenarioFiles[i]; if (scenario.Loaded) { visiblescenarios[scenario.Name] = scenario; } } ymts.Clear(); foreach (var ymt in visiblescenarios.Values) { ymts.Add(ymt); } } } public void GetVisibleAudioFiles(Camera camera, List rels) { if (hidegtavmap) { rels.Clear(); } lock (projectsyncroot) { if (CurrentProjectFile == null) return; visibleaudiofiles.Clear(); for (int i = 0; i < rels.Count; i++) { var rel = rels[i]; visibleaudiofiles[rel.RpfFileEntry.NameHash] = rel; } for (int i = 0; i < CurrentProjectFile.AudioRelFiles.Count; i++) { var rel = CurrentProjectFile.AudioRelFiles[i]; if (rel.Loaded) { visibleaudiofiles[rel.RpfFileEntry.NameHash] = rel; } } rels.Clear(); foreach (var rel in visibleaudiofiles.Values) { rels.Add(rel); } } } public void GetVisibleWaterQuads(Camera camera, List quads) { if (hidegtavmap) { quads.Clear(); } } public void GetMouseCollision(Camera camera, ref MapSelection curHit) { var mray = new Ray(); mray.Position = camera.MouseRay.Position + camera.Position; mray.Direction = camera.MouseRay.Direction; var bounds = curHit.CollisionBounds ?? curHit.CollisionPoly?.Owner ?? curHit.CollisionVertex?.Owner; var curybn = bounds?.GetRootYbn(); var eray = mray; if (hidegtavmap && (curybn != null)) { curHit.Clear(); } lock (projectsyncroot) { if (renderitems && (CurrentProjectFile != null)) { for (int i = 0; i < CurrentProjectFile.YbnFiles.Count; i++) { var ybn = CurrentProjectFile.YbnFiles[i]; if (ybn.Loaded) { if (ybn.Name == curybn?.Name) { curHit.Clear(); } if (ybn.Bounds != null) { var hit = ybn.Bounds.RayIntersect(ref mray); if (hit.Hit && (hit.HitDist < curHit.HitDist)) { curHit.UpdateCollisionFromRayHit(ref hit, camera); } } } } for (int i = 0; i < interiorslist.Count; i++) { var mlo = interiorslist[i]; var hash = mlo._CEntityDef.archetypeName; if (projectybns.TryGetValue(hash, out YbnFile ybn)) { if ((ybn != null) && (ybn.Loaded) && (ybn.Bounds != null)) { var eorinv = Quaternion.Invert(mlo.Orientation); eray.Position = eorinv.Multiply(mray.Position - mlo.Position); eray.Direction = eorinv.Multiply(mray.Direction); var hit = ybn.Bounds.RayIntersect(ref eray); if (hit.Hit && (hit.HitDist < curHit.HitDist)) { hit.HitYbn = ybn; hit.HitEntity = mlo; hit.Position = mlo.Orientation.Multiply(hit.Position) + mlo.Position; hit.Normal = mlo.Orientation.Multiply(hit.Normal); curHit.UpdateCollisionFromRayHit(ref hit, camera); } } } } } } } 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) { try { if (InvokeRequired) { BeginInvoke(new Action(() => { OnWorldSelectionChanged(sel); })); } else { var wasmult = (CurrentMulti != null); if ((sel.MultipleSelectionItems != null) && (sel.MultipleSelectionItems.Length > 0)) { SetObject(ref sel.MultipleSelectionItems[sel.MultipleSelectionItems.Length - 1]); SetObject(ref sel); ProjectExplorer?.DeselectNode(); ShowProjectItemInProcess = true; ShowCurrentProjectItem(false); ShowProjectItemInProcess = false; return; } else { CurrentMulti = null; } var mlo = sel.MloEntityDef; var room = sel.MloRoomDef; var ent = sel.EntityDef; var cargen = sel.CarGenerator; var grassbatch = sel.GrassBatch; var collvert = sel.CollisionVertex; var collpoly = sel.CollisionPoly; var collbound = sel.CollisionBounds ?? collpoly?.Owner ?? collvert?.Owner; var pathnode = sel.PathNode; var pathlink = sel.PathLink; var navpoly = sel.NavPoly; var navpoint = sel.NavPoint; var navportal = sel.NavPortal; var trainnode = sel.TrainTrackNode; var scenariond = sel.ScenarioNode; var scenarioedge = sel.ScenarioEdge; var audiopl = sel.Audio; Archetype arch = mlo?.Archetype ?? ent?.MloParent?.Archetype ?? ent?.Archetype; YtypFile ytyp = mlo?.Archetype?.Ytyp ?? ent?.MloParent?.Archetype?.Ytyp ?? ent?.Archetype?.Ytyp ?? room?.OwnerMlo?.Ytyp; YmapFile ymap = ent?.Ymap ?? cargen?.Ymap ?? grassbatch?.Ymap ?? mlo?.Ymap; YbnFile ybn = collbound?.GetRootYbn(); YndFile ynd = pathnode?.Ynd; YnvFile ynv = navpoly?.Ynv ?? navpoint?.Ynv ?? navportal?.Ynv; TrainTrack traintrack = trainnode?.Track; YmtFile scenario = scenariond?.Ymt ?? scenarioedge?.Region?.Ymt; RelFile audiofile = audiopl?.RelFile; bool showcurrent = false; if (YmapExistsInProject(ymap) && (ybn == null)) { if (wasmult || (ent != CurrentEntity)) { ProjectExplorer?.TrySelectEntityTreeNode(ent); } if (wasmult || (cargen != CurrentCarGen)) { ProjectExplorer?.TrySelectCarGenTreeNode(cargen); } if (wasmult || (grassbatch != CurrentGrassBatch)) { ProjectExplorer?.TrySelectGrassBatchTreeNode(grassbatch); } } else if (YtypExistsInProject(ytyp)) { if (wasmult || (arch != CurrentArchetype)) { ProjectExplorer?.TrySelectArchetypeTreeNode(mlo?.Archetype); } if (wasmult || (ent != CurrentEntity)) { MloInstanceData mloInstance = ent.MloParent?.MloInstance; if (mloInstance != null) { MCEntityDef entityDef = mloInstance.TryGetArchetypeEntity(ent); ProjectExplorer?.TrySelectMloEntityTreeNode(entityDef); } } if (wasmult || (room != CurrentMloRoom)) { ProjectExplorer?.TrySelectMloRoomTreeNode(room); } } else if (YbnExistsInProject(ybn)) { if ((collvert != null) && (wasmult || (collvert != CurrentCollisionVertex))) { ProjectExplorer?.TrySelectCollisionVertexTreeNode(collvert); } else if ((collpoly != null) && (wasmult || (collpoly != CurrentCollisionPoly))) { ProjectExplorer?.TrySelectCollisionPolyTreeNode(collpoly); } else if (wasmult || (collbound != CurrentCollisionBounds)) { ProjectExplorer?.TrySelectCollisionBoundsTreeNode(collbound); } } else if (YndExistsInProject(ynd)) { if (wasmult || (pathnode != CurrentPathNode)) { ProjectExplorer?.TrySelectPathNodeTreeNode(pathnode); } } else if (YnvExistsInProject(ynv)) { if (wasmult || (navpoly != CurrentNavPoly)) { ProjectExplorer?.TrySelectNavPolyTreeNode(navpoly); } if (wasmult || (navpoint != CurrentNavPoint)) { ProjectExplorer?.TrySelectNavPointTreeNode(navpoint); } if (wasmult || (navportal != CurrentNavPortal)) { ProjectExplorer?.TrySelectNavPortalTreeNode(navportal); } } else if (TrainTrackExistsInProject(traintrack)) { if (wasmult || (trainnode != CurrentTrainNode)) { ProjectExplorer?.TrySelectTrainNodeTreeNode(trainnode); } } else if (ScenarioExistsInProject(scenario)) { if ((scenariond != null) && (wasmult || (scenariond != CurrentScenarioNode))) { ProjectExplorer?.TrySelectScenarioNodeTreeNode(scenariond); } } else if (AudioFileExistsInProject(audiofile)) { if ((audiopl?.AudioZone != null) && (wasmult || (audiopl != CurrentAudioZone))) { ProjectExplorer?.TrySelectAudioZoneTreeNode(audiopl); } if ((audiopl?.AudioEmitter != null) && (wasmult || (audiopl != CurrentAudioEmitter))) { ProjectExplorer?.TrySelectAudioEmitterTreeNode(audiopl); } } else { ProjectExplorer?.DeselectNode(); showcurrent = true; } CurrentMloRoom = room; CurrentMloPortal = null; CurrentMloEntitySet = null; CurrentYmapFile = ymap; CurrentYtypFile = ytyp; CurrentArchetype = arch; CurrentEntity = ent ?? mlo; CurrentCarGen = cargen; CurrentGrassBatch = grassbatch; CurrentYbnFile = ybn; CurrentCollisionVertex = collvert; CurrentCollisionPoly = collpoly; CurrentCollisionBounds = collbound; CurrentYndFile = ynd; CurrentPathNode = pathnode; CurrentPathLink = pathlink; CurrentYnvFile = ynv; CurrentNavPoly = navpoly; CurrentNavPoint = navpoint; CurrentNavPortal = navportal; CurrentTrainTrack = traintrack; CurrentTrainNode = trainnode; CurrentScenario = scenario; CurrentScenarioNode = scenariond; CurrentScenarioChainEdge = scenarioedge; CurrentAudioFile = audiofile; CurrentAudioZone = (audiopl?.AudioZone != null) ? audiopl : null; CurrentAudioEmitter = (audiopl?.AudioEmitter != null) ? audiopl : null; CurrentAudioZoneList = null; CurrentAudioEmitterList = null; RefreshUI(); if (showcurrent) { ShowProjectItemInProcess = true; ShowCurrentProjectItem(false); ShowProjectItemInProcess = false; } } } catch { } } public void OnWorldSelectionModified(MapSelection sel) { try { if (InvokeRequired) { BeginInvoke(new Action(() => { OnWorldSelectionModified(sel); })); } else { if (sel.MultipleSelectionItems != null) { OnWorldMultiModified(sel.MultipleSelectionItems); } else if (sel.CollisionVertex != null) { OnWorldCollisionVertexModified(sel.CollisionVertex); } else if (sel.CollisionPoly != null) { OnWorldCollisionPolyModified(sel.CollisionPoly); } else if (sel.CollisionBounds != null) { OnWorldCollisionBoundsModified(sel.CollisionBounds); } else if (sel.EntityDef != null) { OnWorldEntityModified(sel.EntityDef); } else if (sel.CarGenerator != null) { OnWorldCarGenModified(sel.CarGenerator); } else if (sel.PathNode != null) { OnWorldPathNodeModified(sel.PathNode, sel.PathLink); } else if (sel.NavPoly != null) { OnWorldNavPolyModified(sel.NavPoly); } else if (sel.NavPoint != null) { OnWorldNavPointModified(sel.NavPoint); } else if (sel.NavPortal != null) { OnWorldNavPortalModified(sel.NavPortal); } else if (sel.TrainTrackNode != null) { OnWorldTrainNodeModified(sel.TrainTrackNode); } else if (sel.ScenarioNode != null) { OnWorldScenarioNodeModified(sel.ScenarioNode); } else if (sel.Audio != null) { OnWorldAudioPlacementModified(sel.Audio); } } } catch { } } private void OnWorldMultiModified(MapSelection[] items) { if (items == CurrentMulti) { ShowEditMultiPanel(false); } } private void OnWorldEntityModified(YmapEntityDef ent) { if ((ent.Ymap == null) && (ent.MloParent == null)) { return;//TODO: properly handle interior entities! } if (CurrentProjectFile == null) { NewProject(); } if (ent.MloParent == null && ent.Ymap != null) { if (!YmapExistsInProject(ent.Ymap)) { 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); } } } } private void OnWorldCarGenModified(YmapCarGen cargen) { if (cargen?.Ymap == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!YmapExistsInProject(cargen.Ymap)) { cargen.Ymap.HasChanged = true; AddYmapToProject(cargen.Ymap); ProjectExplorer?.TrySelectCarGenTreeNode(cargen); } if (cargen != CurrentCarGen) { CurrentCarGen = cargen; ProjectExplorer?.TrySelectCarGenTreeNode(cargen); } if (cargen == CurrentCarGen) { ShowEditYmapCarGenPanel(false); ProjectExplorer?.UpdateCarGenTreeNode(cargen); if (cargen.Ymap != null) { SetYmapHasChanged(true); } } } private void OnWorldCollisionVertexModified(BoundVertex vert) { var ybn = vert?.Owner?.GetRootYbn(); if (ybn == null) return; CurrentYbnFile = ybn; if (CurrentProjectFile == null) { NewProject(); } if (!YbnExistsInProject(ybn)) { ybn.HasChanged = true; vert.Owner.HasChanged = true; AddYbnToProject(ybn); ProjectExplorer?.TrySelectCollisionVertexTreeNode(vert); } if (vert != CurrentCollisionVertex) { CurrentCollisionVertex = vert; ProjectExplorer?.TrySelectCollisionVertexTreeNode(vert); } if (vert == CurrentCollisionVertex) { ShowEditYbnBoundVertexPanel(false); //////UpdateCollisionVertexTreeNode(poly); if (ybn != null) { SetYbnHasChanged(true); } } } private void OnWorldCollisionPolyModified(BoundPolygon poly) { var ybn = poly?.Owner?.GetRootYbn(); if (ybn == null) return; CurrentYbnFile = ybn; if (CurrentProjectFile == null) { NewProject(); } if (!YbnExistsInProject(ybn)) { ybn.HasChanged = true; poly.Owner.HasChanged = true; AddYbnToProject(ybn); ProjectExplorer?.TrySelectCollisionPolyTreeNode(poly); } if (poly != CurrentCollisionPoly) { CurrentCollisionPoly = poly; ProjectExplorer?.TrySelectCollisionPolyTreeNode(poly); } if (poly == CurrentCollisionPoly) { ShowEditYbnBoundPolyPanel(false); //////UpdateCollisionPolyTreeNode(poly); if (ybn != null) { SetYbnHasChanged(true); } } } private void OnWorldCollisionBoundsModified(Bounds bounds) { var ybn = bounds?.GetRootYbn(); if (ybn == null) return; CurrentYbnFile = ybn; if (CurrentProjectFile == null) { NewProject(); } if (!YbnExistsInProject(ybn)) { ybn.HasChanged = true; bounds.HasChanged = true; AddYbnToProject(ybn); ProjectExplorer?.TrySelectCollisionBoundsTreeNode(bounds); } if (bounds != CurrentCollisionBounds) { CurrentCollisionBounds = bounds; ProjectExplorer?.TrySelectCollisionBoundsTreeNode(bounds); } if (bounds == CurrentCollisionBounds) { ShowEditYbnBoundsPanel(false); //////UpdateCollisionBoundsTreeNode(bounds); if (ybn != null) { SetYbnHasChanged(true); } } } private void OnWorldPathNodeModified(YndNode node, YndLink link) { if (node?.Ynd == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!YndExistsInProject(node.Ynd)) { node.Ynd.HasChanged = true; AddYndToProject(node.Ynd); ProjectExplorer?.TrySelectPathNodeTreeNode(node); } if (node != CurrentPathNode) { CurrentPathNode = node; ProjectExplorer?.TrySelectPathNodeTreeNode(node); } //////if (link != CurrentPathLink) //////{ ////// CurrentPathLink = link; ////// ShowEditYndLinkPanel(false); //////} if (node == CurrentPathNode) { //////ShowEditYndPanel(false); ShowEditYndNodePanel(false); //////UpdatePathNodeTreeNode(node); if (node.Ynd != null) { SetYndHasChanged(true); } } } private void OnWorldNavPolyModified(YnvPoly poly) { if (poly?.Ynv == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!YnvExistsInProject(poly.Ynv)) { poly.Ynv.HasChanged = true; AddYnvToProject(poly.Ynv); ProjectExplorer?.TrySelectNavPolyTreeNode(poly); } if (poly != CurrentNavPoly) { CurrentNavPoly = poly; ProjectExplorer?.TrySelectNavPolyTreeNode(poly); } if (poly == CurrentNavPoly) { ShowEditYnvPolyPanel(false); //////UpdateNavPolyTreeNode(poly); if (poly.Ynv != null) { SetYnvHasChanged(true); } } } private void OnWorldNavPointModified(YnvPoint point) { if (point?.Ynv == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!YnvExistsInProject(point.Ynv)) { point.Ynv.HasChanged = true; AddYnvToProject(point.Ynv); ProjectExplorer?.TrySelectNavPointTreeNode(point); } if (point != CurrentNavPoint) { CurrentNavPoint = point; ProjectExplorer?.TrySelectNavPointTreeNode(point); } if (point == CurrentNavPoint) { ShowEditYnvPointPanel(false); //////UpdateNavPointTreeNode(poly); if (point.Ynv != null) { SetYnvHasChanged(true); } } } private void OnWorldNavPortalModified(YnvPortal portal) { if (portal?.Ynv == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!YnvExistsInProject(portal.Ynv)) { portal.Ynv.HasChanged = true; AddYnvToProject(portal.Ynv); ProjectExplorer?.TrySelectNavPortalTreeNode(portal); } if (portal != CurrentNavPortal) { CurrentNavPortal = portal; ProjectExplorer?.TrySelectNavPortalTreeNode(portal); } if (portal == CurrentNavPortal) { ShowEditYnvPortalPanel(false); //////UpdateNavPortalTreeNode(poly); if (portal.Ynv != null) { SetYnvHasChanged(true); } } } private void OnWorldTrainNodeModified(TrainTrackNode node) { if (node?.Track == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!TrainTrackExistsInProject(node.Track)) { node.Track.HasChanged = true; AddTrainTrackToProject(node.Track); ProjectExplorer?.TrySelectTrainNodeTreeNode(node); } if (node != CurrentTrainNode) { CurrentTrainNode = node; ProjectExplorer?.TrySelectTrainNodeTreeNode(node); } if (node == CurrentTrainNode) { ShowEditTrainNodePanel(false); if (node.Track != null) { SetTrainTrackHasChanged(true); } } } private void OnWorldScenarioNodeModified(ScenarioNode node) { if (node?.Ymt == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!ScenarioExistsInProject(node.Ymt)) { node.Ymt.HasChanged = true; AddScenarioToProject(node.Ymt); ProjectExplorer?.TrySelectScenarioNodeTreeNode(node); } if (node != CurrentScenarioNode) { CurrentScenarioNode = node; ProjectExplorer?.TrySelectScenarioNodeTreeNode(node); } if (node == CurrentScenarioNode) { //ShowEditScenarioPanel(false); ShowEditScenarioNodePanel(false); if (node?.Ymt != null) { SetScenarioHasChanged(true); } } } private void OnWorldAudioPlacementModified(AudioPlacement audio) { if (audio?.RelFile == null) return; if (CurrentProjectFile == null) { NewProject(); } if (!AudioFileExistsInProject(audio.RelFile)) { audio.RelFile.HasChanged = true; AddAudioFileToProject(audio.RelFile); if (audio.AudioZone != null) { ProjectExplorer?.TrySelectAudioZoneTreeNode(audio); } if (audio.AudioEmitter != null) { ProjectExplorer?.TrySelectAudioEmitterTreeNode(audio); } } if ((audio.AudioZone != null) && (audio != CurrentAudioZone)) { CurrentAudioZone = audio; ProjectExplorer?.TrySelectAudioZoneTreeNode(audio); } if ((audio.AudioEmitter != null) && (audio != CurrentAudioEmitter)) { CurrentAudioEmitter = audio; ProjectExplorer?.TrySelectAudioEmitterTreeNode(audio); } if (audio == CurrentAudioZone) { ShowEditAudioZonePanel(false); if (audio.RelFile != null) { SetAudioFileHasChanged(true); } } else if (audio == CurrentAudioEmitter) { ShowEditAudioEmitterPanel(false); if (audio.RelFile != null) { SetAudioFileHasChanged(true); } } } public void SetProjectHasChanged(bool changed) { if (CurrentProjectFile == null) return; CurrentProjectFile.HasChanged = changed; ProjectExplorer?.SetProjectHasChanged(changed); UpdateFormTitleText(); } public void SetYmapHasChanged(bool changed) { if (CurrentYmapFile == null) return; bool changechange = changed != CurrentYmapFile.HasChanged; if (!changechange) return; CurrentYmapFile.HasChanged = changed; ProjectExplorer?.SetYmapHasChanged(CurrentYmapFile, changed); PromoteIfPreviewPanelActive(); } public void SetYtypHasChanged(bool changed) { if (CurrentYtypFile == null) return; bool changechange = changed != CurrentYtypFile.HasChanged; if (!changechange) return; CurrentYtypFile.HasChanged = changed; ProjectExplorer?.SetYtypHasChanged(CurrentYtypFile, changed); PromoteIfPreviewPanelActive(); } public void SetYbnHasChanged(bool changed) { if (CurrentYbnFile == null) return; bool changechange = changed != CurrentYbnFile.HasChanged; if (!changechange) return; CurrentYbnFile.HasChanged = changed; ProjectExplorer?.SetYbnHasChanged(CurrentYbnFile, changed); PromoteIfPreviewPanelActive(); } public void SetYndHasChanged(bool changed) { if (CurrentYndFile == null) return; bool changechange = changed != CurrentYndFile.HasChanged; if (!changechange) return; CurrentYndFile.HasChanged = changed; ProjectExplorer?.SetYndHasChanged(CurrentYndFile, changed); PromoteIfPreviewPanelActive(); } public void SetYnvHasChanged(bool changed) { if (CurrentYnvFile == null) return; bool changechange = changed != CurrentYnvFile.HasChanged; if (!changechange) return; CurrentYnvFile.HasChanged = changed; ProjectExplorer?.SetYnvHasChanged(CurrentYnvFile, changed); PromoteIfPreviewPanelActive(); } public void SetTrainTrackHasChanged(bool changed) { if (CurrentTrainTrack == null) return; bool changechange = changed != CurrentTrainTrack.HasChanged; if (!changechange) return; CurrentTrainTrack.HasChanged = changed; ProjectExplorer?.SetTrainTrackHasChanged(CurrentTrainTrack, changed); PromoteIfPreviewPanelActive(); } public void SetScenarioHasChanged(bool changed) { if (CurrentScenario == null) return; bool changechange = changed != CurrentScenario.HasChanged; if (!changechange) return; CurrentScenario.HasChanged = changed; ProjectExplorer?.SetScenarioHasChanged(CurrentScenario, changed); PromoteIfPreviewPanelActive(); } public void SetAudioFileHasChanged(bool changed) { if (CurrentAudioFile == null) return; bool changechange = changed != CurrentAudioFile.HasChanged; if (!changechange) return; CurrentAudioFile.HasChanged = changed; ProjectExplorer?.SetAudioRelHasChanged(CurrentAudioFile, changed); PromoteIfPreviewPanelActive(); } public void SetGrassBatchHasChanged(bool changed) { if (CurrentGrassBatch == null) return; bool changechange = changed != CurrentGrassBatch.HasChanged; if (!changechange) return; CurrentGrassBatch.HasChanged = true; ProjectExplorer?.SetGrassBatchHasChanged(CurrentGrassBatch, changed); PromoteIfPreviewPanelActive(); } public Vector3 GetSpawnPos(float dist) { Vector3 pos = Vector3.Zero; if (WorldForm != null) { Vector3 campos = WorldForm.GetCameraPosition(); Vector3 camdir = WorldForm.GetCameraViewDir(); pos = campos + camdir * dist; } 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) { foreach (var ymap in CurrentProjectFile.YmapFiles) { if ((ymap._CMapData.name.Hash == hash) || (JenkHash.GenHash(Path.GetFileNameWithoutExtension(ymap.Name)) == hash)) { return ymap.RpfFileEntry; } } } if ((GameFileCache != null) && (GameFileCache.IsInited)) { return GameFileCache.GetYmapEntry(hash); } return null; } //######## Private methods private void LoadYmapFromFile(YmapFile ymap, string filename) { byte[] data = File.ReadAllBytes(filename); ymap.Load(data); ymap.InitYmapEntityArchetypes(GameFileCache); //this needs to be done after calling YmapFile.Load() } private void LoadYtypFromFile(YtypFile ytyp, string filename) { byte[] data = File.ReadAllBytes(filename); ytyp.Load(data); AddProjectArchetypes(ytyp); } private void LoadYbnFromFile(YbnFile ybn, string filename) { byte[] data = File.ReadAllBytes(filename); ybn.Load(data); if (WorldForm != null) { if (ybn?.Bounds != null) { WorldForm.UpdateCollisionBoundsGraphics(ybn?.Bounds); } } } private void LoadYndFromFile(YndFile ynd, string filename) { byte[] data = File.ReadAllBytes(filename); ynd.Load(data); if (WorldForm != null) { WorldForm.UpdatePathYndGraphics(ynd, true); //links don't get drawn until something changes otherwise //note: this is actually necessary to properly populate junctions data........ } } private void LoadYnvFromFile(YnvFile ynv, string filename) { byte[] data = File.ReadAllBytes(filename); ynv.Load(data); if (WorldForm != null) { WorldForm.UpdateNavYnvGraphics(ynv, true); //polys don't get drawn until something changes otherwise } } private void LoadTrainTrackFromFile(TrainTrack track, string filename) { byte[] data = File.ReadAllBytes(filename); string fname = new FileInfo(filename).Name; track.Load(data); track.Name = fname; track.FilePath = filename; track.RpfFileEntry.Name = fname; track.RpfFileEntry.NameLower = fname.ToLowerInvariant(); if (WorldForm != null) { WorldForm.UpdateTrainTrackGraphics(track, true); //links don't get drawn until something changes otherwise } } private void LoadScenarioFromFile(YmtFile ymt, string filename) { byte[] data = File.ReadAllBytes(filename); ymt.Load(data); } private void LoadAudioRelFromFile(RelFile rel, string filename) { byte[] data = File.ReadAllBytes(filename); rel.Load(data, rel?.RpfFileEntry); } private void LoadProjectUI() { RefreshProjectUI(); UpdateFormTitleText(); LoadProjectTree(); RefreshUI(); } private void LoadProjectTree() { ProjectExplorer?.LoadProjectTree(CurrentProjectFile); } private void UpdateFormTitleText() { if (CurrentProjectFile == null) { Text = "Project - CodeWalker by dexyfex"; } else { Text = CurrentProjectFile.Name + " - CodeWalker by dexyfex"; } } private void RefreshProjectUI() { bool enable = (CurrentProjectFile != null); FileCloseProjectMenu.Enabled = enable; FileSaveProjectMenu.Enabled = enable; FileSaveProjectAsMenu.Enabled = enable; } private void RefreshUI() { RefreshYmapUI(); RefreshEntityUI(); RefreshCarGenUI(); RefreshYtypUI(); RefreshYbnUI(); RefreshYndUI(); RefreshYnvUI(); RefreshTrainTrackUI(); RefreshScenarioUI(); RefreshAudioUI(); SetCurrentSaveItem(); //ShowEditYmapPanel(false); //ShowEditYmapEntityPanel(false); //ShowEditYmapCarGenPanel(false); //ShowEditYtypPanel(false); //ShowEditYndPanel(false); //ShowEditYnvPanel(false); //ShowEditYndNodePanel(false); //ShowEditTrainTrackPanel(false); //ShowEditTrainNodePanel(false); //ShowEditScenarioPanel(false); //ShowEditScenarioNodePanel(false); } private void RefreshYmapUI() { bool enable = (CurrentYmapFile != null); bool inproj = YmapExistsInProject(CurrentYmapFile); YmapNewEntityMenu.Enabled = enable && inproj; YmapNewCarGenMenu.Enabled = enable && inproj; YmapNewGrassBatchMenu.Enabled = enable && inproj; if (CurrentYmapFile != null) { YmapNameMenu.Text = "(" + CurrentYmapFile.Name + ")"; } else { YmapNameMenu.Text = "(No .ymap file selected)"; } YmapAddToProjectMenu.Enabled = enable && !inproj; YmapRemoveFromProjectMenu.Enabled = inproj; YmapMenu.Visible = enable; if (WorldForm != null) { WorldForm.EnableYmapUI(enable, CurrentYmapFile?.Name ?? ""); } } private void RefreshEntityUI() { //bool enable = (CurrentEntity != null); //bool isinproj = false; //if (CurrentEntity != null) //{ // isinproj = YmapExistsInProject(CurrentEntity.Ymap); //} //EntityAddToProjectButton.Enabled = !isinproj; //EntityDeleteButton.Enabled = isinproj; } private void RefreshCarGenUI() { //bool enable = (CurrentCarGen != null); //bool isinproj = false; //if (CurrentCarGen != null) //{ // isinproj = YmapExistsInProject(CurrentCarGen.Ymap); //} //CarAddToProjectButton.Enabled = !isinproj; //CarDeleteButton.Enabled = isinproj; } private void RefreshYtypUI() { bool enable = (CurrentYtypFile != null); bool inproj = YtypExistsInProject(CurrentYtypFile); bool ismlo = ((CurrentEntity != null) && (CurrentEntity.MloParent != null)) || (CurrentMloRoom != null) || (CurrentMloPortal != null) || (CurrentMloEntitySet != null) || (CurrentArchetype is MloArchetype); YtypNewArchetypeMenu.Enabled = enable && inproj; YtypMloToolStripMenuItem.Enabled = enable && inproj && ismlo; YtypMloNewEntityToolStripMenuItem.Enabled = YtypMloToolStripMenuItem.Enabled; if (CurrentYtypFile != null) { YtypNameMenu.Text = "(" + CurrentYtypFile.Name + ")"; } else { YtypNameMenu.Text = "(No .ytyp file selected)"; } YtypAddToProjectMenu.Enabled = enable && !inproj; YtypRemoveFromProjectMenu.Enabled = inproj; YtypMenu.Visible = enable; if (WorldForm != null) { //WorldForm.EnableYtypUI(enable, CurrentYtypFile?.Name ?? ""); } } private void RefreshYbnUI() { bool enable = (CurrentYbnFile != null); bool inproj = YbnExistsInProject(CurrentYbnFile); YbnNewBoundsMenu.Enabled = enable && inproj; YbnNewPolygonMenu.Enabled = (CurrentCollisionBounds is BoundGeometry bgeom) && inproj; if (CurrentYbnFile != null) { YbnNameMenu.Text = "(" + CurrentYbnFile.Name + ")"; } else { YbnNameMenu.Text = "(No .ybn file selected)"; } YbnAddToProjectMenu.Enabled = enable && !inproj; YbnRemoveFromProjectMenu.Enabled = inproj; YbnMenu.Visible = enable; if (WorldForm != null) { WorldForm.EnableYbnUI(enable, CurrentYbnFile?.Name ?? ""); } } private void RefreshYndUI() { bool enable = (CurrentYndFile != null); bool inproj = YndExistsInProject(CurrentYndFile); YndNewNodeMenu.Enabled = enable && inproj; if (CurrentYndFile != null) { YndNameMenu.Text = "(" + CurrentYndFile.Name + ")"; } else { YndNameMenu.Text = "(No .ynd file selected)"; } YndAddToProjectMenu.Enabled = enable && !inproj; YndRemoveFromProjectMenu.Enabled = inproj; YndMenu.Visible = enable; if (WorldForm != null) { WorldForm.EnableYndUI(enable, CurrentYndFile?.Name ?? ""); } } private void RefreshYnvUI() { bool enable = (CurrentYnvFile != null); bool inproj = YnvExistsInProject(CurrentYnvFile); YnvNewPolygonMenu.Enabled = enable && inproj; if (CurrentYnvFile != null) { YnvNameMenu.Text = "(" + CurrentYnvFile.Name + ")"; } else { YnvNameMenu.Text = "(No .ynv file selected)"; } YnvAddToProjectMenu.Enabled = enable && !inproj; YnvRemoveFromProjectMenu.Enabled = inproj; YnvMenu.Visible = enable; if (WorldForm != null) { WorldForm.EnableYnvUI(enable, CurrentYnvFile?.Name ?? ""); } } private void RefreshTrainTrackUI() { bool enable = (CurrentTrainTrack != null); bool inproj = TrainTrackExistsInProject(CurrentTrainTrack); TrainsNewNodeMenu.Enabled = enable && inproj; if (CurrentTrainTrack != null) { TrainsNameMenu.Text = "(" + CurrentTrainTrack.Name + ")"; } else { TrainsNameMenu.Text = "(No train track selected)"; } TrainsAddToProjectMenu.Enabled = enable && !inproj; TrainsRemoveFromProjectMenu.Enabled = inproj; TrainsMenu.Visible = enable; if (WorldForm != null) { WorldForm.EnableTrainsUI(enable, CurrentTrainTrack?.Name ?? ""); } } private void RefreshScenarioUI() { bool enable = (CurrentScenario != null); bool inproj = ScenarioExistsInProject(CurrentScenario); ScenarioNewPointMenu.Enabled = enable && inproj; ScenarioNewPointFromSelectedMenu.Enabled = enable && inproj && (CurrentScenarioNode != null); ScenarioNewEntityOverrideMenu.Enabled = enable && inproj; ScenarioNewChainMenu.Enabled = enable && inproj; ScenarioNewClusterMenu.Enabled = enable && inproj; ScenarioImportChainMenu.Enabled = enable && inproj; if (CurrentScenario != null) { ScenarioNameMenu.Text = "(" + CurrentScenario.Name + ")"; } else { ScenarioNameMenu.Text = "(No scenario region selected)"; } ScenarioAddToProjectMenu.Enabled = enable && !inproj; ScenarioRemoveFromProjectMenu.Enabled = inproj; ScenarioMenu.Visible = enable; if (WorldForm != null) { WorldForm.EnableScenarioUI(enable, CurrentScenario?.Name ?? ""); } } private void RefreshAudioUI() { bool enable = (CurrentAudioFile != null); bool inproj = AudioFileExistsInProject(CurrentAudioFile); AudioNewAmbientEmitterMenu.Enabled = enable && inproj; AudioNewAmbientEmitterListMenu.Enabled = enable && inproj; AudioNewAmbientZoneMenu.Enabled = enable && inproj; AudioNewAmbientZoneListMenu.Enabled = enable && inproj; AudioNewInteriorMenu.Enabled = enable && inproj; AudioNewInteriorRoomMenu.Enabled = enable && inproj; if (CurrentAudioFile != null) { AudioNameMenu.Text = "(" + CurrentAudioFile.Name + ")"; } else { AudioNameMenu.Text = "(No audio dat file selected)"; } AudioAddToProjectMenu.Enabled = enable && !inproj; AudioRemoveFromProjectMenu.Enabled = inproj; AudioMenu.Visible = enable; if (WorldForm != null) { WorldForm.EnableAudioUI(enable, CurrentAudioFile?.Name ?? ""); } } private void SetCurrentSaveItem() { string filename = null; if (CurrentYmapFile != null) { filename = CurrentYmapFile.RpfFileEntry?.Name; } else if (CurrentYtypFile != null) { filename = CurrentYtypFile.RpfFileEntry?.Name; } else if (CurrentYbnFile != null) { filename = CurrentYbnFile.RpfFileEntry?.Name; } else if (CurrentYndFile != null) { filename = CurrentYndFile.RpfFileEntry?.Name; } else if (CurrentYnvFile != null) { filename = CurrentYnvFile.RpfFileEntry?.Name; } else if (CurrentTrainTrack != null) { filename = CurrentTrainTrack.RpfFileEntry?.Name; } else if (CurrentScenario != null) { filename = CurrentScenario.RpfFileEntry?.Name; } else if (CurrentAudioFile != null) { filename = CurrentAudioFile.RpfFileEntry?.Name; } bool enable = !string.IsNullOrEmpty(filename); if (enable) { FileSaveItemMenu.Text = "Save " + filename; FileSaveItemAsMenu.Text = "Save " + filename + " As..."; ToolbarSaveButton.Text = "Save " + filename; } else { FileSaveItemMenu.Text = "Save"; FileSaveItemAsMenu.Text = "Save As..."; ToolbarSaveButton.Text = "Save"; } FileSaveItemMenu.Tag = filename; FileSaveItemAsMenu.Tag = filename; FileSaveItemMenu.Enabled = enable; FileSaveItemMenu.Visible = enable; FileSaveItemAsMenu.Enabled = enable; FileSaveItemAsMenu.Visible = enable; ToolbarSaveButton.Enabled = enable; if (WorldForm != null) { WorldForm.SetCurrentSaveItem(filename); } } private string ShowSaveDialog(string filter, string filename) { SaveFileDialog.FileName = filename; SaveFileDialog.Filter = filter; if (SaveFileDialog.ShowDialog(this) != DialogResult.OK) { return string.Empty; } return SaveFileDialog.FileName; } private string ShowOpenDialog(string filter, string filename) { OpenFileDialog.FileName = filename; OpenFileDialog.Filter = filter; OpenFileDialog.Multiselect = false; if (OpenFileDialog.ShowDialog(this) != DialogResult.OK) { return string.Empty; } return OpenFileDialog.FileName; } private string[] ShowOpenDialogMulti(string filter, string filename) { OpenFileDialog.FileName = filename; OpenFileDialog.Filter = filter; OpenFileDialog.Multiselect = true; if (OpenFileDialog.ShowDialog(this) != DialogResult.OK) { return null; } return OpenFileDialog.FileNames; } //######## events private void ProjectForm_FormClosing(object sender, FormClosingEventArgs e) { if (CurrentProjectFile != null) { var msg = "Are you sure you want to close the project window?"; var tit = "Confirm close"; if (e.CloseReason == CloseReason.FormOwnerClosing) { msg = "Are you sure you want to quit CodeWalker?"; tit = "Confirm quit"; } if (MessageBox.Show(msg, tit, MessageBoxButtons.YesNo) != DialogResult.Yes) { e.Cancel = true; return; } } CloseProject(); } private void ProjectForm_FormClosed(object sender, FormClosedEventArgs e) { if (WorldForm != null) { WorldForm.OnProjectFormClosed(); } } private void ProjectExplorer_OnItemSelected(object item) { ShowProjectItem(item, false); } private void ProjectExplorer_OnItemActivated(object item) { //promote from preview panel to full panel... ShowProjectItem(item, true); } private void MainDockPanel_ActiveContentChanged(object sender, EventArgs e) { if (!ShowProjectItemInProcess) { var panel = MainDockPanel.ActiveContent as ProjectPanel; if (panel != null) { MainDockPanel.DefaultFloatWindowSize = panel.Size; } if (panel?.Tag != null) { SetProjectItem(panel.Tag); RefreshUI(); } } } private void MainDockPanel_DocumentDragged(object sender, EventArgs e) { PromoteIfPreviewPanel(MainDockPanel.ActiveContent); } private void FileNewProjectMenu_Click(object sender, EventArgs e) { NewProject(); } private void FileNewYmapMenu_Click(object sender, EventArgs e) { NewYmap(); } private void FileNewYtypMenu_Click(object sender, EventArgs e) { NewYtyp(); } private void FileNewYbnMenu_Click(object sender, EventArgs e) { NewYbn(); } private void FileNewYndMenu_Click(object sender, EventArgs e) { NewYnd(); } private void FileNewYnvMenu_Click(object sender, EventArgs e) { NewYnv(); } private void FileNewTrainsMenu_Click(object sender, EventArgs e) { NewTrainTrack(); } private void FileNewScenarioMenu_Click(object sender, EventArgs e) { NewScenario(); } private void FileNewAudioDatMenu_Click(object sender, EventArgs e) { NewAudioFile(); } private void FileOpenProjectMenu_Click(object sender, EventArgs e) { OpenProject(); } private void FileOpenYmapMenu_Click(object sender, EventArgs e) { OpenYmap(); } private void FileOpenYtypMenu_Click(object sender, EventArgs e) { OpenYtyp(); } private void FileOpenYbnMenu_Click(object sender, EventArgs e) { OpenYbn(); } private void FileOpenYndMenu_Click(object sender, EventArgs e) { OpenYnd(); } private void FileOpenYnvMenu_Click(object sender, EventArgs e) { OpenYnv(); } private void FileOpenTrainsMenu_Click(object sender, EventArgs e) { OpenTrainTrack(); } private void FileOpenScenarioMenu_Click(object sender, EventArgs e) { OpenScenario(); } private void FileOpenAudioDatMenu_Click(object sender, EventArgs e) { OpenAudioFile(); } private void FileCloseProjectMenu_Click(object sender, EventArgs e) { CloseProject(); } private void FileSaveProjectMenu_Click(object sender, EventArgs e) { SaveProject(); } private void FileSaveProjectAsMenu_Click(object sender, EventArgs e) { SaveProject(true); } private void FileSaveItemMenu_Click(object sender, EventArgs e) { SaveCurrentItem(); } private void FileSaveItemAsMenu_Click(object sender, EventArgs e) { SaveCurrentItem(true); } private void ViewProjectExplorerMenu_Click(object sender, EventArgs e) { ShowProjectExplorer(); } private void ViewThemeBlueMenu_Click(object sender, EventArgs e) { SetTheme("Blue"); } private void ViewThemeLightMenu_Click(object sender, EventArgs e) { SetTheme("Light"); } private void ViewThemeDarkMenu_Click(object sender, EventArgs e) { SetTheme("Dark"); } private void YmapNewEntityMenu_Click(object sender, EventArgs e) { NewEntity(); } private void YmapNewCarGenMenu_Click(object sender, EventArgs e) { NewCarGen(); } private void YmapNewGrassBatchMenu_Click(object sender, EventArgs e) { NewGrassBatch(); } private void YmapAddToProjectMenu_Click(object sender, EventArgs e) { AddYmapToProject(CurrentYmapFile); } private void YmapRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveYmapFromProject(); } private void YtypAddToProjectMenu_Click(object sender, EventArgs e) { AddYtypToProject(CurrentYtypFile); } private void YtypRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveYtypFromProject(); } private void YtypNewArchetypeMenu_Click(object sender, EventArgs e) { NewArchetype(); } private void YtypMloNewEntityToolStripMenuItem_Click(object sender, EventArgs e) { NewMloEntity(); } private void YtypMloNewRoomToolStripMenuItem_Click(object sender, EventArgs e) { NewMloRoom(); } private void YtypMloNewPortalToolStripMenuItem_Click(object sender, EventArgs e) { NewMloPortal(); } private void YtypMloNewEntitySetToolStripMenuItem_Click(object sender, EventArgs e) { NewMloEntitySet(); } private void YbnNewBoundBoxMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Box); } private void YbnNewBoundSphereMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Sphere); } private void YbnNewBoundCapsuleMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Capsule); } private void YbnNewBoundCylinderMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Cylinder); } private void YbnNewBoundDiscMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Disc); } private void YbnNewBoundClothMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Cloth); } private void YbnNewBoundGeometryMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Geometry); } private void YbnNewBoundGeometryBVHMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.GeometryBVH); } private void YbnNewBoundCompositeMenu_Click(object sender, EventArgs e) { NewCollisionBounds(BoundsType.Composite); } private void YbnNewPolygonTriangleMenu_Click(object sender, EventArgs e) { NewCollisionPoly(BoundPolygonType.Triangle); } private void YbnNewPolygonSphereMenu_Click(object sender, EventArgs e) { NewCollisionPoly(BoundPolygonType.Sphere); } private void YbnNewPolygonCapsuleMenu_Click(object sender, EventArgs e) { NewCollisionPoly(BoundPolygonType.Capsule); } private void YbnNewPolygonBoxMenu_Click(object sender, EventArgs e) { NewCollisionPoly(BoundPolygonType.Box); } private void YbnNewPolygonCylinderMenu_Click(object sender, EventArgs e) { NewCollisionPoly(BoundPolygonType.Cylinder); } private void YbnAddToProjectMenu_Click(object sender, EventArgs e) { AddYbnToProject(CurrentYbnFile); } private void YbnRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveYbnFromProject(); } private void YndNewNodeMenu_Click(object sender, EventArgs e) { NewPathNode(); } private void YndAddToProjectMenu_Click(object sender, EventArgs e) { AddYndToProject(CurrentYndFile); } private void YndRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveYndFromProject(); } private void YnvNewPolygonMenu_Click(object sender, EventArgs e) { NewNavPoly(); } private void YnvAddToProjectMenu_Click(object sender, EventArgs e) { AddYnvToProject(CurrentYnvFile); } private void YnvRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveYnvFromProject(); } private void TrainsNewNodeMenu_Click(object sender, EventArgs e) { NewTrainNode(); } private void TrainsAddToProjectMenu_Click(object sender, EventArgs e) { AddTrainTrackToProject(CurrentTrainTrack); } private void TrainsRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveTrainTrackFromProject(); } private void ScenarioNewPointMenu_Click(object sender, EventArgs e) { CurrentScenarioNode = null; NewScenarioNode(); } private void ScenarioNewPointFromSelectedMenu_Click(object sender, EventArgs e) { NewScenarioNode(); } private void ScenarioNewEntityOverrideMenu_Click(object sender, EventArgs e) { AddScenarioEntity(); } private void ScenarioNewChainMenu_Click(object sender, EventArgs e) { AddScenarioChain(); } private void ScenarioNewClusterMenu_Click(object sender, EventArgs e) { AddScenarioCluster(); } private void ScenarioImportChainMenu_Click(object sender, EventArgs e) { ImportScenarioChain(); } private void ScenarioAddToProjectMenu_Click(object sender, EventArgs e) { AddScenarioToProject(CurrentScenario); } private void ScenarioRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveScenarioFromProject(); } private void AudioNewAmbientEmitterMenu_Click(object sender, EventArgs e) { NewAudioEmitter(); } private void AudioNewAmbientEmitterListMenu_Click(object sender, EventArgs e) { NewAudioEmitterList(); } private void AudioNewAmbientZoneMenu_Click(object sender, EventArgs e) { NewAudioZone(); } private void AudioNewAmbientZoneListMenu_Click(object sender, EventArgs e) { NewAudioZoneList(); } private void AudioNewInteriorMenu_Click(object sender, EventArgs e) { NewAudioInterior(); } private void AudioNewInteriorRoomMenu_Click(object sender, EventArgs e) { NewAudioInteriorRoom(); } private void AudioAddToProjectMenu_Click(object sender, EventArgs e) { AddAudioFileToProject(CurrentAudioFile); } private void AudioRemoveFromProjectMenu_Click(object sender, EventArgs e) { RemoveAudioFileFromProject(); } private void ToolsManifestGeneratorMenu_Click(object sender, EventArgs e) { ShowEditProjectManifestPanel(false); } private void ToolsLODLightsGeneratorMenu_Click(object sender, EventArgs e) { ShowGenerateLODLightsPanel(false); } private void ToolsNavMeshGeneratorMenu_Click(object sender, EventArgs e) { ShowGenerateNavMeshPanel(false); } private void ToolsImportMenyooXmlMenu_Click(object sender, EventArgs e) { ImportMenyooXml(); } private void RenderShowGtavMapMenu_Click(object sender, EventArgs e) { RenderShowGtavMapMenu.Checked = !RenderShowGtavMapMenu.Checked; hidegtavmap = !RenderShowGtavMapMenu.Checked; } private void RenderShowProjectItemsMenu_Click(object sender, EventArgs e) { RenderShowProjectItemsMenu.Checked = !RenderShowProjectItemsMenu.Checked; renderitems = RenderShowProjectItemsMenu.Checked; } private void ToolbarNewButton_ButtonClick(object sender, EventArgs e) { if (CurrentProjectFile == null) { NewProject(); } else { NewYmap(); } } private void ToolbarNewProjectMenu_Click(object sender, EventArgs e) { NewProject(); } private void ToolbarNewYmapMenu_Click(object sender, EventArgs e) { NewYmap(); } private void ToolbarNewYtypMenu_Click(object sender, EventArgs e) { NewYtyp(); } private void ToolbarNewYbnMenu_Click(object sender, EventArgs e) { NewYbn(); } private void ToolbarNewYndMenu_Click(object sender, EventArgs e) { NewYnd(); } private void ToolbarNewYnvMenu_Click(object sender, EventArgs e) { NewYnv(); } private void ToolbarNewTrainsMenu_Click(object sender, EventArgs e) { NewTrainTrack(); } private void ToolbarNewScenarioMenu_Click(object sender, EventArgs e) { NewScenario(); } private void ToolbarOpenButton_ButtonClick(object sender, EventArgs e) { if (CurrentProjectFile == null) { OpenProject(); } else { OpenYmap(); } } private void ToolbarOpenProjectMenu_Click(object sender, EventArgs e) { OpenProject(); } private void ToolbarOpenYmapMenu_Click(object sender, EventArgs e) { OpenYmap(); } private void ToolbarOpenYtypMenu_Click(object sender, EventArgs e) { OpenYtyp(); } private void ToolbarOpenYbnMenu_Click(object sender, EventArgs e) { OpenYbn(); } private void ToolbarOpenYndMenu_Click(object sender, EventArgs e) { OpenYnd(); } private void ToolbarOpenYnvMenu_Click(object sender, EventArgs e) { OpenYnv(); } private void ToolbarOpenTrainsMenu_Click(object sender, EventArgs e) { OpenTrainTrack(); } private void ToolbarOpenScenarioMenu_Click(object sender, EventArgs e) { OpenScenario(); } private void ToolbarSaveButton_Click(object sender, EventArgs e) { Save(); } private void ToolbarSaveAllButton_Click(object sender, EventArgs e) { SaveAll(); } } }