diff --git a/osrs-toolbox/APIs/Runescape/DataModels/Activity.cs b/osrs-toolbox/APIs/Runescape/DataModels/Activity.cs new file mode 100644 index 0000000..79eebab --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/DataModels/Activity.cs @@ -0,0 +1,9 @@ +namespace osrs_toolbox +{ + public class Activity : IPlayerInfoProperty + { + public string Name { get; set; } + public int Rank { get; set; } + public int Score { get; set; } + } +} diff --git a/osrs-toolbox/APIs/Runescape/DataModels/Boss.cs b/osrs-toolbox/APIs/Runescape/DataModels/Boss.cs new file mode 100644 index 0000000..d58a14a --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/DataModels/Boss.cs @@ -0,0 +1,9 @@ +namespace osrs_toolbox +{ + public class Boss : IPlayerInfoProperty + { + public string Name { get; set; } + public int Rank { get; set; } + public int Kills { get; set; } + } +} diff --git a/osrs-toolbox/APIs/Runescape/DataModels/IPlayerInfoProperty.cs b/osrs-toolbox/APIs/Runescape/DataModels/IPlayerInfoProperty.cs new file mode 100644 index 0000000..9fe1822 --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/DataModels/IPlayerInfoProperty.cs @@ -0,0 +1,7 @@ +namespace osrs_toolbox +{ + public interface IPlayerInfoProperty + { + + } +} diff --git a/osrs-toolbox/APIs/Runescape/DataModels/PlayerInfo.cs b/osrs-toolbox/APIs/Runescape/DataModels/PlayerInfo.cs new file mode 100644 index 0000000..5f10da3 --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/DataModels/PlayerInfo.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Reflection; + +namespace osrs_toolbox +{ + public class PlayerInfo + { + private static readonly Skill InitialSkillState = new Skill { Rank = -1, Level = 1, Experience = 1 }; + private static readonly Activity InitialActivityState = new Activity { Rank = -1, Score = -1 }; + private static readonly Boss InitialBossState = new Boss { Rank = -1, Kills = -1 }; + + public string Name { get; set; } = ""; + public PlayerInfoStatus Status { get; internal set; } = PlayerInfoStatus.Unknown; + public PlayerType AccountType { get; internal set; } = PlayerType.Unknown; + + //skills + public Skill Overall { get; set; } = InitialSkillState; + public Skill Attack { get; set; } = InitialSkillState; + public Skill Defence { get; set; } = InitialSkillState; + public Skill Strength { get; set; } = InitialSkillState; + public Skill Hitpoints { get; set; } = InitialSkillState; + public Skill Ranged { get; set; } = InitialSkillState; + public Skill Prayer { get; set; } = InitialSkillState; + public Skill Magic { get; set; } = InitialSkillState; + public Skill Cooking { get; set; } = InitialSkillState; + public Skill Woodcutting { get; set; } = InitialSkillState; + public Skill Fletching { get; set; } = InitialSkillState; + public Skill Fishing { get; set; } = InitialSkillState; + public Skill Firemaking { get; set; } = InitialSkillState; + public Skill Crafting { get; set; } = InitialSkillState; + public Skill Smithing { get; set; } = InitialSkillState; + public Skill Mining { get; set; } = InitialSkillState; + public Skill Herblore { get; set; } = InitialSkillState; + public Skill Agility { get; set; } = InitialSkillState; + public Skill Thieving { get; set; } = InitialSkillState; + public Skill Slayer { get; set; } = InitialSkillState; + public Skill Farming { get; set; } = InitialSkillState; + public Skill Runecrafting { get; set; } = InitialSkillState; + public Skill Hunter { get; set; } = InitialSkillState; + public Skill Construction { get; set; } = InitialSkillState; + + //minigames + public Activity LeaguePoints { get; set; } = InitialActivityState; + public Activity BountyHunterRogues { get; set; } = InitialActivityState; + public Activity BountyHunter { get; set; } = InitialActivityState; + public Activity BountyHunterRoguesLegacy { get; set; } = InitialActivityState; + public Activity BountyHunterLegacy { get; set; } = InitialActivityState; + public Activity DeadManMode { get; set; } = InitialActivityState; + public Activity TotalCluesScrolls { get; set; } = InitialActivityState; + public Activity BeginnerClueScrolls { get; set; } = InitialActivityState; + public Activity EasyClueScrolls { get; set; } = InitialActivityState; + public Activity MediumClueScrolls { get; set; } = InitialActivityState; + public Activity HardClueScrolls { get; set; } = InitialActivityState; + public Activity EliteClueScrolls { get; set; } = InitialActivityState; + public Activity MasterClueScrolls { get; set; } = InitialActivityState; + public Activity LastManStanding { get; set; } = InitialActivityState; + public Activity PvPArena { get; set; } = InitialActivityState; + public Activity SoulWarsZeal { get; set; } = InitialActivityState; + public Activity RiftsClosed { get; set; } = InitialActivityState; + + //bosses + public Boss AbyssalSire { get; set; } = InitialBossState; + public Boss AlchemicalHydra { get; set; } = InitialBossState; + public Boss Artio { get; set; } = InitialBossState; + public Boss BarrowsChests { get; set; } = InitialBossState; + public Boss Bryophyta { get; set; } = InitialBossState; + public Boss Callisto { get; set; } = InitialBossState; + public Boss Calvarion { get; set; } = InitialBossState; + public Boss Cerberus { get; set; } = InitialBossState; + public Boss ChambersofXeric { get; set; } = InitialBossState; + public Boss ChambersofXericChallengeMode { get; set; } = InitialBossState; + public Boss ChaosElemental { get; set; } = InitialBossState; + public Boss ChaosFanatic { get; set; } = InitialBossState; + public Boss CommanderZilyana { get; set; } = InitialBossState; + public Boss CorporealBeast { get; set; } = InitialBossState; + public Boss CrazyArchaeologist { get; set; } = InitialBossState; + public Boss DagannothPrime { get; set; } = InitialBossState; + public Boss DagannothRex { get; set; } = InitialBossState; + public Boss DagannothSupreme { get; set; } = InitialBossState; + public Boss DerangedArchaeologist { get; set; } = InitialBossState; + public Boss DukeSucellus { get; set; } = InitialBossState; + public Boss GeneralGraardor { get; set; } = InitialBossState; + public Boss GiantMole { get; set; } = InitialBossState; + public Boss GrotesqueGuardians { get; set; } = InitialBossState; + public Boss Hespori { get; set; } = InitialBossState; + public Boss KalphiteQueen { get; set; } = InitialBossState; + public Boss KingBlackDragon { get; set; } = InitialBossState; + public Boss Kraken { get; set; } = InitialBossState; + public Boss Kree { get; set; } = InitialBossState; + public Boss Kril { get; set; } = InitialBossState; + public Boss Mimic { get; set; } = InitialBossState; + public Boss Nex { get; set; } = InitialBossState; + public Boss Nightmare { get; set; } = InitialBossState; + public Boss PhosanisNightmare { get; set; } = InitialBossState; + public Boss Obor { get; set; } = InitialBossState; + public Boss PhantomMuspah { get; set; } = InitialBossState; + public Boss Sarachnis { get; set; } = InitialBossState; + public Boss Scorpia { get; set; } = InitialBossState; + public Boss Skotizo { get; set; } = InitialBossState; + public Boss Spindel { get; set; } = InitialBossState; + public Boss Tempoross { get; set; } = InitialBossState; + public Boss Gauntlet { get; set; } = InitialBossState; + public Boss CorruptedGauntlet { get; set; } = InitialBossState; + public Boss Leviathan { get; set; } = InitialBossState; + public Boss Whisperer { get; set; } = InitialBossState; + public Boss TheatreofBlood { get; set; } = InitialBossState; + public Boss TheatreofBloodHardMode { get; set; } = InitialBossState; + public Boss ThermonuclearSmokeDevil { get; set; } = InitialBossState; + public Boss TombsOfAmascut { get; set; } = InitialBossState; + public Boss TombsOfAmascutExpertMode { get; set; } = InitialBossState; + public Boss Zuk { get; set; } = InitialBossState; + public Boss Jad { get; set; } = InitialBossState; + public Boss Vardorvis { get; set; } = InitialBossState; + public Boss Venenatis { get; set; } = InitialBossState; + public Boss Vetion { get; set; } = InitialBossState; + public Boss Vorkath { get; set; } = InitialBossState; + public Boss Wintertodt { get; set; } = InitialBossState; + public Boss Yama { get; set; } = InitialBossState; + public Boss Zalcano { get; set; } = InitialBossState; + public Boss Zulrah { get; set; } = InitialBossState; + + public PlayerInfo() { } + + //returns all info in a big string. + public string GetAllValuesToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append($"Player Name : {Name} \n"); + // retrieve the property information of the Player Info Class + PropertyInfo[] properties = typeof(PlayerInfo).GetProperties(); + foreach (PropertyInfo info in properties) + { + if (info.PropertyType == typeof(Skill) || info.PropertyType == typeof(Activity)) + { + // gets the value of the PropertyInfo (Skill/Minigame) and returns its Properties + PropertyInfo[] SkillProperties = info.GetValue(this).GetType().GetProperties(); + //Skill Name + sb.Append($"{info.Name} : "); + // Add the Minigame/Skill Properties into the sb + foreach (PropertyInfo SkillInfo in SkillProperties) + { + sb.Append($"{SkillInfo.Name} : {SkillInfo.GetValue(info.GetValue(this))}, "); + } + sb.Append("\n"); + } + } + return sb.ToString(); + } + + //IEnumerable for looping over all Skills + public IEnumerable Skills() + { + PropertyInfo[] properties = typeof(PlayerInfo).GetProperties(); + + foreach (PropertyInfo info in properties.Where(info => info.PropertyType == typeof(Skill))) + { + Skill skill = (Skill)info.GetValue(this, null); + yield return skill; + } + } + + //IEnumberable for looping over all Minigames + public IEnumerable Minigames() + { + PropertyInfo[] properties = typeof(PlayerInfo).GetProperties(); + + foreach (PropertyInfo info in properties.Where(info => info.PropertyType == typeof(Activity))) + { + Activity skill = (Activity)info.GetValue(this, null); + yield return skill; + } + } + + //IEnumberable for looping over all Bosses + public IEnumerable Bosses() + { + PropertyInfo[] properties = typeof(PlayerInfo).GetProperties(); + + foreach (PropertyInfo info in properties.Where(info => info.PropertyType == typeof(Boss))) + { + Boss skill = (Boss)info.GetValue(this, null); + yield return skill; + } + } + } +} diff --git a/osrs-toolbox/APIs/Runescape/DataModels/PlayerInfoStatus.cs b/osrs-toolbox/APIs/Runescape/DataModels/PlayerInfoStatus.cs new file mode 100644 index 0000000..9856c5d --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/DataModels/PlayerInfoStatus.cs @@ -0,0 +1,9 @@ +namespace osrs_toolbox +{ + public enum PlayerInfoStatus + { + Unknown, + NotFound, + Success + } +} diff --git a/osrs-toolbox/APIs/Runescape/DataModels/PlayerType.cs b/osrs-toolbox/APIs/Runescape/DataModels/PlayerType.cs new file mode 100644 index 0000000..38c6a89 --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/DataModels/PlayerType.cs @@ -0,0 +1,11 @@ +namespace osrs_toolbox +{ + public enum PlayerType + { + Main, + Ironman, + HardcoreIronman, + UltimateIronman, + Unknown + } +} diff --git a/osrs-toolbox/APIs/Runescape/DataModels/Skill.cs b/osrs-toolbox/APIs/Runescape/DataModels/Skill.cs new file mode 100644 index 0000000..d3222c7 --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/DataModels/Skill.cs @@ -0,0 +1,10 @@ +namespace osrs_toolbox +{ + public class Skill : IPlayerInfoProperty + { + public string Name { get; set; } + public int Rank { get; set; } + public int Level { get; set; } + public int Experience { get; set; } + } +} \ No newline at end of file diff --git a/osrs-toolbox/APIs/Runescape/PlayerInfoService.cs b/osrs-toolbox/APIs/Runescape/PlayerInfoService.cs new file mode 100644 index 0000000..7fb374c --- /dev/null +++ b/osrs-toolbox/APIs/Runescape/PlayerInfoService.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Net; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace osrs_toolbox +{ + public class PlayerInfoService + { + private readonly HttpClient _httpClient; + private bool _throwMismatchException; + + internal bool ThrowMismatchException + { + get => _throwMismatchException; + set => _throwMismatchException = value; + } + + public PlayerInfoService(HttpClient httpClient, bool throwMismatchException = true) + { + _httpClient = httpClient; + _throwMismatchException = throwMismatchException; + } + + public async Task GetPlayerInfoAsync(string userName) + { + bool playerFound = false; + var playerInfo = new PlayerInfo { Name = userName }; + + //HttpResponseMessage response = null; + HttpResponseMessage response = await _httpClient.GetAsync("https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=" + userName).ConfigureAwait(false); + + if (response.StatusCode == HttpStatusCode.NotFound) + { + playerInfo.Status = PlayerInfoStatus.NotFound; + return playerInfo; + } + + PlayerInfo mainPlayerInfo = new PlayerInfo { Name = userName }; + PlayerInfo ironPlayerInfo = new PlayerInfo { Name = userName }; + PlayerInfo hcimPlayerInfo = new PlayerInfo { Name = userName }; + PlayerInfo uimPlayerInfo = new PlayerInfo { Name = userName }; + + return await ParseHttpResponse(playerInfo, response).ConfigureAwait(false); + + HttpResponseMessage mainResponse = await _httpClient.GetAsync("https://secure.runescape.com/m=hiscore_oldschool/index_lite.ws?player=" + userName).ConfigureAwait(false); + HttpResponseMessage ironResponse = await _httpClient.GetAsync("https://secure.runescape.com/m=hiscore_oldschool_ironman/index_lite.ws?player=" + userName).ConfigureAwait(false); + HttpResponseMessage hcimResponse = await _httpClient.GetAsync("https://secure.runescape.com/m=hiscore_oldschool_hardcore_ironman/index_lite.ws?player=" + userName).ConfigureAwait(false); + HttpResponseMessage uimResponse = await _httpClient.GetAsync("https://secure.runescape.com/m=hiscore_oldschool_ultimate/index_lite.ws?player=" + userName).ConfigureAwait(false); + + if (mainResponse.StatusCode != HttpStatusCode.NotFound) + { + playerFound = true; + mainPlayerInfo = await ParseHttpResponse(mainPlayerInfo, mainResponse).ConfigureAwait(false); + } + if (ironResponse.StatusCode != HttpStatusCode.NotFound) + { + playerFound = true; + ironPlayerInfo = await ParseHttpResponse(ironPlayerInfo, ironResponse).ConfigureAwait(false); + } + if (hcimResponse.StatusCode != HttpStatusCode.NotFound) + { + playerFound = true; + hcimPlayerInfo = await ParseHttpResponse(hcimPlayerInfo, hcimResponse).ConfigureAwait(false); + } + if (uimResponse.StatusCode != HttpStatusCode.NotFound) + { + playerFound = true; + uimPlayerInfo = await ParseHttpResponse(uimPlayerInfo, uimResponse).ConfigureAwait(false); + } + + if (!playerFound) + { + playerInfo.Status = PlayerInfoStatus.NotFound; + return playerInfo; + } + else + { + + } + } + + public async Task> GetPlayerInfoAsync(string[] userNames) + { + var tasks = userNames.Select(x => GetPlayerInfoAsync(x)); + return await Task.WhenAll(tasks) + .ConfigureAwait(false); + } + + private async Task ParseHttpResponse(PlayerInfo playerInfo, HttpResponseMessage response) + { + var stream = await response.Content.ReadAsStreamAsync() + .ConfigureAwait(false); + + using var reader = new StreamReader(stream); + + var properties = typeof(PlayerInfo).GetProperties() + .Where(x => typeof(IPlayerInfoProperty).IsAssignableFrom(x.PropertyType)).ToArray(); + + if (properties.Count() != TotalLines(reader) && _throwMismatchException) + throw new FormatException("Property mismatch; OSRS API Contains more properties than PlayerInfo class. Please contact Repository creator"); + + foreach (PropertyInfo info in properties) + { + string[] values = reader.ReadLine().Split(','); + var property = ParseLine(values, info); + + info.SetValue(playerInfo, property); + } + + playerInfo.Status = PlayerInfoStatus.Success; + + return playerInfo; + } + + private int TotalLines(StreamReader reader) + { + int i = 0; + while (reader.ReadLine() != null) i++; + + reader.BaseStream.Position = 0; + + return i; + } + + private IPlayerInfoProperty ParseLine(string[] data, PropertyInfo info) + { + if (info.PropertyType == typeof(Skill)) + { + return new Skill + { + Name = info.Name, + Rank = int.Parse(data[0]), + Level = int.Parse(data[1]), + Experience = int.Parse(data[2]) + }; + } + + if (info.PropertyType == typeof(Activity)) + { + return new Activity + { + Name = info.Name, + Rank = int.Parse(data[0]), + Score = int.Parse(data[1]) + }; + } + + if (info.PropertyType == typeof(Boss)) + { + return new Boss + { + Name = info.Name, + Rank = int.Parse(data[0]), + Kills = int.Parse(data[1]) + }; + } + + throw new NotImplementedException($"Unimplemented type {info.PropertyType}"); + } + } +}