Readded CoC saving, hopefuly works

This commit is contained in:
Kwoth 2016-08-25 19:23:47 +02:00
parent d1e6501b62
commit 26f79063c9
20 changed files with 466 additions and 200 deletions

View File

@ -8,14 +8,58 @@ using NadekoBot.Services.Database.Impl;
namespace NadekoBot.Migrations namespace NadekoBot.Migrations
{ {
[DbContext(typeof(NadekoSqliteContext))] [DbContext(typeof(NadekoSqliteContext))]
[Migration("20160825131849_FirstMigration")] [Migration("20160825172257_first")]
partial class FirstMigration partial class first
{ {
protected override void BuildTargetModel(ModelBuilder modelBuilder) protected override void BuildTargetModel(ModelBuilder modelBuilder)
{ {
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431"); .HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -98,6 +142,14 @@ namespace NadekoBot.Migrations
b.ToTable("Quotes"); b.ToTable("Quotes");
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
} }
} }
} }

View File

@ -4,10 +4,28 @@ using Microsoft.EntityFrameworkCore.Migrations;
namespace NadekoBot.Migrations namespace NadekoBot.Migrations
{ {
public partial class FirstMigration : Migration public partial class first : Migration
{ {
protected override void Up(MigrationBuilder migrationBuilder) protected override void Up(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.CreateTable(
name: "ClashOfClans",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
ChannelId = table.Column<ulong>(nullable: false),
EnemyClan = table.Column<string>(nullable: true),
GuildId = table.Column<ulong>(nullable: false),
Size = table.Column<int>(nullable: false),
StartedAt = table.Column<DateTime>(nullable: false),
WarState = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClashOfClans", x => x.Id);
});
migrationBuilder.CreateTable( migrationBuilder.CreateTable(
name: "Donators", name: "Donators",
columns: table => new columns: table => new
@ -66,6 +84,34 @@ namespace NadekoBot.Migrations
table.PrimaryKey("PK_Quotes", x => x.Id); table.PrimaryKey("PK_Quotes", x => x.Id);
}); });
migrationBuilder.CreateTable(
name: "ClashCallers",
columns: table => new
{
Id = table.Column<int>(nullable: false)
.Annotation("Autoincrement", true),
BaseDestroyed = table.Column<bool>(nullable: false),
CallUser = table.Column<string>(nullable: true),
ClashWarId = table.Column<int>(nullable: false),
Stars = table.Column<int>(nullable: false),
TimeAdded = table.Column<DateTime>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ClashCallers", x => x.Id);
table.ForeignKey(
name: "FK_ClashCallers_ClashOfClans_ClashWarId",
column: x => x.ClashWarId,
principalTable: "ClashOfClans",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ClashCallers_ClashWarId",
table: "ClashCallers",
column: "ClashWarId");
migrationBuilder.CreateIndex( migrationBuilder.CreateIndex(
name: "IX_Donators_UserId", name: "IX_Donators_UserId",
table: "Donators", table: "Donators",
@ -81,6 +127,9 @@ namespace NadekoBot.Migrations
protected override void Down(MigrationBuilder migrationBuilder) protected override void Down(MigrationBuilder migrationBuilder)
{ {
migrationBuilder.DropTable(
name: "ClashCallers");
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Donators"); name: "Donators");
@ -89,6 +138,9 @@ namespace NadekoBot.Migrations
migrationBuilder.DropTable( migrationBuilder.DropTable(
name: "Quotes"); name: "Quotes");
migrationBuilder.DropTable(
name: "ClashOfClans");
} }
} }
} }

View File

@ -15,6 +15,50 @@ namespace NadekoBot.Migrations
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "1.0.0-rtm-21431"); .HasAnnotation("ProductVersion", "1.0.0-rtm-21431");
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<bool>("BaseDestroyed");
b.Property<string>("CallUser");
b.Property<int>("ClashWarId");
b.Property<int>("Stars");
b.Property<DateTime>("TimeAdded");
b.HasKey("Id");
b.HasIndex("ClashWarId");
b.ToTable("ClashCallers");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashWar", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<ulong>("ChannelId");
b.Property<string>("EnemyClan");
b.Property<ulong>("GuildId");
b.Property<int>("Size");
b.Property<DateTime>("StartedAt");
b.Property<int>("WarState");
b.HasKey("Id");
b.ToTable("ClashOfClans");
});
modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b => modelBuilder.Entity("NadekoBot.Services.Database.Models.Donator", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -97,6 +141,14 @@ namespace NadekoBot.Migrations
b.ToTable("Quotes"); b.ToTable("Quotes");
}); });
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
{
b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar")
.WithMany("Bases")
.HasForeignKey("ClashWarId")
.OnDelete(DeleteBehavior.Cascade);
});
} }
} }
} }

