using UnityEngine; using UnityEngine.Networking; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Oxide.Core; using Oxide.Core.Libraries; using Oxide.Core.Configuration; using Newtonsoft.Json; namespace Oxide.Plugins { [Info("Steam Friends", "8SecSleeper", "1.0.4")] [Description("Developer API used to check a player's Steam friends")] class SteamFriends : RustPlugin { #region Fields private static SteamFriends Instance { get; set; } private const string STEAM_API_URL = "https://api.steampowered.com/ISteamUser/GetFriendList/v0001/?key={0}&steamid={1}"; private JsonSerializerSettings errorHandling = new JsonSerializerSettings { Error = (se, ev) => { ev.ErrorContext.Handled = true; } }; private static HashSet loadedFriendsData = new HashSet(); private Coroutine coroutine; #endregion #region Configuration private static ConfigData config; private class ConfigData { [JsonProperty(PropertyName = "Steam API key (get one here https://steamcommunity.com/dev/apikey)")] public string SteamAPIKey; [JsonProperty(PropertyName = "Delay between Steam query during plugin load event, min = 1 max = 10, default is 1 second")] public int InitDelay; [JsonProperty(PropertyName = "Minimum time before a user's friend list can be updated, min = 60 max = 86400, default is 3600 seconds")] public int RefreshInterval; } private ConfigData GetDefaultConfig() { return new ConfigData { SteamAPIKey = "-1", InitDelay = 1, RefreshInterval = 3600 }; } protected override void LoadConfig() { base.LoadConfig(); try { config = Config.ReadObject(); if (config == null) { LoadDefaultConfig(); } if (config.InitDelay < 1) config.InitDelay = 1; if (config.InitDelay > 10) config.InitDelay = 10; if (config.RefreshInterval < 60) config.RefreshInterval = 60; if (config.RefreshInterval > 86400) config.RefreshInterval = 86400; } catch { Puts("Configuration file is corrupt! Check your config file at https://jsonlint.com/"); LoadDefaultConfig(); return; } SaveConfig(); } protected override void LoadDefaultConfig() { config = GetDefaultConfig(); } protected override void SaveConfig() { Config.WriteObject(config); } #endregion #region Oxide Hooks private void Init() { Instance = this; } private void OnServerInitialized() { if (config.SteamAPIKey == "-1") { DoUnload(); return; } coroutine = ServerMgr.Instance.StartCoroutine(InitFriendsData()); } private void OnPlayerConnected(BasePlayer player) { FriendsData.TryFindByID(player.userID); } private void Unload() { if (coroutine != null) { ServerMgr.Instance.StopCoroutine(coroutine); coroutine = null; } Instance = null; config = null; loadedFriendsData = null; } #endregion #region Api Hooks private bool IsSteamFriend(ulong steamID, ulong targetSteamID) { FriendsData friendsData = FriendsData.TryFindByID(steamID); if (friendsData != null) { if (friendsData.Friends.Contains(targetSteamID)) return true; } friendsData = FriendsData.TryFindByID(targetSteamID); if (friendsData != null) { if (friendsData.Friends.Contains(steamID)) return true; } return false; } private List InGameSteamFriends(ulong steamID) { List friends = new List(); foreach(BasePlayer player in BasePlayer.activePlayerList) { if (IsSteamFriend(steamID, player.userID)) friends.Add(player); } return friends; } #endregion #region Functions private void GetSteamFriends(ulong steamID) { webrequest.Enqueue(string.Format(STEAM_API_URL, config.SteamAPIKey, steamID), null, (code, response) => ProcessSteamQuery(code, response, steamID), this, RequestMethod.GET, null, 10f); } private IEnumerator InitFriendsData() { foreach(BasePlayer player in BasePlayer.activePlayerList) { FriendsData.TryFindByID(player.userID); yield return CoroutineEx.waitForSeconds(config.InitDelay); } yield break; } private void ProcessSteamQuery(int code, string response, ulong steamID) { if (response != null && code == 200) { FriendsData friendsData = FriendsData.FindByID(steamID); if (friendsData == null) return; try { FriendsObject rootObject = JsonConvert.DeserializeObject(response, errorHandling); friendsData.Friends.Clear(); if (rootObject.friendslist.friends != null) { int count = rootObject.friendslist.friends.Count; if (count > 0) { for (int i=0; i Invalid SteamAPIKey detected, plugin has been disabled, get one here https://steamcommunity.com/dev/apikey"); timer.Once(.1f, () => { Interface.Oxide.UnloadPlugin(Name); }); } private static void UpdateIfNeeded(FriendsData friendsData) { if (UnityEngine.Time.time > friendsData.LastUpdated + config.RefreshInterval) { FriendsData.RequestSteamFriends(friendsData.UserID, friendsData); } } #endregion #region Data Management public class FriendsData { public ulong UserID = 0; public float LastUpdated = 0; public HashSet Friends = new HashSet(); internal static void RemoveByID(ulong userID) { FriendsData friendsData = FindByID(userID); if (friendsData != null) { loadedFriendsData.Remove(friendsData); } } internal static void RequestSteamFriends(ulong userID, FriendsData friendsData = null) { if (friendsData == null) { friendsData = new FriendsData { UserID = userID, LastUpdated = UnityEngine.Time.time }; } else { friendsData.LastUpdated = UnityEngine.Time.time; } friendsData.Save(userID); loadedFriendsData.Add(friendsData); Instance.GetSteamFriends(userID); } internal static FriendsData TryFindByID(ulong userID) { foreach (var friendsData in loadedFriendsData) { if (friendsData.UserID == userID) { UpdateIfNeeded(friendsData); return friendsData; } } FriendsData friendsDataFromFile = Interface.Oxide.DataFileSystem.ReadObject($"SteamFriends/friendInfo_{userID}"); if (friendsDataFromFile != null && friendsDataFromFile.UserID != 0) { loadedFriendsData.Add(friendsDataFromFile); UpdateIfNeeded(friendsDataFromFile); return friendsDataFromFile; } else { RequestSteamFriends(userID); } return null; } internal static FriendsData FindByID(ulong userID) { foreach (var friendsData in loadedFriendsData) { if (friendsData.UserID == userID) { return friendsData; } } return null; } internal void Save(ulong userID) { if (userID != 0) Interface.Oxide.DataFileSystem.WriteObject($"SteamFriends/friendInfo_{userID}", this, true); } } public class FriendsObject { public Friendslist friendslist { get; set; } public class Friendslist { public List friends = new List(); public class Friends { public string steamid { get; set; } public string relationship { get; set; } public int friend_since { get; set; } } } } #endregion } }