Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_EditorManagerEntity.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameScripted/Editor", description: "Core Editor manager", color: "251 91 0 255", icon: "WBData/EntityEditorProps/entityEditor.png")]
3 {
4 };
5 
27 {
29  //--- Attributes
30  [Attribute("true", UIWidgets.Auto, "Are default modes created automatically?", category: "Editor Manager")]
31  private bool m_bIsAutoModes;
32 
33  [Attribute("false", UIWidgets.Auto, "Is the editor launched by default?", category: "Editor Manager")]
34  private bool m_bIsAutoInit;
35 
37  //--- Variables
38  private bool m_bIsOpened;
39  private bool m_bIsInTransition; //--- Opening or closing
40  private EEditorCanOpen m_CanOpen = EEditorCanOpen.SCRIPT;
41  private EEditorCanOpen m_CanClose = EEditorCanOpen.SCRIPT;
42  private EEditorCanOpen m_CanOpenSum;
43  private EEditorCanOpen m_CanCloseSum;
44 
45  private RplComponent m_RplComponent;
46  private int m_iPlayerID;
47  private bool m_bInit;
48  private ref array<SCR_EditorModeEntity> m_Modes = new array<SCR_EditorModeEntity>;
49  protected ref map<EEditorModeAccess, EEditorMode> m_ModesByAccess = new map<EEditorModeAccess, EEditorMode>();
50  private EEditorMode m_PrevMode = -1;
51  private EEditorMode m_CurrentMode = -1;
52  private EEditorMode m_ProcessedMode = -1;
53  private SCR_EditorModeEntity m_CurrentModeEntity;
54  private bool m_bIsModeChangeRequested;
55  private bool m_bIsLimited;
56  protected SCR_NotificationsComponent m_NotificationsComponent;
57 
58  private EEditorEventOperation m_iEventOperation = EEditorEventOperation.NONE;
59  private EEditorEvent m_iEvent = EEditorEvent.NONE;
60  private int m_iEventComponent;
61  private int m_iEventAttempt;
62  private float m_iEventProgress;
63  private float m_iEventProgressMax;
64  private float m_fEventAsyncStart;
65  private ref array<SCR_BaseEditorComponent> m_aEventComponentsActivate;
66  private ref array<SCR_BaseEditorComponent> m_aEventComponentsDeactivate;
67  private ref array<EEditorEvent> m_aEvents;
68 
69  private ref ScriptInvoker Event_OnInit = new ScriptInvoker();
70  private ref ScriptInvoker Event_OnRequest = new ScriptInvoker();
71  private ref ScriptInvoker Event_OnOpened = new ScriptInvoker();
72  private ref ScriptInvoker Event_OnCanOpen = new ScriptInvoker();
73  private ref ScriptInvoker Event_OnCanClose = new ScriptInvoker();
74  private ref ScriptInvoker Event_OnPreActivate = new ScriptInvoker();
75  private ref ScriptInvoker Event_OnActivate = new ScriptInvoker();
76  private ref ScriptInvoker Event_OnPostActivate = new ScriptInvoker();
77  private ref ScriptInvoker Event_OnDeactivate = new ScriptInvoker();
78  private ref ScriptInvoker Event_OnClosed = new ScriptInvoker();
79  private ref ScriptInvoker Event_OnDebug = new ScriptInvoker();
80  private ref ScriptInvoker Event_OnOpenedServer = new ScriptInvoker();
81  private ref ScriptInvoker Event_OnOpenedServerCallback = new ScriptInvoker();
82  private ref ScriptInvoker Event_OnClosedServer = new ScriptInvoker();
83  private ref ScriptInvoker Event_OnClosedServerCallback = new ScriptInvoker();
84  private ref ScriptInvoker Event_OnModeAdd = new ScriptInvoker();
85  private ref ScriptInvoker Event_OnModeRemove = new ScriptInvoker();
86  private ref ScriptInvoker Event_OnModeChangeRequest = new ScriptInvoker();
87  private ref ScriptInvoker Event_OnModeChange = new ScriptInvoker();
88  private ref ScriptInvoker Event_OnLimitedChange = new ScriptInvoker();
89  private ref ScriptInvoker Event_OnAsyncLoad = new ScriptInvoker();
90  private ref ScriptInvoker Event_OnCanEndGameChanged = new ScriptInvoker();
91 
93  //--- Opening
98  override bool IsOpened()
99  {
100  if (m_bIsInTransition)
101  return !m_bIsOpened; //--- Don't return current state until async loading is finished
102  else
103  return m_bIsOpened;
104  }
109  void Toggle()
110  {
111  if (m_bIsOpened)
112  Close();
113  else
114  Open();
115  }
121  void Open(bool showErrorNotification = true)
122  {
123  if (m_bIsOpened || !IsAuthority()) return; //--- Exit when already opened or attempting to edit non-local editor
124  if (!CanOpen())
125  {
126  if (showErrorNotification)
127  SCR_NotificationsComponent.SendToPlayer(GetPlayerID(), ENotification.EDITOR_CANNOT_OPEN);
128 
129  return;
130  }
131  StartEvents(EEditorEventOperation.REQUEST_OPEN);
132  Rpc(ToggleServer, true);
133  }
139  void Close(bool showErrorNotification = true)
140  {
141  if (!m_bIsOpened || !IsAuthority()) return; //--- Exit when already closed or attempting to edit non-local editor
142  if (!CanClose())
143  {
144  if (showErrorNotification)
145  SCR_NotificationsComponent.SendToPlayer(GetPlayerID(), ENotification.EDITOR_CANNOT_CLOSE);
146 
147  return;
148  }
149  StartEvents(EEditorEventOperation.REQUEST_CLOSE);
150  //Event_OnRequest.Invoke(false);
151  Rpc(ToggleServer, false);
152  }
153  [RplRpc(RplChannel.Reliable, RplRcver.Server)]
154  protected void ToggleServer(bool open)
155  {
156  if (m_bIsOpened == open || RplSession.Mode() == RplMode.Client) return;
157 
158  // Attempting to open when it's not allowed
159  if (open && !CanOpen())
160  {
161  SCR_NotificationsComponent.SendToPlayer(GetPlayerID(), ENotification.EDITOR_CANNOT_OPEN);
162  return;
163  }
164  // Attempting to close when it's not allowed
165  if (!open && !CanClose())
166  {
167  SCR_NotificationsComponent.SendToPlayer(GetPlayerID(), ENotification.EDITOR_CANNOT_CLOSE);
168  return;
169  }
170 
171  m_bIsOpened = open;
172  Rpc(ToggleOwner, m_bIsOpened);
173 
174  if (m_bIsOpened)
175  {
176  if (m_CurrentModeEntity)
177  m_CurrentModeEntity.ActivateModeServer();
178 
179  Event_OnOpenedServer.Invoke();
180  }
181  else
182  {
183  if (m_CurrentModeEntity)
184  m_CurrentModeEntity.DeactivateModeServer();
185 
186  Event_OnClosedServer.Invoke();
187  }
188  }
189  [RplRpc(RplChannel.Reliable, RplRcver.Owner)]
190  protected void ToggleOwner(bool open)
191  {
192  m_bIsOpened = open;
193  if (m_bIsOpened)
194  StartEvents(EEditorEventOperation.OPEN);
195  else
196  StartEvents(EEditorEventOperation.CLOSE);
197 
198  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_IS_OPENED, m_bIsOpened);
199  }
200  [RplRpc(RplChannel.Reliable, RplRcver.Server)]
201  protected void ToggleOwnerServerCallback(bool open)
202  {
203  if (open)
204  {
205  Event_OnOpenedServerCallback.Invoke();
206 
207  GameStatsApi statsApi = GetGame().GetStatsApi();
208  if (statsApi)
209  statsApi.IncrementEditorCounter(GetPlayerID());
210  }
211  else
212  {
213  Event_OnClosedServerCallback.Invoke();
214  }
215  }
216 
217  protected int GetEnumSum(typename enumType)
218  {
219  int enumCount = enumType.GetVariableCount();
220  int val, sum;
221 
222  for (int i = 0; i < enumCount; i++)
223  {
224  if (enumType.GetVariableType(i) == int && enumType.GetVariableValue(null, i, val))
225  {
226  sum += val;
227  }
228  }
229  return sum;
230  }
231 
233  //--- Access
238  bool CanToggle()
239  {
240  if (m_bIsOpened)
241  return CanClose();
242  else
243  return CanOpen();
244  }
249  bool CanOpen()
250  {
251  //--- No modes available
252  if (m_Modes.IsEmpty())
253  return false;
254 
255  if (IsLimited())
256  return m_CanOpen == m_CanOpenSum;
257  else
258  return m_CanOpen | EEditorCanOpen.ALIVE == m_CanOpenSum;
259  }
265  bool CanOpen(EEditorCanOpen accessType)
266  {
267  return m_CanOpen & accessType;
268  }
274  [RplRpc(RplChannel.Reliable, RplRcver.Server)]
275  void SetCanOpen(bool canOpen, EEditorCanOpen accessType)
276  {
277  if (canOpen == CanOpen(accessType) || RplSession.Mode() == RplMode.Client) return;
278 
279  if (canOpen)
280  m_CanOpen = m_CanOpen | accessType;
281  else
282  m_CanOpen = m_CanOpen &~ accessType;
283 
284  Rpc(SetCanOpenOwner, m_CanOpen);
285 
286  //--- Opening disabled, close the editor if it's
287  if (!CanOpen() && IsOpened()) ToggleServer(false);
288  }
289  [RplRpc(RplChannel.Reliable, RplRcver.Owner)]
290  protected void SetCanOpenOwner(EEditorCanOpen canOpen)
291  {
292  m_CanOpen = canOpen;
293  Event_OnCanOpen.Invoke(m_CanOpen);
294  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_OPEN, CanOpen(EEditorCanOpen.SCRIPT));
295  }
296  protected void SetCanOpenDebug(bool canOpen, EEditorCanOpen accessType = EEditorCanOpen.SCRIPT)
297  {
298  if (canOpen == CanOpen(accessType)) return;
299  Rpc(SetCanOpen, canOpen, accessType);
300  }
301 
306  bool CanClose()
307  {
308  return
309  m_CanClose == m_CanCloseSum;
310  }
316  bool CanClose(EEditorCanClose accessType)
317  {
318  return m_CanClose & accessType;
319  }
325  [RplRpc(RplChannel.Reliable, RplRcver.Server)]
326  void SetCanClose(bool canClose, EEditorCanClose accessType)
327  {
328  if (canClose == CanClose(accessType) || RplSession.Mode() == RplMode.Client) return;
329 
330  if (canClose)
331  m_CanClose = m_CanClose | accessType;
332  else
333  m_CanClose = m_CanClose &~ accessType;
334 
335  Rpc(SetCanCloseOwner, m_CanClose);
336  }
337  [RplRpc(RplChannel.Reliable, RplRcver.Owner)]
338  protected void SetCanCloseOwner(EEditorCanClose canClose)
339  {
340  m_CanClose = canClose;
341  Event_OnCanClose.Invoke(m_CanClose);
342  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_CLOSE, CanClose(EEditorCanClose.SCRIPT));
343  }
344  protected void SetCanCloseDebug(bool canClose, EEditorCanClose accessType = EEditorCanClose.SCRIPT)
345  {
346  if (canClose == CanClose(accessType)) return;
347  Rpc(SetCanClose, canClose, accessType);
348  }
349 
351  //--- Setters & Getters
356  void SetAutoInit(bool isAutoInit = false)
357  {
358  m_bIsAutoInit = isAutoInit;
359  }
363  bool IsAutoInit()
364  {
365  return m_bIsAutoInit;
366  }
372  void SetAutoModes(bool isAutoModes = false)
373  {
374  m_bIsAutoModes = isAutoModes;
375  }
380  int GetPlayerID()
381  {
382  return m_iPlayerID;
383  }
384  protected bool IsAuthority()
385  {
386  return this == GetInstance() || RplSession.Mode() != RplMode.Client;
387  }
388  bool IsOwner()
389  {
390  //--- Ignore when not initialized, e.g., when setting up the entity by a game mode before its ownership is transferred to client
391  return m_bInit && m_RplComponent && m_RplComponent.IsOwner();
392  }
397  bool IsInTransition()
398  {
399  return m_bIsInTransition;
400  }
406  bool IsLimited()
407  {
408  return m_bIsLimited || DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_FORCE_LIMITED);
409  }
415  static bool IsLimitedInstance()
416  {
417  SCR_EditorManagerEntity editorManager = SCR_EditorManagerEntity.GetInstance();
418  return !editorManager || editorManager.IsLimited();
419  }
420  override SCR_EditorManagerEntity GetManager()
421  {
422  return this;
423  }
424 
433  void SendNotification(ENotification notificationID, int selfID = 0, int targetID = 0, vector position = vector.Zero)
434  {
435  //Send notification
436  SCR_NotificationsComponent.SendLocal(notificationID, position, selfID, targetID);
437  }
438 
439  /*
440  [RplRpc(RplChannel.Reliable, RplRcver.Owner)]
441  protected void SendNotificationRpc(EEditorNotification notificationType)
442  {
443  SendNotificationImpl(notificationType);
444  }*/
445  protected void UpdateLimited()
446  {
447  //--- Check if the editor is in limited mode
448  bool limitedPrev = m_bIsLimited;
449  m_bIsLimited = true;
450  foreach (SCR_EditorModeEntity mode: m_Modes)
451  {
452  if (mode && !mode.IsLimited())
453  {
454  m_bIsLimited = false;
455  break;
456  }
457  }
458 
459  //--- Assign player role used by game code systems
460  if (Replication.IsServer() && GetGame().GetGameMode())
461  {
462  if (m_bIsLimited)
463  GetGame().GetPlayerManager().ClearPlayerRole(m_iPlayerID, EPlayerRole.GAME_MASTER);
464  else
465  GetGame().GetPlayerManager().GivePlayerRole(m_iPlayerID, EPlayerRole.GAME_MASTER);
466  }
467 
468  if (m_bIsLimited != limitedPrev)
469  Event_OnLimitedChange.Invoke(m_bIsLimited);
470  }
471 
473  //--- Events
474  override ScriptInvoker GetOnInit()
475  {
476  return Event_OnInit;
477  }
478  override ScriptInvoker GetOnOpened()
479  {
480  return Event_OnOpened;
481  }
482  override ScriptInvoker GetOnPreActivate()
483  {
484  return Event_OnPreActivate;
485  }
486  override ScriptInvoker GetOnActivate()
487  {
488  return Event_OnActivate;
489  }
490  override ScriptInvoker GetOnPostActivate()
491  {
492  return Event_OnPostActivate;
493  }
494  override ScriptInvoker GetOnDeactivate()
495  {
496  return Event_OnDeactivate;
497  }
498  override ScriptInvoker GetOnClosed()
499  {
500  return Event_OnClosed;
501  }
502  override ScriptInvoker GetOnDebug()
503  {
504  return Event_OnDebug;
505  }
506  override ScriptInvoker GetOnOpenedServer()
507  {
508  return Event_OnOpenedServer;
509  }
510  override ScriptInvoker GetOnOpenedServerCallback()
511  {
512  return Event_OnOpenedServerCallback;
513  }
514  override ScriptInvoker GetOnClosedServer()
515  {
516  return Event_OnClosedServer;
517  }
518  override ScriptInvoker GetOnClosedServerCallback()
519  {
520  return Event_OnClosedServerCallback;
521  }
522  override ScriptInvoker GetOnActivateServer()
523  {
524  return Event_OnOpenedServer;
525  }
526  override ScriptInvoker GetOnDeactivateServer()
527  {
528  return Event_OnClosedServer;
529  }
530  override ScriptInvoker GetOnRequest()
531  {
532  return Event_OnRequest;
533  }
534  ScriptInvoker GetOnCanOpen()
535  {
536  return Event_OnCanOpen;
537  }
538  ScriptInvoker GetOnCanClose()
539  {
540  return Event_OnCanClose;
541  }
542  ScriptInvoker GetOnModeAdd()
543  {
544  return Event_OnModeAdd;
545  }
546  ScriptInvoker GetOnModeRemove()
547  {
548  return Event_OnModeRemove;
549  }
550  ScriptInvoker GetOnModeChangeRequest()
551  {
552  return Event_OnModeChangeRequest;
553  }
554  ScriptInvoker GetOnModeChange()
555  {
556  return Event_OnModeChange;
557  }
558  ScriptInvoker GetOnLimitedChange()
559  {
560  return Event_OnLimitedChange;
561  }
562  ScriptInvoker GetOnAsyncLoad()
563  {
564  return Event_OnAsyncLoad;
565  }
566  ScriptInvoker GetOnCanEndGameChanged()
567  {
568  return Event_OnCanEndGameChanged;
569  }
570 
572  //-- Static
577  static bool ToggleInstance()
578  {
579  SCR_EditorManagerEntity instance = GetInstance();
580  if (!instance) return false;
581  instance.Toggle();
582  return true;
583  }
588  static bool OpenInstance()
589  {
590  SCR_EditorManagerEntity instance = GetInstance();
591  if (!instance) return false;
592  instance.Open();
593  return true;
594  }
599  static bool CloseInstance()
600  {
601  SCR_EditorManagerEntity instance = GetInstance();
602  if (!instance) return false;
603  instance.Close();
604  return true;
605  }
611  static bool IsOpenedInstance(bool includeLimited = true)
612  {
613  SCR_EditorManagerEntity instance = GetInstance();
614  return instance
615  && instance.IsOpened()
616  && (includeLimited || !instance.IsLimited());
617  }
622  static bool CanOpenInstance()
623  {
624  SCR_EditorManagerEntity instance = GetInstance();
625  if (!instance) return false;
626  return instance.CanOpen();
627  }
632  static bool CanCloseInstance()
633  {
634  SCR_EditorManagerEntity instance = GetInstance();
635  if (!instance) return false;
636  return instance.CanClose();
637  }
642  static SCR_EditorManagerEntity GetInstance()
643  {
644  ArmaReforgerScripted game = GetGame();
645  if (!game) return null;
646 
648  if (!manager) return null;
649 
650  return manager.GetEditorManager();
651  }
652 
654  //--- Editor modes
658 
667  SCR_EditorModeEntity CreateEditorMode(EEditorMode mode, bool isInit, ResourceName prefab = "")
668  {
669  if (RplSession.Mode() == RplMode.Client)
670  return null;
671 
672  RplComponent rplEditor = RplComponent.Cast(FindComponent(RplComponent));
673  if (!rplEditor)
674  return null;
675 
677  if (!core)
678  return null;
679 
680  if (FindModeEntity(mode))
681  {
682  Print(string.Format("Cannot create %1 mode manager, it already exists!", Type().EnumToString(EEditorMode, mode)), LogLevel.ERROR);
683  return null;
684  }
685 
686  //--- Find default prefab
687  bool autoSelect;
688  if (prefab.IsEmpty())
689  {
690  array<SCR_EditorModePrefab> modePrefabs = {};
691  core.GetBaseModePrefabs(modePrefabs, -1, true);
692  foreach (SCR_EditorModePrefab basePrefab: modePrefabs)
693  {
694  if (mode == basePrefab.GetMode())
695  {
696  prefab = basePrefab.GetPrefab();
697  autoSelect = SCR_Enum.HasFlag(basePrefab.GetFlags(), EEditorModeFlag.AUTO_SELECT);
698  break;
699  }
700  }
701  }
702 
703  //--- No prefab found, exit
704  if (prefab.IsEmpty())
705  {
706  Print(string.Format("No prefab found for editor mode '%1'!", Type().EnumToString(EEditorMode, mode)), LogLevel.ERROR);
707  return null;
708  }
709 
710  //--- Spawn mode entity
711  EntitySpawnParams spawnParams = new EntitySpawnParams;
712  spawnParams.Parent = this;
713  SCR_EditorModeEntity modeEntity = SCR_EditorModeEntity.Cast(GetGame().SpawnEntityPrefab(Resource.Load(prefab), GetGame().GetWorld(), spawnParams));
714  if (!modeEntity)
715  {
716  Print(string.Format("Prefab %1 for editor mode %2 is not SCR_EditorModeEntity!", prefab.GetPath(), Type().EnumToString(EEditorMode, mode)), LogLevel.ERROR);
717  delete modeEntity;
718  return null;
719  }
720  if (!modeEntity.GetParent())
721  {
722  Print(string.Format("Prefab %1 for editor mode %2 is missing Hierarchy component!", prefab.GetPath(), Type().EnumToString(EEditorMode, mode)), LogLevel.ERROR);
723  delete modeEntity;
724  return null;
725  }
726  RplComponent rplMode = RplComponent.Cast(modeEntity.FindComponent(RplComponent));
727  if (!rplMode)
728  {
729  Print(string.Format("Prefab %1 for editor mode %2 is missing RplComponent!", prefab.GetPath(), Type().EnumToString(EEditorMode, mode)), LogLevel.ERROR);
730  delete modeEntity;
731  return null;
732  }
733 
734  modeEntity.InitServer(this); //--- Called before AddMode, so events invoked from there can already work with variables defined in init
735 
736  AddMode(modeEntity, isInit);
737 
738  Rpc(CreateEditorModeOwner, mode, Replication.FindId(modeEntity), isInit);
739  SetCanOpen(true, EEditorCanOpen.MODES);
740 
741  //--- Set current mode in certain conditions
742  if (
743  (
744  !m_CurrentModeEntity //--- There is no current mode
745  || (autoSelect && !IsOpened()) //--- Newly created mode has AUTO_SELECT flag and editor is not opened
746  )
747  && !m_Modes.Contains(null) //--- No mode was deleted in this frame (would try to run MODE_DELETE and MODE_CHANGE operations at the same time, failing both)
748  )
749  {
750  SetCurrentMode(mode);
751  }
752 
753  return modeEntity;
754  }
755 
761  void AddEditorModes(EEditorModeAccess access, EEditorMode modes, bool isInit = false)
762  {
763  SetEditorModes(access, GetEditorModes() | modes, isInit);
764  }
770  void RemoveEditorModes(EEditorModeAccess access, EEditorMode modes)
771  {
772  SetEditorModes(access, GetEditorModes() & ~modes, false);
773  }
779  void SetEditorModes(EEditorModeAccess access, EEditorMode modes, bool isInit = false)
780  {
781  EEditorMode preActiveModes = GetEditorModes();
782  m_ModesByAccess.Set(access, modes);
783  EEditorMode activeModes = GetEditorModes();
784 
785  //--- Remove
786  array<EEditorMode> flags = {};
787  for (int i, count = SCR_Enum.BitToIntArray(preActiveModes & ~activeModes, flags); i < count; i++)
788  {
789  RplComponent.DeleteRplEntity(FindModeEntity(flags[i]), false);
790  }
791  RepairEditorModes(isInit);
792  }
796  void RepairEditorModes(bool isInit)
797  {
798  array<EEditorMode> flags = {};
799  for (int i, count = SCR_Enum.BitToIntArray(GetEditorModes(), flags); i < count; i++)
800  {
801  if (!FindModeEntity(flags[i]))
802  CreateEditorMode(flags[i], isInit);
803  }
804  }
808  EEditorMode GetEditorModes()
809  {
810  EEditorMode modes, defaultModes;
811  for(int i, count = m_ModesByAccess.Count(); i < count; i++)
812  {
813  modes |= m_ModesByAccess.GetElement(i);
814  }
815  return modes;
816  }
821  EEditorMode GetDefaultMode()
822  {
823  foreach (SCR_EditorModeEntity modeEntity: m_Modes)
824  {
825  if (modeEntity && !modeEntity.IsDeleted())
826  return modeEntity.GetModeType();
827  }
828  return -1;
829  }
833  void RestorePreviousMode()
834  {
835  SetCurrentMode(m_PrevMode);
836  }
842  bool SetCurrentMode(bool isLimited)
843  {
844  foreach (SCR_EditorModeEntity modeEntity: m_Modes)
845  {
846  if (modeEntity.IsLimited() == isLimited)
847  {
848  SetCurrentMode(modeEntity.GetModeType());
849  return true;
850  }
851  }
852  return false;
853  }
858  void SetCurrentMode(EEditorMode mode)
859  {
860  //--- Check also if existing entity exists, so it can be reset after all modes were removed and a previosuly current mode was added again.
861  if (m_CurrentMode == mode && m_CurrentModeEntity)
862  return;
863 
864  m_bIsModeChangeRequested = true;
865  Event_OnModeChangeRequest.Invoke(FindModeEntity(mode), m_CurrentModeEntity);
866  Rpc(SetCurrentModeServer, mode);
867  }
872  EEditorMode GetCurrentMode()
873  {
874  if (m_bIsModeChangeRequested && m_CurrentMode == m_ProcessedMode)
875  return m_PrevMode; //--- Don't return current mode until async loading is finished
876  else
877  return m_CurrentMode;
878  }
883  SCR_EditorModeEntity GetCurrentModeEntity()
884  {
885  return m_CurrentModeEntity;
886  }
891  bool HasMode(EEditorMode mode)
892  {
893  foreach (SCR_EditorModeEntity modeEntity: m_Modes)
894  {
895  if (modeEntity && modeEntity.GetModeType() == mode)
896  return true;
897  }
898  return false;
899  }
904  SCR_EditorModeEntity FindModeEntity(EEditorMode mode)
905  {
906  foreach (SCR_EditorModeEntity modeEntity: m_Modes)
907  {
908  if (modeEntity && modeEntity.GetModeType() == mode) return modeEntity;
909  }
910  return null;
911  }
917  int GetModeEntities(out notnull array<SCR_EditorModeEntity> modeEntities)
918  {
919  modeEntities.Copy(m_Modes);
920  return modeEntities.Count();
921  }
927  int GetModes(out notnull array<EEditorMode> modes)
928  {
929  modes.Clear();
930  foreach (SCR_EditorModeEntity editorMode: m_Modes)
931  {
932  modes.Insert(editorMode.GetModeType());
933  }
934  return modes.Count();
935  }
940  EEditorMode GetModes()
941  {
942  EEditorMode modes;
943  foreach (SCR_EditorModeEntity editorMode: m_Modes)
944  {
945  modes = modes | editorMode.GetModeType();
946  }
947  return modes;
948  }
953  bool IsModeChangeRequested()
954  {
955  return m_bIsModeChangeRequested;
956  }
958 
959  protected void AddMode(notnull SCR_EditorModeEntity modeEntity, bool isInit)
960  {
961  //--- Mode already registered, ignore
962  if (m_Modes.Find(modeEntity) >= 0) return;
963 
964  int order = modeEntity.GetOrder();
965  if (order < 0)
966  {
967  //--- When default order is used, place at the back
968  m_Modes.Insert(modeEntity);
969  }
970  else
971  {
972  //--- Place according to custom order
973  int index = 0;
974  for (int c = m_Modes.Count() - 1; c >= 0; c--)
975  {
976  index = c;
977  if (m_Modes[c] && order > m_Modes[c].GetOrder())
978  {
979  index++;
980  break;
981  }
982  }
983  m_Modes.InsertAt(modeEntity, index);
984  }
985 
986  //Notification
987  if (!isInit && Replication.IsServer())
988  {
989  int playerID = GetPlayerID();
990  if (playerID > 0)
991  {
992  if (!modeEntity.SendNotificationLocalOnly())
993  SCR_NotificationsComponent.SendToUnlimitedEditorPlayersAndPlayer(playerID, modeEntity.GetOnAddNotification(), playerID);
994  else if (SCR_PlayerController.GetLocalPlayerId() == playerID)
995  SCR_NotificationsComponent.SendLocal(modeEntity.GetOnAddNotification(), playerID);
996  }
997  }
998 
999 
1000  UpdateLimited();
1001  Event_OnModeAdd.Invoke(modeEntity);
1002  }
1003  void RemoveMode(notnull SCR_EditorModeEntity modeEntity, bool OnDisconnnect)
1004  {
1005  if (!m_Modes.Contains(modeEntity))
1006  return;
1007 
1008  if (IsOwner())
1009  {
1010  m_ProcessedMode = modeEntity.GetModeType();
1011  StartEvents(EEditorEventOperation.MODE_DELETE);
1012  Rpc(RemoveModeServer, modeEntity.GetModeType());
1013  }
1014 
1015  m_Modes.RemoveItem(modeEntity);
1016  UpdateLimited();
1017 
1018  Event_OnModeRemove.Invoke(modeEntity);
1019 
1020  if (!OnDisconnnect)
1021  {
1022  int playerID = GetPlayerID();
1023 
1024  if (playerID > 0)
1025  {
1026  if (!modeEntity.SendNotificationLocalOnly())
1027  SCR_NotificationsComponent.SendToUnlimitedEditorPlayersAndPlayer(playerID, modeEntity.GetOnRemoveNotification(), playerID);
1028  else if (SCR_PlayerController.GetLocalPlayerId() == playerID)
1029  SCR_NotificationsComponent.SendLocal(modeEntity.GetOnRemoveNotification(), playerID);
1030  }
1031 
1032  }
1033  }
1034  [RplRpc(RplChannel.Reliable, RplRcver.Server)]
1035  protected void RemoveModeServer(EEditorMode mode)
1036  {
1037  if (!m_Modes.IsEmpty())
1038  {
1039  //--- Current mode was removed, switch to another one
1040  if (mode == m_CurrentMode)
1041  SetCurrentMode(-1);
1042 
1043  //--- Close when removing the mode changed access rules (e.g., remaining mode is limited)
1044  if (!CanOpen() && IsOpened())
1045  ToggleServer(false);
1046  }
1047  else
1048  {
1049  //--- Last mode was removed, close editor
1050  //if (Replication.IsRunning()) //--- Call only when the world is not shutting down
1051  SetCanOpen(false, EEditorCanOpen.MODES);
1052  }
1053  }
1054  [RplRpc(RplChannel.Reliable, RplRcver.Owner)]
1055  protected void CreateEditorModeOwner(EEditorMode mode, int modeEntityId, bool isInit)
1056  {
1057  SCR_EditorModeEntity modeEntity = SCR_EditorModeEntity.Cast(Replication.FindItem(modeEntityId));
1058  if (!modeEntity) return;
1059 
1060  AddMode(modeEntity, isInit);
1061  modeEntity.InitOwner();
1062 
1063  m_ProcessedMode = mode;
1064  StartEvents(EEditorEventOperation.MODE_CREATE);
1065  }
1066  [RplRpc(RplChannel.Reliable, RplRcver.Server)]
1067  protected void SetCurrentModeServer(EEditorMode mode)
1068  {
1069  //--- Try to use the first enabled mode
1070  if (mode < 0)
1071  mode = GetDefaultMode();
1072 
1073  //--- Ignore when there is no mode change, or when all modes were removed (i.e., GetDefaultMode() didn't find a replacement)
1074  if ((m_CurrentMode == mode && m_CurrentModeEntity) || mode == -1)
1075  return;
1076 
1077  //--- Check if mode entity is enabled
1078  SCR_EditorModeEntity modeEntity = null;
1079  if (mode >= 0)
1080  {
1081  modeEntity = FindModeEntity(mode);
1082  if (!modeEntity)
1083  {
1084  Print(string.Format("SCR_EditorModeEntity for mode '%1' not found!", Type().EnumToString(EEditorMode, mode)), LogLevel.ERROR);
1085  return;
1086  }
1087  }
1088 
1089  if (m_CurrentModeEntity && m_bIsOpened)
1090  m_CurrentModeEntity.DeactivateModeServer();
1091 
1092  Rpc(SetCurrentModeOwner, mode);
1093  m_CurrentMode = mode;
1094  m_CurrentModeEntity = modeEntity;
1095 
1096  if (m_CurrentModeEntity && m_bIsOpened)
1097  m_CurrentModeEntity.ActivateModeServer();
1098  }
1099  [RplRpc(RplChannel.Reliable, RplRcver.Owner)]
1100  protected void SetCurrentModeOwner(EEditorMode mode)
1101  {
1102  //--- When closing the game, instance reference is already removed. Don't set any mode in such case.
1103  if (!SCR_EditorManagerEntity.GetInstance()) return;
1104 
1105  SCR_EditorModeEntity modeEntity = FindModeEntity(mode);
1106  if (!modeEntity && mode >= 0)
1107  {
1108  Print(string.Format("Editor mode '%1' not found!", Type().EnumToString(EEditorMode, mode)), LogLevel.ERROR);
1109  return;
1110  }
1111  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_MODE, Math.Log2(mode));
1112 
1113  m_ProcessedMode = mode;
1114  StartEvents(EEditorEventOperation.MODE_CHANGE);
1115  }
1116 
1118  //--- Component events
1119  protected void StartEvents(EEditorEventOperation type = EEditorEventOperation.NONE)
1120  {
1121  //--- New operation requested when another one is being processed - close the editor to prevent conflicts!
1122  //--- Happens for example when editor mode is deleted while being processed.
1123  if (m_iEventOperation != EEditorEventOperation.NONE)
1124  {
1125  Print(string.Format("Editor operation %1 was requested while %2 was still running! Editor closed to prevent conflicts!", typename.EnumToString(EEditorEventOperation, type), typename.EnumToString(EEditorEventOperation, m_iEventOperation)), LogLevel.WARNING);
1126  m_aEvents = {EEditorEvent.EXIT_OPERATION};
1127  ProcessEvent();
1128  ToggleOwner(false);
1129  return;
1130  }
1131 
1132  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_ASYNC_LOAD_DEBUG))
1133  {
1134  string currentMode = typename.EnumToString(EEditorMode, m_CurrentMode);
1135  if (!m_CurrentModeEntity)
1136  currentMode += " (null)";
1137  Print(string.Format("StartEvents: %1 | current mode: %2 | processed mode: %3", typename.EnumToString(EEditorEventOperation, type), currentMode, typename.EnumToString(EEditorMode, m_ProcessedMode)), LogLevel.DEBUG);
1138  }
1139 
1140  m_iEventOperation = type;
1141  m_iEventProgress = 0;
1142 
1143  switch (type)
1144  {
1145  case EEditorEventOperation.INIT:
1146  {
1147  GetAllComponents(m_aEventComponentsActivate);
1148  m_aEvents = {
1149  EEditorEvent.INIT,
1150  EEditorEvent.EXIT_OPERATION
1151  };
1152  ProcessEvent();
1153  break;
1154  }
1155  case EEditorEventOperation.DELETE:
1156  {
1157  FindEditorComponents(m_aEventComponentsDeactivate);
1158  if (IsOpened())
1159  {
1160  if (m_ProcessedMode == m_CurrentMode)
1161  {
1162  //--- Currently opened mode
1163  m_aEvents = {
1164  EEditorEvent.DEACTIVATE,
1165  EEditorEvent.DEACTIVATE_ASYNC,
1166  EEditorEvent.POST_DEACTIVATE,
1167  EEditorEvent.CLOSE,
1168  EEditorEvent.DELETE,
1169  EEditorEvent.EXIT_OPERATION,
1170  };
1171  }
1172  else
1173  {
1174  //--- Inactive mode in opened editor
1175  m_aEvents = {
1176  EEditorEvent.CLOSE,
1177  EEditorEvent.DELETE,
1178  EEditorEvent.EXIT_OPERATION,
1179  };
1180  }
1181  }
1182  else
1183  {
1184  m_aEvents = {
1185  EEditorEvent.DELETE,
1186  EEditorEvent.EXIT_OPERATION,
1187  };
1188  }
1189  ProcessEvent();
1190  break;
1191  }
1192  case EEditorEventOperation.REQUEST_OPEN:
1193  {
1194  GetAllComponents(m_aEventComponentsActivate);
1195  m_aEvents = {
1196  EEditorEvent.REQUEST_OPEN,
1197  EEditorEvent.EXIT_OPERATION
1198  };
1199  ProcessEvent();
1200  break;
1201  }
1202  case EEditorEventOperation.OPEN:
1203  {
1204  m_iEventProgressMax = 1;
1205 
1206  FindEditorComponents(m_aEventComponentsActivate);
1207  if (m_CurrentModeEntity) m_CurrentModeEntity.FindEditorComponents(m_aEventComponentsActivate);
1208  m_aEventComponentsDeactivate = {};
1209  m_bIsInTransition = true;
1210 
1211  m_aEvents = {
1212  EEditorEvent.OPEN_ALL,
1213  EEditorEvent.PRE_ACTIVATE,
1214  EEditorEvent.ACTIVATE,
1215  EEditorEvent.ACTIVATE_ASYNC,
1216  EEditorEvent.POST_ACTIVATE,
1217  EEditorEvent.EXIT_OPERATION,
1218  };
1219  ProcessEvent();
1220  break;
1221  }
1222  case EEditorEventOperation.REQUEST_CLOSE:
1223  {
1224  GetAllComponents(m_aEventComponentsActivate);
1225  m_aEvents = {
1226  EEditorEvent.REQUEST_CLOSE,
1227  EEditorEvent.EXIT_OPERATION
1228  };
1229  ProcessEvent();
1230  break;
1231  }
1232  case EEditorEventOperation.CLOSE:
1233  {
1234  m_iEventProgressMax = 1;
1235 
1236  FindEditorComponents(m_aEventComponentsDeactivate);
1237  if (m_CurrentModeEntity) m_CurrentModeEntity.FindEditorComponents(m_aEventComponentsDeactivate);
1238  m_aEventComponentsActivate = {};
1239  m_bIsInTransition = true;
1240 
1241  m_aEvents = {
1242  EEditorEvent.DEACTIVATE,
1243  EEditorEvent.DEACTIVATE_ASYNC,
1244  EEditorEvent.POST_DEACTIVATE,
1245  EEditorEvent.CLOSE,
1246  EEditorEvent.EXIT_OPERATION
1247  };
1248  ProcessEvent();
1249  break;
1250  }
1251  case EEditorEventOperation.MODE_CHANGE:
1252  {
1253  m_iEventProgressMax = 2;
1254 
1255  FindModeEntity(m_ProcessedMode).FindEditorComponents(m_aEventComponentsActivate);
1256  m_aEventComponentsDeactivate = {};
1257  if (m_CurrentModeEntity) m_CurrentModeEntity.FindEditorComponents(m_aEventComponentsDeactivate);
1258 
1259  if (IsOpened())
1260  m_aEvents = {
1261  EEditorEvent.PRE_ACTIVATE,
1262  EEditorEvent.DEACTIVATE,
1263  EEditorEvent.DEACTIVATE_ASYNC,
1264  EEditorEvent.UPDATE_MODE,
1265  EEditorEvent.ACTIVATE,
1266  EEditorEvent.ACTIVATE_ASYNC,
1267  EEditorEvent.POST_DEACTIVATE,
1268  EEditorEvent.POST_ACTIVATE,
1269  EEditorEvent.EXIT_OPERATION,
1270  };
1271  else
1272  m_aEvents = {
1273  EEditorEvent.UPDATE_MODE,
1274  EEditorEvent.EXIT_OPERATION,
1275  };
1276  ProcessEvent();
1277  break;
1278  }
1279  case EEditorEventOperation.MODE_CREATE:
1280  {
1281  FindModeEntity(m_ProcessedMode).FindEditorComponents(m_aEventComponentsActivate);
1282  if (IsOpened())
1283  m_aEvents = {
1284  EEditorEvent.INIT,
1285  EEditorEvent.OPEN,
1286  EEditorEvent.EXIT_OPERATION
1287  };
1288  else
1289  m_aEvents = {
1290  EEditorEvent.INIT,
1291  EEditorEvent.EXIT_OPERATION
1292  };
1293  ProcessEvent();
1294  break;
1295  }
1296  case EEditorEventOperation.MODE_DELETE:
1297  {
1298  FindModeEntity(m_ProcessedMode).FindEditorComponents(m_aEventComponentsDeactivate);
1299  if (IsOpened())
1300  {
1301  if (m_ProcessedMode == m_CurrentMode)
1302  {
1303  m_aEvents = {
1304  EEditorEvent.DEACTIVATE,
1305  EEditorEvent.DEACTIVATE_ASYNC,
1306  EEditorEvent.POST_DEACTIVATE,
1307  EEditorEvent.CLOSE,
1308  EEditorEvent.DELETE,
1309  EEditorEvent.EXIT_OPERATION,
1310  };
1311  }
1312  else
1313  {
1314  m_aEvents = {
1315  EEditorEvent.CLOSE,
1316  EEditorEvent.DELETE,
1317  EEditorEvent.EXIT_OPERATION,
1318  };
1319  }
1320  }
1321  else
1322  {
1323  m_aEvents = {
1324  EEditorEvent.DELETE,
1325  EEditorEvent.EXIT_OPERATION,
1326  };
1327  }
1328  ProcessEvent();
1329  break;
1330  }
1331  }
1332  }
1333 
1334  //--- This would be so much nicer as a flow chart
1335  protected void ProcessEvent()
1336  {
1337  m_iEvent = m_aEvents[0];
1338 
1339  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_ASYNC_LOAD_DEBUG) && m_iEventComponent == 0 && m_iEventAttempt == 0)
1340  {
1341  Print(typename.EnumToString(EEditorEvent, m_iEvent), LogLevel.NORMAL);
1342  }
1343 
1344  switch (m_iEvent)
1345  {
1347  case EEditorEvent.INIT:
1348  {
1349  foreach (SCR_BaseEditorComponent component: m_aEventComponentsActivate)
1350  component.OnInitBase();
1351  break;
1352  }
1354  case EEditorEvent.REQUEST_OPEN:
1355  {
1356  foreach (SCR_BaseEditorComponent component: m_aEventComponentsActivate)
1357  component.OnRequestBase(true);
1358 
1359  Event_OnRequest.Invoke(true);
1360  break;
1361  }
1363  case EEditorEvent.REQUEST_CLOSE:
1364  {
1365  foreach (SCR_BaseEditorComponent component: m_aEventComponentsActivate)
1366  if (component) component.OnRequestBase(false);
1367 
1368  Event_OnRequest.Invoke(false);
1369  break;
1370  }
1372  case EEditorEvent.OPEN:
1373  {
1374  foreach (SCR_BaseEditorComponent component: m_aEventComponentsActivate)
1375  {
1376  if (component) component.OnOpenedBase();
1377  }
1378  break;
1379  }
1381  case EEditorEvent.OPEN_ALL:
1382  {
1383  array<SCR_BaseEditorComponent> allComponents;
1384  GetAllComponents(allComponents);
1385 
1386  foreach (SCR_BaseEditorComponent component: allComponents)
1387  {
1388  if (component) component.OnOpenedBase();
1389  }
1390  break;
1391  }
1393  case EEditorEvent.PRE_ACTIVATE:
1394  {
1395  foreach (SCR_BaseEditorComponent component: m_aEventComponentsActivate)
1396  {
1397  if (component) component.OnPreActivateBase();
1398  }
1399 
1400  SCR_EditorModeEntity processedMode = FindModeEntity(m_ProcessedMode);
1401  if (processedMode)
1402  processedMode.PreActivateMode();
1403 
1404  Event_OnPreActivate.Invoke();
1405  break;
1406  }
1408  case EEditorEvent.DEACTIVATE:
1409  {
1410  foreach (SCR_BaseEditorComponent component: m_aEventComponentsDeactivate)
1411  {
1412  if (component) component.OnDeactivateBase();
1413  }
1414  if (m_ProcessedMode == m_CurrentMode && m_CurrentModeEntity)
1415  m_CurrentModeEntity.DeactivateMode();
1416 
1417  Event_OnDeactivate.Invoke();
1418  break;
1419  }
1421  case EEditorEvent.DEACTIVATE_ASYNC:
1422  {
1423  bool instantContinue;
1424  if (ProcessAsyncEvent(false, instantContinue))
1425  {
1426  }
1427  else if (instantContinue)
1428  {
1429  ProcessEvent();
1430  return;
1431  }
1432  else
1433  {
1434  return;
1435  }
1436 
1437  break;
1438  }
1440  case EEditorEvent.ACTIVATE:
1441  {
1442  foreach (SCR_BaseEditorComponent component: m_aEventComponentsActivate)
1443  {
1444  if (component) component.OnActivateBase();
1445  }
1446 
1447  if (m_CurrentModeEntity)
1448  m_CurrentModeEntity.ActivateMode();
1449 
1450  Event_OnActivate.Invoke();
1451  break;
1452  }
1454  case EEditorEvent.ACTIVATE_ASYNC:
1455  {
1456  bool instantContinue;
1457  if (ProcessAsyncEvent(true, instantContinue))
1458  {
1459  }
1460  else if (instantContinue)
1461  {
1462  ProcessEvent();
1463  return;
1464  }
1465  else
1466  {
1467  return;
1468  }
1469 
1470  break;
1471  }
1473  case EEditorEvent.POST_DEACTIVATE:
1474  {
1475  foreach (SCR_BaseEditorComponent component: m_aEventComponentsDeactivate)
1476  {
1477  if (component) component.OnPostDeactivateBase();
1478  }
1479  break;
1480  }
1482  case EEditorEvent.POST_ACTIVATE:
1483  {
1484  foreach (SCR_BaseEditorComponent component: m_aEventComponentsActivate)
1485  {
1486  if (component) component.OnPostActivateBase();
1487  }
1488 
1489  if (m_CurrentModeEntity)
1490  m_CurrentModeEntity.PostActivateMode();
1491 
1492  Event_OnPostActivate.Invoke();
1493  break;
1494  }
1496  case EEditorEvent.CLOSE:
1497  {
1498  foreach (SCR_BaseEditorComponent component: m_aEventComponentsDeactivate)
1499  {
1500  if (component) component.OnClosedBase();
1501  }
1502  break;
1503  }
1505  case EEditorEvent.DELETE:
1506  {
1507  foreach (SCR_BaseEditorComponent component: m_aEventComponentsDeactivate)
1508  {
1509  if (component) component.OnDeleteBase();
1510  }
1511  break;
1512  }
1514  case EEditorEvent.UPDATE_MODE:
1515  {
1516  m_PrevMode = m_CurrentMode;
1517  m_CurrentMode = m_ProcessedMode;
1518  m_CurrentModeEntity = FindModeEntity(m_CurrentMode);
1519  break;
1520  }
1522  case EEditorEvent.EXIT_OPERATION:
1523  {
1524  //--- Set before invokers are called, so using getters in them will not see transition as active anymore
1525  m_bIsInTransition = false;
1526 
1527  //--- Call invokers once all events are processed
1528  switch (m_iEventOperation)
1529  {
1530  case EEditorEventOperation.OPEN:
1531  {
1532  Event_OnAsyncLoad.Invoke(1);
1533  Event_OnOpened.Invoke();
1534  Rpc(ToggleOwnerServerCallback, true);
1535  break;
1536  }
1537  case EEditorEventOperation.CLOSE:
1538  {
1539  Event_OnAsyncLoad.Invoke(1);
1540  Event_OnClosed.Invoke();
1541  Rpc(ToggleOwnerServerCallback, false);
1542  break;
1543  }
1544  case EEditorEventOperation.MODE_CHANGE:
1545  {
1546  m_bIsModeChangeRequested = false;
1547  if (IsOpened()) Event_OnAsyncLoad.Invoke(1);
1548  Event_OnModeChange.Invoke(m_CurrentModeEntity, FindModeEntity(m_PrevMode));
1549  break;
1550  }
1551  }
1552 
1553  //--- Clean up
1554  m_iEventOperation = EEditorEventOperation.NONE;
1555  m_aEventComponentsActivate = null;
1556  m_aEventComponentsDeactivate = null;
1557  m_iEvent = EEditorEvent.NONE;
1558  m_ProcessedMode = 0;
1559  return;
1560  }
1561  }
1562 
1563  //--- Next event
1564  m_aEvents.RemoveOrdered(0);
1565  if (!m_aEvents.IsEmpty())
1566  ProcessEvent();
1567  }
1568  protected bool ProcessAsyncEvent(bool toActivate, out bool instantContinue)
1569  {
1570  //--- Get components to be processed
1571  array<SCR_BaseEditorComponent> components;
1572  if (toActivate)
1573  components = m_aEventComponentsActivate;
1574  else
1575  components = m_aEventComponentsDeactivate;
1576 
1577  //--- All processed, clean up and exit
1578  if (m_iEventComponent >= components.Count())
1579  {
1580  m_iEventComponent = 0;
1581  m_iEventAttempt = 0;
1582  return true;
1583  }
1584 
1585  //--- Block input
1586  GetGame().GetInputManager().ActivateContext("DebugContext");
1587 
1588  //--- Start timer
1589  if (m_iEventAttempt == 0)
1590  m_fEventAsyncStart = GetGame().GetWorld().GetWorldTime();
1591 
1592  //--- Process component
1593  bool isProcessed;
1594  SCR_BaseEditorComponent component = components[m_iEventComponent];
1595  if (component)
1596  {
1597  if (toActivate)
1598  isProcessed = component.OnActivateAsyncBase(m_iEventAttempt);
1599  else
1600  isProcessed = component.OnDeactivateAsyncBase(m_iEventAttempt);
1601 
1602  //--- Editor mode to which the component belongs to is being deleted - execute instantly, no time for async
1603  instantContinue = IsDeleted() || !component.GetOwner() || component.GetOwner().IsDeleted();
1604  }
1605  else
1606  {
1607  //--- Component was meanwhile deleted, skip it
1608  isProcessed = true;
1609  instantContinue = true;
1610  m_iEventAttempt = 0;
1611  }
1612 
1613  if (isProcessed)
1614  {
1615  //--- Next component
1616  if (m_iEventAttempt == 0)
1617  instantContinue = true;
1618 
1619  m_iEventComponent++;
1620  m_iEventAttempt = 0;
1621  m_iEventProgress += 1 / components.Count() / m_iEventProgressMax;
1622  Event_OnAsyncLoad.Invoke(m_iEventProgress);
1623 
1624  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_ASYNC_LOAD_DEBUG) && component)
1625  Print(string.Format("%1 (%2), %3 ms", Math.Round(m_iEventProgress * 100), component.Type(), GetGame().GetWorld().GetWorldTime() - m_fEventAsyncStart), LogLevel.VERBOSE);
1626  }
1627  else
1628  {
1629  //--- Next attempt
1630  m_iEventAttempt++;
1631  }
1632  return false;
1633  }
1634  protected void GetAllComponents(out array<SCR_BaseEditorComponent> outComponents)
1635  {
1636  FindEditorComponents(outComponents);
1637  foreach (SCR_EditorModeEntity mode: m_Modes)
1638  {
1639  if (mode)
1640  mode.FindEditorComponents(outComponents);
1641  }
1642  }
1643 
1645  //--- Actions
1646  protected void Action_EditorToggle(float value, EActionTrigger reason)
1647  {
1648  Toggle();
1649  }
1650 
1651  protected void Action_GoToLatestNotification(float value, EActionTrigger reason)
1652  {
1653  if (!m_NotificationsComponent)
1654  m_NotificationsComponent = SCR_NotificationsComponent.GetInstance();
1655 
1656  if (IsOpened() && !IsLimited() && m_NotificationsComponent)
1657  {
1658  vector goToPosition;
1659  if (m_NotificationsComponent.GetLastNotificationLocation(goToPosition))
1660  {
1661  SCR_ManualCamera camera = SCR_CameraEditorComponent.GetCameraInstance();
1663  cursorManualCameraComponent.TeleportCamera(goToPosition);
1664  }
1665 
1666  }
1667 
1668  }
1669 
1671  //--- Debug
1672  protected void ShowDebug()
1673  {
1674  array<string> debugTexts = new array<string>;
1675 
1676  string accessSuffix = "";
1677  debugTexts.Insert(string.Format("CanOpen: %1/%2", m_CanOpen, m_CanOpenSum));
1678  debugTexts.Insert(string.Format("CanClose: %1/%2", m_CanClose, m_CanCloseSum));
1679 
1680  string currentModeName = "N/A";
1681  if (m_CurrentModeEntity) currentModeName = typename.EnumToString(EEditorMode, m_CurrentModeEntity.GetModeType());
1682  debugTexts.Insert(string.Format("Current Mode: %1", currentModeName));
1683  debugTexts.Insert(string.Format("Available Modes: %1", m_Modes.Count()));
1684  debugTexts.Insert(string.Format("Limited: %1", m_bIsLimited));
1685  GetOnDebug().Invoke(debugTexts);
1686 
1687  DbgUI.Begin("SCR_EditorManagerEntity", 0, 0);
1688  foreach (string text: debugTexts)
1689  {
1690  DbgUI.Text(text);
1691  }
1692  DbgUI.End();
1693  }
1694  protected void ProcessDebug()
1695  {
1696 #ifdef ENABLE_DIAG
1697  bool isOpened = DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_IS_OPENED);
1698  if (isOpened != IsOpened())
1699  {
1700  //--- Make sure the editor can be opened / closed
1701  if (isOpened)
1702  {
1703  SetCanOpenDebug(true, EEditorCanOpen.SCRIPT);
1704  }
1705  else
1706  {
1707  SetCanCloseDebug(true);
1708  }
1709  Toggle();
1710  }
1711  bool canOpen = DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_OPEN);
1712  if (canOpen != CanOpen(EEditorCanOpen.SCRIPT))
1713  {
1714  SetCanOpenDebug(canOpen, EEditorCanOpen.SCRIPT);
1715  }
1716  bool canClose = DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_CLOSE);
1717  if (canClose != CanClose(EEditorCanOpen.SCRIPT))
1718  {
1719  SetCanCloseDebug(canClose);
1720  }
1721 
1722  if (m_CurrentModeEntity)
1723  {
1724  int debugMode = 1 << DiagMenu.GetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_MODE);
1725  if (m_CurrentMode != debugMode && FindModeEntity(debugMode))
1726  {
1727  SetCurrentMode(debugMode);
1728  }
1729  }
1730 
1731  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_SHOW_DEBUG)) ShowDebug();
1732 #endif
1733  }
1734 
1736  //--- Init
1737  void InitServer(int playerID)
1738  {
1739  if (m_bInit)
1740  return;
1741 
1742  m_bInit = true;
1743  m_iPlayerID = playerID;
1744 
1745  InitComponents(true);
1746  Rpc(InitOwner, playerID);
1747 
1748  //--- Initialize modes
1749  IEntity child = GetChildren();
1750  while (child)
1751  {
1752  SCR_EditorModeEntity modeEntity = SCR_EditorModeEntity.Cast(child);
1753  if (modeEntity) modeEntity.InitServer(this);
1754  child = child.GetSibling();
1755  }
1756  }
1757  [RplRpc(RplChannel.Reliable, RplRcver.Owner)]
1758  protected void InitOwner(int playerID)
1759  {
1760  if (GetInstance())
1761  return; //--- Exit when already initialized
1762 
1764  if (!core || !core.SetEditorManager(this))
1765  return;
1766 
1767  m_bInit = true;
1768  m_RplComponent = RplComponent.Cast(FindComponent(RplComponent));
1769  if (!m_RplComponent) Print("SCR_EditorManagerEntity is missing RplComponent component!", LogLevel.ERROR);
1770 
1771  m_iPlayerID = playerID;
1772  InitComponents(false);
1773 
1774  StartEvents(EEditorEventOperation.INIT); //--- Init on all editor components
1775  //Event_OnInit.Invoke();
1776  core.Event_OnEditorManagerInitOwner.Invoke(this); //--- External init
1777 
1778  SetEventMask(EntityEvent.FRAME);
1779 
1780  InputManager inputManager = GetGame().GetInputManager();
1781  if (inputManager)
1782  {
1783  inputManager.AddActionListener("EditorToggle", EActionTrigger.PRESSED, Action_EditorToggle);
1784  inputManager.AddActionListener("EditorLastNotificationTeleport", EActionTrigger.DOWN, Action_GoToLatestNotification);
1785  }
1786 
1787  //--- Debug
1788  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_EDITOR_IS_OPENED, "", "Is Opened", "Editor");
1789  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_OPEN, "", "Can Open", "Editor");
1790  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_CLOSE, "", "Can Close", "Editor");
1791  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_EDITOR_SHOW_DEBUG, "", "Show Debug", "Editor");
1792  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_EDITOR_FORCE_LIMITED, "", "Force Limited", "Editor");
1793  DiagMenu.RegisterBool(SCR_DebugMenuID.DEBUGUI_EDITOR_ASYNC_LOAD_DEBUG, "", "Log Async Load", "Editor");
1794  DiagMenu.RegisterRange(SCR_DebugMenuID.DEBUGUI_EDITOR_NETWORK_DELAY, "", "Simulated Network Delay", "Editor", "0 1000 0 100");
1795 
1796  //--- Reset values, they're stored from the previous session
1797  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_IS_OPENED, m_bIsOpened);
1798  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_OPEN, m_CanOpen);
1799  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_CLOSE, m_CanClose);
1800 
1801  typename enumType = EEditorMode;
1802  int enumCount = enumType.GetVariableCount();
1803  DiagMenu.RegisterRange(SCR_DebugMenuID.DEBUGUI_EDITOR_MODE, "", "Mode", "Editor", string.Format("0 %1 0 1", enumCount - 1));
1804  DiagMenu.SetValue(SCR_DebugMenuID.DEBUGUI_EDITOR_MODE, Math.Max(m_CurrentMode, 0));
1805  }
1806  void PostInitServer()
1807  {
1808  if (m_CurrentMode < 0)
1809  {
1810  SetCurrentModeServer(-1);
1811  }
1812  }
1813  void AutoInit()
1814  {
1815  if (m_bIsAutoInit && !m_bIsLimited)
1816  {
1817  Open(false);
1818  }
1819  m_bIsAutoInit = false;
1820  }
1821 
1823  //--- Default functions
1824  override void EOnInit(IEntity owner)
1825  {
1826  super.EOnInit(owner);
1827 
1828  ChimeraWorld world = GetGame().GetWorld();
1829  if (world)
1830  {
1831  world.RegisterEntityToBeUpdatedWhileGameIsPaused(this);
1832  }
1833  }
1834  override void EOnFrame(IEntity owner, float timeSlice) //--- Active only when the entity is local (see InitOwner())
1835  {
1836  if (m_iEvent == EEditorEvent.NONE)
1837  ProcessDebug();
1838  else
1839  ProcessEvent();
1840  }
1841  void SCR_EditorManagerEntity(IEntitySource src, IEntity parent)
1842  {
1843  m_CanOpenSum = GetEnumSum(EEditorCanOpen);
1844  m_CanCloseSum = GetEnumSum(EEditorCanClose);
1845 
1846  SetFlags(EntityFlags.NO_TREE | EntityFlags.NO_LINK);
1847  }
1848  void ~SCR_EditorManagerEntity()
1849  {
1850  while (!m_Modes.IsEmpty())
1851  {
1852  if (m_Modes[0])
1853  RemoveMode(m_Modes[0], true);
1854  else
1855  m_Modes.RemoveOrdered(0);
1856  }
1857 
1858  if (m_CurrentModeEntity)
1859  m_CurrentModeEntity.DeactivateModeServer();
1860 
1861  if (Replication.IsServer() && IsOpened())
1862  Event_OnClosedServer.Invoke();
1863 
1864  if (IsOwner())
1865  StartEvents(EEditorEventOperation.DELETE);
1866 
1867  if (GetInstance() == this)
1868  {
1869  //--- Local entity
1870  DiagMenu.Unregister(SCR_DebugMenuID.DEBUGUI_EDITOR_IS_OPENED);
1871  DiagMenu.Unregister(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_OPEN);
1872  DiagMenu.Unregister(SCR_DebugMenuID.DEBUGUI_EDITOR_CAN_CLOSE);
1873  DiagMenu.Unregister(SCR_DebugMenuID.DEBUGUI_EDITOR_SHOW_DEBUG);
1874  DiagMenu.Unregister(SCR_DebugMenuID.DEBUGUI_EDITOR_MODE);
1875  DiagMenu.Unregister(SCR_DebugMenuID.DEBUGUI_EDITOR_ASYNC_LOAD_DEBUG);
1876  DiagMenu.Unregister(SCR_DebugMenuID.DEBUGUI_EDITOR_NETWORK_DELAY);
1877  }
1878 
1879  ChimeraWorld world = GetGame().GetWorld();
1880  if (world)
1881  {
1882  world.UnregisterEntityToBeUpdatedWhileGameIsPaused(this);
1883  }
1884  }
1885 };
1886 
1889 {
1890  [Attribute(string.Format("%1", EEditorMode.EDIT), desc: "", uiwidget: UIWidgets.ComboBox, enums: ParamEnumArray.FromEnum(EEditorMode))]
1891  private EEditorMode m_Mode;
1892 
1893  [Attribute("", UIWidgets.ResourceNamePicker, "Individual editor manager", "et")]
1894  private ResourceName m_Prefab;
1895 
1896  [Attribute("", desc: "", uiwidget: UIWidgets.Flags, enums: ParamEnumArray.FromEnum(EEditorModeFlag))]
1897  private EEditorModeFlag m_Flags;
1898 
1899  [Attribute()]
1900  protected ref SCR_EditorModeUIInfo m_ModeUIInfo;
1901 
1902  EEditorMode GetMode()
1903  {
1904  return m_Mode;
1905  }
1906  ResourceName GetPrefab()
1907  {
1908  return m_Prefab;
1909  }
1910  EEditorModeFlag GetFlags()
1911  {
1912  return m_Flags;
1913  }
1914 
1915  SCR_EditorModeUIInfo GetInfo()
1916  {
1917  return m_ModeUIInfo;
1918  }
1919 };
ChimeraWorld
Definition: ChimeraWorld.c:12
SCR_ManualCamera
Definition: SCR_ManualCamera.c:16
SCR_PlayerController
Definition: SCR_PlayerController.c:31
SCR_EditorBaseEntityClass
Definition: SCR_EditorBaseEntity.c:2
SCR_Enum
Definition: SCR_Enum.c:1
EEditorEvent
EEditorEvent
Editor event processed in components.
Definition: EEditorEvent.c:5
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
EPlayerRole
EPlayerRole
Definition: EPlayerRole.c:7
SCR_BaseContainerCustomTitleEnum
class SCR_CampaignHintStorage SCR_BaseContainerCustomTitleEnum(EHint, "m_eHintId")
Definition: SCR_CampaignHintStorage.c:22
EEditorModeAccess
EEditorModeAccess
Definition: EEditorModeAccess.c:1
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
SCR_CameraEditorComponent
Definition: SCR_CameraEditorComponent.c:13
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
SCR_EditorModeEntity
Definition: SCR_EditorModeEntity.c:22
SCR_EditorManagerEntityClass
Definition: SCR_EditorManagerEntity.c:2
RplRpc
SCR_AchievementsHandlerClass ScriptComponentClass RplRpc(RplChannel.Reliable, RplRcver.Owner)] void UnlockOnClient(AchievementId achievement)
Definition: SCR_AchievementsHandler.c:11
m_Modes
EEditorMode m_Modes
Definition: SCR_EditorManagerCore.c:582
GetGameMode
SCR_BaseGameMode GetGameMode()
Definition: SCR_BaseGameModeComponent.c:15
ENotification
ENotification
Definition: ENotification.c:4
SCR_BaseEditorComponent
Definition: SCR_BaseEditorComponent.c:119
Attribute
typedef Attribute
Post-process effect of scripted camera.
SCR_EditorManagerCore
Core component to manage SCR_EditorManagerEntity.
Definition: SCR_EditorManagerCore.c:5
m_bInit
protected bool m_bInit
Definition: SCR_BaseHintCondition.c:5
EEditorModeFlag
EEditorModeFlag
Definition: EEditorModeFlag.c:1
EEditorMode
EEditorMode
Editor mode that defines overall functionality.
Definition: EEditorMode.c:5
m_RplComponent
protected RplComponent m_RplComponent
Definition: SCR_CampaignBuildingManagerComponent.c:42
index
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
Definition: SCR_DestructionSynchronizationComponent.c:17
GetOrder
int GetOrder()
Definition: SCR_Faction.c:78
EEditorCanOpen
EEditorCanOpen
Layers allowing editor to be opened. All of them have to be activated (certain exceptions may apply w...
Definition: EEditorCanOpen.c:5
type
EDamageType type
Definition: SCR_DestructibleTreeV2.c:32
GameStatsApi
Statistical Api - Analytics.
Definition: GameStatsApi.c:13
m_iPlayerID
SCR_EditorManagerCore m_iPlayerID
SCR_TeleportToCursorManualCameraComponent
Teleport the camera to the cursor's world position.
Definition: SCR_TeleportToCursorManualCameraComponent.c:5
GetChildren
void GetChildren(out array< SCR_ScenarioFrameworkLayerBase > children)
Definition: SCR_ScenarioFrameworkLayerBase.c:359
EEditorCanClose
EEditorCanClose
Layers allowing editor to be closed. All of them have to be activated.
Definition: EEditorCanClose.c:5
SCR_EditorModePrefab
Definition: SCR_EditorManagerEntity.c:1888
m_Prefab
ResourceName m_Prefab
Definition: ForestGeneratorObjects.c:48
SCR_EditorBaseEntity
Definition: SCR_EditorBaseEntity.c:14
SCR_DebugMenuID
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition: DebugMenuID.c:3
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
EEditorEventOperation
EEditorEventOperation
Type of event-processing operation.
Definition: EEditorEventOperation.c:5
BaseContainerProps
SCR_AIGoalReaction_Follow BaseContainerProps
Handles insects that are supposed to be spawned around selected prefabs defined in prefab names array...
Definition: SCR_AIGoalReaction.c:468
SCR_EditorModeUIInfo
Definition: SCR_EditorModeUIInfo.c:2
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180
SCR_EditorManagerEntity
Definition: SCR_EditorManagerEntity.c:26