67 [
EntityEditorProps(
category:
"", description:
"A centralized system which lets many users perform actions on addons. Most likely only needed in the main menu world.")]
77 static const string ADDONS_CLI =
"addons";
78 static const string VERSION_DOT =
".";
79 protected const static float ADDONS_ENABLED_UPDATE_INTERVAL_S = 1/30;
80 protected const static float ADDONS_OUTDATED_UPDATE_INTERVAL_S = 1.0;
83 ref ScriptInvoker m_OnAddonsChecked =
new ScriptInvoker;
86 ref ScriptInvoker m_OnAddonOfflineStateChanged =
new ScriptInvoker;
89 ref ScriptInvoker m_OnAddonReportedStateChanged =
new ScriptInvoker;
92 ref ScriptInvoker m_OnUgcPrivilegeResult =
new ScriptInvoker;
95 ref ScriptInvoker m_OnAddonsEnabledChanged =
new ScriptInvoker;
99 protected ref array<WorkshopItem> m_aAddonsToRegister = {};
100 protected ref map<string, ref SCR_WorkshopItem> m_mItems =
new map<string, ref SCR_WorkshopItem>();
103 protected int m_iAddonsOutdated;
104 protected float m_fAddonsOutdatedTimer = 0;
105 protected float m_fAddonsEnabledTimer = 0;
106 protected string m_sAddonsEnabledPrev;
109 protected bool m_bAddonsChecked =
false;
112 protected bool m_bInitFinished =
false;
121 ref ScriptInvoker m_OnNewDownload =
new ScriptInvoker;
132 array<ref SCR_WorkshopItem> GetAllAddons()
134 array<ref SCR_WorkshopItem> ret = {};
144 array<ref SCR_WorkshopItem> GetOfflineAddons()
146 array<ref SCR_WorkshopItem> ret = {};
149 if (item.GetOffline())
160 string id = GetItemId(item);
163 #ifdef WORKSHOP_DEBUG
164 _print(
string.Format(
"Register WorkshopItem: ID: %1, Name: %2, Found in map: %3",
id, item.Name(), existingItem !=
null));
169 existingItem.Internal_UpdateObjects(item,
null);
171 #ifdef WORKSHOP_DEBUG
179 RegisterNewItem(
id, newItem);
181 #ifdef WORKSHOP_DEBUG
193 string id = GetItemId(item);
196 #ifdef WORKSHOP_DEBUG
197 _print(
string.Format(
"Register Dependency: ID: %1, Name: %2, Found in map: %3",
id, item.GetName(), existingItem !=
null));
202 existingItem.Internal_UpdateObjects(
null, item);
204 #ifdef WORKSHOP_DEBUG
212 RegisterNewItem(
id, newItem);
214 #ifdef WORKSHOP_DEBUG
225 bool GetReady() {
return m_bInitFinished && m_bAddonsChecked; }
232 bool GetAddonsChecked() {
return m_bAddonsChecked; }
236 bool GetUgcPrivilege()
238 return GetGame().GetPlatformService().GetPrivilege(UserPrivilege.USER_GEN_CONTENT);
243 int GetCountAddonsOutdated()
245 return m_iAddonsOutdated;
252 void NegotiateUgcPrivilegeAsync()
254 _print(
"CheckPrivilege()", LogLevel.NORMAL);
256 if (!m_CallbackGetPrivilege)
259 m_CallbackGetPrivilege.m_OnResult.Insert(Callback_GetPrivilege_OnPrivilegeResult);
262 GetGame().GetPlatformService().GetPrivilegeAsync(UserPrivilege.USER_GEN_CONTENT, m_CallbackGetPrivilege);
270 protected static bool GetAddonsEnabledExternally()
272 return System.IsCLIParam(ADDONS_CLI);
279 if (!GetAddonsEnabledExternally())
282 return item.GetLoaded();
288 static array<ref SCR_WorkshopItem> SelectItemsBasic(array<ref SCR_WorkshopItem> items,
EWorkshopItemQuery query)
290 array<ref SCR_WorkshopItem> ret = {};
293 if (CheckQueryFlag(item, query))
303 static int CountItemsBasic(array<ref SCR_WorkshopItem> items,
EWorkshopItemQuery query,
bool returnOnFirstMatch =
false)
308 if (CheckQueryFlag(item, query))
311 if (returnOnFirstMatch)
323 static array<ref SCR_WorkshopItem> SelectItemsAnd(array<ref SCR_WorkshopItem> items,
EWorkshopItemQuery query)
325 array<ref SCR_WorkshopItem> ret = {};
328 if (CheckQueryFlagsAnd(item, query))
338 static int CountItemsAnd(array<ref SCR_WorkshopItem> items,
EWorkshopItemQuery query,
bool returnOnFirstMatch =
false)
343 if (CheckQueryFlagsAnd(item, query))
346 if (returnOnFirstMatch)
358 static array<ref SCR_WorkshopItem> SelectItemsOr(array<ref SCR_WorkshopItem> items,
EWorkshopItemQuery query)
360 array<ref SCR_WorkshopItem> ret = {};
363 if (CheckQueryFlagsOr(item, query))
373 static int CountItemsOr(array<ref SCR_WorkshopItem> items,
EWorkshopItemQuery query,
bool returnOnFirstMatch =
false)
378 if (CheckQueryFlagsOr(item, query))
381 if (returnOnFirstMatch)
396 array<string> fromNums = {};
397 vFrom.Split(VERSION_DOT, fromNums,
false);
399 array<string> toNums = {};
400 vTo.Split(VERSION_DOT, toNums,
false);
403 int count = fromNums.Count();
404 if (count > toNums.Count())
405 count = toNums.Count();
407 for (
int i; i < count; i++)
409 int iFrom = fromNums[i].ToInt();
410 int iTo = toNums[i].ToInt();
418 else if (iFrom > iTo)
423 else if (iFrom == iTo)
426 int end = vTo.IndexOfFrom(i, VERSION_DOT) - 1;
441 Revision currentRev = item.GetActiveRevision();
445 if (item.GetDownloadingRevision())
449 if (item.GetStateFlags() & EWorkshopItemState.EWSTATE_OFFLINE)
450 Print(
"ItemAvailability() - Can't find item offline although offline flag is present " + item.Name() +
" current revision", LogLevel.WARNING);
455 ERevisionAvailability currentAvailability = currentRev.GetAvailability();
458 if (currentAvailability == ERevisionAvailability.ERA_AVAILABLE)
461 Revision latestRev = item.GetLatestRevision();
462 ERevisionAvailability latestAvailability = latestRev.GetAvailability();
466 Print(
"ItemAvailability() - Can't compare availability of item " + item.Name() +
" latest revision", LogLevel.WARNING);
471 if (currentAvailability == ERevisionAvailability.ERA_DELETED)
474 if (latestAvailability == ERevisionAvailability.ERA_AVAILABLE)
481 if (currentAvailability == ERevisionAvailability.ERA_OBSOLETE)
484 if (latestAvailability == ERevisionAvailability.ERA_AVAILABLE)
496 protected ref ScriptInvoker<SCR_WorkshopItem, int> Event_OnAddonEnabled;
497 protected ref ScriptInvoker<> Event_OnAllAddonsEnabled;
502 if (Event_OnAddonEnabled)
503 Event_OnAddonEnabled.Invoke(arg0, arg1);
507 ScriptInvoker GetEventOnAddonEnabled()
509 if (!Event_OnAddonEnabled)
510 Event_OnAddonEnabled =
new ScriptInvoker();
512 return Event_OnAddonEnabled;
516 protected void InvokeEventOnAllAddonsEnabled()
518 if (Event_OnAllAddonsEnabled)
519 Event_OnAllAddonsEnabled.Invoke();
523 ScriptInvoker GetEventOnAllAddonsEnabled()
525 if (!Event_OnAllAddonsEnabled)
526 Event_OnAllAddonsEnabled =
new ScriptInvoker();
528 return Event_OnAllAddonsEnabled;
533 void EnableMultipleAddons(array<ref SCR_WorkshopItem> items,
bool enable)
535 int count = items.Count() - 1;
537 GetGame().GetCallqueue().CallLater(EnableAddonsRecursively, 0,
false, items, count, enable);
547 protected void EnableAddonsRecursively(array<ref SCR_WorkshopItem> addons, out
int remaining,
bool enable)
551 addons[remaining].SetEnabled(enable);
552 InvokeEventOnAddonEnabled(addons[remaining], remaining);
555 GetGame().GetCallqueue().CallLater(EnableAddonsRecursively, 0,
false, addons, remaining, enable);
562 InvokeEventOnAllAddonsEnabled();
566 InvokeEventOnAllAddonsEnabled();
588 protected void Internal_CheckAddons()
590 _print(
"Internal_CheckAddons()", LogLevel.NORMAL);
593 if (!m_AddonCheckCallback)
596 WorkshopApi api =
GetGame().GetBackendApi().GetWorkshop();
600 m_AddonCheckCallback.GetEventOnResponse().Insert(AddonCheckResponse);
601 api.OnItemsChecked(m_AddonCheckCallback);
608 #ifdef WORKSHOP_DEBUG
609 _print(
string.Format(
"Registered new item: %1", itemWrapper.GetName()));
612 itemWrapper.m_OnOfflineStateChanged.Insert(Callback_OnAddonOfflineStateChanged);
613 itemWrapper.m_OnReportStateChanged.Insert(Callback_OnAddonReportStateChanged);
614 itemWrapper.m_OnDownloadComplete.Insert(CountOutdatedAddons);
616 m_mItems.Insert(
id, itemWrapper);
618 CountOutdatedAddons();
622 protected string GetItemId(WorkshopItem item)
628 protected string GetItemId(Dependency item)
647 case EWorkshopItemQuery.LOCAL_VERSION_MATCH_DEPENDENCY:
return item.GetCurrentLocalVersionMatchDependency();
648 case EWorkshopItemQuery.NOT_LOCAL_VERSION_MATCH_DEPENDENCY:
return !item.GetCurrentLocalVersionMatchDependency();
650 case EWorkshopItemQuery.DEPENDENCY_UPDATE_AVAILABLE:
return item.GetAnyDependencyUpdateAvailable();
653 case EWorkshopItemQuery.DEPENDENCY_NOT_MISSING:
return !item.GetAnyDependencyMissing();
654 case EWorkshopItemQuery.ENABLED_AND_DEPENDENCY_DISABLED:
return item.GetEnabledAndAnyDependencyDisabled();
657 default:
return false;
669 for (
int bit = 0; bit < 32; bit++)
671 if (flags & currentFlag)
673 if (!CheckQueryFlag(item, currentFlag))
676 currentFlag = currentFlag << 1;
686 for (
int bit = 0; bit < 32; bit++)
688 if (flags & currentFlag)
690 if (CheckQueryFlag(item, currentFlag))
693 currentFlag = currentFlag << 1;
702 SetEventMask(EntityEvent.FRAME | EntityEvent.INIT);
703 SetFlags(EntityFlags.NO_TREE | EntityFlags.NO_LINK);
717 protected void FinalizeInitAfterAsyncChecks()
719 if (m_bInitFinished || !m_bAddonsChecked )
722 _print(
"FinalizeInitAfterAsyncChecks()", LogLevel.NORMAL);
724 m_bInitFinished =
true;
726 _print(
"Init Finished", LogLevel.NORMAL);
727 _print(
string.Format(
" User Workshop access: %1", GetReady()), LogLevel.NORMAL);
731 override void EOnInit(IEntity owner)
739 WorkshopApi api =
GetGame().GetBackendApi().GetWorkshop();
742 api.ScanOfflineItems();
745 array<WorkshopItem> items = {};
746 api.GetOfflineItems(items);
749 foreach (WorkshopItem item : items)
751 m_aAddonsToRegister.Insert(item);
757 if (!GetUgcPrivilege())
760 item.SetEnabled(
false);
763 Internal_CheckAddons();
781 Callback_CheckAddons_OnSuccess();
785 protected void Callback_CheckAddons_OnSuccess()
787 m_bAddonsChecked =
true;
789 _print(
"Callback_CheckAddons_OnSuccess()", LogLevel.NORMAL);
791 array<ref SCR_WorkshopItem> pendingDownloads = {};
795 for (
int i = 0; i < m_aAddonsToRegister.Count(); i++)
798 scrItem.Internal_OnAddonsChecked();
799 array<ref SCR_WorkshopItem> dependencies = scrItem.GetLoadedDependencies();
801 if (scrItem.GetOffline())
802 pendingDownloads.Insert(scrItem);
805 m_aAddonsToRegister.Clear();
807 FinalizeInitAfterAsyncChecks();
810 m_OnAddonsChecked.Invoke();
813 array<string> addonIds = {};
814 GetGame().ReloadFailureAddons(addonIds);
815 array<ref SCR_WorkshopItem> arr = {};
816 foreach(
auto addon: addonIds)
828 protected void Callback_GetPrivilege_OnPrivilegeResult(UserPrivilege privilege, UserPrivilegeResult result)
830 _print(
"Callback_GetPrivilege_OnPrivilegeResult()", LogLevel.NORMAL);
832 if (privilege == UserPrivilege.USER_GEN_CONTENT)
834 bool allowed = result == UserPrivilegeResult.ALLOWED;
836 _print(
string.Format(
" UserPrivilege.USER_GEN_CONTENT: %1", allowed), LogLevel.NORMAL);
838 m_OnUgcPrivilegeResult.Invoke(allowed);
845 protected void Callback_OnAddonOfflineStateChanged(
SCR_WorkshopItem item,
bool newState)
847 m_OnAddonOfflineStateChanged.Invoke(item, newState);
852 protected void Callback_OnAddonReportStateChanged(
SCR_WorkshopItem item,
bool newReport)
854 m_OnAddonReportedStateChanged.Invoke(item, newReport);
859 override void EOnFrame(IEntity owner,
float timeSlice)
861 array<string> unregisterIds;
862 array<SCR_WorkshopItem> updateItems;
871 int refCount = item.GetRefCount();
872 bool canBeUnregistered = item.Internal_GetCanBeUnregistered();
873 if (canBeUnregistered && item.GetRefCount() == 2)
878 unregisterIds.Insert(
id);
886 updateItems.Insert(item);
894 item.Internal_Update(timeSlice);
900 #ifdef WORKSHOP_DEBUG
901 _print(
string.Format(
"Unregistering items: %1", unregisterIds.Count()));
904 foreach (
string id : unregisterIds)
906 #ifdef WORKSHOP_DEBUG
908 _print(
string.Format(
"Unregistered item: %1", item.GetName()));
918 m_fAddonsEnabledTimer += timeSlice;
919 if (m_fAddonsEnabledTimer > ADDONS_ENABLED_UPDATE_INTERVAL_S)
921 string addonsEnabled;
924 if (item.GetEnabled())
925 addonsEnabled = addonsEnabled +
id +
" ";
928 if (addonsEnabled != m_sAddonsEnabledPrev)
930 m_OnAddonsEnabledChanged.Invoke();
931 m_sAddonsEnabledPrev = addonsEnabled;
934 m_fAddonsEnabledTimer = 0;
956 m_OnNewDownload.Invoke(item, action);
961 protected void CountOutdatedAddons()
963 m_iAddonsOutdated = 0;
964 array<ref SCR_WorkshopItem> items = GetOfflineAddons();
968 auto wi = item.Internal_GetWorkshopItem();
969 if (!wi || !wi.HasLatestVersion())
988 return m_mItems.Get(
id);
991 protected SCR_WorkshopAddonPreset m_SelectedPreset;
992 protected ref array<ref SCR_WorkshopAddonPresetAddonMeta> m_aAddonsNotFound = {};
996 void SelectPreset(SCR_WorkshopAddonPreset preset, notnull array<ref SCR_WorkshopAddonPresetAddonMeta> addonsNotFound)
998 array<ref SCR_WorkshopItem> addons = GetOfflineAddons();
999 GetEventOnAllAddonsEnabled().Insert(OnOfflineAddonsDisabled);
1000 m_SelectedPreset = preset;
1001 EnableMultipleAddons(addons,
false);
1005 protected void OnOfflineAddonsDisabled()
1007 GetEventOnAllAddonsEnabled().Remove(OnOfflineAddonsDisabled);
1009 array<ref SCR_WorkshopAddonPresetAddonMeta> enabledAddons = m_SelectedPreset.GetAddons();
1010 array<ref SCR_WorkshopItem> addons = {};
1014 string guid = meta.GetGuid();
1017 if (item && item.GetOffline())
1018 addons.Insert(item);
1020 m_aAddonsNotFound.Insert(meta);
1023 GetEventOnAllAddonsEnabled().Insert(OnAllAddonsEnabledCorrupted);
1024 EnableMultipleAddons(addons,
true);
1025 m_SelectedPreset =
null;
1030 protected void OnAllAddonsEnabledCorrupted()
1032 if (!m_aAddonsNotFound.IsEmpty())
1035 m_aAddonsNotFound.Clear();
1038 GetEventOnAllAddonsEnabled().Remove(OnAllAddonsEnabledCorrupted);
1043 SCR_WorkshopAddonPreset CreatePresetFromEnabledAddons(
string presetName)
1049 array<ref SCR_WorkshopAddonPresetAddonMeta> addonsMeta = {};
1052 string guid = item.GetId();
1056 if (addonsMeta.IsEmpty())
1059 SCR_WorkshopAddonPreset preset = (
new SCR_WorkshopAddonPreset()).
Init(presetName, addonsMeta);
1066 int CountOfEnabledAddons()
1069 return enabledAddons.Count();
1073 map<string, ref SCR_WorkshopItem> GetItemsMap()
1084 void _print(
string str, LogLevel logLevel = LogLevel.DEBUG)
1086 Print(
string.Format(
"[SCR_AddonManager] %1 %2",
this, str), logLevel);