View File

@ -2,7 +2,6 @@ using Discord;
using Discord.Commands; using Discord.Commands;
using Discord.WebSocket; using Discord.WebSocket;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Classes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;

View File

@ -1,7 +1,6 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Classes;
using NadekoBot.Services; using NadekoBot.Services;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using NLog; using NLog;

View File

@ -1,5 +1,4 @@
using Discord.Commands; using Discord.Commands;
using NadekoBot.Classes.ClashOfClans;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -9,23 +8,43 @@ using Discord;
using NadekoBot.Services; using NadekoBot.Services;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using Discord.WebSocket; using Discord.WebSocket;
using NadekoBot.Services.Database.Models;
using System.Linq;
using NadekoBot.Services.Database;
//todo DB //todo DB
namespace NadekoBot.Modules.ClashOfClans namespace NadekoBot.Modules.ClashOfClans
{ {
[Module(",",AppendSpace = false)] [Module(",", AppendSpace = false)]
public class ClashOfClans : DiscordModule public class ClashOfClans : DiscordModule
{ {
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>(); public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
public ClashOfClans(ILocalization loc, CommandService cmds, IBotConfiguration config, DiscordSocketClient client) : base(loc, cmds, config, client) public ClashOfClans(ILocalization loc, CommandService cmds, IBotConfiguration config, DiscordSocketClient client) : base(loc, cmds, config, client)
{ {
using (var uow = DbHandler.UnitOfWork())
{
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(
uow.ClashOfClans
.GetAll()
.Select(cw => {
cw.Channel = NadekoBot.Client.GetGuilds()
.FirstOrDefault(s => s.Id == cw.GuildId)?
.GetChannels()
.FirstOrDefault(c => c.Id == cw.ChannelId)
as ITextChannel;
cw.Bases.Capacity = cw.Size;
return cw;
})
.GroupBy(cw => cw.GuildId)
.ToDictionary(g => g.Key, g => g.ToList()));
}
} }
private static async Task CheckWar(TimeSpan callExpire, ClashWar war) private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
{ {
var Bases = war.Bases; var Bases = war.Bases;
for (var i = 0; i < Bases.Length; i++) for (var i = 0; i < Bases.Capacity; i++)
{ {
if (Bases[i] == null) continue; if (Bases[i] == null) continue;
if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire) if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire)
@ -62,7 +81,7 @@ namespace NadekoBot.Modules.ClashOfClans
} }
var cw = new ClashWar(enemyClan, size, channel.Guild.Id, imsg.Channel.Id); var cw = await CreateWar(enemyClan, size, channel.Guild.Id, imsg.Channel.Id);
//cw.Start(); //cw.Start();
wars.Add(cw); wars.Add(cw);
@ -94,6 +113,7 @@ namespace NadekoBot.Modules.ClashOfClans
{ {
await channel.SendMessageAsync($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false); await channel.SendMessageAsync($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false);
} }
SaveWar(war);
} }
[LocalizedCommand, LocalizedDescription, LocalizedSummary] [LocalizedCommand, LocalizedDescription, LocalizedSummary]
@ -136,7 +156,7 @@ namespace NadekoBot.Modules.ClashOfClans
await channel.SendMessageAsync("💢🔰 **That war does not exist.**").ConfigureAwait(false); await channel.SendMessageAsync("💢🔰 **That war does not exist.**").ConfigureAwait(false);
return; return;
} }
await channel.SendMessageAsync(warsInfo.Item1[warsInfo.Item2].ToString()).ConfigureAwait(false); await channel.SendMessageAsync(warsInfo.Item1[warsInfo.Item2].ToPrettyString()).ConfigureAwait(false);
} }
[LocalizedCommand, LocalizedDescription, LocalizedSummary] [LocalizedCommand, LocalizedDescription, LocalizedSummary]
@ -158,6 +178,7 @@ namespace NadekoBot.Modules.ClashOfClans
{ {
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
war.Call(usr, baseNumber - 1); war.Call(usr, baseNumber - 1);
SaveWar(war);
await channel.SendMessageAsync($"🔰**{usr}** claimed a base #{baseNumber} for a war against {war.ShortPrint()}").ConfigureAwait(false); await channel.SendMessageAsync($"🔰**{usr}** claimed a base #{baseNumber} for a war against {war.ShortPrint()}").ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
@ -202,7 +223,9 @@ namespace NadekoBot.Modules.ClashOfClans
await channel.SendMessageAsync("💢🔰 That war does not exist.").ConfigureAwait(false); await channel.SendMessageAsync("💢🔰 That war does not exist.").ConfigureAwait(false);
return; return;
} }
warsInfo.Item1[warsInfo.Item2].End(); var war = warsInfo.Item1[warsInfo.Item2];
war.End();
SaveWar(war);
await channel.SendMessageAsync($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false); await channel.SendMessageAsync($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false);
var size = warsInfo.Item1[warsInfo.Item2].Size; var size = warsInfo.Item1[warsInfo.Item2].Size;
@ -229,6 +252,7 @@ namespace NadekoBot.Modules.ClashOfClans
{ {
var war = warsInfo.Item1[warsInfo.Item2]; var war = warsInfo.Item1[warsInfo.Item2];
var baseNumber = war.Uncall(usr); var baseNumber = war.Uncall(usr);
SaveWar(war);
await channel.SendMessageAsync($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false); await channel.SendMessageAsync($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
@ -255,6 +279,7 @@ namespace NadekoBot.Modules.ClashOfClans
try try
{ {
var baseNum = war.FinishClaim(usr, stars); var baseNum = war.FinishClaim(usr, stars);
SaveWar(war);
await channel.SendMessageAsync($"❗🔰{imsg.Author.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false); await channel.SendMessageAsync($"❗🔰{imsg.Author.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
} }
catch (Exception ex) catch (Exception ex)
@ -282,5 +307,48 @@ namespace NadekoBot.Modules.ClashOfClans
//get the actual war //get the actual war
return new Tuple<List<ClashWar>, int>(wars, num); return new Tuple<List<ClashWar>, int>(wars, num);
} }
public static async Task<ClashWar> CreateWar(string enemyClan, int size, ulong serverId, ulong channelId)
{
using (var uow = DbHandler.UnitOfWork())
{
var cw = new ClashWar
{
EnemyClan = enemyClan,
Size = size,
Bases = new List<ClashCaller>(size),
GuildId = serverId,
ChannelId = channelId,
Channel = NadekoBot.Client.GetGuilds()
.FirstOrDefault(s => s.Id == serverId)?
.GetChannels()
.FirstOrDefault(c => c.Id == channelId)
as ITextChannel
};
uow.ClashOfClans.Add(cw);
await uow.CompleteAsync();
return cw;
}
}
public static void SaveWar(ClashWar cw)
{
if (cw.WarState == ClashWar.StateOfWar.Ended)
{
using (var uow = DbHandler.UnitOfWork())
{
uow.ClashOfClans.Remove(cw);
uow.CompleteAsync();
}
return;
}
using (var uow = DbHandler.UnitOfWork())
{
uow.ClashOfClans.Update(cw);
uow.CompleteAsync();
}
}
} }
} }

