This commit is contained in:
Aigio Liu
2021-02-24 22:29:08 +08:00
parent 3e3204412f
commit 5de392588e
23 changed files with 763 additions and 14 deletions
@@ -0,0 +1,50 @@
using System.Globalization;
using static System.Application.SteamApiUrls;
namespace System.Application.Models
{
public class AchievementInfo
{
public int AppId { get; set; }
public string? Id { get; set; }
public float Percent { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public string? IconNormal { get; set; }
public string? IconLocked { get; set; }
public bool IsHidden { get; set; }
public bool IsAchieved { get; set; }
public bool IsChecked { get; set; }
public long UnlockTimeUnix { get; set; }
public DateTime UnlockTime { get; set; }
public string IconUrl => string.Format(
STEAMAPP_ICON_URL,
AppId,
IsAchieved ? IconNormal : IconLocked);
public int Permission { get; set; }
public bool IsProtection => (Permission & 3) != 0;
public override string ToString()
{
return string.Format(
CultureInfo.CurrentCulture,
"{0}: {1}",
Name ?? Id ?? base.ToString(),
Permission);
}
}
}
@@ -0,0 +1,44 @@
namespace System.Application.Models
{
public class FloatStatInfo : StatInfo
{
public float OriginalValue { get; set; }
public float FloatValue { get; set; }
public float MinValue { get; set; }
public float MaxValue { get; set; }
public float MaxChange { get; set; }
public bool IncrementOnly { get; set; }
public float DefaultValue { get; set; }
public override object Value
{
get { return FloatValue; }
set
{
var b = float.TryParse((string)value, out float f);
if (b)
{
if ((Permission & 2) != 0 && FloatValue != f)
{
//this.FloatValue = this.FloatValue;
}
else
{
FloatValue = f;
}
}
}
}
public override bool IsModified
{
get { return FloatValue.Equals(OriginalValue) == false; }
}
}
}
@@ -0,0 +1,44 @@
namespace System.Application.Models
{
public class IntStatInfo : StatInfo
{
public int OriginalValue { get; set; }
public int IntValue { get; set; }
public int MinValue { get; set; }
public int MaxValue { get; set; }
public int MaxChange { get; set; }
public bool IncrementOnly { get; set; }
public int DefaultValue { get; set; }
public override object Value
{
get { return IntValue; }
set
{
var b = int.TryParse((string)value, out int i);
if (b)
{
if ((Permission & 2) != 0 && IntValue != i)
{
//this.IntValue = this.IntValue;
}
else
{
IntValue = i;
}
}
}
}
public override bool IsModified
{
get { return IntValue != OriginalValue; }
}
}
}
@@ -0,0 +1,47 @@
using System.ComponentModel;
namespace System.Application.Models
{
public abstract class StatInfo
{
public abstract bool IsModified { get; }
public string? Id { get; set; }
public string? DisplayName { get; set; }
public abstract object Value { get; set; }
public bool IsIncrementOnly { get; set; }
public int Permission { get; set; }
public string Extra
{
get
{
var flags = StatFlags.None;
flags |= IsIncrementOnly == false ? 0 : StatFlags.IncrementOnly;
flags |= (Permission & 2) != 0 == false ? 0 : StatFlags.Protected;
flags |= (Permission & ~2) != 0 == false ? 0 : StatFlags.UnknownPermission;
return flags.ToString();
}
}
}
[Flags]
public enum StatFlags
{
[Description("默认")]
None = 0,
[Description("仅增加")]
IncrementOnly = 1 << 0,
[Description("受保护")]
Protected = 1 << 1,
[Description("未知权限")]
UnknownPermission = 1 << 2,
}
}
@@ -0,0 +1,47 @@
using System.Diagnostics;
using static System.Application.SteamApiUrls;
namespace System.Application.Models
{
public class SteamApp : IComparable<SteamApp>
{
public int Index { get; set; }
public uint AppId { get; set; }
public bool IsInstalled { get; set; }
public string? InstalledDir { get; set; }
public string? Name { get; set; }
public string? Logo { get; set; }
public string? Icon { get; set; }
public SteamAppType Type { get; set; }
public string? LogoUrl => string.IsNullOrEmpty(Logo) ? null :
string.Format(STEAMAPP_LOGO_URL, AppId, Logo);
public string HeaderLogoUrl => string.Format(STEAMAPP_CAPSULE_URL, AppId);
public string? IconUrl => string.IsNullOrEmpty(Icon) ? null :
string.Format(STEAMAPP_LOGO_URL, AppId, Icon);
public Process? Process { get; set; }
public TradeCard? Card { get; set; }
public SteamAppInfo? Common { get; set; }
public int CompareTo(SteamApp? other) => string.Compare(Name, other?.Name);
public string GetIdAndName()
{
return $"{AppId} | {Name}";
}
}
}
@@ -0,0 +1,31 @@
using System.Collections.Generic;
namespace System.Application.Models
{
public class SteamAppInfo
{
public string? ClientIcon { get; set; }
public string? ClientTga { get; set; }
public string? Name { get; set; }
public Dictionary<string, short>? Languages { get; set; }
public string? Logo { get; set; }
public string? Logo_Small { get; set; }
public string? Icon { get; set; }
public string? OsList { get; set; }
public string? Type { get; set; }
public string? Metacritic_Name { get; set; }
public Dictionary<string, string>? Small_Capsule { get; set; }
public Dictionary<string, string>? Header_Image { get; set; }
}
}
@@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace System.Application.Models
{
public class SteamAppList
{
public List<SteamApp>? Apps { get; set; }
}
}
@@ -0,0 +1,70 @@
using System.ComponentModel;
namespace System.Application.Models
{
public enum SteamAppType : byte
{
[Description("未知")]
Unknown = 0,
[Description("游戏")]
Game = 1,
[Description("软件")]
Application = 2,
[Description("工具")]
Tool = 3,
[Description("Demo")]
Demo = 4,
[Description("预告视频")]
Media = 5,
[Description("DLC")]
DLC = 6,
[Description("指南")]
Guide = 7,
[Description("驱动")]
Driver = 8,
[Description("隐藏软件")]
Config = 9,
[Description("硬件")]
Hardware = 10,
[Description("授权")]
Franchise = 11,
[Description("视频")]
Video = 12,
[Description("插件")]
Plugin = 13,
[Description("原声音轨")]
Music = 14,
[Description("影视集")]
Series = 15,
[Description("快捷方式")]
Shortcut = 16,
[Description("仓库")]
DepotOnly = 17,
}
#if DEBUG
[Obsolete("use SteamAppType", true)]
public enum SteamAppTypeEnum
{
}
#endif
}
@@ -0,0 +1,7 @@
namespace System.Application.Models
{
public class SteamApps
{
public SteamAppList? AppList { get; set; }
}
}
@@ -0,0 +1,147 @@
using System.Xml.Serialization;
using static System.Application.SteamApiUrls;
namespace System.Application.Models
{
[XmlRoot("profile")]
public class SteamUser
{
public SteamUser()
{
}
public SteamUser(string vdfstring)
{
OriginVdfString = vdfstring;
}
public string SteamId3 { get; set; }
public long SteamId3_Int => (SteamId64 >> 0) & 0xFFFFFFFF;
public string SteamId32 { get; set; }
public long SteamId32_Int { get; set; }
[XmlElement("steamID64")]
public long SteamId64 { get; set; }
/// <summary>
/// 个人资料链接
/// </summary>
public string ProfileUrl => string.Format(STEAM_PROFILES_URL, SteamId64);
/// <summary>
/// 在线状态
/// </summary>
[XmlElement("onlineState")]
public string OnlineState { get; set; }
public string IPCountry { get; set; }
/// <summary>
/// 公开状态
/// friendsonly
/// public
/// </summary>
[XmlElement("privacyState")]
public string PrivacyState { get; set; }
/// <summary>
/// 头像小图标
/// </summary>
[XmlElement("avatarIcon")]
public string AvatarIcon { get; set; }
/// <summary>
/// 头像中等图片链接
/// </summary>
[XmlElement("avatarMedium")]
public string AvatarMedium { get; set; } = "/Resources/Asstes/avater.jpg";
/// <summary>
/// 头像大图链接
/// </summary>
[XmlElement("avatarFull")]
public string AvatarFull { get; set; }
/// <summary>
/// 昵称
/// </summary>
[XmlElement("steamID")]
public string SteamID { get; set; }
/// <summary>
/// 昵称
/// </summary>
public string SteamNickName => string.IsNullOrEmpty(SteamID) ? PersonaName : SteamID;
/// <summary>
/// 从 Valve Data File 读取到的用户名
/// </summary>
public string PersonaName { get; set; }
/// <summary>
/// 用户名
/// </summary>
public string AccountName { get; set; }
/// <summary>
/// 是否记住密码
/// </summary>
public bool RememberPassword { get; set; }
/// <summary>
/// 密码
/// </summary>
public string PassWord { get; set; }
/// <summary>
/// 最后登录时间戳
/// </summary>
public long Timestamp { get; set; }
/// <summary>
/// 最后登录时间
/// </summary>
public DateTime LastLoginTime { get; set; }
/// <summary>
/// 最近登录
/// </summary>
public bool MostRecent { get; set; }
/// <summary>
/// 离线模式
/// </summary>
public bool WantsOfflineMode { get; set; }
/// <summary>
/// 忽略离线模式警告弹窗
/// </summary>
public bool SkipOfflineModeWarning { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 来源VDF字符串
/// </summary>
public string OriginVdfString { get; set; }
/// <summary>
/// 导出VDF配置字符串
/// </summary>
public string CurrentVdfString =>
"\"" + SteamId64 + "\"\n{\n" +
"\t\t\"AccountName\"\t\t\"" + AccountName + "\"\n" +
"\t\t\"PersonaName\"\t\t\"" + PersonaName + "\"\n" +
"\t\t\"RememberPassword\"\t\t\"" + Convert.ToByte(RememberPassword) + "\"\n" +
"\t\t\"MostRecent\"\t\t\"" + Convert.ToByte(MostRecent) + "\"\n" +
"\t\t\"WantsOfflineMode\"\t\t\"" + Convert.ToByte(WantsOfflineMode) + "\"\n" +
"\t\t\"SkipOfflineModeWarning\"\t\t\"" + Convert.ToByte(SkipOfflineModeWarning) + "\"\n" +
"\t\t\"Timestamp\"\t\t\"" + Timestamp + "\"\n}";
}
}
@@ -0,0 +1,11 @@
namespace System.Application.Models
{
public class TradeCard
{
public double MinutesPlayed { get; set; }
public double Price { get; set; }
public int CardSremaining { get; set; }
}
}
@@ -0,0 +1,46 @@
namespace System.Application.Services
{
public interface ISteamService
{
public static ISteamService Instance => DI.Get<ISteamService>();
/// <summary>
/// Steam 文件夹目录
/// </summary>
string SteamDirPath { get; }
/// <summary>
/// Steam 主程序文件目录
/// </summary>
string SteamProgramPath { get; }
/// <summary>
/// 结束 Steam 进程
/// </summary>
void KillSteamProcess();
/// <summary>
/// 启动 Steam
/// </summary>
/// <param name="arguments"></param>
void StartSteam(string arguments = "");
/// <summary>
/// 获取最后一次自动登陆 Steam 用户名称
/// </summary>
/// <returns></returns>
string GetLastLoginUserName();
}
#if DEBUG
[Obsolete("use ISteamService", true)]
public class SteamToolService
{
[Obsolete("use SteamDirPath", true)]
public string? SteamPath { get; }
}
#endif
}
@@ -128,7 +128,7 @@ namespace System.Application.Services
}
/// <inheritdoc cref="OperationResultBase{T}.OperationResultBase(OperationResultType, string, string, T)"/>
public OperationResult(OperationResultType resultType, string message, string logMessage, T appendData) : base(resultType, message, logMessage, appendData)
public OperationResult(OperationResultType resultType, string message, string logMessage, object? appendData) : base(resultType, message, logMessage, appendData)
{
}
@@ -0,0 +1,36 @@
namespace System.Application
{
public static class SteamApiUrls
{
public const string MY_PROFILE_URL = "https://steamcommunity.com/profiles/76561198289531723/";
public const string MY_WISHLIST_URL = "https://store.steampowered.com/wishlist/profiles/76561198289531723/";
public const string MY_MINIPROFILE_URL = "https://steamcommunity.com/miniprofile/329265995";
public const string STEAM_PROFILES_URL = "https://steamcommunity.com/profiles/{0}/badges/";
public const string STEAM_LOGIN_URL = "https://steamcommunity.com/login/home/?goto=my/profile";
public const string STEAM_BADGES_URL = "https://steamcommunity.com/profiles/{0}/badges/";
public const string STEAMAPP_LIST_URL = "https://api.steampowered.com/ISteamApps/GetAppList/v2";
public const string STORE_APP_URL = "https://store.steampowered.com/app/{0}";
public const string STEAMAPP_LOGO_URL = "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/{0}/{1}.jpg";
public const string STEAMAPP_ICON_URL = "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/{0}/{1}";
public const string STEAMAPP_CAPSULE_URL = "https://steamcdn-a.akamaihd.net/steam/apps/{0}/capsule_184x69.jpg";
public const string STEAMAPP_HEADIMAGE_URL = "https://steamcdn-a.akamaihd.net/steam/apps/{0}/header.jpg";
public const string STEAM_MEDIA_URL = "https://steamcdn-a.akamaihd.net/steam/apps/{0}/movie_max.webm";
public const string STEAM_VIDEO_URL = "https://store.steampowered.com/video/watch/{0}/";
public const string STEAM_REGISTERKEY_URL = "https://store.steampowered.com/account/registerkey?key={0}";
public const string STEAM_FRIENDMESSAGESLOG_URL = "https://help.steampowered.com/zh-cn/accountdata/GetFriendMessagesLog";
public const string STEAM_INSTALL_URL = "steam://install/{0}";
public const string STEAM_RUNGAME_URL = "steam://rungameid/{0}";
public const string STEAM_OPENURL = "steam://openurl/{0}";
public const string STEAM_RUN_KEYURL = "steam://openurl/https://store.steampowered.com/account/registerkey?key={0}";
public const string STEAMDB_USERINFO_URL = "https://api.steamdb.ml/v1/users/{0}";
public const string STEAMDB_APPINFO_URL = "https://api.steamdb.ml/v1/apps/{0}";
public const string STEAM_USERINFO_XML_URL = "https://steamcommunity.com/profiles/{0}?xml=1";
public const string STEAMCN_USERINFO_XML_URL = "https://my.steamchina.com/profiles/76561198289531723?xml=1";
}
}
@@ -12,6 +12,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Gameloop.Vdf" Version="0.6.1" />
<PackageReference Include="NLog" Version="4.7.7" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.0" />
<PackageReference Include="ReactiveUI" Version="13.1.1" />
@@ -0,0 +1,72 @@
using Gameloop.Vdf;
using Gameloop.Vdf.Linq;
using System.IO;
using System.Text;
namespace System.Application
{
/// <summary>
/// Valve Data File 格式助手类
/// </summary>
public static class VdfHelper
{
/// <summary>
/// 根据路径读取 Valve Data File 内容
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public static VProperty Read(string filePath)
{
var text = File.ReadAllText(filePath, Encoding.UTF8);
return VdfConvert.Deserialize(text);
}
public static void UpdateValueByReplace(string filePath, string oldVaule, string newValue)
{
var text = File.ReadAllText(filePath, Encoding.UTF8);
text = text.RemovePattern().Replace(
oldVaule.RemovePattern().Replace(" ", string.Empty), newValue);
File.WriteAllText(filePath, text, Encoding.UTF8);
}
public static void DeleteValueByKey(string filePath, string key)
{
var text = File.ReadAllText(filePath, Encoding.UTF8);
// 如此实现的功能非常简单,但是应付嵌套的格式时会有问题
var index = text.IndexOf($"\"{key}\"");
var lastIndex = text.IndexOf('}', index);
text = text.Remove(index, lastIndex - index + 1);
File.WriteAllText(filePath, text, Encoding.UTF8);
}
public static void DeleteValueByReplace(string filePath, string oldVaule)
{
var text = File.ReadAllText(filePath, Encoding.UTF8);
text = text.Replace(oldVaule, string.Empty);
File.WriteAllText(filePath, text, Encoding.UTF8);
}
}
#if DEBUG
[Obsolete("use VdfHelper", true)]
public class VdfService
{
[Obsolete("use VdfHelper.UpdateValueByReplace", true)]
public void UpdateVdfValueByReplace(string path, string oldVaule, string newValue)
{
}
[Obsolete("use VdfHelper.DeleteValueByKey", true)]
public void DeleteVdfValueByKey(string path, string key)
{
}
[Obsolete("use VdfHelper.DeleteValueByReplace", true)]
public void DeleteVdfValueByReplace(string path, string oldVaule)
{
}
}
#endif
}