Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/Steam/SteamManager.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Collections.Immutable;
4 using System.Linq;
5 using System.Runtime.InteropServices;
7 using Barotrauma.IO;
8 
9 namespace Barotrauma.Steam
10 {
11  static partial class SteamManager
12  {
13  public const int STEAMP2P_OWNER_PORT = 30000;
14 
15  public const uint AppID = 602960;
16 
17  private static readonly Dictionary<string, int> tagCommonness = new Dictionary<string, int>()
18  {
19  { "submarine", 10 },
20  { "item", 10 },
21  { "monster", 8 },
22  { "art", 8 },
23  { "mission", 8 },
24  { "event set", 8 },
25  { "total conversion", 5 },
26  { "environment", 5 },
27  { "item assembly", 5 },
28  { "language", 5 }
29  };
30 
31  public static bool IsInitialized => IsInitializedProjectSpecific;
32 
33  private static readonly List<string> popularTags = new List<string>();
34  public static IEnumerable<string> PopularTags
35  {
36  get
37  {
38  if (!IsInitialized) { return Enumerable.Empty<string>(); }
39  return popularTags;
40  }
41  }
42 
43  public static bool SteamworksLibExists
44  => RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
45  ? File.Exists("steam_api64.dll")
46  : RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
47  ? File.Exists("libsteam_api64.dylib")
48  : RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
49  ? File.Exists("libsteam_api64.so")
50  : false;
51 
52  public static void Initialize()
53  {
54  InitializeProjectSpecific();
55  }
56 
57  public static Option<SteamId> GetSteamId()
58  {
59  if (!IsInitialized || !Steamworks.SteamClient.IsValid)
60  {
61  return Option<SteamId>.None();
62  }
63 
64  return Option<SteamId>.Some(new SteamId(Steamworks.SteamClient.SteamId));
65  }
66 
67  public static Option<SteamId> GetOwnerSteamId()
68  {
69  if (!IsInitialized || !Steamworks.SteamClient.IsValid)
70  {
71  return Option<SteamId>.None();
72  }
73 
74  return Option<SteamId>.Some(new SteamId(Steamworks.SteamClient.SteamId));
75  }
76 
77  public static bool IsFamilyShared()
78  {
79  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return false; }
80 
81  return Steamworks.SteamApps.IsSubscribedFromFamilySharing;
82  }
83 
84  public static bool IsFreeWeekend()
85  {
86  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return false; }
87 
88  return Steamworks.SteamApps.IsSubscribedFromFreeWeekend;
89  }
90 
91  public static string GetUsername()
92  {
93  if (!IsInitialized || !Steamworks.SteamClient.IsValid)
94  {
95  return "";
96  }
97  return Steamworks.SteamClient.Name;
98  }
99 
100  public static uint GetNumSubscribedItems()
101  {
102  if (!IsInitialized || !Steamworks.SteamClient.IsValid)
103  {
104  return 0;
105  }
106  return Steamworks.SteamUGC.NumSubscribedItems;
107  }
108 
109  public static bool UnlockAchievement(string achievementIdentifier) =>
110  UnlockAchievement(achievementIdentifier.ToIdentifier());
111 
112  public static bool UnlockAchievement(Identifier achievementIdentifier)
113  {
114  if (!IsInitialized || !Steamworks.SteamClient.IsValid)
115  {
116  return false;
117  }
118 
119  DebugConsole.Log("Unlocked achievement \"" + achievementIdentifier + "\"");
120 
121  var achievements = Steamworks.SteamUserStats.Achievements.ToList();
122  int achIndex = achievements.FindIndex(ach => ach.Identifier == achievementIdentifier);
123  bool unlocked = achIndex >= 0 ? achievements[achIndex].Trigger() : false;
124  if (!unlocked)
125  {
126  //can be caused by an incorrect identifier, but also happens during normal gameplay:
127  //SteamAchievementManager tries to unlock achievements that may or may not exist
128  //(discovered[whateverbiomewasentered], kill[withwhateveritem], kill[somemonster] etc) so that we can add
129  //some types of new achievements without the need for client-side changes.
130  DebugConsole.Log($"Failed to unlock achievement \"{achievementIdentifier}\".");
131  }
132 
133  return unlocked;
134  }
135 
141  public static void IncrementStats(params (AchievementStat Identifier, float Increment)[] stats)
142  => Array.ForEach(stats, static s
143  => IncrementStat(s.Identifier, s.Increment, storeStats: false));
144 
145  public static bool IncrementStat(AchievementStat statName, int increment, bool storeStats = true)
146  {
147  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return false; }
148  DebugConsole.Log($"Incremented stat \"{statName}\" by " + increment);
149  bool success = Steamworks.SteamUserStats.AddStatInt(statName.ToIdentifier().Value.ToLowerInvariant(), increment);
150  if (!success)
151  {
152  DebugConsole.Log("Failed to increment stat \"" + statName + "\".");
153  }
154  else if (storeStats)
155  {
156  StoreStats();
157  }
158  return success;
159  }
160 
161  public static bool IncrementStat(AchievementStat statName, float increment, bool storeStats = true)
162  {
163  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return false; }
164  DebugConsole.Log($"Incremented stat \"{statName}\" by " + increment);
165  bool success = Steamworks.SteamUserStats.AddStatFloat(statName.ToIdentifier().Value.ToLowerInvariant(), increment);
166  if (!success)
167  {
168  DebugConsole.Log("Failed to increment stat \"" + statName + "\".");
169  }
170  else if (storeStats)
171  {
172  StoreStats();
173  }
174  return success;
175  }
176 
177  public static int GetStatInt(AchievementStat stat)
178  {
179  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return 0; }
180  return Steamworks.SteamUserStats.GetStatInt(stat.ToString().ToLowerInvariant());
181  }
182 
183  public static float GetStatFloat(AchievementStat stat)
184  {
185  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return 0f; }
186  return Steamworks.SteamUserStats.GetStatFloat(stat.ToString().ToLowerInvariant());
187  }
188 
189  public static ImmutableDictionary<AchievementStat, float> GetAllStats()
190  {
191  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return ImmutableDictionary<AchievementStat, float>.Empty; }
192 
193  var builder = ImmutableDictionary.CreateBuilder<AchievementStat, float>();
194 
195  foreach (AchievementStat stat in AchievementStatExtension.SteamStats)
196  {
197  if (stat.IsFloatStat())
198  {
199  builder.Add(stat, GetStatFloat(stat));
200  }
201  else
202  {
203  builder.Add(stat, GetStatInt(stat));
204  }
205  }
206 
207  return builder.ToImmutable();
208  }
209 
210  public static bool StoreStats()
211  {
212  if (!IsInitialized || !Steamworks.SteamClient.IsValid) { return false; }
213  DebugConsole.Log("Storing Steam stats...");
214  bool success = Steamworks.SteamUserStats.StoreStats();
215  if (!success)
216  {
217  DebugConsole.Log("Failed to store Steam stats.");
218  }
219  return success;
220  }
221 
222  public static bool TryGetUnlockedAchievements(out List<Steamworks.Data.Achievement> achievements)
223  {
224  if (!IsInitialized || !Steamworks.SteamClient.IsValid)
225  {
226  achievements = null;
227  return false;
228  }
229  achievements = Steamworks.SteamUserStats.Achievements.Where(a => a.State).ToList();
230  return true;
231  }
232 
233  public static void Update(float deltaTime)
234  {
235  //this should be run even if SteamManager is uninitialized
236  //servers need to be able to notify clients of unlocked talents even if the server isn't connected to Steam
237  AchievementManager.Update(deltaTime);
238 
239  if (!IsInitialized) { return; }
240 
241  if (Steamworks.SteamClient.IsValid) { Steamworks.SteamClient.RunCallbacks(); }
242  if (Steamworks.SteamServer.IsValid) { Steamworks.SteamServer.RunCallbacks(); }
243  }
244 
245  public static void ShutDown()
246  {
247  if (!IsInitialized) { return; }
248 
249  if (Steamworks.SteamClient.IsValid) { Steamworks.SteamClient.Shutdown(); }
250  if (Steamworks.SteamServer.IsValid) { Steamworks.SteamServer.Shutdown(); }
251  }
252 
253  public static IEnumerable<ulong> WorkshopUrlsToIds(IEnumerable<string> urls)
254  {
255  return urls.Select((u) =>
256  {
257  if (string.IsNullOrEmpty(u))
258  {
259  return (ulong)0;
260  }
261  else
262  {
263  return GetWorkshopItemIDFromUrl(u);
264  }
265  });
266  }
267 
268  public static ulong GetWorkshopItemIDFromUrl(string url)
269  {
270  try
271  {
272  Uri uri = new Uri(url);
273  string idStr = HttpUtility.ParseQueryString(uri.Query)["id".ToIdentifier()];
274  if (ulong.TryParse(idStr, out ulong id))
275  {
276  return id;
277  }
278  }
279  catch (Exception e)
280  {
281  DebugConsole.ThrowError("Failed to get Workshop item ID from the url \"" + url + "\"!", e);
282  }
283 
284  return 0;
285  }
286  }
287 }