View File

@ -1,183 +0,0 @@
using Discord;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Text;
namespace NadekoBot.Classes.ClashOfClans
{
public class ClashWar
{
public enum DestroyStars
{
One, Two, Three
}
public enum StateOfWar
{
Started, Ended, Created
}
public class Caller
{
public string CallUser { get; set; }
public DateTime TimeAdded { get; set; }
public bool BaseDestroyed { get; set; }
public int Stars { get; set; } = 3;
public Caller() { }
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed)
{
CallUser = callUser;
TimeAdded = timeAdded;
BaseDestroyed = baseDestroyed;
}
public void ResetTime()
{
TimeAdded = DateTime.UtcNow;
}
public void Destroy()
{
BaseDestroyed = true;
}
}
private static TimeSpan callExpire => new TimeSpan(2, 0, 0);
public string EnemyClan { get; set; }
public int Size { get; set; }
public Caller[] Bases { get; set; }
public StateOfWar WarState { get; set; } = StateOfWar.Created;
//public bool Started { get; set; } = false;
public DateTime StartedAt { get; set; }
//public bool Ended { get; private set; } = false;
public ulong ServerId { get; set; }
public ulong ChannelId { get; set; }
[JsonIgnore]
public ITextChannel 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.ServerId = serverId;
this.ChannelId = channelId;
this.Channel = NadekoBot.Client.GetGuildsAsync() //nice api you got here volt,
.GetAwaiter() //especially like how getguildsasync isn't async at all internally.
.GetResult() //But hey, lib has to be async kek
.FirstOrDefault(s => s.Id == serverId)? // srsly
.GetChannelsAsync() //wtf is this
.GetAwaiter() // oh i know, its the implementation detail
.GetResult() // and makes library look consistent
.FirstOrDefault(c => c.Id == channelId) // its not common sense to make library work like this.
as ITextChannel; // oh and don't forget to cast it to this arbitrary bullshit
}
public void End()
{
//Ended = true;
WarState = StateOfWar.Ended;
}
public void Call(string u, int baseNumber)
{
if (baseNumber < 0 || baseNumber >= Bases.Length)
throw new ArgumentException("Invalid base number");
if (Bases[baseNumber] != null)
throw new ArgumentException("That base is already claimed.");
for (var i = 0; i < Bases.Length; i++)
{
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.UtcNow, false);
}
public void Start()
{
if (WarState == StateOfWar.Started)
throw new InvalidOperationException("War already started");
//if (Started)
// throw new InvalidOperationException();
//Started = true;
WarState = StateOfWar.Started;
StartedAt = DateTime.UtcNow;
foreach (var b in Bases.Where(b => b != null))
{
b.ResetTime();
}
}
public int Uncall(string user)
{
user = user.Trim();
for (var i = 0; i < Bases.Length; i++)
{
if (Bases[i]?.CallUser != user) continue;
Bases[i] = null;
return i;
}
throw new InvalidOperationException("You are not participating in that war.");
}
public string ShortPrint() =>
$"`{EnemyClan}` ({Size} v {Size})";
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
if (WarState == StateOfWar.Created)
sb.AppendLine("`not started`");
for (var i = 0; i < Bases.Length; i++)
{
if (Bases[i] == null)
{
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
}
else
{
if (Bases[i].BaseDestroyed)
{
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}");
}
else
{
var left = (WarState == StateOfWar.Started) ? callExpire - (DateTime.UtcNow - Bases[i].TimeAdded) : callExpire;
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
}
}
}
return sb.ToString();
}
public int FinishClaim(string user, int stars = 3)
{
user = user.Trim();
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;
return i;
}
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
}
}
}

