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.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
//using Manatee.Json.Serialization;
|
||||
|
||||
namespace NadekoBot.Classes.ClashOfClans
|
||||
{
|
||||
@ -11,13 +14,14 @@ namespace NadekoBot.Classes.ClashOfClans
|
||||
{
|
||||
One, Two, Three
|
||||
}
|
||||
[System.Serializable]
|
||||
internal class Caller
|
||||
{
|
||||
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;
|
||||
|
||||
@ -47,94 +51,76 @@ namespace NadekoBot.Classes.ClashOfClans
|
||||
public string EnemyClan { get; }
|
||||
public int Size { get; }
|
||||
|
||||
private Caller[] bases { get; }
|
||||
private CancellationTokenSource[] baseCancelTokens;
|
||||
private CancellationTokenSource endTokenSource { get; } = new CancellationTokenSource();
|
||||
public event Action<string> OnUserTimeExpired = delegate { };
|
||||
public event Action OnWarEnded = delegate { };
|
||||
public Caller[] Bases { get; }
|
||||
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.Size = size;
|
||||
this.bases = new Caller[size];
|
||||
this.baseCancelTokens = new CancellationTokenSource[size];
|
||||
this.Bases = new Caller[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()
|
||||
{
|
||||
if (endTokenSource.Token.IsCancellationRequested) return;
|
||||
endTokenSource.Cancel();
|
||||
OnWarEnded();
|
||||
Ended = true;
|
||||
}
|
||||
|
||||
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");
|
||||
if (bases[baseNumber] != null)
|
||||
if (Bases[baseNumber] != null)
|
||||
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)
|
||||
throw new ArgumentException($"@{u} You already claimed a base #{i + 1}. You can't claim a new one.");
|
||||
if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u)
|
||||
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)
|
||||
throw new InvalidOperationException();
|
||||
try
|
||||
Started = true;
|
||||
StartedAt = DateTime.Now;
|
||||
foreach (var b in Bases.Where(b => b != null))
|
||||
{
|
||||
Started = true;
|
||||
foreach (var b in bases.Where(b => b != null))
|
||||
{
|
||||
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();
|
||||
b.ResetTime();
|
||||
}
|
||||
}
|
||||
|
||||
internal int Uncall(string user)
|
||||
{
|
||||
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;
|
||||
bases[i] = null;
|
||||
if (Bases[i]?.CallUser != user) continue;
|
||||
Bases[i] = null;
|
||||
return i;
|
||||
}
|
||||
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() =>
|
||||
$"`{EnemyClan}` ({Size} v {Size})";
|
||||
|
||||
@ -145,22 +131,22 @@ namespace NadekoBot.Classes.ClashOfClans
|
||||
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
|
||||
if (!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*");
|
||||
}
|
||||
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
|
||||
{
|
||||
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");
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,11 +157,11 @@ namespace NadekoBot.Classes.ClashOfClans
|
||||
internal int FinishClaim(string user, int stars = 3)
|
||||
{
|
||||
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;
|
||||
bases[i].BaseDestroyed = true;
|
||||
bases[i].Stars = stars;
|
||||
if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue;
|
||||
Bases[i].BaseDestroyed = true;
|
||||
Bases[i].Stars = stars;
|
||||
return i;
|
||||
}
|
||||
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.Threading.Tasks;
|
||||
using NadekoBot.Modules.Permissions.Classes;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NadekoBot.Modules.ClashOfClans
|
||||
{
|
||||
@ -15,65 +17,166 @@ namespace NadekoBot.Modules.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)
|
||||
{
|
||||
manager.CreateCommands("", cgb =>
|
||||
{
|
||||
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
cgb.AddCheck(PermissionChecker.Instance);
|
||||
|
||||
cgb.CreateCommand(Prefix + "createwar")
|
||||
.Alias(Prefix + "cw")
|
||||
.Description($"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. |{Prefix}cw 15 The Enemy Clan")
|
||||
.Parameter("size")
|
||||
.Parameter("enemy_clan", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageChannels)
|
||||
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");
|
||||
if (string.IsNullOrWhiteSpace(enemyClan))
|
||||
{
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
if (!int.TryParse(e.GetArg("size"), out size) || size < 10 || size > 50 || size % 5 != 0)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var cw = new ClashWar(enemyClan, size, e);
|
||||
cgb.CreateCommand(Prefix + "createwar")
|
||||
.Alias(Prefix + "cw")
|
||||
.Description($"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. |{Prefix}cw 15 The Enemy Clan")
|
||||
.Parameter("size")
|
||||
.Parameter("enemy_clan", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
{
|
||||
if (!e.User.ServerPermissions.ManageChannels)
|
||||
return;
|
||||
var enemyClan = e.GetArg("enemy_clan");
|
||||
if (string.IsNullOrWhiteSpace(enemyClan))
|
||||
{
|
||||
return;
|
||||
}
|
||||
int size;
|
||||
if (!int.TryParse(e.GetArg("size"), out size) || size < 10 || size > 50 || size % 5 != 0)
|
||||
{
|
||||
await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
|
||||
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 cw = new ClashWar(enemyClan, size, e.Server.Id, e.Channel.Id);
|
||||
//cw.Start();
|
||||
|
||||
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.
|
||||
});
|
||||
|
||||
@ -92,13 +195,12 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
var war = warsInfo.Item1[warsInfo.Item2];
|
||||
try
|
||||
{
|
||||
var startTask = war.Start();
|
||||
war.Start();
|
||||
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
|
||||
await startTask.ConfigureAwait(false);
|
||||
}
|
||||
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")
|
||||
.Alias(Prefix + "uncall")
|
||||
.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("other_name", ParameterType.Unparsed)
|
||||
.Do(async e =>
|
||||
@ -245,12 +347,16 @@ namespace NadekoBot.Modules.ClashOfClans
|
||||
return;
|
||||
}
|
||||
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;
|
||||
warsInfo.Item1.RemoveAt(warsInfo.Item2);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
private async Task FinishClaim(CommandEventArgs e, int stars = 3)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user