clash of clans saving started, needs more work
This commit is contained in:
parent
0521a71fa8
commit
961a42a8c3
@ -4,6 +4,9 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
//using Manatee.Json.Serialization;
|
||||||
|
|
||||||
namespace NadekoBot.Classes.ClashOfClans
|
namespace NadekoBot.Classes.ClashOfClans
|
||||||
{
|
{
|
||||||
@ -11,13 +14,14 @@ namespace NadekoBot.Classes.ClashOfClans
|
|||||||
{
|
{
|
||||||
One, Two, Three
|
One, Two, Three
|
||||||
}
|
}
|
||||||
|
[System.Serializable]
|
||||||
internal class Caller
|
internal class Caller
|
||||||
{
|
{
|
||||||
public string CallUser { get; }
|
public string CallUser { get; }
|
||||||
|
|
||||||
public DateTime TimeAdded { get; private set; }
|
public DateTime TimeAdded { get; set; }
|
||||||
|
|
||||||
public bool BaseDestroyed { get; internal set; }
|
public bool BaseDestroyed { get; set; }
|
||||||
|
|
||||||
public int Stars { get; set; } = 3;
|
public int Stars { get; set; } = 3;
|
||||||
|
|
||||||
@ -47,94 +51,76 @@ namespace NadekoBot.Classes.ClashOfClans
|
|||||||
public string EnemyClan { get; }
|
public string EnemyClan { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
|
||||||
private Caller[] bases { get; }
|
public Caller[] Bases { get; }
|
||||||
private CancellationTokenSource[] baseCancelTokens;
|
|
||||||
private CancellationTokenSource endTokenSource { get; } = new CancellationTokenSource();
|
|
||||||
public event Action<string> OnUserTimeExpired = delegate { };
|
|
||||||
public event Action OnWarEnded = delegate { };
|
|
||||||
public bool Started { get; set; } = false;
|
public bool Started { get; set; } = false;
|
||||||
|
public DateTime StartedAt { get; private set; }
|
||||||
|
public bool Ended { get; private set; } = false;
|
||||||
|
|
||||||
public ClashWar(string enemyClan, int size, CommandEventArgs e)
|
public ulong ServerId { get; set; }
|
||||||
|
public ulong ChannelId { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public Discord.Channel Channel { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This init is purely for the deserialization
|
||||||
|
/// </summary>
|
||||||
|
public ClashWar() { }
|
||||||
|
|
||||||
|
public ClashWar(string enemyClan, int size, ulong serverId, ulong channelId)
|
||||||
{
|
{
|
||||||
this.EnemyClan = enemyClan;
|
this.EnemyClan = enemyClan;
|
||||||
this.Size = size;
|
this.Size = size;
|
||||||
this.bases = new Caller[size];
|
this.Bases = new Caller[size];
|
||||||
this.baseCancelTokens = new CancellationTokenSource[size];
|
this.ServerId = serverId;
|
||||||
|
this.ChannelId = channelId;
|
||||||
|
this.Channel = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id == serverId)?.TextChannels.FirstOrDefault(c => c.Id == channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void End()
|
internal void End()
|
||||||
{
|
{
|
||||||
if (endTokenSource.Token.IsCancellationRequested) return;
|
Ended = true;
|
||||||
endTokenSource.Cancel();
|
|
||||||
OnWarEnded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Call(string u, int baseNumber)
|
internal void Call(string u, int baseNumber)
|
||||||
{
|
{
|
||||||
if (baseNumber < 0 || baseNumber >= bases.Length)
|
if (baseNumber < 0 || baseNumber >= Bases.Length)
|
||||||
throw new ArgumentException("Invalid base number");
|
throw new ArgumentException("Invalid base number");
|
||||||
if (bases[baseNumber] != null)
|
if (Bases[baseNumber] != null)
|
||||||
throw new ArgumentException("That base is already claimed.");
|
throw new ArgumentException("That base is already claimed.");
|
||||||
for (var i = 0; i < bases.Length; i++)
|
for (var i = 0; i < Bases.Length; i++)
|
||||||
{
|
{
|
||||||
if (bases[i]?.BaseDestroyed == false && bases[i]?.CallUser == u)
|
if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u)
|
||||||
throw new ArgumentException($"@{u} You already claimed a base #{i + 1}. You can't claim a new one.");
|
throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
|
||||||
}
|
}
|
||||||
|
|
||||||
bases[baseNumber] = new Caller(u.Trim(), DateTime.Now, false);
|
Bases[baseNumber] = new Caller(u.Trim(), DateTime.Now, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task Start()
|
internal void Start()
|
||||||
{
|
{
|
||||||
if (Started)
|
if (Started)
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
try
|
|
||||||
{
|
|
||||||
Started = true;
|
Started = true;
|
||||||
foreach (var b in bases.Where(b => b != null))
|
StartedAt = DateTime.Now;
|
||||||
|
foreach (var b in Bases.Where(b => b != null))
|
||||||
{
|
{
|
||||||
b.ResetTime();
|
b.ResetTime();
|
||||||
}
|
}
|
||||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
|
||||||
Task.Run(async () => await ClearArray()).ConfigureAwait(false);
|
|
||||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
|
||||||
await Task.Delay(new TimeSpan(24, 0, 0), endTokenSource.Token).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
End();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int Uncall(string user)
|
internal int Uncall(string user)
|
||||||
{
|
{
|
||||||
user = user.Trim();
|
user = user.Trim();
|
||||||
for (var i = 0; i < bases.Length; i++)
|
for (var i = 0; i < Bases.Length; i++)
|
||||||
{
|
{
|
||||||
if (bases[i]?.CallUser != user) continue;
|
if (Bases[i]?.CallUser != user) continue;
|
||||||
bases[i] = null;
|
Bases[i] = null;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException("You are not participating in that war.");
|
throw new InvalidOperationException("You are not participating in that war.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ClearArray()
|
|
||||||
{
|
|
||||||
while (!endTokenSource.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
|
||||||
for (var i = 0; i < bases.Length; i++)
|
|
||||||
{
|
|
||||||
if (bases[i] == null) continue;
|
|
||||||
if (!bases[i].BaseDestroyed && DateTime.Now - bases[i].TimeAdded >= callExpire)
|
|
||||||
{
|
|
||||||
OnUserTimeExpired(bases[i].CallUser);
|
|
||||||
bases[i] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ShortPrint() =>
|
public string ShortPrint() =>
|
||||||
$"`{EnemyClan}` ({Size} v {Size})";
|
$"`{EnemyClan}` ({Size} v {Size})";
|
||||||
|
|
||||||
@ -145,22 +131,22 @@ namespace NadekoBot.Classes.ClashOfClans
|
|||||||
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
|
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
|
||||||
if (!Started)
|
if (!Started)
|
||||||
sb.AppendLine("`not started`");
|
sb.AppendLine("`not started`");
|
||||||
for (var i = 0; i < bases.Length; i++)
|
for (var i = 0; i < Bases.Length; i++)
|
||||||
{
|
{
|
||||||
if (bases[i] == null)
|
if (Bases[i] == null)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
|
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (bases[i].BaseDestroyed)
|
if (Bases[i].BaseDestroyed)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {new string('⭐', bases[i].Stars)}");
|
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var left = Started ? callExpire - (DateTime.Now - bases[i].TimeAdded) : callExpire;
|
var left = Started ? callExpire - (DateTime.Now - Bases[i].TimeAdded) : callExpire;
|
||||||
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
|
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,11 +157,11 @@ namespace NadekoBot.Classes.ClashOfClans
|
|||||||
internal int FinishClaim(string user, int stars = 3)
|
internal int FinishClaim(string user, int stars = 3)
|
||||||
{
|
{
|
||||||
user = user.Trim();
|
user = user.Trim();
|
||||||
for (var i = 0; i < bases.Length; i++)
|
for (var i = 0; i < Bases.Length; i++)
|
||||||
{
|
{
|
||||||
if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue;
|
if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue;
|
||||||
bases[i].BaseDestroyed = true;
|
Bases[i].BaseDestroyed = true;
|
||||||
bases[i].Stars = stars;
|
Bases[i].Stars = stars;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
|
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
|
||||||
|
@ -7,7 +7,9 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Modules.Permissions.Classes;
|
using NadekoBot.Modules.Permissions.Classes;
|
||||||
using System.Threading;
|
using System.Linq;
|
||||||
|
using System.IO;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.ClashOfClans
|
namespace NadekoBot.Modules.ClashOfClans
|
||||||
{
|
{
|
||||||
@ -15,8 +17,124 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
{
|
{
|
||||||
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
|
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
|
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
|
||||||
|
|
||||||
|
private readonly object writeLock = new object();
|
||||||
|
|
||||||
|
public ClashOfClansModule()
|
||||||
|
{
|
||||||
|
NadekoBot.OnReady += () => Task.Run(async () =>
|
||||||
|
{
|
||||||
|
if (File.Exists("data/clashofclans/wars.json"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var content = File.ReadAllText("data/clashofclans/wars.json");
|
||||||
|
|
||||||
|
var dict = JsonConvert.DeserializeObject<Dictionary<ulong, List<ClashWar>>>(content);
|
||||||
|
|
||||||
|
foreach (var cw in dict)
|
||||||
|
{
|
||||||
|
cw.Value.ForEach(war =>
|
||||||
|
{
|
||||||
|
war.Channel = NadekoBot.Client.GetServer(war.ServerId)?.GetChannel(war.ChannelId);
|
||||||
|
if (war.Channel == null)
|
||||||
|
{
|
||||||
|
cw.Value.Remove(war);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
//urgh
|
||||||
|
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(dict);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Could not load coc wars: " + e.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
//Can't this be disabled if the modules is disabled too :)
|
||||||
|
var callExpire = new TimeSpan(2, 0, 0);
|
||||||
|
var warExpire = new TimeSpan(23, 0, 0);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var hash = ClashWars.GetHashCode();
|
||||||
|
foreach (var cw in ClashWars)
|
||||||
|
{
|
||||||
|
foreach (var war in cw.Value)
|
||||||
|
{
|
||||||
|
await CheckWar(callExpire, war);
|
||||||
|
}
|
||||||
|
List<ClashWar> newVal = new List<ClashWar>();
|
||||||
|
foreach (var w in cw.Value)
|
||||||
|
{
|
||||||
|
if (!w.Ended && (DateTime.Now - w.StartedAt <= warExpire))
|
||||||
|
{
|
||||||
|
newVal.Add(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//var newVal = cw.Value.Where(w => !(w.Ended || DateTime.Now - w.StartedAt >= warExpire)).ToList();
|
||||||
|
foreach (var exWar in cw.Value.Except(newVal))
|
||||||
|
{
|
||||||
|
await exWar.Channel.SendMessage($"War against {exWar.EnemyClan} ({exWar.Size}v{exWar.Size})has ended.");
|
||||||
|
}
|
||||||
|
ClashWars.AddOrUpdate(cw.Key, newVal, (x, s) => newVal);
|
||||||
|
if (cw.Value.Count == 0)
|
||||||
|
{
|
||||||
|
List<ClashWar> obj;
|
||||||
|
ClashWars.TryRemove(cw.Key, out obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hash != ClashWars.GetHashCode()) //something changed
|
||||||
|
{
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
await Task.Delay(5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Save()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory("data/clashofclans");
|
||||||
|
File.WriteAllText("data/clashofclans/wars.json", JsonConvert.SerializeObject(ClashWars, Formatting.Indented));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
|
||||||
|
{
|
||||||
|
var Bases = war.Bases;
|
||||||
|
for (var i = 0; i < Bases.Length; i++)
|
||||||
|
{
|
||||||
|
if (Bases[i] == null) continue;
|
||||||
|
if (!Bases[i].BaseDestroyed && DateTime.Now - Bases[i].TimeAdded >= callExpire)
|
||||||
|
{
|
||||||
|
await war.Channel.SendMessage($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false);
|
||||||
|
Bases[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region commands
|
||||||
public override void Install(ModuleManager manager)
|
public override void Install(ModuleManager manager)
|
||||||
{
|
{
|
||||||
manager.CreateCommands("", cgb =>
|
manager.CreateCommands("", cgb =>
|
||||||
@ -33,13 +151,6 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
{
|
{
|
||||||
if (!e.User.ServerPermissions.ManageChannels)
|
if (!e.User.ServerPermissions.ManageChannels)
|
||||||
return;
|
return;
|
||||||
List<ClashWar> wars;
|
|
||||||
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
|
|
||||||
{
|
|
||||||
wars = new List<ClashWar>();
|
|
||||||
if (!ClashWars.TryAdd(e.Server.Id, wars))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var enemyClan = e.GetArg("enemy_clan");
|
var enemyClan = e.GetArg("enemy_clan");
|
||||||
if (string.IsNullOrWhiteSpace(enemyClan))
|
if (string.IsNullOrWhiteSpace(enemyClan))
|
||||||
{
|
{
|
||||||
@ -51,29 +162,21 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
|
await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var cw = new ClashWar(enemyClan, size, e);
|
List<ClashWar> wars;
|
||||||
|
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
|
||||||
|
{
|
||||||
|
wars = new List<ClashWar>();
|
||||||
|
if (!ClashWars.TryAdd(e.Server.Id, wars))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var cw = new ClashWar(enemyClan, size, e.Server.Id, e.Channel.Id);
|
||||||
//cw.Start();
|
//cw.Start();
|
||||||
|
|
||||||
wars.Add(cw);
|
wars.Add(cw);
|
||||||
cw.OnUserTimeExpired += async (u) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await
|
|
||||||
e.Channel.SendMessage(
|
|
||||||
$"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**")
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
};
|
|
||||||
cw.OnWarEnded += async () =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
};
|
|
||||||
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
|
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
|
||||||
|
Save();
|
||||||
//war with the index X started.
|
//war with the index X started.
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -92,13 +195,12 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
var war = warsInfo.Item1[warsInfo.Item2];
|
var war = warsInfo.Item1[warsInfo.Item2];
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var startTask = war.Start();
|
war.Start();
|
||||||
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
|
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
|
||||||
await startTask.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**").ConfigureAwait(false);
|
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -205,7 +307,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
cgb.CreateCommand(Prefix + "unclaim")
|
cgb.CreateCommand(Prefix + "unclaim")
|
||||||
.Alias(Prefix + "uncall")
|
.Alias(Prefix + "uncall")
|
||||||
.Alias(Prefix + "uc")
|
.Alias(Prefix + "uc")
|
||||||
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | {Prefix}uc [war_number] [optional_other_name]")
|
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | {Prefix}uc [war_number] [optional_other_name]")
|
||||||
.Parameter("number", ParameterType.Required)
|
.Parameter("number", ParameterType.Required)
|
||||||
.Parameter("other_name", ParameterType.Unparsed)
|
.Parameter("other_name", ParameterType.Unparsed)
|
||||||
.Do(async e =>
|
.Do(async e =>
|
||||||
@ -245,12 +347,16 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
warsInfo.Item1[warsInfo.Item2].End();
|
warsInfo.Item1[warsInfo.Item2].End();
|
||||||
|
await e.Channel.SendMessage($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false);
|
||||||
|
|
||||||
var size = warsInfo.Item1[warsInfo.Item2].Size;
|
var size = warsInfo.Item1[warsInfo.Item2].Size;
|
||||||
warsInfo.Item1.RemoveAt(warsInfo.Item2);
|
warsInfo.Item1.RemoveAt(warsInfo.Item2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
private async Task FinishClaim(CommandEventArgs e, int stars = 3)
|
private async Task FinishClaim(CommandEventArgs e, int stars = 3)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user