Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_WorkshopItem.c
Go to the documentation of this file.
1/*
2! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
3! ! If you use SCR_WorkshopItem, make sure you hold a strong reference (ref) to it:
4! ! Example: ref SCR_WorkshopItem m_Item;
5! ! The object is shared by nature and exists as long as at least something holds a strong
6! ! reference to it, if it is offline or as if any download is active.
7! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !
8*/
11typedef ScriptInvokerBase<ScriptInvokerMissionWorkshopItemMethod> ScriptInvokerMissionWorkshopItem;
12
13// Enum for possible issues of addons
23
24//---- REFACTOR NOTE START: This code will need to be refactored as current implementation is not conforming to the standards ----
25// Confusing architecture: this class adds a huge layer of complexity on top of the backend API: it's a wrapper of multiple API (WorkshopItem, Dependency, Revision, MissionWorkshopItem), it's thigtly coupled with other script classes (SCR_AddonManager, SCR_WorkshopItemAction), acted upon by even more (SCR_DownloadManager, a plethora of UIs), and apparently it's cached data is not guaranteed to be up to date with backend's. Also, old untyped scrip invokers and auto keyword
26
27class SCR_WorkshopItem
28{
29 // friend class SCR_WorkshopItemAction
30
31 // ---- Public variables ----
32 ref ScriptInvoker m_OnChanged = new ScriptInvoker(); // (SCR_WorkshopItem item) - Called on any change and any event which affects state. Might be called on next frame!
33 ref ScriptInvoker m_OnGetAsset = new ScriptInvoker(); // (SCR_WorkshopItem item) - Called on failure to load details too.
34 ref ScriptInvoker m_OnDependenciesLoaded = new ScriptInvoker(); // (SCR_WorkshopItem item)
35 ref ScriptInvoker m_OnScenariosLoaded = new ScriptInvoker(); // (SCR_WorkshopItem item)
36 ref ScriptInvoker m_OnError = new ScriptInvoker(); // (SCR_WorkshopItem item) - Called on any error event
37 ref ScriptInvoker m_OnTimeout = new ScriptInvoker(); // (SCR_WorkshopItem item) - Called on any timeout event
38 ref ScriptInvoker m_OnDownloadComplete = new ScriptInvoker(); // (SCR_WorkshopItem item) - Called when any download has been completed (including an update)
39 ref ScriptInvoker m_OnOfflineStateChanged = new ScriptInvoker(); // (SCR_WorkshopItem item, bool newState) - Called when the addon was downloaded first time or deleted (OFFLINE flag changed its value)
40 ref ScriptInvoker m_OnReportStateChanged = new ScriptInvoker(); // (SCR_WorkshopItem, bool newReported) - Called when reported state has changed
41 ref ScriptInvoker m_OnMyReportLoaded = new ScriptInvoker(); // (SCR_WorkshopItem item) - called after report loading is done.
42 ref ScriptInvoker m_OnMyReportLoadError = new ScriptInvoker();
43 ref ScriptInvoker m_OnRedownload = new ScriptInvoker();
44 ref ScriptInvoker m_OnCanceled = new ScriptInvoker();
45
46 // ---- Protected / Private ----
47
48 protected ref WorkshopItem m_Item; // Strong reference!
49 protected ref Dependency m_Dependency;
51
52 // Revision to download and measure patch size when item is not dependency
54 protected float m_fTargetRevisionPatchSize; // cached size for target revision
55
56 protected ref array<MissionWorkshopItem> m_aMissions;
57 protected ref array<ref SCR_WorkshopItem> m_aDependencies; // Strong references!
58 protected ref array<SCR_WorkshopItem> m_aDependent = new array<SCR_WorkshopItem>; // Weak refs - array of addons which depend on this addon
59 protected ref array<Revision> m_aRevisions;
60
61 // Name and id - just to check them in debugger
62 #ifdef WORKSHOP_DEBUG
63 protected string m_sName;
64 protected string m_sId;
65 #endif
66
67 // Flags for state of partially loaded data
68 protected bool m_bDetailsLoaded; // Details are loaded - After LoadDetails
69 protected bool m_bSizeRequesting; // Patch Size is loaded - After ComputePatchSize
70
71 // Backend callbacks
80
81 // Various state flags
82 protected bool m_bMyRating;
83 protected bool m_bMyRatingSet;
84 protected bool m_bFavourite;
85 protected bool m_bFavouriteRequesting;
86 protected bool m_bSubscribed;
87 protected bool m_bChanged; // Checked every frame, if something changes then this flag can be set to OnChanged script invoker is called during update.
88 protected bool m_bRequestFailed; // Set to true on HTTP request failures
89 protected bool m_bOffline;
90 protected int m_iAccessState;
91
92 // Data loading flags
93 protected bool m_bWaitingLoadDetails; // With current API it's always true after a LoadDetails call, since we can't know when it's done for sure
94 protected float m_fPrevDownloadProgress; // Used to detect when download progress changes
95
96 // Actions
100 protected ref SCR_WorkshopItemActionComposite m_ActionDependency; // Composite action we have started for dependencies
103
104
105 //-----------------------------------------------------------------------------------------------
106 // P U B L I C M E T H O D S
107 //-----------------------------------------------------------------------------------------------
108
112
114 bool GetItemDataLoaded() { return m_Item != null; }
115 bool GetDetailsLoaded() { return m_bDetailsLoaded; } // GetAsset request was completed, doesn't mean that anything else related to it is loaded
116 bool GetScenariosLoaded() { return m_aMissions != null; } // Scenarios were loaded after GetAsset request
117 bool GetRevisionsLoaded() { return m_aRevisions != null; } // Revisions were loaded after GetAsset request
118 bool GetDependenciesLoaded() { return m_aDependencies != null; } // Latest dependencies were loaded after GetAsset request
119 bool GetRequestFailed() { return m_bRequestFailed; } // True when any request has failed
120
121 //-----------------------------------------------------------------------------------------------
123 {
124 if (!m_ActionDownload)
125 return false;
126
127 return m_ActionDownload.IsActive();
128 }
129
130 //-----------------------------------------------------------------------------------------------
132 void LogState()
133 {
134 bool myRating, myRatingSet;
135 GetMyRating(myRatingSet, myRating);
136
137 string description = GetDescription();
138 if (description.Length() > 32)
139 {
140 description = description.Substring(0, 32);
141 description = description + " <truncated>";
142 }
143
144 string summary = GetSummary();
145 if (summary.Length() > 32)
146 {
147 summary = summary.Substring(0, 32);
148 summary = summary + " <truncated>";
149 }
150
152
153 array<ref SCR_WorkshopItem> dependencies = GetLatestDependencies();
154
155 _print("\nLogState:");
156 _print(string.Format(" Name: %1", GetName()));
157 _print(string.Format(" ID: %1", GetId()));
158 _print(string.Format(" Dependency: %1", m_Dependency));
159 _print(string.Format(" WorkshopItem: %1", m_Item));
160 _print(string.Format(" Subscribed: %1", GetSubscribed()));
161 _print(string.Format(" Enabled: %1", GetEnabled()));
162 _print(string.Format(" Online: %1", GetOnline()));
163 _print(string.Format(" Offline: %1", GetOffline()));
164 _print(string.Format(" Blocked: %1", GetBlocked()));
165 _print(string.Format(" ReportedByMe: %1", GetReportedByMe()));
167 _print(string.Format(" CurrentLocalVersion: %1", GetCurrentLocalRevision().GetVersion()));
168
169 if (GetLatestVersion())
170 _print(string.Format(" LatestVersion: %1", GetLatestVersion()));
171
172 _print(string.Format(" ItemDataLoaded: %1", GetItemDataLoaded()));
173 _print(string.Format(" DetailsLoaded: %1", GetDetailsLoaded()));
174 _print(string.Format(" ScenariosLoaded: %1", GetScenariosLoaded()));
175 _print(string.Format(" DependenciesLoaded: %1", GetDependenciesLoaded()));
176 _print(string.Format(" RequestFailed: %1", GetRequestFailed()));
177 //_print(string.Format(" OfflineAndUpToDate: %1", GetIsOfflineAndUpToDate()));
178 _print(string.Format(" AuthorName: %1", GetAuthorName()));
179 _print(string.Format(" MyRating: %1", myRating));
180 _print(string.Format(" MyRatingSet: %1", myRatingSet));
181 _print(string.Format(" Favourite: %1", GetFavourite()));
182 _print(string.Format(" Corrupted: %1", GetCorrupted()));
183 _print(string.Format(" Description: %1", description));
184 _print(string.Format(" Summary: %1", summary));
185 _print(string.Format(" RatingCount: %1", GetRatingCount()));
186 _print(string.Format(" SizeBytes: %1", GetSizeBytes()));
187 _print(string.Format(" UpdateAvailable: %1", GetUpdateAvailable()));
188 _print(string.Format(" EnabledExternally: %1", mgr.GetAddonEnabledExternally(this)));
189 _print(string.Format(" TimeSinceLastPlay: %1, %2", GetTimeSinceLastPlay(), SCR_FormatHelper.GetTimeSinceEventImprecise(GetTimeSinceLastPlay())));
191
192 //if (m_Item)
193 //_print(string.Format(" HasBackendThumbnail: %1", m_Item.HasBackendThumbnail()));
194
195 _print(string.Format(" AnyDepDisabled: %1", GetEnabledAndAnyDependencyDisabled()));
196 _print(string.Format(" AnyDepOutdated: %1", GetAnyDependencyUpdateAvailable()));
197 _print(string.Format(" AnyDepMissing: %1", GetAnyDependencyMissing()));
198
199 _print(string.Format(" Dependencies: %1", dependencies.Count()));
200 foreach (SCR_WorkshopItem dep : dependencies)
201 {
202 _print(string.Format(" - %1, Offline: %2, Update Available: %3", dep.GetName(), dep.GetOffline(), dep.GetUpdateAvailable()));
203 }
204
205 // todo scenarios, dependencies
206
207 _print("\n\n");
208 }
209
210 //-----------------------------------------------------------------------------------------------
213 {
214 #ifdef WORKSHOP_DEBUG
215 _print("LoadDetails");
216 #endif
217
219 {
221 }
222 }
223
224 //-----------------------------------------------------------------------------------------------
226 void GetScenarios(array<MissionWorkshopItem> scenarios)
227 {
228 if (!m_aMissions)
229 return;
230
231 scenarios.Clear();
232 scenarios.Copy(m_aMissions);
233 }
234
235
236 //-----------------------------------------------------------------------------------------------
238 array<ref SCR_WorkshopItem> GetLatestDependencies()
239 {
240 array<ref SCR_WorkshopItem> dependencies = new array<ref SCR_WorkshopItem>;
241
242 if (!m_aDependencies)
243 return dependencies;
244
245 foreach (auto a : m_aDependencies)
246 dependencies.Insert(a);
247
248 return dependencies;
249 }
250
251 //-----------------------------------------------------------------------------------------------
253 array<ref SCR_WorkshopItem> GetDependentAddons()
254 {
255 array<ref SCR_WorkshopItem> dependent = new array<ref SCR_WorkshopItem>;
256
257 if (!m_aDependent)
258 return dependent;
259
260 foreach (auto a : m_aDependent)
261 {
262 if (a)
263 dependent.Insert(a);
264 }
265
266 return dependent;
267 }
268
269 //-----------------------------------------------------------------------------------------------
271 {
273
274 if (!rev)
275 return string.Empty;
276
277 return rev.GetVersion();
278 }
279
280 //-----------------------------------------------------------------------------------------------
282 array<string> GetVersions()
283 {
284 array<string> versions = new array<string>;
285
286 if (!GetRevisionsLoaded())
287 return versions;
288
289 foreach (auto rev : m_aRevisions)
290 {
291 versions.Insert(rev.GetVersion());
292 }
293
294 return versions;
295 }
296
297 //-----------------------------------------------------------------------------------------------
300 {
301 if (!GetOffline())
302 return false;
303
304 // Hard coded check for 1.0 - should be replaced with specific version
305 string targetClientVersion = "1.0.0";
306 string addonClientVersion = m_Item.GetActiveRevision().GetGameVersion();
307
308 array<string> targetNumbers = {};
309 targetClientVersion.Split(".", targetNumbers, false);
310
311 array<string> addonNumbers = {};
312 addonClientVersion.Split(".", addonNumbers, false);
313
314 for (int i = 0, count = targetNumbers.Count(); i < count; i++)
315 {
316 int targetNumber = targetNumbers[i].ToInt();
317 int addonNumber = addonNumbers[i].ToInt();
318
319 if (targetNumber > addonNumber)
320 return false;
321 }
322
323 return true;
324 }
325
326 //-----------------------------------------------------------------------------------------------
327 void SetMyRating(bool newRating)
328 {
329 if (!m_Item)
330 return;
331
332 m_bMyRatingSet = true;
333 m_bMyRating = newRating;
334
335 #ifdef WORKSHOP_DEBUG
336 _print("WorkshopItem.Rate(%1)", newRating);
337 #endif
338
339 m_Item.Rate(newRating, null);
340
341 #ifdef WORKSHOP_DEBUG
342 _print("OnChanged: SetMyRating()");
343 #endif
344
345 SetChanged();
346 }
347
348
349 //-----------------------------------------------------------------------------------------------
351 {
352 if (!m_Item)
353 return;
354
355 m_bMyRatingSet = false;
356
357 #ifdef WORKSHOP_DEBUG
358 _print("WorkshopItem.ResetRating()");
359 #endif
360
361 m_Item.ResetRating(null);
362
363 #ifdef WORKSHOP_DEBUG
364 _print("OnChanged: ResetMyRating()");
365 #endif
366
367 SetChanged();
368 }
369
370
371 //-----------------------------------------------------------------------------------------------
372 void GetMyRating(out bool ratingSet, out bool rating)
373 {
374 ratingSet = m_bMyRatingSet;
375 rating = m_bMyRating;
376 }
377
378
379 //-----------------------------------------------------------------------------------------------
380 void SetFavourite(bool favourite)
381 {
382 if (!m_Item)
383 {
384 Debug.Error("SCR_WorkshopItem: Missing item to change favorite state!");
385 return;
386 }
387
389 return;
390
394
395 m_Item.SetFavorite(m_CallbackRequestFavourite, favourite);
396
397 m_bFavourite = favourite;
399
400 #ifdef WORKSHOP_DEBUG
401 _print("OnChanged: SetFavourite()");
402 #endif
403 }
404
405 //-----------------------------------------------------------------------------------------------
407 {
408 if (m_Item)
409 return m_Item.IsFavorite();
410
411 return m_bFavourite;
412 }
413
414 //-----------------------------------------------------------------------------------------------
416 {
418 SetChanged();
419 }
420
421 //-----------------------------------------------------------------------------------------------
423 {
426 SetChanged();
427 }
428
429 //-----------------------------------------------------------------------------------------------
430 void SetSubscribed(bool subscribe)
431 {
432 if (!m_Item)
433 return;
434
435 if (subscribe)
436 m_Item.Subscribe(null);
437 else
438 m_Item.Unsubscribe(null);
439
440 m_bSubscribed = subscribe;
441
442 #ifdef WORKSHOP_DEBUG
443 _print("OnChanged: Subscribe()");
444 #endif
445
446 SetChanged();
447 }
448
449 //-----------------------------------------------------------------------------------------------
451 {
452 return m_bSubscribed;
453 }
454
455 //-----------------------------------------------------------------------------------------------
456 void SetEnabled(bool enable)
457 {
458 if (!GetOffline())
459 return;
460
461 m_Item.Enable(enable);
462
463 #ifdef WORKSHOP_DEBUG
464 _print("OnChanged: SetEnabled()");
465 #endif
466
467 if (enable)
468 m_Item.NotifyPlay();
469
470 SetChanged();
471 }
472
473
474 //-----------------------------------------------------------------------------------------------
476 void SetDependenciesEnabled(bool enable)
477 {
478 if (!m_aDependencies)
479 return;
480
481 // Check for missing dependencies
482 array<ref SCR_WorkshopItem> missing = SCR_AddonManager.GetInstance().SelectItemsBasic(m_aDependencies, EWorkshopItemQuery.NOT_OFFLINE);
483 if (!missing.IsEmpty())
484 {
485
486 return;
487 }
488
489 // Enable all
490 foreach (auto dep : m_aDependencies)
491 {
492 if (dep.GetOffline() && dep.GetEnabled() != enable)
493 {
494 dep.SetEnabled(enable);
495 }
496 }
497 }
498
499 //-----------------------------------------------------------------------------------------------
501 {
502 if (!m_Item)
503 return false;
504
505 if (!GetOffline())
506 return false;
507
508 return m_Item.IsEnabled();
509 }
510
511
512 //-----------------------------------------------------------------------------------------------
515 {
516 if (!m_Item)
517 return false;
518
519 return m_Item.IsLoaded();
520 }
521
522 //-----------------------------------------------------------------------------------------------
524 {
525 if (m_Item)
526 {
527 int accessState = m_Item.GetAccessState();
528 return accessState & EWorkshopItemAccessState.EWASTATE_BLOCKED;
529 }
530 else
531 return false;
532 }
533
534 //-----------------------------------------------------------------------------------------------
536 {
537 if (m_Item)
538 return m_Item.GetAccessState() & EWorkshopItemAccessState.EWASTATE_REPORTED;
539 else
540 return false;
541 }
542
543 //-----------------------------------------------------------------------------------------------
545 {
546 if (m_Item)
547 {
548 WorkshopAuthor author = m_Item.Author();
549
550 if (author)
551 return author.IsBlocked();
552
553 return false;
554 }
555
556 return false;
557 }
558
559 //-----------------------------------------------------------------------------------------------
561 {
562 if (!m_Item)
563 return false;
564
565 return WorldSaveItem.Cast(m_Item);
566 }
567
568 //-----------------------------------------------------------------------------------------------
571 {
573 }
574
575 //-----------------------------------------------------------------------------------------------
577 {
578 if (!m_Item)
579 {
580 Debug.Error("SCR_WorkshopItem: Missing item to delete!");
581 return false;
582 }
583
584
585 if (!m_Item.GetPendingDownload() && !m_Item.GetActiveRevision())
586 {
587 Debug.Error("SCR_WorkshopItem: Attempt to delete item which is not downloaded!");
588 return true; // Already deleted
589 }
590
591 m_Item.DeleteLocally();
592
593 #ifdef WORKSHOP_DEBUG
594 _print("OnChanged: DeleteLocally()");
595 #endif
596
597 SetChanged();
598
599 return true;
600 }
601 //-----------------------------------------------------------------------------------------------
603 {
604 if (!m_Item)
605 return;
606 m_Item.DeleteDownloadProgress();
607 SetChanged();
608 }
609 //-----------------------------------------------------------------------------------------------
610 string GetName()
611 {
612 if (m_Item)
613 return m_Item.Name();
614 else if (m_Dependency)
615 return m_Dependency.GetName();
616 else
617 return string.Empty;
618 }
619
620 //-----------------------------------------------------------------------------------------------
621 string GetId()
622 {
623 if (m_Item)
624 return m_Item.Id();
625 else if (m_Dependency)
626 return m_Dependency.GetID();
627 else
628 return string.Empty;
629 }
630
631 //-----------------------------------------------------------------------------------------------
633 {
634 if (m_Item)
635 {
636 WorkshopAuthor author = m_Item.Author();
637
638 if (author)
639 return author.Name();
640 }
641
642 return string.Empty;
643 }
644
645 //-----------------------------------------------------------------------------------------------
648 {
649 if (m_Item)
650 return m_Item.GetLatestRevision() && m_Item.GetLatestRevision().GetBackendEnv() == GetGame().GetBackendApi().GetBackendEnv();
651 else if (m_Dependency) // TODO Apparently, if it's a dependency, then it's online
652 return true;
653 return false;
654 }
655
656 //-----------------------------------------------------------------------------------------------
659 {
660 if (m_Item)
661 return m_Item.GetActiveRevision();
662 else if (m_Dependency)
663 return m_Dependency.IsOffline();
664 else
665 return false;
666 }
667
668 //-----------------------------------------------------------------------------------------------
671 {
672 if (m_Item && GetOffline())
673 return m_Item.GetActiveRevision();
674 return null;
675 }
676
677
678 //-----------------------------------------------------------------------------------------------
681 {
682 if (!m_Item || !m_Dependency)
683 return false;
684
685 // Does active version match required?
687 Revision RequiredV = m_Dependency.GetRevision();
688
689 return Revision.AreEqual(ActiveV, RequiredV);
690 }
691
692
693 //-----------------------------------------------------------------------------------------------
695 {
696 if (m_Item)
697 return m_Item.GetActiveRevision().IsCorrupted();
698 else if (m_Dependency)
699 return false; // TODO this is not valid for dependency object
700 else
701 return false;
702 }
703
704 //-----------------------------------------------------------------------------------------------
706 {
707 if (!m_Item)
708 return null;
709
710 return m_Item.Thumbnail();
711 }
712
713 //-----------------------------------------------------------------------------------------------
714 array<BackendImage> GetGallery()
715 {
716 array<BackendImage> gallery = {};
717
718 if (!m_Item)
719 return gallery;
720
721 m_Item.Gallery(gallery);
722 return gallery;
723 }
724
725 //-----------------------------------------------------------------------------------------------
727 {
728 if (!m_Item)
729 return string.Empty;
730
731 return m_Item.Description();
732 }
733
734 //-----------------------------------------------------------------------------------------------
735 string GetSummary()
736 {
737 if (!m_Item)
738 return string.Empty;
739
740 return m_Item.Summary();
741 }
742
743 //-----------------------------------------------------------------------------------------------
745 {
746 if (!m_Item)
747 return 0;
748
749 return m_Item.RatingCount();
750 }
751
752 //-----------------------------------------------------------------------------------------------
754 {
755 if (m_Dependency)
756 {
757 return m_Dependency.TotalFileSize();
758 }
759 else if (m_Item)
760 {
761 if (!m_LatestRevision)
762 m_LatestRevision = m_Item.GetLatestRevision();
763
764 return m_LatestRevision.GetTotalSize();
765 }
766 else
767 {
768 Debug.Error("SCR_WorkshopItem: Dependency or WorkshopItem are not set!");
769 return 0;
770 }
771 }
772
773 //-----------------------------------------------------------------------------------------------
774 protected void OnPatchComputed()
775 {
777 m_bSizeRequesting = false;
778 m_OnChanged.Invoke();
779 }
780
781 //-----------------------------------------------------------------------------------------------
782 protected void OnPatchComputedFailed()
783 {
784 m_bSizeRequesting = false;
785 }
786
787 //-----------------------------------------------------------------------------------------------
789 {
790 if (!m_Item)
791 return 0;
792
793 return m_Item.AverageRating();
794 }
795
796 //-----------------------------------------------------------------------------------------------
798 void GetDownloadState(out bool inProgress, out bool paused, out float progress, out Revision targetRevision)
799 {
800 if (!m_ActionDownload || !m_Item)
801 {
802 inProgress = false;
803 paused = false;
804 progress = 0;
805 targetRevision = null;
806 return;
807 }
808
809 inProgress = m_ActionDownload.IsActive() || m_ActionDownload.IsPaused();
810 paused = m_ActionDownload.IsPaused();
811 progress = m_Item.GetProgress();
812 targetRevision = m_ActionDownload.GetTargetRevision();
813 }
814
815 //-----------------------------------------------------------------------------------------------
821
822 //-----------------------------------------------------------------------------------------------
828
829 //-----------------------------------------------------------------------------------------------
832 {
833 bool rawUpdateAvailable = false;
834 if (!m_Item)
835 {
836 Debug.Error("GetUpdateAvailable() was called on null item.");
837 return false;
838 }
839
840 Revision rev = m_Item.GetLatestRevision();
841 rawUpdateAvailable = rev && !rev.IsDownloaded();
842
843 bool updateAvailableByVersions = Internal_GetUpdateAvailable();
844
845 return rawUpdateAvailable || updateAvailableByVersions;
846 }
847
848 //-----------------------------------------------------------------------------------------------
850 array<ref SCR_WorkshopItem> GetMissingDependencies()
851 {
852 array<ref SCR_WorkshopItem> dependencies = GetLatestDependencies();
853
854 return SCR_AddonManager.SelectItemsBasic(dependencies, EWorkshopItemQuery.NOT_OFFLINE);
855 }
856
857 //-----------------------------------------------------------------------------------------------
859 {
860 if (!m_aDependencies)
861 return false;
862
864 return count;
865 }
866
867 //-----------------------------------------------------------------------------------------------
869 {
870 if (!m_aDependencies)
871 return false;
872
873 bool count = SCR_AddonManager.CountItemsBasic(m_aDependencies, EWorkshopItemQuery.UPDATE_AVAILABLE, true);
874 return count;
875 }
876
877 //-----------------------------------------------------------------------------------------------
880 {
881 if (!m_aDependencies)
882 return false;
883
884 if (!GetEnabled())
885 return false;
886
888 return count;
889 }
890
891 //-----------------------------------------------------------------------------------------------
896 {
897 if (!GetOffline())
898 return EWorkshopItemProblem.NO_PROBLEM;
899
901 return EWorkshopItemProblem.DEPENDENCY_MISSING;
903 return EWorkshopItemProblem.DEPENDENCY_DISABLED;
904 else if (GetUpdateAvailable())
905 return EWorkshopItemProblem.UPDATE_AVAILABLE;
907 return EWorkshopItemProblem.DEPENDENCY_OUTDATED;
908
909 return EWorkshopItemProblem.NO_PROBLEM;
910 }
911
912 //-----------------------------------------------------------------------------------------------
914 array<ref SCR_WorkshopItem> GetOutdatedDependencies()
915 {
916 array<ref SCR_WorkshopItem> dependencies = GetLatestDependencies();
917
918 if (dependencies.IsEmpty())
919 return new array<ref SCR_WorkshopItem>;
920
921 return SCR_AddonManager.SelectItemsBasic(dependencies, EWorkshopItemQuery.UPDATE_AVAILABLE);
922 }
923
924 //-----------------------------------------------------------------------------------------------
926 {
927 if (!m_Item)
928 return -1;
929
930 return m_Item.GetTimeSinceLastPlay();
931 }
932
933 //-----------------------------------------------------------------------------------------------
935 {
936 if (!m_Item)
937 return -1;
938
939 return m_Item.GetTimeSinceFirstDownload();
940 }
941
942 //-----------------------------------------------------------------------------------------------
946 protected SCR_WorkshopItemActionDownload DownloadRevision(Revision targetRevision, bool isDownloadRunning)
947 {
948 if (!m_Item && !m_Dependency)
949 return null;
950
951 bool latestRevision = (targetRevision == null);
952
953 // Create new download
954 if (!m_ActionDownload)
955 {
956 m_ActionDownload = new SCR_WorkshopItemActionDownload(this, latestRevision, targetRevision);
958
959 return m_ActionDownload;
960 }
961
962 // Check if same download is running
963 if (isDownloadRunning)
964 {
965 // Same kind of download is already running
966 return m_ActionDownload; // TODO if action was canceled or failed, create a new one
967 }
968
969 // Another download is running, but downloading a different version
970 m_ActionDownload.Cancel();
971 m_ActionDownload.Internal_Detach();
972 m_ActionDownload = null;
973
974 m_ActionDownload = new SCR_WorkshopItemActionDownload(this, latestVersion: latestRevision, targetRevision);
976 return m_ActionDownload;
977 }
978
979 //-----------------------------------------------------------------------------------------------
992 {
993 #ifdef WORKSHOP_DEBUG
994 if (targetRevision)
995 _print(string.Format("Download: %1", targetRevision.GetVersion()));
996 else
997 _print(string.Format("Download: the latest one"));
998 #endif
999
1000 bool running = false;
1001 if (m_ActionDownload && targetRevision)
1002 running = Revision.AreEqual(m_ActionDownload.GetTargetRevision(), targetRevision);
1003
1004 return DownloadRevision(targetRevision, running);
1005 }
1006
1007 //-----------------------------------------------------------------------------------------------
1009 {
1010 #ifdef WORKSHOP_DEBUG
1011 _print("DownloadLatestVersion()");
1012 #endif
1013
1014 if (!m_LatestRevision)
1015 m_LatestRevision = GetLatestRevision(); // Might return empty string if revs not loaded!
1016
1017 bool running = false;
1019 running = m_ActionDownload.GetTargetedAtLatestVersion() || Revision.AreEqual(m_LatestRevision, m_ActionDownload.GetTargetRevision());
1020
1021 return DownloadRevision(null, running);
1022 }
1023
1024 //-----------------------------------------------------------------------------------------------
1026 {
1027 if (!m_ActionDownload)
1028 m_ActionDownload = new SCR_WorkshopItemActionDownload(this, latestVersion: false, targetRevision);
1029
1031
1032 m_ActionDownload.Activate();
1033
1034 return m_ActionDownload;
1035 }
1036
1037 //-----------------------------------------------------------------------------------------------
1042 {
1043 #ifdef WORKSHOP_DEBUG
1044 _print("DownloadDependenciesLatest()");
1045 #endif
1046
1047 if (!m_Item)
1048 return null;
1049
1051 {
1053 if (action)
1054 {
1055 // Download action with dependencies is running
1056 return action;
1057 }
1058 else
1059 {
1060 // Another kind of action with dependencies is running, cancel it
1061 m_ActionDependency.Cancel();
1062 m_ActionDependency.Internal_Detach();
1063 m_ActionDependency = null;
1064
1065 action = new SCR_WorkshopItemActionDownloadDependenciesLatest(this, dependencies);
1066 m_ActionDependency = action;
1067 return action;
1068 }
1069 }
1070 else
1071 {
1072 auto action = new SCR_WorkshopItemActionDownloadDependenciesLatest(this, dependencies);
1073 m_ActionDependency = action;
1074 return action;
1075 }
1076 }
1077
1078 //-----------------------------------------------------------------------------------------------
1081 {
1082 if (!m_Item)
1083 return false;
1084
1085 if (m_ActionDownload)
1086 {
1087 return m_ActionDownload.Pause();
1088 }
1089
1090 return false;
1091 }
1092
1093 //-----------------------------------------------------------------------------------------------
1096 {
1097 if (!m_Item)
1098 return false;
1099
1100 if (m_ActionDownload)
1101 {
1102 return m_ActionDownload.Cancel();
1103 }
1104
1105 return false;
1106 }
1107
1108 //-----------------------------------------------------------------------------------------------
1111 {
1112 if (!m_Item)
1113 return false;
1114
1115 if (m_ActionDownload)
1116 {
1117 return m_ActionDownload.Resume();
1118 }
1119
1120 return false;
1121 }
1122
1123
1124 //-----------------------------------------------------------------------------------------------
1132 {
1133 if (!m_Item)
1134 return null;
1135
1136 if (m_ActionReport)
1137 {
1138 // We can't abort it or change while it's being sent anyway,
1139 // Return the existing action
1140 return m_ActionReport;
1141 }
1142 else
1143 {
1144 m_ActionReport = new SCR_WorkshopItemActionReport(this, eReport, sMessage);
1145 return m_ActionReport;
1146 }
1147 }
1148
1149 //-----------------------------------------------------------------------------------------------
1152 {
1153 if (!m_Item)
1154 return;
1155
1157 {
1161 }
1162
1163 m_Item.LoadReport(m_CallbackLoadMyReport);
1164 }
1165
1166
1167 //-----------------------------------------------------------------------------------------------
1170 void GetReport(out EWorkshopReportType reportType, out string reportDescription)
1171 {
1172 if (!m_Item)
1173 {
1174 reportType = EWorkshopReportType.EWREPORT_OTHER;
1175 reportDescription = string.Empty;
1176 return;
1177 }
1178
1179 reportType = m_Item.GetReportType();
1180 reportDescription = m_Item.GetReportDescription();
1181 }
1182
1183
1184 //-----------------------------------------------------------------------------------------------
1187 {
1188 if (!m_Item)
1189 return null;
1190
1191 if (m_ActionReport)
1192 {
1193 // We can't abort it or change while it's being sent anyway,
1194 // Return the existing action
1195 return m_ActionCancelReport;
1196 }
1197 else
1198 {
1200 return m_ActionCancelReport;
1201 }
1202 }
1203
1204 //-----------------------------------------------------------------------------------------------
1216
1217 //-----------------------------------------------------------------------------------------------
1229
1230 //-----------------------------------------------------------------------------------------------
1232 Revision FindRevision(string version)
1233 {
1234 if (!m_aRevisions)
1235 return null;
1236
1237 foreach (Revision r : m_aRevisions)
1238 {
1239 if (r.GetVersion() == version)
1240 return r;
1241 }
1242
1243 return null;
1244 }
1245
1246 //-----------------------------------------------------------------------------------------------
1247 // P R O T E C T E D / P R I V A T E
1248 //-----------------------------------------------------------------------------------------------
1249
1250
1251 //-----------------------------------------------------------------------------------------------
1253 {
1254
1255 if (!m_Item)
1256 {
1257 Debug.Error("SCR_WorkshopItem: Item is null!");
1258 return null;
1259 }
1260
1261
1262 Revision rev = m_Item.GetLatestRevision();
1263 if (!rev && GetOnline() )
1264 Debug.Error("SCR_WorkshopItem: Item is present but LatestRevision is null!");
1265
1266 return rev;
1267 }
1268
1269
1270 //-----------------------------------------------------------------------------------------------
1271 // C A L L B A C K S
1272 //-----------------------------------------------------------------------------------------------
1273
1274
1275 // --- Ask Details ---
1276
1277 //-----------------------------------------------------------------------------------------------
1279 {
1280 #ifdef WORKSHOP_DEBUG
1281 _print("Callback_AskDetails_OnGetAsset()");
1282 #endif
1283
1285
1287
1288 if (!m_aRevisions || m_aRevisions.IsEmpty())
1289 {
1290 #ifdef WORKSHOP_DEBUG
1291 _print("Callback_AskDetails_OnGetAsset(): Received no revisions", LogLevel.ERROR);
1292 #endif
1293 }
1294 else
1295 {
1296 #ifdef WORKSHOP_DEBUG
1297 _print("Callback_AskDetails_OnGetAsset(): Received revisions:");
1298 array<string> versions = GetVersions();
1299 foreach (string ver : versions)
1300 {
1301 _print(string.Format("Callback_AskDetails_OnGetAsset(): %1", ver));
1302 }
1303 #endif
1304
1306 {
1310 }
1311
1313 {
1317 }
1318
1319 if (m_Item)
1320 {
1321 if (!m_LatestRevision)
1323
1324 if (m_LatestRevision)
1325 {
1328 }
1329 }
1330 }
1331
1332 m_bDetailsLoaded = true;
1333 m_OnGetAsset.Invoke(this);
1334
1335 #ifdef WORKSHOP_DEBUG
1336 _print("OnChanged: Callback_AskDetails_OnGetAsset");
1337 #endif
1338
1339 SetChanged();
1340 m_bWaitingLoadDetails = false;
1341 }
1342
1343 //-----------------------------------------------------------------------------------------------
1345 {
1346 m_bWaitingLoadDetails = false;
1347 if (callback.GetRestResult() == ERestResult.EREST_ERROR_TIMEOUT)
1348 {
1349 #ifdef WORKSHOP_DEBUG
1350 _print("Callback_AskDetails_OnTimeout()");
1351 #endif
1352
1353 m_OnTimeout.Invoke(this);
1354 return;
1355 }
1356
1357 m_bRequestFailed = true;
1358
1359 // We still have received a response, but with an error.
1360 m_OnGetAsset.Invoke(this);
1361
1362 SetChanged();
1363
1364 //CustomDebugError("SCR_WorkshopItem failed to load details");
1365 }
1366
1367
1368 //-----------------------------------------------------------------------------------------------
1370 {
1371 #ifdef WORKSHOP_DEBUG
1372 _print("Callback_LoadDependencies_OnSuccess()");
1373 #endif
1374
1375 TryLoadDependencies(); // For now we support only dependencies of latest version
1376 }
1377
1378 //-----------------------------------------------------------------------------------------------
1380 {
1381 #ifdef WORKSHOP_DEBUG
1382 _print("Callback_LoadDependencies_OnError()");
1383 #endif
1384
1385 if (cb.GetRestResult() == ERestResult.EREST_ERROR_TIMEOUT)
1386 {
1387 m_OnTimeout.Invoke(this);
1388 }
1389 else
1390 {
1391 m_OnError.Invoke(this);
1392 }
1393
1394 CustomDebugError("SCR_WorkshopItem failed to load dependencies");
1395 }
1396
1397
1398 //-----------------------------------------------------------------------------------------------
1400 {
1401 #ifdef WORKSHOP_DEBUG
1402 _print("Callback_LoadScenarios_OnSuccess()");
1403 #endif
1404
1406 }
1407
1408 //-----------------------------------------------------------------------------------------------
1410 {
1411 #ifdef WORKSHOP_DEBUG
1412 _print("Callback_LoadScenarios_OnError()");
1413 #endif
1414
1415 if (cb.GetRestResult() == ERestResult.EREST_ERROR_TIMEOUT)
1416 {
1417 m_OnTimeout.Invoke(this);
1418 }
1419 else
1420 {
1421 m_OnError.Invoke(this);
1422 }
1423
1424 CustomDebugError("SCR_WorkshopItem failed to load scenarios");
1425 }
1426
1427 //-----------------------------------------------------------------------------------------------
1429 {
1430 m_OnMyReportLoaded.Invoke(this);
1431 }
1432
1433 //-----------------------------------------------------------------------------------------------
1435 {
1436 m_OnMyReportLoadError.Invoke(this);
1437 }
1438
1439 //-----------------------------------------------------------------------------------------------
1441 {
1442 // Try to get WorkshopItem from Dependency, if we have only Dependency
1443 if (!m_Item && m_Dependency)
1444 {
1445 m_Item = m_Dependency.GetCachedItem();
1446
1447 if (m_Item)
1448 {
1450 }
1451
1452 #ifdef WORKSHOP_DEBUG
1453 if (m_Item)
1454 _print(string.Format("WorkshopItem was missing, but was loaded: %1", m_Item.Name()));
1455 #endif
1456 }
1457 }
1458
1459
1460 //-----------------------------------------------------------------------------------------------
1461 protected void TryLoadRevisions(bool log = true)
1462 {
1463 if (!m_Item)
1464 return;
1465
1466 array<Revision> revisionsTemp = new array<Revision>;
1467 m_Item.GetRevisions(revisionsTemp);
1468
1469 if (revisionsTemp.IsEmpty() && m_Dependency)
1470 revisionsTemp.Insert(m_Dependency.GetRevision());
1471
1472 if (revisionsTemp.IsEmpty())
1473 {
1474 #ifdef WORKSHOP_DEBUG
1475 if (log)
1476 _print(string.Format("Revisions are not loaded yet. Revision array is empty."));
1477 #endif
1478
1479 return;
1480 }
1481
1482 // The revision array is not empty, so we can store it
1483 // When m_aRevisions is not null, it means revisions are loaded
1484 m_aRevisions = revisionsTemp;
1485 }
1486
1487 //-----------------------------------------------------------------------------------------------
1488 array<ref SCR_WorkshopItem> GetLoadedDependencies()
1489 {
1490 return m_aDependencies;
1491 }
1492
1493 //-----------------------------------------------------------------------------------------------
1494 protected void TryLoadDependencies(bool log = true)
1495 {
1496 #ifdef WORKSHOP_DEBUG
1497 if (log)
1498 _print("TryLoadDependencies()");
1499 #endif
1500
1501
1502 // Get array of dependencies - TODO: differentiate between dependencies version to load
1504 array<WorkshopItem> dependencies = new array<WorkshopItem>;
1505
1506 if (m_LatestRevision && !SCR_Enum.HasFlag(m_LatestRevision.GetLoadFlags(), EPendingLoadState.ELS_DEPENDENCIES))
1507 m_LatestRevision.GetDependencies(dependencies);
1508 else
1509 {
1510 m_OnDependenciesLoaded.Invoke(this);
1511 return;
1512 }
1513
1514 if (!m_aDependencies)
1515 m_aDependencies = new array<ref SCR_WorkshopItem>;
1516
1517 m_aDependencies.Clear();
1518
1519 foreach (WorkshopItem dep : dependencies)
1520 {
1521 SCR_WorkshopItem registeredItem = SCR_AddonManager.GetInstance().Register(dep);
1522 RegisterDependency(registeredItem);
1523 registeredItem.RegisterDependent(this);
1524 }
1525
1526 m_OnDependenciesLoaded.Invoke(this);
1527 }
1528
1529
1530
1531 //-----------------------------------------------------------------------------------------------
1532 protected void TryLoadScenarios(bool log = true)
1533 {
1534 #ifdef WORKSHOP_DEBUG
1535 if (log)
1536 _print("TryLoadScenarios()");
1537 #endif
1538
1539 // Load scenarios of latest revision
1541
1542 m_aMissions = new array<MissionWorkshopItem>;
1543
1544 if (m_LatestRevision && !SCR_Enum.HasFlag(m_LatestRevision.GetLoadFlags(), EPendingLoadState.ELS_SCENARIOS))
1545 m_LatestRevision.GetScenarios(m_aMissions);
1546
1547 #ifdef WORKSHOP_DEBUG
1548 _print(string.Format("TryLoadScenarios(): Received %1 scenarios", m_aMissions.Count()));
1549 _print("OnChanged: Callback_AskDetails_OnGetScenarios");
1550 #endif
1551
1552 SetChanged();
1553
1554 m_OnScenariosLoaded.Invoke(this);
1555 }
1556
1557
1558
1559 //-----------------------------------------------------------------------------------------------
1560 protected void RegisterDependency(SCR_WorkshopItem item)
1561 {
1562 int id = m_aDependencies.Find(item);
1563 if (id == -1)
1564 m_aDependencies.Insert(item);
1565 }
1566
1567
1568 //-----------------------------------------------------------------------------------------------
1569 protected void UnregisterDependency(SCR_WorkshopItem item)
1570 {
1571 m_aDependencies.RemoveItem(item);
1572 }
1573
1574
1575 //-----------------------------------------------------------------------------------------------
1576 protected void RegisterDependent(SCR_WorkshopItem item)
1577 {
1578 int id = m_aDependent.Find(item);
1579 if (id == -1)
1580 m_aDependent.Insert(item);
1581 }
1582
1583
1584 //-----------------------------------------------------------------------------------------------
1585 protected void UnregisterDependent(SCR_WorkshopItem item)
1586 {
1587 m_aDependent.RemoveItem(item);
1588 }
1589
1590 //-----------------------------------------------------------------------------------------------
1591 //-----------------------------------------------------------------------------------------------
1592 //-----------------------------------------------------------------------------------------------
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603 //-----------------------------------------------------------------------------------------------
1604 // I N T E R A C T I O N S W I T H W O R K S H O P A P I
1605 //-----------------------------------------------------------------------------------------------
1606
1607 //-----------------------------------------------------------------------------------------------
1608 bool Internal_StartDownload(notnull Revision targetRevision, BackendCallback callback)
1609 {
1610 #ifdef WORKSHOP_DEBUG
1611 _print(string.Format("Internal_StartDownload(): %1, %2", targetRevision.GetVersion(), callback));
1612 #endif
1613
1614 // Check privileges
1616 {
1617 #ifdef WORKSHOP_DEBUG
1618 _print("Internal_StartDownload(): UGC privileges were not checked or false!");
1619 #endif
1620 return false;
1621 }
1622
1623
1624 #ifdef WORKSHOP_DEBUG
1625 _print("Internal_StartDownload(): Calling WorkshopItem.Download ...");
1626 #endif
1627
1628 if (!m_Item)
1629 {
1630 if (!m_Dependency)
1631 {
1632 Debug.Error("SCR_WorkshopItem: Cannot download because Item and Dependency are missing!");
1633 return false;
1634 }
1635
1636 m_Item = m_Dependency.GetCachedItem();
1637
1638 if (!m_Item)
1639 {
1640 Debug.Error("SCR_WorkshopItem: Cannot download because Item was not cached!");
1641 return false;
1642 }
1643 }
1644
1645
1646 m_Item.Download(callback, targetRevision);
1647 return true;
1648 }
1649
1650 //-----------------------------------------------------------------------------------------------
1652 {
1653 // Check
1654 #ifdef WORKSHOP_DEBUG
1655 _print("Internal_CancelDownload()");
1656 #endif
1657
1658 if (!m_Item)
1659 {
1660 Debug.Error("SCR_WorkshopItem: Cannot cancel download because Item is missing!");
1661 return false;
1662 }
1663
1664
1665 // Pause
1669 return true;
1670 }
1671
1672 //-----------------------------------------------------------------------------------------------
1674 {
1675 m_OnCanceled.Invoke(this);
1676 }
1677
1678 //-----------------------------------------------------------------------------------------------
1680 {
1681 m_OnError.Invoke(this);
1682 m_OnCanceled.Invoke(this);
1683 }
1684
1685 /*
1686 protected ref SCR_BackendCallback m_PauseDownloadCallback = new SCR_BackendCallback();
1687 protected bool m_bRunningRequested;
1688 protected bool m_bRunningProccessed;
1689
1690 //-----------------------------------------------------------------------------------------------
1691 bool Internal_PauseDownload()
1692 {
1693 // Check
1694 #ifdef WORKSHOP_DEBUG
1695 _print("Internal_PauseDownload()");
1696 #endif
1697
1698 if (!m_Item)
1699 return false;
1700
1701 // Pause
1702 m_bRunningRequested = false;
1703
1704 m_PauseDownloadCallback.GetEventOnResponse().Insert(OnPauseDownloadResponse);
1705 m_Item.PauseDownload(m_PauseDownloadCallback);
1706 return true;
1707 }
1708
1709 //-----------------------------------------------------------------------------------------------
1710 protected void OnPauseDownloadResponse(SCR_BackendCallback callback)
1711 {
1712 m_PauseDownloadCallback.GetEventOnResponse().Remove(OnPauseDownloadResponse);
1713 m_bRunningProccessed = false;
1714 }
1715
1716 //-----------------------------------------------------------------------------------------------
1717 bool Internal_ResumeDownload(BackendCallback callback)
1718 {
1719 #ifdef WORKSHOP_DEBUG
1720 _print("Internal_ResumeDownload()");
1721 #endif
1722
1723 if (!m_Item)
1724 return false;
1725
1726 // Resume
1727 m_bRunningRequested = true;
1728
1729 m_Item.ResumeDownload(callback);
1730 return true;
1731 }
1732 */
1733
1734 //-----------------------------------------------------------------------------------------------
1735 bool Internal_Report(EWorkshopReportType eReport, string sMessage, BackendCallback callback)
1736 {
1737 #ifdef WORKSHOP_DEBUG
1738 _print(string.Format("Internal_Report(): %1, %2, %3", eReport, sMessage, callback));
1739 #endif
1740
1741 if (!m_Item)
1742 return false;
1743
1744 m_Item.Report(eReport, sMessage, callback);
1745
1746 #ifdef WORKSHOP_DEBUG
1747 _print("OnChanged: Internal_Report()");
1748 #endif
1749
1750 SetChanged();
1751
1752 return true;
1753 }
1754
1755
1756 //-----------------------------------------------------------------------------------------------
1758 {
1759 #ifdef WORKSHOP_DEBUG
1760 _print(string.Format("Internal_CancelReport(): %1", callback));
1761 #endif
1762
1763 if (!m_Item)
1764 return false;
1765
1766 m_Item.CancelReport(callback);
1767
1768 #ifdef WORKSHOP_DEBUG
1769 _print("OnChanged: Internal_CancelReport()");
1770 #endif
1771
1772 SetChanged();
1773
1774 return true;
1775 }
1776
1777 //-----------------------------------------------------------------------------------------------
1779 {
1780 #ifdef WORKSHOP_DEBUG
1781 _print(string.Format("Internal_AddAuthorBlock(): %1", callback));
1782 #endif
1783
1784 if (!m_Item)
1785 return false;
1786
1787 WorkshopAuthor author = m_Item.Author();
1788 if (!author)
1789 return false;
1790
1791 author.AddBlock(callback);
1792
1793 #ifdef WORKSHOP_DEBUG
1794 _print("OnChanged: Internal_AddAuthorBlock()");
1795 #endif
1796
1797 SetChanged();
1798
1799 return true;
1800 }
1801
1802 //-----------------------------------------------------------------------------------------------
1804 {
1805 #ifdef WORKSHOP_DEBUG
1806 _print(string.Format("Internal_RemoveAuthorBlock(): %1", callback));
1807 #endif
1808
1809 if (!m_Item)
1810 return false;
1811
1812 WorkshopAuthor author = m_Item.Author();
1813 if (!author)
1814 return false;
1815
1816 author.RemoveBlock(callback);
1817
1818 #ifdef WORKSHOP_DEBUG
1819 _print("OnChanged: Internal_RemoveAuthorBlock()");
1820 #endif
1821
1822 SetChanged();
1823
1824 return true;
1825 }
1826
1827 //-----------------------------------------------------------------------------------------------
1829 void Internal_Update(float timeSlice)
1830 {
1831 // Check if we are waiting for dependencies or revisions
1832 /*
1833 if (!GetRevisionsLoaded())
1834 TryLoadRevisions(false);
1835 */
1836 //if (!GetDependenciesLoaded())
1837 // TryLoadDependencies(false);
1838
1839
1840 // Update all our current actions
1841 // If our own action are completed, we unref and detach them
1842 // We don't delete the actions so that users can still access them
1843 if (m_ActionDownload)
1844 {
1845
1846
1847 m_ActionDownload.Internal_Update(timeSlice);
1848
1849 float newProgress;
1850 if (m_Item)
1851 newProgress = m_Item.GetProgress();
1852 if (newProgress != m_fPrevDownloadProgress)
1853 {
1854 /*
1855 // Too spammy
1856 #ifdef WORKSHOP_DEBUG
1857 _print(string.Format("OnChanged: Internal_Update: Download Progress Changed: %1", newProgress));
1858 #endif
1859 */
1860 m_fPrevDownloadProgress = newProgress;
1861 }
1862
1863 if (m_ActionDownload.IsCompleted())
1864 {
1865 #ifdef WORKSHOP_DEBUG
1866 _print("OnChanged: Internal_Update: Download Is Completed");
1867 #endif
1868
1869 m_ActionDownload.Internal_Detach();
1870 m_ActionDownload = null;
1871 m_OnDownloadComplete.Invoke(this);
1872 SetChanged();
1873 }
1874 else if (m_ActionDownload.IsCanceled())
1875 {
1876 #ifdef WORKSHOP_DEBUG
1877 _print("OnChanged: Internal_Update: Download was canceled, unregistering");
1878 #endif
1879
1880 m_ActionDownload.Internal_Detach();
1881 m_ActionDownload = null;
1882 SetChanged();
1883 }
1884 else if (m_ActionDownload.IsFailed())
1885 {
1886 #ifdef WORKSHOP_DEBUG
1887 _print("OnChanged: Internal_Update: Download has failed, unregistering");
1888 #endif
1889
1890 m_ActionDownload.Internal_Detach();
1891 m_ActionDownload = null;
1892 SetChanged();
1893 }
1894 }
1895
1896 if (m_ActionReport)
1897 {
1898 m_ActionReport.Internal_Update(timeSlice);
1899
1900 if (m_ActionReport.IsCompleted())
1901 {
1902 m_ActionReport.Internal_Detach();
1903 m_ActionReport = null;
1904
1905 #ifdef WORKSHOP_DEBUG
1906 _print("OnChanged: Internal_Update: Report Action Was Completed");
1907 #endif
1908
1909 SetChanged();
1910 m_OnReportStateChanged.Invoke(this, true);
1911 }
1912 }
1913
1915 {
1916 m_ActionCancelReport.Internal_Update(timeSlice);
1917
1918 if (m_ActionCancelReport.IsCompleted())
1919 {
1920 m_ActionCancelReport.Internal_Detach();
1921 m_ActionCancelReport = null;
1922
1923 #ifdef WORKSHOP_DEBUG
1924 _print("OnChanged: Internal_Update: Cancel report Action Was Completed");
1925 #endif
1926
1927 SetChanged();
1928 m_OnReportStateChanged.Invoke(this, false);
1929 }
1930 }
1931
1933 {
1934 m_ActionDependency.Internal_Update(timeSlice);
1935
1936 if (m_ActionDependency.IsCompleted())
1937 {
1938 #ifdef WORKSHOP_DEBUG
1939 _print("OnChanged: Internal_Update: Dependency action is completed, unregistering");
1940 #endif
1941
1942 m_ActionDependency.Internal_Detach();
1943 m_ActionDependency = null;
1944 SetChanged();
1945 return;
1946 }
1947 else if (m_ActionDependency.IsCanceled())
1948 {
1949 #ifdef WORKSHOP_DEBUG
1950 _print("OnChanged: Internal_Update: Dependency action is canceled, unregistering");
1951 #endif
1952
1953 m_ActionDependency.Internal_Detach();
1954 m_ActionDependency = null;
1955 SetChanged();
1956 }
1957 else if (m_ActionDependency.IsFailed())
1958 {
1959 #ifdef WORKSHOP_DEBUG
1960 _print("OnChanged: Internal_Update: Dependency action has failed, unregistering");
1961 #endif
1962
1963 m_ActionDependency.Internal_Detach();
1964 m_ActionDependency = null;
1965 SetChanged();
1966 }
1967 }
1968
1969 // Update mod author block state
1971
1972 // Update the offline state
1973 bool offlineNew = GetOffline();
1974 if (offlineNew != m_bOffline)
1975 {
1976 m_OnOfflineStateChanged.Invoke(this, offlineNew);
1977 }
1978 m_bOffline = offlineNew;
1979
1980 // Update the access state
1981 if (m_Item)
1982 {
1983 int accessState = m_Item.GetAccessState();
1984 if (accessState != m_iAccessState)
1985 {
1986 #ifdef WORKSHOP_DEBUG
1987 _print("OnChanged: Internal_Update: Access state has changed");
1988 #endif
1989 SetChanged();
1990 m_iAccessState = accessState;
1991 }
1992 }
1993
1994 // Invoke changed script invoker
1995 if (m_bChanged)
1996 {
1997
1998 #ifdef WORKSHOP_DEBUG
1999 _print(string.Format("Invoking OnChanged: ID: %1, Name: %2", GetId(), GetName()));
2000 #endif
2001
2002 m_OnChanged.Invoke(this);
2003 m_bChanged = false;
2004
2005 // Invoke it for dependent addons too
2006 foreach (auto i : m_aDependent)
2007 {
2008 if (i)
2009 {
2010 #ifdef WORKSHOP_DEBUG
2011 _print(string.Format("Invoking OnChanged: ID: %1, Name: %2, for dependent: %3, %4", GetId(), GetName(), i.GetId(), i.GetName()));
2012 #endif
2013 i.m_OnChanged.Invoke(i);
2014 }
2015 }
2016 }
2017 }
2018
2019 //-----------------------------------------------------------------------------------------------
2021 protected void UpdateAuthorBlock()
2022 {
2023 // Add block
2025 {
2026 m_ActionAddAuthorBlock.Internal_Update(0);
2027
2028 if (m_ActionAddAuthorBlock.IsCompleted())
2029 {
2030 m_ActionAddAuthorBlock.Internal_Detach();
2032
2033 #ifdef WORKSHOP_DEBUG
2034 _print("OnChanged: Internal_Update: Add author block action Was Completed");
2035 #endif
2036
2037 SetChanged();
2038 m_OnReportStateChanged.Invoke(this, true);
2039 }
2040 }
2041
2042 // Remove block
2044 {
2045 m_ActionRemoveAuthorBlock.Internal_Update(0);
2046
2047 if (m_ActionRemoveAuthorBlock.IsCompleted())
2048 {
2049 m_ActionRemoveAuthorBlock.Internal_Detach();
2051
2052 #ifdef WORKSHOP_DEBUG
2053 _print("OnChanged: Internal_Update: Add author block action Was Completed");
2054 #endif
2055
2056 SetChanged();
2057 m_OnReportStateChanged.Invoke(this, false);
2058 }
2059 }
2060 }
2061
2062 //-----------------------------------------------------------------------------------------------
2065 {
2066 SetChanged();
2067 }
2068
2069
2070 //-----------------------------------------------------------------------------------------------
2074 {
2077 return false;
2078 else
2079 return true;
2080 }
2081
2082
2083 //-----------------------------------------------------------------------------------------------
2086 {
2087 if (!m_Item)
2088 m_Item = m_Dependency.GetCachedItem();
2089 return m_Item;
2090 }
2091
2092 //-----------------------------------------------------------------------------------------------
2094 {
2095 if (!m_Item)
2096 return 0;
2097
2098 return m_Item.GetProgress();
2099 }
2100
2101 //-----------------------------------------------------------------------------------------------
2103 {
2104 if (!m_Item)
2105 return false;
2106
2107 Revision rev = m_Item.GetDownloadingRevision();
2108 if (!rev)
2109 return false;
2110
2111 return rev.IsProcessing();
2112 }
2113
2114 //-----------------------------------------------------------------------------------------------
2116 {
2117 if (!m_Item)
2118 return 0;
2119
2120 Revision rev = m_Item.GetDownloadingRevision();
2121 if (!rev)
2122 return 0;
2123
2124 return rev.GetProcessingProgress();
2125 }
2126
2127 //-----------------------------------------------------------------------------------------------
2130 {
2132 {
2136 }
2137
2138 //Restarts waiting for details? - TODO review logic
2140 {
2141 if (m_Item)
2142 {
2143 if (m_Item.GetLatestRevision() && m_Item.GetLatestRevision().GetBackendEnv() == GetGame().GetBackendApi().GetBackendEnv())
2144 {
2145 m_bWaitingLoadDetails = true;
2146 m_Item.AskDetail(m_CallbackAskDetails); // Internally both methods perform the same request
2147 }
2148 }
2149 else if (m_Dependency)
2150 {
2151 m_bWaitingLoadDetails = true;
2153 }
2154 }
2155 }
2156
2157 //-----------------------------------------------------------------------------------------------
2159 {
2160 m_ItemTargetRevision = revision;
2161 }
2162
2163 //-----------------------------------------------------------------------------------------------
2168
2169 //-----------------------------------------------------------------------------------------------
2174
2175 //-----------------------------------------------------------------------------------------------
2179 {
2181 }
2182
2183 //-----------------------------------------------------------------------------------------------
2184 protected void SetChanged()
2185 {
2186 m_bChanged = true;
2187 }
2188
2189 //-----------------------------------------------------------------------------------------------
2190 //-----------------------------------------------------------------------------------------------
2191 //-----------------------------------------------------------------------------------------------
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202 //-----------------------------------------------------------------------------------------------
2203 // C O N S T R U C T I O N
2204 //-----------------------------------------------------------------------------------------------
2205
2206 //-----------------------------------------------------------------------------------------------
2208 private void SCR_WorkshopItem(WorkshopItem item, Dependency dependency)
2209 {
2210 m_Item = item;
2211
2212 m_Dependency = dependency;
2213
2214 if (m_Item)
2215 {
2216 #ifdef WORKSHOP_DEBUG
2217 _print(string.Format("NEW for WorkshopItem: ID: %1, Name: %2", m_Item.Id(), m_Item.Name()));
2218 #endif
2219
2221 }
2222
2223 if(m_Dependency)
2224 {
2225 #ifdef WORKSHOP_DEBUG
2226 _print(string.Format("NEW for Dependency: ID: %1, Name: %2", m_Dependency.GetID(), m_Dependency.GetName()));
2227 #endif
2228 }
2229
2230 if (!m_Item && !m_Dependency)
2231 Print("Can't be set!");
2232
2234
2235 #ifdef WORKSHOP_DEBUG
2236 m_sName = GetName();
2237 m_sId = GetId();
2238 #endif
2239 }
2240
2241 //-----------------------------------------------------------------------------------------------
2242 void ~SCR_WorkshopItem()
2243 {
2244 #ifdef WORKSHOP_DEBUG
2245 _print(string.Format("DELETE for: ID: %1, Name: %2", this.GetId(), this.GetName()));
2246 #endif
2247
2248 if (m_aDependencies)
2249 {
2250 foreach (SCR_WorkshopItem dependency : m_aDependencies)
2251 {
2252 if (dependency)
2253 {
2254 // Unregister this from dependency, so that it doesn't point back at a null
2255 dependency.UnregisterDependent(this);
2256 }
2257 }
2258 }
2259 }
2260
2261
2262 //-----------------------------------------------------------------------------------------------
2263 void Internal_UpdateObjects(WorkshopItem item, Dependency dependency)
2264 {
2265 #ifdef WORKSHOP_DEBUG
2266 _print(string.Format("Internal_UpdateObjects: %1, %2", item, dependency));
2267 #endif
2268
2269 if (!m_Item && item)
2270 {
2271 m_Item = item;
2273 }
2274
2275 // Alwasys update dependency - because it might be required to join a different server and thus dependency object
2276 // will be different!
2277 if (dependency)
2278 m_Dependency = dependency;
2279 }
2280
2281 //-----------------------------------------------------------------------------------------------
2283 void Internal_OnAddonsChecked()
2284 {
2286 }
2287
2288 //-----------------------------------------------------------------------------------------------
2290 {
2292 return GetCurrentLocalRevision().CompareTo(GetLatestRevision()) < 0;
2293 else
2294 return false;
2295 }
2296
2297 //-----------------------------------------------------------------------------------------------
2298 static SCR_WorkshopItem Internal_CreateFromWorkshopItem(WorkshopItem item)
2299 {
2300 SCR_WorkshopItem wrapper = new SCR_WorkshopItem(item, null);
2301 return wrapper;
2302 }
2303
2304
2305 //-----------------------------------------------------------------------------------------------
2306 static SCR_WorkshopItem Internal_CreateFromDependency(Dependency dependency)
2307 {
2308
2309 SCR_WorkshopItem wrapper = new SCR_WorkshopItem(null, dependency);
2310 return wrapper;
2311 }
2312
2313 //-----------------------------------------------------------------------------------------------
2315 {
2316 if (m_Item)
2317 {
2318 m_bSubscribed = m_Item.IsSubscribed();
2319 m_bMyRating = m_Item.MyRating();
2320 m_bMyRatingSet = m_Item.IsRatingSet();
2321 m_bFavourite = m_Item.IsFavorite();
2322
2323 Revision pendingDownload = m_Item.GetPendingDownload();
2324 if (pendingDownload)
2325 SetItemTargetRevision(pendingDownload);
2326
2327 if (m_Item.IsEnabled())
2328 m_Item.NotifyPlay();
2329 }
2330
2333 }
2334
2335 //-----------------------------------------------------------------------------------------------
2336 //-----------------------------------------------------------------------------------------------
2337 //-----------------------------------------------------------------------------------------------
2338
2339 //------------------------------------------------------------------------------------------------
2340 static void _sprint(string str, LogLevel logLevel = LogLevel.DEBUG)
2341 {
2342 Print(string.Format("[SCR_AddonManager] %1", str), logLevel);
2343 }
2344
2345 //------------------------------------------------------------------------------------------------
2346 void _print(string str, LogLevel logLevel = LogLevel.DEBUG)
2347 {
2348 Print(string.Format("[SCR_AddonManager] %1 %2", this, str), logLevel);
2349 }
2350
2351 //-----------------------------------------------------------------------------------------------
2352 protected void CustomDebugError(string message)
2353 {
2354 string addonEnv = "unknown due to missing item";
2355 if (m_Item)
2356 addonEnv = m_Item.GetBackendEnv();
2357
2358 string CurrentEnv = GetGame().GetBackendApi().GetBackendEnv();
2359 //Debug.Error(string.Format("Addon: %1 [id: %2, from: %3] - %4 [current env: %5]", GetName(), GetId(), addonEnv, message, CurrentEnv));
2360 }
2361};
2362
2363//---- REFACTOR NOTE END ----
ArmaReforgerScripted GetGame()
Definition game.c:1398
int size
SCR_AddonListDialog m_Dependency
Dialog which is used when an addon is disabled but some dependent addons depend on it.
EWorkshopItemQuery
@ UPDATE_AVAILABLE
@ DEPENDENCY_MISSING
LocalizedString m_sName
NewsFeedItem m_Item
enum SCR_EServicePointType BROKEN
func ScriptInvokerMissionWorkshopItemMethod
EWorkshopItemProblem
@ NO_PROBLEM
@ DEPENDENCY_OUTDATED
@ DEPENDENCY_DISABLED
ScriptInvokerBase< ScriptInvokerMissionWorkshopItemMethod > ScriptInvokerMissionWorkshopItem
Definition Debug.c:13
static int CountItemsBasic(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query, bool returnOnFirstMatch=false)
SCR_WorkshopItem Register(WorkshopItem item)
Returns a SCR_WorkshopItem. If it's not registered, creates a new one and registers it.
static bool GetAddonEnabledExternally(SCR_WorkshopItem item)
Returns true if addon was enabled through external configuration (CLI or other).
static array< ref SCR_WorkshopItem > SelectItemsBasic(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query)
static int CountItemsAnd(array< ref SCR_WorkshopItem > items, EWorkshopItemQuery query, bool returnOnFirstMatch=false)
Counts items which match query. All flags must match.
void Internal_OnNewDownload(SCR_WorkshopItem item, SCR_WorkshopItemActionDownload action)
Called by SCR_WorkshopItem when it starts a new download.
bool GetUgcPrivilege()
Returns immediate value of UserPrivilege.USER_GEN_CONTENT.
static SCR_AddonManager GetInstance()
static string GetTimeSinceEventImprecise(int timeDiffSeconds)
Action for canceling report of an item.
Composite action which includes multiple subactions.
Action for downloading latest dependencies. Doesn't download this addon, but only downloads dependenc...
Action for removing author mod content blocking.
Action for reporting an item.
array< ref SCR_WorkshopItem > GetLoadedDependencies()
array< string > GetVersions()
Returns array of versions.
void Internal_OnChanged()
Called by actions when some change happens.
void SetItemTargetRevision(Revision revision)
Revision GetCurrentLocalRevision()
Returns the revision which we currently have on the local storage.
void LoadReport()
Loads report of current user from backend. Subscribe to m_OnMyReportLoaded to get result.
ref SCR_WorkshopItemActionCancelReport m_ActionCancelReport
void TryLoadRevisions(bool log=true)
float Internal_GetDownloadProgress()
void OnCancelDownloadResponse(BackendCallback callback)
ref SCR_WorkshopItemActionComposite m_ActionDependency
array< ref SCR_WorkshopItem > GetLatestDependencies()
Returns array of dependencies.
void UpdateAuthorBlock()
Check state of action to add and remove author block in update.
bool Internal_GetCanBeUnregistered()
void RegisterDependency(SCR_WorkshopItem item)
ref BackendCallback m_CallbackLoadGallery
Revision FindRevision(string version)
Finds revision object by string version.
bool Internal_AddAuthorBlock(BackendCallback callback)
void LogState()
Logs all properties of the object into console.
ref BackendCallback m_CallbackLoadDependencies
Revision GetLatestRevision()
void SetFavourite(bool favourite)
bool GetLoaded()
True when addon is loaded by engine. It means that the game is already running with this mod.
ref BackendCallback m_ComputeCallback
void Callback_LoadDependencies_OnSuccess()
bool GetOffline()
True when we have the item on our local storage.
bool GetEnabledAndAnyDependencyDisabled()
Returns true if any dependency is offline and disabled.
array< ref SCR_WorkshopItem > GetOutdatedDependencies()
Returns dependencies which can be updated.
bool PauseDownload()
Pauses current download, if possible.
void Callback_LoadMyReport_OnError()
SCR_WorkshopItemActionDownload DownloadLatestVersion()
void GetScenarios(array< MissionWorkshopItem > scenarios)
Returns array of scenarios.
SCR_WorkshopItemActionReport Report(EWorkshopReportType eReport, string sMessage)
bool Internal_CancelReport(BackendCallback callback)
void Callback_AskDetails_OnGetAsset()
void Internal_LoadDetails()
Creates a callback object, requests workshop API to load details.
ref array< MissionWorkshopItem > m_aMissions
EWorkshopItemProblem GetHighestPriorityProblem()
bool GetAnyDependencyUpdateAvailable()
ref Revision m_LatestRevision
ref WorkshopItem m_Item
SCR_WorkshopItemActionDownloadDependenciesLatest DownloadDependenciesLatest(array< ref SCR_WorkshopItem > dependencies)
bool IsDownloadedVersionCompatible()
Returns true if downloaded revision was uploded after 1.0.
array< ref SCR_WorkshopItem > GetDependentAddons()
Returns array of dependendent addons.
bool Internal_StartDownload(notnull Revision targetRevision, BackendCallback callback)
void GetDownloadState(out bool inProgress, out bool paused, out float progress, out Revision targetRevision)
Returns state of the download process.
void Callback_LoadMyReport_OnSuccess()
BackendImage GetThumbnail()
void UnregisterDependent(SCR_WorkshopItem item)
bool GetUpdateAvailable()
Returns true when we have an old version offline, and the new version.
void GetMyRating(out bool ratingSet, out bool rating)
ref SCR_WorkshopItemCallback_AskDetails m_CallbackAskDetails
void SetSubscribed(bool subscribe)
ref SCR_WorkshopItemActionReport m_ActionReport
SCR_WorkshopItemActionComposite GetDependencyCompositeAction()
Returns the current composite action performed for dependencies of this addon.
void SetEnabled(bool enable)
ref BackendCallback m_CallbackRequestFavourite
void Callback_AskDetails_OnError(BackendCallback callback)
float GetTargetRevisionPatchSize()
SCR_WorkshopItemActionCancelReport CancelReport()
Sends a cancel report about this workshop item.
void LoadDetails()
Loads details from backend, or if they are already loaded, calls the callbacks immediately.
void TryLoadScenarios(bool log=true)
bool Internal_RemoveAuthorBlock(BackendCallback callback)
WorkshopItem Internal_GetWorkshopItem()
Returns true when it can be unregistered bu addon manager.
bool GetRestricted()
Returns true when item is restricted for any reason (blocked or reported).
SCR_WorkshopItemActionDownload Download(notnull Revision targetRevision)
void RegisterDependent(SCR_WorkshopItem item)
static void _sprint(string str, LogLevel logLevel=LogLevel.DEBUG)
ref BackendCallback m_CallbackLoadScenarios
SCR_WorkshopItemActionRemoveAuthorBlock RemoveAuthorBlock()
Add block for workshop author and all author mods.
void Internal_Update(float timeSlice)
Called each frame by Addon Manager.
array< BackendImage > GetGallery()
void Callback_LoadScenarios_OnSuccess()
SCR_WorkshopItemActionDownload RetryDownload(Revision targetRevision)
void OnCancelDownloadError(BackendCallback callback)
ref array< SCR_WorkshopItem > m_aDependent
void SetDependenciesEnabled(bool enable)
Enables/disables all downloaded dependencies.
bool ResumeDownload()
Resumes current download, if it's already started.
static SCR_WorkshopItem Internal_CreateFromWorkshopItem(WorkshopItem item)
bool Internal_Report(EWorkshopReportType eReport, string sMessage, BackendCallback callback)
ref SCR_WorkshopItemActionAddAuthorBlock m_ActionAddAuthorBlock
void GetReport(out EWorkshopReportType reportType, out string reportDescription)
void UnregisterDependency(SCR_WorkshopItem item)
void Callback_LoadDependencies_OnError(BackendCallback cb)
SCR_WorkshopItemActionDownload DownloadRevision(Revision targetRevision, bool isDownloadRunning)
ref Revision m_ItemTargetRevision
void _print(string str, LogLevel logLevel=LogLevel.DEBUG)
ref BackendCallback m_CancelDownloadCallback
float Internal_GetProcessingProgress()
ref Dependency m_Dependency
bool GetItemDataLoaded()
Getters for loading state.
ref array< ref SCR_WorkshopItem > m_aDependencies
bool GetOnline()
True when the item is stored in the backend.
ref SCR_WorkshopItemActionRemoveAuthorBlock m_ActionRemoveAuthorBlock
SCR_WorkshopItemActionDownload GetDownloadAction()
Returns current download action.
Revision GetItemTargetRevision()
void Callback_LoadScenarios_OnError(BackendCallback cb)
ref SCR_WorkshopItemActionDownload m_ActionDownload
Dependency GetDependency()
ref array< Revision > m_aRevisions
ref BackendCallback m_CallbackLoadMyReport
bool GetCurrentLocalVersionMatchDependency()
Returns true if current local version matches version of dependency.
void SetTargetRevisionPatchSize(float size)
void SetMyRating(bool newRating)
static SCR_WorkshopItem Internal_CreateFromDependency(Dependency dependency)
SCR_WorkshopItemActionAddAuthorBlock AddAuthorBlock()
Add block for workshop author and all author mods.
WorkshopItem GetWorkshopItem()
Use these only if absoulutely necessary to intarract with game API.
bool CancelDownload()
Cancels current download, if possible.
void CustomDebugError(string message)
array< ref SCR_WorkshopItem > GetMissingDependencies()
Returns dependencies which are missing.
void TryLoadDependencies(bool log=true)
Workshop Item instance.
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
ERestResult
States and result + error code produced by RestApi.
Definition ERestResult.c:14
EPendingLoadState
Specifies which data of Revision were not yet loaded from the backend,.
EWorkshopReportType
ScriptInvokerBase< func > ScriptInvoker
Definition tools.c:134