Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_AddonManager.c
Go to the documentation of this file.
1/*
2Several classes for addon manager.
3
4SCR_WorkshopItem
5
6Wraps functionality of WorkshopItem and Dependency objects. The main purpose of this class is to
7provide access to WorkshopItem from multiple menus at the same time. For everything to work correctly, perform all
8actions with workshop items through this class, instead of accessing the WorkshopItem methods direcly.
9
10To create a SCR_WorkshopItem object, use SCR_AddonManager.Register() methods.
11
12Make sure you use strong refs (ref keyword) to store pointers to SCR_WorkshopItem object, because it might get garbage
13collected by SCR_AddonManager if it is not needed by any other object.
14
15
16SCR_AddonManager
17
18Centralized storage of all SCR_WorkshopItem objects. It performs registration and updates of SCR_WorkshopItem objects.
19
20It is an Entity and must be placed in the world to use it.
21
22
23SCR_WorkshopItemAction
24
25Base class for asynchronous operations of workshop items. Some methods of SCR_WorkshopItem return an action object,
26which you can use to monitor the result of the operation, cancel/pause/resume it, or subscribe to its events. It's also the only way to know
27if the action was canceled by something else.
28
29
30!!! Methods marked with "Internal_" are not meant to be used publicly, although they are declared public.
31*/
32
33// Enum of bit flags used for doing queries
69
72typedef ScriptInvokerBase<ScriptInvokerSCRWorkshopItemMethod> ScriptInvokerWorkshopItem;
73
74[EntityEditorProps(category: "", description: "A centralized system which lets many users perform actions on addons. Most likely only needed in the main menu world.")]
75class SCR_AddonManagerClass: GenericEntityClass
76{
77};
78
79class SCR_AddonManager : GenericEntity
80{
81 // friend class SCR_WorkshopItem
82
83 // Constants
84 static const string ADDONS_CLI = "addons"; // Cli parameter used to load addons.
85 static const string VERSION_DOT = ".";
86 protected const static float ADDONS_ENABLED_UPDATE_INTERVAL_S = 1/30;
87 protected const static float ADDONS_OUTDATED_UPDATE_INTERVAL_S = 1.0;
88
89 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
90 // Old untyped invokers. This code is old and unmantained, and we also have a SCR_DonwloadManager class that seems to share some responsibilitites and that fires it's own invokers and some of them seem to happen on the same events as this one, making it unclear to which ones classes should listen to
91
92 // Public callbacks
94
95 // Called when a new addon is downloaded or uninstalled
96 ref ScriptInvoker m_OnAddonOfflineStateChanged = new ScriptInvoker; // (SCR_WorkshopItem item, bool newState) - newState: true - addon downloaded, false - addon deleted
97
98 // Called when reported state of addon is changed
99 ref ScriptInvoker m_OnAddonReportedStateChanged = new ScriptInvoker; // (SCR_WorkshopItem item, bool newReported) - newReported: new reported value
100
101 // Called as a result of NegotiateUgcPrivilege
103
104 // Called wherever set of enabled addons has changed
106
107 // Other
108 protected ref array<WorkshopItem> m_aAddonsToRegister = {};
110 protected static SCR_AddonManager s_Instance; // Pointer to instance of this class
112 protected int m_iAddonsOutdated;
113 protected float m_fAddonsOutdatedTimer = 0;
114 protected float m_fAddonsEnabledTimer = 0;
115 protected string m_sAddonsEnabledPrev;
116
117 // Connected to WorkshopApi.OnItemsChecked, which automatically runs at start up.
118 protected bool m_bAddonsChecked = false;
121 protected bool m_bInitFinished = false;
122
124
126
129
130 // Called when a new download have been started
131 ref ScriptInvoker m_OnNewDownload = new ScriptInvoker; // (SCR_WorkshopItem item, SCR_WorkshopItemActionDownload action)
132
133 //---- REFACTOR NOTE END ----
134
135 //-----------------------------------------------------------------------------------------------
136 // P U B L I C A P I
137 //-----------------------------------------------------------------------------------------------
138 //-----------------------------------------------------------------------------------------------
139 static SCR_AddonManager GetInstance()
140 {
141 return s_Instance;
142 }
143
144
145 //-----------------------------------------------------------------------------------------------
147 array<ref SCR_WorkshopItem> GetAllAddons()
148 {
149 array<ref SCR_WorkshopItem> ret = {};
150 foreach (string id, SCR_WorkshopItem item : m_mItems)
151 {
152 ret.Insert(item);
153 }
154 return ret;
155 }
156
157 //-----------------------------------------------------------------------------------------------
159 array<ref SCR_WorkshopItem> GetOfflineAddons()
160 {
161 array<ref SCR_WorkshopItem> ret = {};
162 foreach (string id, SCR_WorkshopItem item : m_mItems)
163 {
164 if (item.GetOffline())
165 ret.Insert(item);
166 }
167 return ret;
168 }
169
170 //-----------------------------------------------------------------------------------------------
173 {
174 string id = GetItemId(item);
175 SCR_WorkshopItem existingItem = m_mItems.Get(id);
176
177 #ifdef WORKSHOP_DEBUG
178 _print(string.Format("Register WorkshopItem: ID: %1, Name: %2, Found in map: %3", id, item.Name(), existingItem != null));
179 #endif
180
181 if (existingItem)
182 {
183 existingItem.Internal_UpdateObjects(item, null);
184
185 #ifdef WORKSHOP_DEBUG
186 //existingItem.LogState();
187 #endif
188
189 return existingItem;
190 }
191
193 RegisterNewItem(id, newItem);
194
195 #ifdef WORKSHOP_DEBUG
196 newItem.LogState();
197 #endif
198
199 return newItem;
200 }
201
202 //-----------------------------------------------------------------------------------------------
205 {
206 string id = GetItemId(item);
207 SCR_WorkshopItem existingItem = m_mItems.Get(id);
208
209 #ifdef WORKSHOP_DEBUG
210 _print(string.Format("Register Dependency: ID: %1, Name: %2, Found in map: %3", id, item.GetName(), existingItem != null));
211 #endif
212
213 if (existingItem)
214 {
215 existingItem.Internal_UpdateObjects(null, item);
216
217 #ifdef WORKSHOP_DEBUG
218 //existingItem.LogState();
219 #endif
220
221 return existingItem;
222 }
223
225 RegisterNewItem(id, newItem);
226
227 #ifdef WORKSHOP_DEBUG
228 newItem.LogState();
229 #endif
230
231 return newItem;
232 }
233
234 //-----------------------------------------------------------------------------------------------
237 bool GetReady()
238 {
240 }
241
242 //-----------------------------------------------------------------------------------------------
244 //bool GetAllAsyncChecksDone() { return m_bAddonsChecked ; }
245
246 //-----------------------------------------------------------------------------------------------
248 {
249 return m_bAddonsChecked;
250 }
251
252 //-----------------------------------------------------------------------------------------------
255 {
256 return SocialComponent.IsPrivilegedTo(EUserInteraction.UserGeneratedContent);
257 }
258
259 //----------------------------------------------------------------------------------------------------------------------------------------------------
262 {
263 return m_iAddonsOutdated;
264 }
265
266 //-----------------------------------------------------------------------------------------------
271 {
272 _print("CheckPrivilege()", LogLevel.NORMAL);
273
275 {
278 }
279
280 SocialComponent.RequestSocialPrivilege(EUserInteraction.UserGeneratedContent, m_CallbackGetPrivilege);
281 }
282
283 // Handling of addons loaded through external configuration
284 //-----------------------------------------------------------------------------------------------
286 protected static bool GetAddonsEnabledExternally()
287 {
288 return System.IsCLIParam(ADDONS_CLI);
289 }
290
291 //-----------------------------------------------------------------------------------------------
294 {
296 return false;
297
298 return item.GetLoaded();
299 }
300
301 //-----------------------------------------------------------------------------------------------
304 static array<ref SCR_WorkshopItem> SelectItemsBasic(array<ref SCR_WorkshopItem> items, EWorkshopItemQuery query)
305 {
306 array<ref SCR_WorkshopItem> ret = {};
307 foreach (SCR_WorkshopItem item : items)
308 {
309 if (CheckQueryFlag(item, query))
310 ret.Insert(item);
311 }
312
313 return ret;
314 }
315
316 //-----------------------------------------------------------------------------------------------
319 static int CountItemsBasic(array<ref SCR_WorkshopItem> items, EWorkshopItemQuery query, bool returnOnFirstMatch = false)
320 {
321 int count = 0;
322 foreach (SCR_WorkshopItem item : items)
323 {
324 if (CheckQueryFlag(item, query))
325 {
326 count++;
327 if (returnOnFirstMatch)
328 return count;
329 }
330 }
331
332 return count;
333 }
334
335 //-----------------------------------------------------------------------------------------------
338 static array<ref SCR_WorkshopItem> SelectItemsAnd(array<ref SCR_WorkshopItem> items, EWorkshopItemQuery query)
339 {
340 array<ref SCR_WorkshopItem> ret = {};
341 foreach (SCR_WorkshopItem item : items)
342 {
343 if (CheckQueryFlagsAnd(item, query))
344 ret.Insert(item);
345 }
346
347 return ret;
348 }
349
350
351 //-----------------------------------------------------------------------------------------------
353 static int CountItemsAnd(array<ref SCR_WorkshopItem> items, EWorkshopItemQuery query, bool returnOnFirstMatch = false)
354 {
355 int count = 0;
356 foreach (SCR_WorkshopItem item : items)
357 {
358 if (CheckQueryFlagsAnd(item, query))
359 {
360 count++;
361 if (returnOnFirstMatch)
362 return count;
363 }
364 }
365
366 return count;
367 }
368
369 //-----------------------------------------------------------------------------------------------
372 static array<ref SCR_WorkshopItem> SelectItemsOr(array<ref SCR_WorkshopItem> items, EWorkshopItemQuery query)
373 {
374 array<ref SCR_WorkshopItem> ret = {};
375 foreach (SCR_WorkshopItem item : items)
376 {
377 if (CheckQueryFlagsOr(item, query))
378 ret.Insert(item);
379 }
380
381 return ret;
382 }
383
384 //-----------------------------------------------------------------------------------------------
386 static int CountItemsOr(array<ref SCR_WorkshopItem> items, EWorkshopItemQuery query, bool returnOnFirstMatch = false)
387 {
388 int count = 0;
389 foreach (SCR_WorkshopItem item : items)
390 {
391 if (CheckQueryFlagsOr(item, query))
392 {
393 count++;
394 if (returnOnFirstMatch)
395 return count;
396 }
397 }
398
399 return count;
400 }
401
402 //-----------------------------------------------------------------------------------------------
404 //OBSOLETE => use Revision.CompareTo
405 static SCR_ComparerOperator DifferenceBetweenVersions(string vFrom, string vTo)
406 {
407 // Get versions numbers
408 array<string> fromNums = {};
409 vFrom.Split(VERSION_DOT, fromNums, false);
410
411 array<string> toNums = {};
412 vTo.Split(VERSION_DOT, toNums, false);
413
414 // Setup count by smaller array
415 int count = fromNums.Count();
416 if (count > toNums.Count())
417 count = toNums.Count();
418
419 for (int i; i < count; i++)
420 {
421 int iFrom = fromNums[i].ToInt();
422 int iTo = toNums[i].ToInt();
423
424 // Compare version
425 if (iFrom < iTo)
426 {
427 // Current is old
428 return SCR_ComparerOperator.LESS_THAN;
429 }
430 else if (iFrom > iTo)
431 {
432 // Current is newer
433 return SCR_ComparerOperator.GREATER_THAN;
434 }
435 else if (iFrom == iTo)
436 {
437 // Versions are same
438 int end = vTo.IndexOfFrom(i, VERSION_DOT) - 1;
439
440 if (end == -1)
441 return SCR_ComparerOperator.EQUAL;
442 }
443 }
444
445 return -1;
446 }
447
448 //------------------------------------------------------------------------------------------------
451 static SCR_ERevisionAvailability ItemAvailability(notnull WorkshopItem item)
452 {
453 Revision currentRev = item.GetActiveRevision();
454 if (!currentRev)
455 {
456 // Downloading was not finished
457 if (item.GetDownloadingRevision())
458 return SCR_ERevisionAvailability.ERA_DOWNLOAD_NOT_FINISHED;
459
460 return SCR_ERevisionAvailability.ERA_UNKNOWN_AVAILABILITY;
461 }
462
463 ERevisionAvailability currentAvailability = currentRev.GetAvailability();
464
465 // Addon is ok
466 if (currentAvailability == ERevisionAvailability.ERA_AVAILABLE)
467 return SCR_ERevisionAvailability.ERA_AVAILABLE;
468
469 Revision latestRev = item.GetLatestRevision();
470 ERevisionAvailability latestAvailability = latestRev.GetAvailability();
471
472 if (!latestRev)
473 {
474 Print("ItemAvailability() - Can't compare availability of item " + item.Name() + " latest revision", LogLevel.WARNING);
475 return SCR_ERevisionAvailability.ERA_DELETED;
476 }
477
478 // Deleted
479 if (currentAvailability == ERevisionAvailability.ERA_DELETED)
480 {
481 // Update is available
482 if (latestAvailability == ERevisionAvailability.ERA_AVAILABLE)
483 return SCR_ERevisionAvailability.ERA_COMPATIBLE_UPDATE_AVAILABLE;
484
485 return SCR_ERevisionAvailability.ERA_DELETED;
486 }
487
488 // Current addon is obsolete (not compatible with client version)
489 if (currentAvailability == ERevisionAvailability.ERA_OBSOLETE)
490 {
491 // Update is available
492 if (latestAvailability == ERevisionAvailability.ERA_AVAILABLE)
493 return SCR_ERevisionAvailability.ERA_COMPATIBLE_UPDATE_AVAILABLE;
494
495 // No compatible update available
496 return SCR_ERevisionAvailability.ERA_OBSOLETE;
497 }
498
499 return SCR_ERevisionAvailability.ERA_AVAILABLE;
500 }
501
502 //------------------------------------------------------------------------------------------------
503 protected void InvokeEventOnAddonEnabled(SCR_WorkshopItem arg0, int arg1)
504 {
506 Event_OnAddonEnabled.Invoke(arg0, arg1);
507 }
508
509 //------------------------------------------------------------------------------------------------
517
518 //------------------------------------------------------------------------------------------------
520 {
523 }
524
525 //------------------------------------------------------------------------------------------------
533
534//---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
535// addon manager system doing UI
536
537 //-----------------------------------------------------------------------------------------------
539 void EnableMultipleAddons(array<ref SCR_WorkshopItem> items, bool enable)
540 {
541 int count = items.Count() - 1;
542
543 GetGame().GetCallqueue().CallLater(EnableAddonsRecursively, 0, false, items, count, enable);
544
545 //m_LoadingOverlay = SCR_LoadingOverlayDialog.Create();
546 if (!m_LoadingOverlay)
547 m_LoadingOverlay = SCR_LoadingOverlay.ShowForWidget(GetGame().GetWorkspace(), string.Empty);
548 else
549 m_LoadingOverlay.SetShown(true);
550 }
551
552//---- REFACTOR NOTE END ----
553
554 //-----------------------------------------------------------------------------------------------
555 protected void EnableAddonsRecursively(array<ref SCR_WorkshopItem> addons, out int remaining, bool enable)
556 {
557 if (remaining > -1)
558 {
559 addons[remaining].SetEnabled(enable);
560 InvokeEventOnAddonEnabled(addons[remaining], remaining);
561 remaining--;
562
563 GetGame().GetCallqueue().CallLater(EnableAddonsRecursively, 0, false, addons, remaining, enable);
564 }
565 else
566 {
568 {
569 m_LoadingOverlay.SetShown(false);
571 }
572 else
573 {
575 }
576 }
577 }
578
579 //-----------------------------------------------------------------------------------------------
580 // P R O T E C T E D / P R I V A T E
581 //-----------------------------------------------------------------------------------------------
582 //-----------------------------------------------------------------------------------------------
584 protected void Internal_CheckAddons()
585 {
586 _print("Internal_CheckAddons()", LogLevel.NORMAL);
587
588
591
592 WorkshopApi api = GetGame().GetBackendApi().GetWorkshop();
593
594 if (api)
595 {
598 api.OnItemsChecked(m_AddonCheckCallback);
599 }
600 }
601
602 //-----------------------------------------------------------------------------------------------
603 protected void RegisterNewItem(string id, SCR_WorkshopItem itemWrapper)
604 {
605 #ifdef WORKSHOP_DEBUG
606 _print(string.Format("Registered new item: %1", itemWrapper.GetName()));
607 #endif
608
609 itemWrapper.m_OnOfflineStateChanged.Insert(Callback_OnAddonOfflineStateChanged);
610 itemWrapper.m_OnReportStateChanged.Insert(Callback_OnAddonReportStateChanged);
611 itemWrapper.m_OnDownloadComplete.Insert(CountOutdatedAddons);
612 //
613
614 m_mItems.Insert(id, itemWrapper);
615
617 }
618
619 //-----------------------------------------------------------------------------------------------
620 protected string GetItemId(WorkshopItem item)
621 {
622 return item.Id();
623 }
624
625 //-----------------------------------------------------------------------------------------------
626 protected string GetItemId(Dependency item)
627 {
628 return item.GetID();
629 }
630
631 //-----------------------------------------------------------------------------------------------
632 protected static bool CheckQueryFlag(SCR_WorkshopItem item, EWorkshopItemQuery flag)
633 {
634 switch(flag)
635 {
636 case EWorkshopItemQuery.ONLINE: return item.GetOnline();
637 case EWorkshopItemQuery.NOT_ONLINE: return !item.GetOnline();
638 case EWorkshopItemQuery.OFFLINE: return item.GetOffline();
639 case EWorkshopItemQuery.NOT_OFFLINE: return !item.GetOffline();
640 case EWorkshopItemQuery.ENABLED: return item.GetEnabled();
641 case EWorkshopItemQuery.NOT_ENABLED: return !item.GetEnabled();
642 case EWorkshopItemQuery.BLOCKED: return item.GetBlocked();
643 case EWorkshopItemQuery.RESTRICTED: return item.GetRestricted();
644 case EWorkshopItemQuery.REPORTED_BY_ME: return item.GetReportedByMe();
645 case EWorkshopItemQuery.LOCAL_VERSION_MATCH_DEPENDENCY: return item.GetCurrentLocalVersionMatchDependency();
646 case EWorkshopItemQuery.NOT_LOCAL_VERSION_MATCH_DEPENDENCY: return !item.GetCurrentLocalVersionMatchDependency();
647 case EWorkshopItemQuery.UPDATE_AVAILABLE: return item.GetUpdateAvailable();
648 case EWorkshopItemQuery.DEPENDENCY_UPDATE_AVAILABLE: return item.GetAnyDependencyUpdateAvailable();
649 case EWorkshopItemQuery.NO_PROBLEMS: return item.GetHighestPriorityProblem() == EWorkshopItemProblem.NO_PROBLEM;
650 case EWorkshopItemQuery.DEPENDENCY_MISSING: return item.GetAnyDependencyMissing();
651 case EWorkshopItemQuery.DEPENDENCY_NOT_MISSING: return !item.GetAnyDependencyMissing();
652 case EWorkshopItemQuery.ENABLED_AND_DEPENDENCY_DISABLED: return item.GetEnabledAndAnyDependencyDisabled();
653 case EWorkshopItemQuery.FAVOURITE: return item.GetFavourite();
654 case EWorkshopItemQuery.AUTHOR_BLOCKED: return item.GetModAuthorReportedByMe();
655 case EWorkshopItemQuery.ONLY_WORKSHOP_ITEM: return !item.IsWorldSave();
656 case EWorkshopItemQuery.ONLY_WORLD_SAVES: return item.IsWorldSave();
657 default: return false;
658 }
659 return false;
660 }
661
662 //-----------------------------------------------------------------------------------------------
665 {
666 // Could optimize to `if ((~item.m_Flags & flags) == 0)`, if we had these flags easily available.
667
668 int currentFlag = 1;
669 for (int bit = 0; bit < 32; bit++)
670 {
671 if (flags & currentFlag) // If this flag is set in query
672 {
673 if (!CheckQueryFlag(item, currentFlag)) // False if any is false
674 return false;
675 }
676 currentFlag = currentFlag << 1;
677 }
678 return true; // True when all set flags are true
679 }
680
681 //-----------------------------------------------------------------------------------------------
684 {
685 int currentFlag = 1;
686 for (int bit = 0; bit < 32; bit++)
687 {
688 if (flags & currentFlag) // If this flag is set in query
689 {
690 if (CheckQueryFlag(item, currentFlag)) // False if any is false
691 return true;
692 }
693 currentFlag = currentFlag << 1;
694 }
695 return false; // False when no conditions are true
696 }
697
698 //-----------------------------------------------------------------------------------------------
699 private void SCR_AddonManager(IEntitySource src, IEntity parent)
700 {
702 SetFlags(EntityFlags.NO_TREE | EntityFlags.NO_LINK);
703
704 s_Instance = this;
705 }
706
707 //-----------------------------------------------------------------------------------------------
708 private void ~SCR_AddonManager()
709 {
710 s_Instance = null;
711 }
712
713 //-----------------------------------------------------------------------------------------------
716 {
718 return;
719
720 _print("FinalizeInitAfterAsyncChecks()", LogLevel.NORMAL);
721
722 m_bInitFinished = true;
723
724 _print("Init Finished", LogLevel.NORMAL);
725 _print(string.Format(" User Workshop access: %1", GetReady()), LogLevel.NORMAL);
726 }
727
728 //-----------------------------------------------------------------------------------------------
729 override void EOnInit(IEntity owner)
730 {
731 // Don't perform scan if not in actual game
732 if (SCR_Global.IsEditMode(this))
733 return;
734
735 // Scan all offline items and register them
736 // Scan offline items if needed
737 WorkshopApi api = GetGame().GetBackendApi().GetWorkshop();
738 if (api)
739 {
740 Internal_CheckAddons(); // sets callback for finished scan
741 api.ScanOfflineItems(); // request scan of already downloaded addons
742 }
743
744 // If user's UGC privilege is disabled, disable all addons
745 // If UGC is blocked, disable addons which are already downloaded
746 if (!GetUgcPrivilege())
747 {
748 foreach (SCR_WorkshopItem item : GetOfflineAddons())
749 item.SetEnabled(false);
750 }
751
752
753
754 if(GetGame().InPlayMode())
756 }
757
758 //------------------------------------------------------------------------------------------------
759 protected void AddonCheckResponse(BackendCallback callback)
760 {
761 // Success
763 }
764
765 //------------------------------------------------------------------------------------------------
766 protected void AddonCheckError(BackendCallback callback)
767 {
768 // TODO: Notify error!
769 }
770
771 //-----------------------------------------------------------------------------------------------
773 {
774 m_bAddonsChecked = true;
775 _print("Callback_CheckAddons_OnSuccess()", LogLevel.NORMAL);
776
777 WorkshopApi api = GetGame().GetBackendApi().GetWorkshop();
778
779 // Get all offline addons and register them
780 array<WorkshopItem> items = {};
781 api.GetOfflineItems(items);
782
783 // Prepare items to registration
784 foreach (WorkshopItem item : items)
785 {
786 m_aAddonsToRegister.Insert(item);
787 }
788
789 array<ref SCR_WorkshopItem> pendingDownloads = {};
790
791 // Update state of items after the check is complete
792 // This will make the addons instantly update list of dependencies and revisions
793 for (int i = 0; i < m_aAddonsToRegister.Count(); i++)
794 {
796 scrItem.Internal_OnAddonsChecked();
797 array<ref SCR_WorkshopItem> dependencies = scrItem.GetLoadedDependencies();
798
799 if (m_aAddonsToRegister[i].GetPendingDownload())
800 pendingDownloads.Insert(scrItem);
801 }
802
803 m_aAddonsToRegister.Clear();
804
807
808 // do not automatically start download without users knowledge
809 // addons will be added to download dialog as paused download
810 foreach (SCR_WorkshopItem download : pendingDownloads)
811 download.PauseDownload();
812
813 m_OnAddonsChecked.Invoke();
814
815 //show reload failure
816 array<string> addonIds = {};
817 GetGame().ReloadFailureAddons(addonIds);
818 array<ref SCR_WorkshopItem> arr = {};
819 foreach(auto addon: addonIds)
820 {
821 SCR_WorkshopItem wi = GetItem(addon);
822 if (wi)
823 arr.Insert(wi);
824 }
825
826 if (!arr.IsEmpty())
828 }
829
830 //-----------------------------------------------------------------------------------------------
832 {
833 _print("Callback_GetPrivilege_OnPrivilegeResult()", LogLevel.NORMAL);
834
835 if (privilege == UserPrivilege.USER_GEN_CONTENT)
836 {
837 bool allowed = result == UserPrivilegeResult.ALLOWED;
838
839 _print(string.Format(" UserPrivilege.USER_GEN_CONTENT: %1", allowed), LogLevel.NORMAL);
840
841 m_OnUgcPrivilegeResult.Invoke(allowed);
842 }
843 }
844
845
846 //-----------------------------------------------------------------------------------------------
848 protected void Callback_OnAddonOfflineStateChanged(SCR_WorkshopItem item, bool newState)
849 {
850 m_OnAddonOfflineStateChanged.Invoke(item, newState);
851 }
852
853 //-----------------------------------------------------------------------------------------------
855 protected void Callback_OnAddonReportStateChanged(SCR_WorkshopItem item, bool newReport)
856 {
857 m_OnAddonReportedStateChanged.Invoke(item, newReport);
858 }
859
860 //-----------------------------------------------------------------------------------------------
861 override void EOnFrame(IEntity owner, float timeSlice)
862 {
863 array<string> unregisterIds;
864 array<SCR_WorkshopItem> updateItems;
865
866 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
867 // Reliance on reference counting
868
869 // Iterate all items
870 // Existins utems are updated
871 // Non-existant items are marked for deletion from the map
872 foreach (string id, SCR_WorkshopItem item : m_mItems)
873 {
874 // Item can be unregistered when no actions are running
875 // And when the addon manager holds the only reference to it
876 int refCount = item.GetRefCount();
877 bool canBeUnregistered = item.Internal_GetCanBeUnregistered();
878 if (canBeUnregistered && item.GetRefCount() == 2) // SCR_WorkshopItem item above also holds one reference! The other reference is the map entry.
879 {
880 if (!unregisterIds)
881 unregisterIds = {};
882
883 unregisterIds.Insert(id);
884 }
885 else
886 {
887 if (!updateItems)
888 updateItems = {};
889
890 // Don't update items directly in case an update causes an insertion of a new item
891 updateItems.Insert(item);
892 }
893 }
894
895 //---- REFACTOR NOTE END ----
896
897 // Update the marked entries
898 if (updateItems)
899 {
900 foreach (SCR_WorkshopItem item : updateItems)
901 item.Internal_Update(timeSlice);
902 }
903
904 // Delete the marked entries
905 if (unregisterIds)
906 {
907 #ifdef WORKSHOP_DEBUG
908 _print(string.Format("Unregistering items: %1", unregisterIds.Count()));
909 #endif
910
911 foreach (string id : unregisterIds)
912 {
913 #ifdef WORKSHOP_DEBUG
914 SCR_WorkshopItem item = m_mItems.Get(id);
915 _print(string.Format("Unregistered item: %1", item.GetName()));
916 #endif
917
918 m_mItems.Remove(id);
919 }
920 }
921
922 // Detection of case when addons get enabled/disabled
923 // Iterate all addons and invoke event whenever current list of enabled addons is different from prev. list
924 // It's not a perfect implementation but it's fine in main menu
925 m_fAddonsEnabledTimer += timeSlice;
927 {
928 string addonsEnabled;
929 foreach (string id, SCR_WorkshopItem item : m_mItems)
930 {
931 if (item.GetEnabled())
932 addonsEnabled = addonsEnabled + id + " ";
933 }
934
935 if (addonsEnabled != m_sAddonsEnabledPrev)
936 {
938 m_sAddonsEnabledPrev = addonsEnabled;
939 }
940
942 }
943
944 // Count and cache amount of outdated addons
945 // This doesn't need to happen often, 1s is enough
946
947 /*
948 m_fAddonsOutdatedTimer += timeSlice;
949 if (m_fAddonsOutdatedTimer > ADDONS_OUTDATED_UPDATE_INTERVAL_S)
950 {
951 m_iAddonsOutdated = CountItemsBasic(GetOfflineAddons(), EWorkshopItemQuery.UPDATE_AVAILABLE);
952
953 m_fAddonsOutdatedTimer = 0;
954 }
955 */
956 }
957
958 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
959 // Public method called "Internal" because we don't allow friend classes: now SCR_WorkshopItems and SCR_AddonManager both call public methods on each other, hold references and duplicate cached data, and have bloated public APIs
960
961 //-----------------------------------------------------------------------------------------------
964 {
965 m_OnNewDownload.Invoke(item, action);
966 }
967
968 //---- REFACTOR NOTE END ----
969
970 //-----------------------------------------------------------------------------------------------
972 protected void CountOutdatedAddons()
973 {
975 array<ref SCR_WorkshopItem> items = GetOfflineAddons();
976
977 foreach (SCR_WorkshopItem item : items)
978 {
979 auto wi = item.Internal_GetWorkshopItem();
980 if (!wi || (wi.GetLatestRevision() && !wi.GetLatestRevision().IsDownloaded()))
982 }
983 }
984
985 //-----------------------------------------------------------------------------------------------
986 // Handling of addon presets
987 //----------------------------------------------------------------------------------------------------------------------------------------------------
992
993
994 //----------------------------------------------------------------------------------------------------------------------------------------------------
995 // Looks up addon from internal map
997 {
998 return m_mItems.Get(id);
999 }
1000
1001 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
1002 // Declare variables at the top of the class
1003
1004 protected SCR_WorkshopAddonPreset m_SelectedPreset;
1005 protected ref array<ref SCR_WorkshopAddonPresetAddonMeta> m_aAddonsNotFound = {};
1006
1007 //---- REFACTOR NOTE END ----
1008
1009 //----------------------------------------------------------------------------------------------------------------------------------------------------
1010 // Enables addons from preset, disables all addons from other presets
1011 void SelectPreset(SCR_WorkshopAddonPreset preset, notnull array<ref SCR_WorkshopAddonPresetAddonMeta> addonsNotFound)
1012 {
1013 array<ref SCR_WorkshopItem> addons = GetOfflineAddons();
1015 m_SelectedPreset = preset;
1016 EnableMultipleAddons(addons, false);
1017 }
1018
1019 //-----------------------------------------------------------------------------------------------
1021 {
1023
1024 array<ref SCR_WorkshopAddonPresetAddonMeta> enabledAddons = m_SelectedPreset.GetAddons();
1025 array<ref SCR_WorkshopItem> addons = {};
1026
1027 foreach (SCR_WorkshopAddonPresetAddonMeta meta : enabledAddons)
1028 {
1029 string guid = meta.GetGuid();
1030 SCR_WorkshopItem item = GetItem(guid);
1031
1032 if (item && item.GetOffline())
1033 addons.Insert(item);
1034 else
1035 m_aAddonsNotFound.Insert(meta);
1036 }
1037
1039 EnableMultipleAddons(addons, true);
1040 m_SelectedPreset = null;
1041 }
1042
1043 //---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
1044 // AddonManager system doing UI stuff
1045
1046 //-----------------------------------------------------------------------------------------------
1049 {
1050 if (!m_aAddonsNotFound.IsEmpty())
1051 {
1053 m_aAddonsNotFound.Clear();
1054 }
1055
1057 }
1058
1059 //---- REFACTOR NOTE END ----
1060
1061 //----------------------------------------------------------------------------------------------------------------------------------------------------
1062 SCR_WorkshopAddonPreset CreatePresetFromEnabledAddons(string presetName)
1063 {
1064 // Get GUIDs of addons which are enabled
1065
1066 array<ref SCR_WorkshopItem> enabledAddons = SCR_AddonManager.SelectItemsBasic(GetOfflineAddons(), EWorkshopItemQuery.ENABLED);
1067
1068 array<ref SCR_WorkshopAddonPresetAddonMeta> addonsMeta = {};
1069 foreach (SCR_WorkshopItem item : enabledAddons)
1070 {
1071 string guid = item.GetId();
1072 addonsMeta.Insert((new SCR_WorkshopAddonPresetAddonMeta()).Init(guid, item.GetName()) );
1073 }
1074
1075 if (addonsMeta.IsEmpty())
1076 return null;
1077
1078 SCR_WorkshopAddonPreset preset = (new SCR_WorkshopAddonPreset()).Init(presetName, addonsMeta);
1079
1080 return preset;
1081 }
1082
1083 //----------------------------------------------------------------------------------------------------------------------------------------------------
1086 {
1087 array<ref SCR_WorkshopItem> enabledAddons = SCR_AddonManager.SelectItemsAnd(GetOfflineAddons(), EWorkshopItemQuery.ENABLED | EWorkshopItemQuery.ONLY_WORKSHOP_ITEM);
1088 return enabledAddons.Count();
1089 }
1090
1091 //-----------------------------------------------------------------------------------------------
1096
1097 //-----------------------------------------------------------------------------------------------
1098 //-----------------------------------------------------------------------------------------------
1099 //-----------------------------------------------------------------------------------------------
1100
1101
1102 //------------------------------------------------------------------------------------------------
1103 void _print(string str, LogLevel logLevel = LogLevel.DEBUG)
1104 {
1105 Print(string.Format("[SCR_AddonManager] %1 %2", this, str), logLevel);
1106 }
1107}
1108
1109enum SCR_ERevisionAvailability : ERevisionAvailability
1110{
1114}
SCR_EAIThreatSectorFlags flags
override void Init()
ArmaReforgerScripted GetGame()
Definition game.c:1398
ScriptInvokerBase< ScriptInvokerSCRWorkshopItemMethod > ScriptInvokerWorkshopItem
func ScriptInvokerSCRWorkshopItemMethod
SCR_AddonManager ERA_COMPATIBLE_UPDATE_AVAILABLE
SCR_AddonManager ERA_UNKNOWN_AVAILABILITY
EWorkshopItemQuery
@ DEPENDENCY_UPDATE_AVAILABLE
@ NO_PROBLEMS
@ LOCAL_VERSION_MATCH_DEPENDENCY
@ UPDATE_AVAILABLE
@ NOT_ONLINE
@ ONLY_WORLD_SAVES
@ NOT_LOCAL_VERSION_MATCH_DEPENDENCY
@ AUTHOR_BLOCKED
@ REPORTED_BY_ME
@ DEPENDENCY_NOT_MISSING
@ ONLY_WORKSHOP_ITEM
@ NOT_OFFLINE
@ DEPENDENCY_MISSING
@ NOT_ENABLED
@ FAVOURITE
@ ENABLED_AND_DEPENDENCY_DISABLED
SCR_AddonManager ERA_DOWNLOAD_NOT_FINISHED
SCR_WorkshopItem GetItem()
@ BLOCKED
User has this asset blocked so it should not be possible to interact with it until unblocked.
SCR_ComparerOperator
Definition SCR_Comparer.c:3
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
SCR_ContentBrowserTileComponent RESTRICTED
enum SCR_EServicePointType OFFLINE
enum SCR_EServicePointType ONLINE
EWorkshopItemProblem
UserPrivilege
UserPrivilegeResult
void IEntity(IEntitySource src, IEntity parent)
protected script Constructor
proto external EntityEvent SetEventMask(EntityEvent e)
proto external EntityFlags SetFlags(EntityFlags flags, bool recursively=false)
Shows a list of addons and some text.
static SCR_AddonListDialog CreateFailedToStartWithMods(array< ref SCR_WorkshopItem > items)
Dialog when failed to load game with selected mods.
static int CountItemsBasic(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query, bool returnOnFirstMatch=false)
ref array< ref SCR_WorkshopAddonPresetAddonMeta > m_aAddonsNotFound
ScriptInvoker GetEventOnAddonEnabled()
static bool CheckQueryFlagsAnd(SCR_WorkshopItem item, EWorkshopItemQuery flags)
Checks if all flags are satisfied.
SCR_WorkshopItem Register(WorkshopItem item)
Returns a SCR_WorkshopItem. If it's not registered, creates a new one and registers it.
int CountOfEnabledAddons()
Return int count of all enabled mods.
void SelectPreset(SCR_WorkshopAddonPreset preset, notnull array< ref SCR_WorkshopAddonPresetAddonMeta > addonsNotFound)
static bool GetAddonEnabledExternally(SCR_WorkshopItem item)
Returns true if addon was enabled through external configuration (CLI or other).
SCR_WorkshopAddonPreset CreatePresetFromEnabledAddons(string presetName)
ref ScriptInvoker m_OnAddonOfflineStateChanged
ref ScriptInvoker Event_OnAllAddonsEnabled
array< ref SCR_WorkshopItem > GetOfflineAddons()
Returns array with all offline addons.
int GetCountAddonsOutdated()
Returns count of outdated addons.
SCR_WorkshopAddonPreset m_SelectedPreset
override void EOnInit(IEntity owner)
void Callback_GetPrivilege_OnPrivilegeResult(UserPrivilege privilege, UserPrivilegeResult result)
ref ScriptInvoker m_OnUgcPrivilegeResult
static const float ADDONS_OUTDATED_UPDATE_INTERVAL_S
void Callback_CheckAddons_OnSuccess()
void Callback_OnAddonOfflineStateChanged(SCR_WorkshopItem item, bool newState)
Called from the specific SCR_WorkshopItem.
void NegotiateUgcPrivilegeAsync()
static array< ref SCR_WorkshopItem > SelectItemsBasic(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query)
void Callback_OnAddonReportStateChanged(SCR_WorkshopItem item, bool newReport)
Called from the specific SCR_WorkshopItem.
static bool GetAddonsEnabledExternally()
Returns true when external addon configuration is used (through CLI or other means).
void AddonCheckError(BackendCallback callback)
string GetItemId(WorkshopItem item)
static int CountItemsAnd(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query, bool returnOnFirstMatch=false)
Counts items which match query. All flags must match.
void AddonCheckResponse(BackendCallback callback)
void _print(string str, LogLevel logLevel=LogLevel.DEBUG)
ref map< string, ref SCR_WorkshopItem > m_mItems
ScriptInvoker GetEventOnAllAddonsEnabled()
ref SCR_ScriptPlatformRequestCallback m_CallbackGetPrivilege
array< ref SCR_WorkshopItem > GetAllAddons()
Returns array with all addons currently in the system - online and offline.
SCR_LoadingOverlay m_LoadingOverlay
void EnableAddonsRecursively(array< ref SCR_WorkshopItem > addons, out int remaining, bool enable)
static SCR_ComparerOperator DifferenceBetweenVersions(string vFrom, string vTo)
Return difference type between current version from current to target.
static SCR_AddonManager s_Instance
map< string, ref SCR_WorkshopItem > GetItemsMap()
static SCR_ERevisionAvailability ItemAvailability(notnull WorkshopItem item)
void Internal_OnNewDownload(SCR_WorkshopItem item, SCR_WorkshopItemActionDownload action)
Called by SCR_WorkshopItem when it starts a new download.
void InvokeEventOnAddonEnabled(SCR_WorkshopItem arg0, int arg1)
void RegisterNewItem(string id, SCR_WorkshopItem itemWrapper)
SCR_WorkshopAddonManagerPresetStorage GetPresetStorage()
ref ScriptInvoker m_OnAddonsChecked
ref array< WorkshopItem > m_aAddonsToRegister
static bool CheckQueryFlag(SCR_WorkshopItem item, EWorkshopItemQuery flag)
bool GetUgcPrivilege()
Returns immediate value of UserPrivilege.USER_GEN_CONTENT.
static int CountItemsOr(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query, bool returnOnFirstMatch=false)
Counts items which match query.Any flag must match.
ref ScriptInvoker m_OnAddonReportedStateChanged
void CountOutdatedAddons()
Go throught all offline addons and count size.
static array< ref SCR_WorkshopItem > SelectItemsOr(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query)
bool GetAddonsChecked()
True when all async checks are done. Doesn't indicate that all checks were successful!
ref ScriptInvoker m_OnNewDownload
void InvokeEventOnAllAddonsEnabled()
string GetItemId(Dependency item)
ref SCR_WorkshopAddonManagerPresetStorage m_Storage
void Internal_CheckAddons()
When internet is disabled, might take a lot of time to complete the request.
static const float ADDONS_ENABLED_UPDATE_INTERVAL_S
SCR_WorkshopItem Register(Dependency item)
Returns a SCR_WorkshopItem. If it's not registered, creates a new one and registers it.
ref ScriptInvoker m_OnAddonsEnabledChanged
void FinalizeInitAfterAsyncChecks()
Finishes init after all async checks are done.
static bool CheckQueryFlagsOr(SCR_WorkshopItem item, EWorkshopItemQuery flags)
Checks if any flag is satisfied.
void OnAllAddonsEnabledCorrupted()
Call this when all dialog are enabled, but some are missing to show which one.
SCR_WorkshopItem GetItem(string id)
ref BackendCallback m_AddonCheckCallback
ref BackendCallback m_CallbackCheckAddons
static array< ref SCR_WorkshopItem > SelectItemsAnd(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query)
void EnableMultipleAddons(array< ref SCR_WorkshopItem > items, bool enable)
Enable/disable multiple mods recursively to save performance.
ref ScriptInvoker< SCR_WorkshopItem, int > Event_OnAddonEnabled
override void EOnFrame(IEntity owner, float timeSlice)
static SCR_AddonManager GetInstance()
static SCR_DownloadManager GetInstance()
array< ref SCR_WorkshopItemActionDownload > DownloadItems(array< ref SCR_WorkshopItem > items)
static bool IsEditMode()
Definition Functions.c:1566
static SCR_LoadingOverlay ShowForWidget(Widget targetWidget, string text=string.Empty, bool showBlur=true, bool showBackground=true)
array< ref SCR_WorkshopItem > GetLoadedDependencies()
void LogState()
Logs all properties of the object into console.
bool GetLoaded()
True when addon is loaded by engine. It means that the game is already running with this mod.
bool GetOffline()
True when we have the item on our local storage.
bool GetEnabledAndAnyDependencyDisabled()
Returns true if any dependency is offline and disabled.
EWorkshopItemProblem GetHighestPriorityProblem()
bool GetAnyDependencyUpdateAvailable()
bool GetUpdateAvailable()
Returns true when we have an old version offline, and the new version.
bool GetRestricted()
Returns true when item is restricted for any reason (blocked or reported).
static SCR_WorkshopItem Internal_CreateFromWorkshopItem(WorkshopItem item)
bool GetOnline()
True when the item is stored in the backend.
bool GetCurrentLocalVersionMatchDependency()
Returns true if current local version matches version of dependency.
static SCR_WorkshopItem Internal_CreateFromDependency(Dependency dependency)
Workshop Api instance.
Definition WorkshopApi.c:14
Workshop Item instance.
Definition Types.c:486
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
EntityEvent
Various entity events.
Definition EntityEvent.c:14
EntityFlags
Various entity flags.
Definition EntityFlags.c:14
EUserInteraction
Interaction type between two players.
ERevisionAvailability
ScriptInvokerBase< func > ScriptInvoker
Definition tools.c:134