View File

@ -0,0 +1,124 @@
using Discord;
using Discord.WebSocket;
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static NadekoBot.Services.Database.Models.ClashWar;
namespace NadekoBot.Modules.ClashOfClans
{
public static class Extensions
{
public static void ResetTime(this ClashCaller c)
{
c.TimeAdded = DateTime.UtcNow;
}
public static void Destroy(this ClashCaller c)
{
c.BaseDestroyed = true;
}
public static void End(this ClashWar cw)
{
//Ended = true;
cw.WarState = StateOfWar.Ended;
}
public static void Call(this ClashWar cw, string u, int baseNumber)
{
if (baseNumber < 0 || baseNumber >= cw.Bases.Capacity)
throw new ArgumentException("Invalid base number");
if (cw.Bases[baseNumber] != null)
throw new ArgumentException("That base is already claimed.");
for (var i = 0; i < cw.Bases.Capacity; i++)
{
if (cw.Bases[i]?.BaseDestroyed == false && cw.Bases[i]?.CallUser == u)
throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
}
cw.Bases[baseNumber] = new ClashCaller() {
CallUser = u.Trim(),
TimeAdded = DateTime.UtcNow,
BaseDestroyed = false
};
}
public static void Start(this ClashWar cw)
{
if (cw.WarState == StateOfWar.Started)
throw new InvalidOperationException("War already started");
//if (Started)
// throw new InvalidOperationException();
//Started = true;
cw.WarState = StateOfWar.Started;
cw.StartedAt = DateTime.UtcNow;
foreach (var b in cw.Bases.Where(b => b != null))
{
b.ResetTime();
}
}
public static int Uncall(this ClashWar cw, string user)
{
user = user.Trim();
for (var i = 0; i < cw.Bases.Capacity; i++)
{
if (cw.Bases[i]?.CallUser != user) continue;
cw.Bases[i] = null;
return i;
}
throw new InvalidOperationException("You are not participating in that war.");
}
public static string ShortPrint(this ClashWar cw) =>
$"`{cw.EnemyClan}` ({cw.Size} v {cw.Size})";
public static string ToPrettyString(this ClashWar cw)
{
var sb = new StringBuilder();
sb.AppendLine($"🔰**WAR AGAINST `{cw.EnemyClan}` ({cw.Size} v {cw.Size}) INFO:**");
if (cw.WarState == StateOfWar.Created)
sb.AppendLine("`not started`");
var twoHours = new TimeSpan(2, 0, 0);
for (var i = 0; i < cw.Bases.Capacity; i++)
{
if (cw.Bases[i] == null)
{
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
}
else
{
if (cw.Bases[i].BaseDestroyed)
{
sb.AppendLine($"`{i + 1}.` ✅ `{cw.Bases[i].CallUser}` {new string('⭐', cw.Bases[i].Stars)}");
}
else
{
var left = (cw.WarState == StateOfWar.Started) ? twoHours - (DateTime.UtcNow - cw.Bases[i].TimeAdded) : twoHours;
sb.AppendLine($"`{i + 1}.` ✅ `{cw.Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
}
}
}
return sb.ToString();
}
public static int FinishClaim(this ClashWar cw, string user, int stars = 3)
{
user = user.Trim();
for (var i = 0; i < cw.Bases.Capacity; i++)
{
if (cw.Bases[i]?.BaseDestroyed != false || cw.Bases[i]?.CallUser != user) continue;
cw.Bases[i].BaseDestroyed = true;
cw.Bases[i].Stars = stars;
return i;
}
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
}
}
}

View File

@ -1,7 +1,6 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Classes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;

View File

@ -1,7 +1,6 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Classes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,5 +1,4 @@
using Discord.Audio; using Discord.Audio;
using NadekoBot.Classes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using System; using System;
using System.Diagnostics; using System.Diagnostics;

View File

@ -1,5 +1,4 @@
using NadekoBot.Classes; using Newtonsoft.Json;
using Newtonsoft.Json;
using System; using System;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;

View File

@ -1,7 +1,6 @@
using Discord; using Discord;
using Discord.Commands; using Discord.Commands;
using NadekoBot.Attributes; using NadekoBot.Attributes;
using NadekoBot.Classes;
using NadekoBot.Extensions; using NadekoBot.Extensions;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NLog; using NLog;

View File

@ -12,6 +12,8 @@ namespace NadekoBot.Services.Database
IQuoteRepository Quotes { get; } IQuoteRepository Quotes { get; }
IConfigRepository GuildConfigs { get; } IConfigRepository GuildConfigs { get; }
IDonatorsRepository Donators { get; } IDonatorsRepository Donators { get; }
IClashOfClansRepository ClashOfClans { get; }
int Complete(); int Complete();
Task<int> CompleteAsync(); Task<int> CompleteAsync();
} }

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Services.Database.Models
{
public class ClashCaller : DbEntity
{
public string CallUser { get; set; }
public DateTime TimeAdded { get; set; }
public bool BaseDestroyed { get; set; }
public int Stars { get; set; } = 3;
public int ClashWarId { get; set; }
[ForeignKey(nameof(ClashWarId))]
public ClashWar ClashWar { get; set; }
}
}

