C#:
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<FriendsData> loadedFriendsData = new HashSet<FriendsData>();
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<ConfigData>();
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<BasePlayer> InGameSteamFriends(ulong steamID)
{
List<BasePlayer> friends = new List<BasePlayer>();
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<FriendsObject>(response, errorHandling);
friendsData.Friends.Clear();
if (rootObject.friendslist.friends != null)
{
int count = rootObject.friendslist.friends.Count;
if (count > 0)
{
for (int i=0; i<count; i++)
{
ulong targetSteamID;
if (ulong.TryParse(rootObject.friendslist.friends[i].steamid, out targetSteamID))
{
friendsData.Friends.Add(targetSteamID);
}
}
}
}
friendsData.Save(steamID);
loadedFriendsData.Add(friendsData);
}
catch {}
return;
}
if (response != null && response.Contains("Please verify your"))
{
DoUnload();
}
}
private void DoUnload()
{
Puts("Invalid Configuration file -> 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<ulong> Friends = new HashSet<ulong>();
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<FriendsData>($"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> friends = new List<Friends>();
public class Friends
{
public string steamid { get; set; }
public string relationship { get; set; }
public int friend_since { get; set; }
}
}
}
#endregion
}
}