-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathModsUpdater.cs
90 lines (80 loc) · 3.05 KB
/
ModsUpdater.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using Cysharp.Threading.Tasks;
using ModLoader;
using SFS.Input;
using SFS.IO;
using SFS.UI;
using UnityEngine;
namespace UITools
{
static class ModsUpdater
{
static readonly HttpClient Http = new();
static readonly MD5 MD5 = MD5.Create();
static int loadedFiles;
public static async UniTask UpdateAll()
{
try
{
IUpdatable[] mods = Loader.main.GetAllMods().OfType<IUpdatable>().ToArray();
if (mods.Length == 0)
return;
foreach (IUpdatable mod in mods)
await Update(mod);
}
catch (Exception e)
{
Debug.LogError(e);
}
finally
{
if (loadedFiles > 0)
MenuGenerator.OpenConfirmation(CloseMode.Current,
() => "Some files were updated. Do you want to restart the game?", () => "Restart",
ApplicationUtility.Relaunch);
}
}
static async UniTask Update(IUpdatable mod)
{
foreach (KeyValuePair<string, FilePath> file in mod.UpdatableFiles)
{
string link =
$"https://files.cucumber-space.online/api/hashes/md5?file={Uri.EscapeDataString(file.Key)}";
HttpResponseMessage response = await Http.GetAsync(link);
if (!response.IsSuccessStatusCode)
continue;
byte[] md5HashLocal = file.Value.FileExists()
? MD5.ComputeHash(file.Value.ReadBytes())
: Array.Empty<byte>();
byte[] md5HashRemote = Convert.FromBase64String(await response.Content.ReadAsStringAsync());
if (md5HashLocal.SequenceEqual(md5HashRemote))
continue;
if (!await MenuGenerator.OpenConfirmationAsync(CloseMode.Current,
() => $"Update for {(mod as Mod)?.DisplayName} is available. Update?", () => "Update"))
continue;
response = await Http.GetAsync(file.Key);
byte[] data = await response.Content.ReadAsByteArrayAsync();
if (data == null)
continue;
file.Value.WriteBytes(data);
loadedFiles += 1;
}
}
}
/// <summary>
/// Implement this interface on main mod class if you want it to be updated at game start
/// </summary>
public interface IUpdatable
{
/// <summary>
/// Returns dictionary of files that should be updated
/// string is web link, FilePath is path where file will downloaded
/// </summary>
/// <returns></returns>
public Dictionary<string, FilePath> UpdatableFiles { get; }
}
}