View File

@ -0,0 +1,36 @@
using Discord;
using Discord.WebSocket;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Services.Database.Models
{
public class ClashWar : DbEntity
{
public enum DestroyStars
{
One, Two, Three
}
public enum StateOfWar
{
Started, Ended, Created
}
public string EnemyClan { get; set; }
public int Size { get; set; }
public StateOfWar WarState { get; set; } = StateOfWar.Created;
public DateTime StartedAt { get; set; }
public ulong GuildId { get; set; }
public ulong ChannelId { get; set; }
[NotMapped]
public ITextChannel Channel { get; internal set; }
public List<ClashCaller> Bases { get; set; }
}
}

View File

@ -13,6 +13,8 @@ namespace NadekoBot.Services.Database
public DbSet<Quote> Quotes { get; set; } public DbSet<Quote> Quotes { get; set; }
public DbSet<Donator> Donators { get; set; } public DbSet<Donator> Donators { get; set; }
public DbSet<GuildConfig> GuildConfigs { get; set; } public DbSet<GuildConfig> GuildConfigs { get; set; }
public DbSet<ClashWar> ClashOfClans { get; set; }
public DbSet<ClashCaller> ClashCallers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
@ -40,6 +42,15 @@ namespace NadekoBot.Services.Database
.IsUnique(); .IsUnique();
#endregion #endregion
#region ClashOfClans
var callersEntity = modelBuilder.Entity<ClashCaller>();
callersEntity
.HasOne(c => c.ClashWar)
.WithMany(c => c.Bases);
#endregion
} }
protected abstract override void OnConfiguring(DbContextOptionsBuilder optionsBuilder); protected abstract override void OnConfiguring(DbContextOptionsBuilder optionsBuilder);
} }

View File

@ -0,0 +1,14 @@
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NadekoBot.Services.Database.Repositories
{
public interface IClashOfClansRepository : IRepository<ClashWar>
{
}
}

View File

@ -0,0 +1,17 @@
using NadekoBot.Services.Database.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
namespace NadekoBot.Services.Database.Repositories.Impl
{
public class ClashOfClansRepository : Repository<ClashWar>, IClashOfClansRepository
{
public ClashOfClansRepository(DbContext context) : base(context)
{
}
}
}

View File

@ -21,6 +21,9 @@ namespace NadekoBot.Services.Database
private IDonatorsRepository _donators; private IDonatorsRepository _donators;
public IDonatorsRepository Donators => _donators ?? (_donators = new DonatorsRepository(_context)); public IDonatorsRepository Donators => _donators ?? (_donators = new DonatorsRepository(_context));
private IClashOfClansRepository _clashOfClans;
public IClashOfClansRepository ClashOfClans => _clashOfClans ?? (_clashOfClans = new ClashOfClansRepository(_context));
public UnitOfWork(NadekoContext context) public UnitOfWork(NadekoContext context)
{ {
_context = context; _context = context;