Compare commits
2 commits
da0eff4339
...
11b3705939
Author | SHA1 | Date | |
---|---|---|---|
11b3705939 | |||
5e95abadc8 |
29 changed files with 1049 additions and 645 deletions
src/EllieBot
Db
Extensions
Models/xp
Migrations
PostgreSql
20250225212147_xp-excl-xp-rate.sql20250226215159_xp-rate-rework.sql20250226215222_init.Designer.cs20250226215222_init.csPostgreSqlContextModelSnapshot.cs
Sqlite
Modules/Xp
Services/GrpcApi
_common
strings
|
@ -121,7 +121,6 @@ public static class GuildConfigExtensions
|
|||
.InsertWithOutputAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ServerExcluded = false,
|
||||
});
|
||||
|
||||
return srs;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#nullable disable
|
||||
namespace EllieBot.Db.Models;
|
||||
|
||||
public class UserXpStats : DbEntity
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
#nullable disable
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace EllieBot.Db.Models;
|
||||
|
||||
public class XpSettings : DbEntity
|
||||
{
|
||||
public ulong GuildId { get; set; }
|
||||
public bool ServerExcluded { get; set; }
|
||||
public HashSet<ExcludedItem> ExclusionList { get; set; } = new();
|
||||
|
||||
public HashSet<XpRoleReward> RoleRewards { get; set; } = new();
|
||||
public HashSet<XpCurrencyReward> CurrencyRewards { get; set; } = new();
|
||||
|
|
|
@ -15,8 +15,5 @@ public class XpSettingsEntityConfiguration : IEntityTypeConfiguration<XpSettings
|
|||
|
||||
builder.HasMany(x => x.RoleRewards)
|
||||
.WithOne();
|
||||
|
||||
builder.HasMany(x => x.ExclusionList)
|
||||
.WithOne();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
START TRANSACTION;
|
||||
ALTER TABLE userfishstats ADD bait integer;
|
||||
|
||||
ALTER TABLE userfishstats ADD pole integer;
|
||||
|
||||
CREATE TABLE channelxpconfig (
|
||||
id integer GENERATED BY DEFAULT AS IDENTITY,
|
||||
guildid numeric(20,0) NOT NULL,
|
||||
channelid numeric(20,0) NOT NULL,
|
||||
xpamount integer NOT NULL,
|
||||
cooldown real NOT NULL,
|
||||
CONSTRAINT pk_channelxpconfig PRIMARY KEY (id),
|
||||
CONSTRAINT ak_channelxpconfig_guildid_channelid UNIQUE (guildid, channelid)
|
||||
);
|
||||
|
||||
CREATE TABLE guildxpconfig (
|
||||
guildid numeric(20,0) NOT NULL,
|
||||
xpamount integer NOT NULL,
|
||||
cooldown integer NOT NULL,
|
||||
xptemplateurl text,
|
||||
CONSTRAINT pk_guildxpconfig PRIMARY KEY (guildid)
|
||||
);
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" (migrationid, productversion)
|
||||
VALUES ('20250225212147_xp-excl-xp-rate', '9.0.1');
|
||||
|
||||
COMMIT;
|
|
@ -0,0 +1,31 @@
|
|||
START TRANSACTION;
|
||||
DROP TABLE excludeditem;
|
||||
|
||||
ALTER TABLE guildxpconfig DROP CONSTRAINT pk_guildxpconfig;
|
||||
|
||||
ALTER TABLE channelxpconfig DROP CONSTRAINT ak_channelxpconfig_guildid_channelid;
|
||||
|
||||
ALTER TABLE xpsettings DROP COLUMN serverexcluded;
|
||||
|
||||
ALTER TABLE guildxpconfig ALTER COLUMN xpamount TYPE bigint;
|
||||
|
||||
ALTER TABLE guildxpconfig ALTER COLUMN cooldown TYPE real;
|
||||
|
||||
ALTER TABLE guildxpconfig ADD id integer GENERATED BY DEFAULT AS IDENTITY;
|
||||
|
||||
ALTER TABLE guildxpconfig ADD ratetype integer NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE channelxpconfig ALTER COLUMN xpamount TYPE bigint;
|
||||
|
||||
ALTER TABLE channelxpconfig ADD ratetype integer NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE guildxpconfig ADD CONSTRAINT ak_guildxpconfig_guildid_ratetype UNIQUE (guildid, ratetype);
|
||||
|
||||
ALTER TABLE guildxpconfig ADD CONSTRAINT pk_guildxpconfig PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE channelxpconfig ADD CONSTRAINT ak_channelxpconfig_guildid_channelid_ratetype UNIQUE (guildid, channelid, ratetype);
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" (migrationid, productversion)
|
||||
VALUES ('20250226215159_xp-rate-rework', '9.0.1');
|
||||
|
||||
COMMIT;
|
|
@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|||
namespace EllieBot.Migrations.PostgreSql
|
||||
{
|
||||
[DbContext(typeof(PostgreSqlContext))]
|
||||
[Migration("20250202124905_init")]
|
||||
[Migration("20250226215222_init")]
|
||||
partial class init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
@ -877,40 +877,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
b.ToTable("discorduser", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<decimal>("ItemId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("itemid");
|
||||
|
||||
b.Property<int>("ItemType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("itemtype");
|
||||
|
||||
b.Property<int?>("XpSettingsId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("xpsettingsid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_excludeditem");
|
||||
|
||||
b.HasIndex("XpSettingsId")
|
||||
.HasDatabaseName("ix_excludeditem_xpsettingsid");
|
||||
|
||||
b.ToTable("excludeditem", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -3359,10 +3325,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<bool>("ServerExcluded")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("serverexcluded");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_xpsettings");
|
||||
|
||||
|
@ -3456,6 +3418,14 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("Bait")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("bait");
|
||||
|
||||
b.Property<int?>("Pole")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("pole");
|
||||
|
||||
b.Property<int>("Skill")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("skill");
|
||||
|
@ -3474,6 +3444,82 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
b.ToTable("userfishstats", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.ChannelXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("ChannelId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("channelid");
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("real")
|
||||
.HasColumnName("cooldown");
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("ratetype");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("xpamount");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_channelxpconfig");
|
||||
|
||||
b.HasAlternateKey("GuildId", "ChannelId", "RateType")
|
||||
.HasName("ak_channelxpconfig_guildid_channelid_ratetype");
|
||||
|
||||
b.ToTable("channelxpconfig", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.GuildXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("real")
|
||||
.HasColumnName("cooldown");
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("ratetype");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("xpamount");
|
||||
|
||||
b.Property<string>("XpTemplateUrl")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("xptemplateurl");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_guildxpconfig");
|
||||
|
||||
b.HasAlternateKey("GuildId", "RateType")
|
||||
.HasName("ak_guildxpconfig_guildid_ratetype");
|
||||
|
||||
b.ToTable("guildxpconfig", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Services.GreetSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -3677,14 +3723,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
b.Navigation("Club");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.XpSettings", null)
|
||||
.WithMany("ExclusionList")
|
||||
.HasForeignKey("XpSettingsId")
|
||||
.HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.GuildFilterConfig", null)
|
||||
|
@ -3971,11 +4009,9 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
{
|
||||
b.Navigation("CurrencyRewards");
|
||||
|
||||
b.Navigation("ExclusionList");
|
||||
|
||||
b.Navigation("RoleRewards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -187,6 +187,24 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
table.UniqueConstraint("ak_buttonrole_roleid_messageid", x => new { x.roleid, x.messageid });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "channelxpconfig",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
ratetype = table.Column<int>(type: "integer", nullable: false),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
channelid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
xpamount = table.Column<long>(type: "bigint", nullable: false),
|
||||
cooldown = table.Column<float>(type: "real", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_channelxpconfig", x => x.id);
|
||||
table.UniqueConstraint("ak_channelxpconfig_guildid_channelid_ratetype", x => new { x.guildid, x.channelid, x.ratetype });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "commandalias",
|
||||
columns: table => new
|
||||
|
@ -487,6 +505,24 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
table.PrimaryKey("pk_guildfilterconfig", x => x.id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "guildxpconfig",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
ratetype = table.Column<int>(type: "integer", nullable: false),
|
||||
xpamount = table.Column<long>(type: "bigint", nullable: false),
|
||||
cooldown = table.Column<float>(type: "real", nullable: false),
|
||||
xptemplateurl = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_guildxpconfig", x => x.id);
|
||||
table.UniqueConstraint("ak_guildxpconfig_guildid_ratetype", x => new { x.guildid, x.ratetype });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "honeypotchannels",
|
||||
columns: table => new
|
||||
|
@ -1033,7 +1069,9 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
userid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
skill = table.Column<int>(type: "integer", nullable: false)
|
||||
skill = table.Column<int>(type: "integer", nullable: false),
|
||||
pole = table.Column<int>(type: "integer", nullable: true),
|
||||
bait = table.Column<int>(type: "integer", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
|
@ -1118,7 +1156,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
guildid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
serverexcluded = table.Column<bool>(type: "boolean", nullable: false),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
|
@ -1473,27 +1510,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "excludeditem",
|
||||
columns: table => new
|
||||
{
|
||||
id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
xpsettingsid = table.Column<int>(type: "integer", nullable: true),
|
||||
itemid = table.Column<decimal>(type: "numeric(20,0)", nullable: false),
|
||||
itemtype = table.Column<int>(type: "integer", nullable: false),
|
||||
dateadded = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("pk_excludeditem", x => x.id);
|
||||
table.ForeignKey(
|
||||
name: "fk_excludeditem_xpsettings_xpsettingsid",
|
||||
column: x => x.xpsettingsid,
|
||||
principalTable: "xpsettings",
|
||||
principalColumn: "id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "xpcurrencyreward",
|
||||
columns: table => new
|
||||
|
@ -1827,11 +1843,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
table: "discorduser",
|
||||
column: "username");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_excludeditem_xpsettingsid",
|
||||
table: "excludeditem",
|
||||
column: "xpsettingsid");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "ix_feedsub_guildid_url",
|
||||
table: "feedsub",
|
||||
|
@ -2310,6 +2321,9 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
migrationBuilder.DropTable(
|
||||
name: "buttonrole");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "channelxpconfig");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "clubapplicants");
|
||||
|
||||
|
@ -2331,9 +2345,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
migrationBuilder.DropTable(
|
||||
name: "discordpermoverrides");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "excludeditem");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "expressions");
|
||||
|
||||
|
@ -2376,6 +2387,9 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
migrationBuilder.DropTable(
|
||||
name: "guildcolors");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "guildxpconfig");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "honeypotchannels");
|
||||
|
||||
|
@ -2551,4 +2565,4 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
name: "discorduser");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -874,40 +874,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
b.ToTable("discorduser", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("timestamp without time zone")
|
||||
.HasColumnName("dateadded");
|
||||
|
||||
b.Property<decimal>("ItemId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("itemid");
|
||||
|
||||
b.Property<int>("ItemType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("itemtype");
|
||||
|
||||
b.Property<int?>("XpSettingsId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("xpsettingsid");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_excludeditem");
|
||||
|
||||
b.HasIndex("XpSettingsId")
|
||||
.HasDatabaseName("ix_excludeditem_xpsettingsid");
|
||||
|
||||
b.ToTable("excludeditem", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -3356,10 +3322,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<bool>("ServerExcluded")
|
||||
.HasColumnType("boolean")
|
||||
.HasColumnName("serverexcluded");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_xpsettings");
|
||||
|
||||
|
@ -3453,6 +3415,14 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("Bait")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("bait");
|
||||
|
||||
b.Property<int?>("Pole")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("pole");
|
||||
|
||||
b.Property<int>("Skill")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("skill");
|
||||
|
@ -3471,6 +3441,82 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
b.ToTable("userfishstats", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.ChannelXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("ChannelId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("channelid");
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("real")
|
||||
.HasColumnName("cooldown");
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("ratetype");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("xpamount");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_channelxpconfig");
|
||||
|
||||
b.HasAlternateKey("GuildId", "ChannelId", "RateType")
|
||||
.HasName("ak_channelxpconfig_guildid_channelid_ratetype");
|
||||
|
||||
b.ToTable("channelxpconfig", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.GuildXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("real")
|
||||
.HasColumnName("cooldown");
|
||||
|
||||
b.Property<decimal>("GuildId")
|
||||
.HasColumnType("numeric(20,0)")
|
||||
.HasColumnName("guildid");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("ratetype");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("bigint")
|
||||
.HasColumnName("xpamount");
|
||||
|
||||
b.Property<string>("XpTemplateUrl")
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("xptemplateurl");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("pk_guildxpconfig");
|
||||
|
||||
b.HasAlternateKey("GuildId", "RateType")
|
||||
.HasName("ak_guildxpconfig_guildid_ratetype");
|
||||
|
||||
b.ToTable("guildxpconfig", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Services.GreetSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -3674,14 +3720,6 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
b.Navigation("Club");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.XpSettings", null)
|
||||
.WithMany("ExclusionList")
|
||||
.HasForeignKey("XpSettingsId")
|
||||
.HasConstraintName("fk_excludeditem_xpsettings_xpsettingsid");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.GuildFilterConfig", null)
|
||||
|
@ -3968,11 +4006,9 @@ namespace EllieBot.Migrations.PostgreSql
|
|||
{
|
||||
b.Navigation("CurrencyRewards");
|
||||
|
||||
b.Navigation("ExclusionList");
|
||||
|
||||
b.Navigation("RoleRewards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
BEGIN TRANSACTION;
|
||||
ALTER TABLE "UserFishStats" ADD "Bait" INTEGER NULL;
|
||||
|
||||
ALTER TABLE "UserFishStats" ADD "Pole" INTEGER NULL;
|
||||
|
||||
CREATE TABLE "ChannelXpConfig" (
|
||||
"Id" INTEGER NOT NULL CONSTRAINT "PK_ChannelXpConfig" PRIMARY KEY AUTOINCREMENT,
|
||||
"GuildId" INTEGER NOT NULL,
|
||||
"ChannelId" INTEGER NOT NULL,
|
||||
"XpAmount" INTEGER NOT NULL,
|
||||
"Cooldown" REAL NOT NULL,
|
||||
CONSTRAINT "AK_ChannelXpConfig_GuildId_ChannelId" UNIQUE ("GuildId", "ChannelId")
|
||||
);
|
||||
|
||||
CREATE TABLE "GuildXpConfig" (
|
||||
"GuildId" INTEGER NOT NULL CONSTRAINT "PK_GuildXpConfig" PRIMARY KEY AUTOINCREMENT,
|
||||
"XpAmount" INTEGER NOT NULL,
|
||||
"Cooldown" INTEGER NOT NULL,
|
||||
"XpTemplateUrl" TEXT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20250225212144_xp-excl-xp-rate', '9.0.1');
|
||||
|
||||
COMMIT;
|
|
@ -0,0 +1,75 @@
|
|||
BEGIN TRANSACTION;
|
||||
DROP TABLE "ExcludedItem";
|
||||
|
||||
ALTER TABLE "GuildXpConfig" ADD "Id" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE "GuildXpConfig" ADD "RateType" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE "ChannelXpConfig" ADD "RateType" INTEGER NOT NULL DEFAULT 0;
|
||||
|
||||
CREATE TABLE "ef_temp_GuildXpConfig" (
|
||||
"Id" INTEGER NOT NULL CONSTRAINT "PK_GuildXpConfig" PRIMARY KEY AUTOINCREMENT,
|
||||
"Cooldown" REAL NOT NULL,
|
||||
"GuildId" INTEGER NOT NULL,
|
||||
"RateType" INTEGER NOT NULL,
|
||||
"XpAmount" INTEGER NOT NULL,
|
||||
"XpTemplateUrl" TEXT NULL,
|
||||
CONSTRAINT "AK_GuildXpConfig_GuildId_RateType" UNIQUE ("GuildId", "RateType")
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_GuildXpConfig" ("Id", "Cooldown", "GuildId", "RateType", "XpAmount", "XpTemplateUrl")
|
||||
SELECT "Id", "Cooldown", "GuildId", "RateType", "XpAmount", "XpTemplateUrl"
|
||||
FROM "GuildXpConfig";
|
||||
|
||||
CREATE TABLE "ef_temp_ChannelXpConfig" (
|
||||
"Id" INTEGER NOT NULL CONSTRAINT "PK_ChannelXpConfig" PRIMARY KEY AUTOINCREMENT,
|
||||
"ChannelId" INTEGER NOT NULL,
|
||||
"Cooldown" REAL NOT NULL,
|
||||
"GuildId" INTEGER NOT NULL,
|
||||
"RateType" INTEGER NOT NULL,
|
||||
"XpAmount" INTEGER NOT NULL,
|
||||
CONSTRAINT "AK_ChannelXpConfig_GuildId_ChannelId_RateType" UNIQUE ("GuildId", "ChannelId", "RateType")
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_ChannelXpConfig" ("Id", "ChannelId", "Cooldown", "GuildId", "RateType", "XpAmount")
|
||||
SELECT "Id", "ChannelId", "Cooldown", "GuildId", "RateType", "XpAmount"
|
||||
FROM "ChannelXpConfig";
|
||||
|
||||
CREATE TABLE "ef_temp_XpSettings" (
|
||||
"Id" INTEGER NOT NULL CONSTRAINT "PK_XpSettings" PRIMARY KEY AUTOINCREMENT,
|
||||
"DateAdded" TEXT NULL,
|
||||
"GuildId" INTEGER NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO "ef_temp_XpSettings" ("Id", "DateAdded", "GuildId")
|
||||
SELECT "Id", "DateAdded", "GuildId"
|
||||
FROM "XpSettings";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 0;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
DROP TABLE "GuildXpConfig";
|
||||
|
||||
ALTER TABLE "ef_temp_GuildXpConfig" RENAME TO "GuildXpConfig";
|
||||
|
||||
DROP TABLE "ChannelXpConfig";
|
||||
|
||||
ALTER TABLE "ef_temp_ChannelXpConfig" RENAME TO "ChannelXpConfig";
|
||||
|
||||
DROP TABLE "XpSettings";
|
||||
|
||||
ALTER TABLE "ef_temp_XpSettings" RENAME TO "XpSettings";
|
||||
|
||||
COMMIT;
|
||||
|
||||
PRAGMA foreign_keys = 1;
|
||||
|
||||
BEGIN TRANSACTION;
|
||||
CREATE UNIQUE INDEX "IX_XpSettings_GuildId" ON "XpSettings" ("GuildId");
|
||||
|
||||
COMMIT;
|
||||
|
||||
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
|
||||
VALUES ('20250226215156_xp-rate-rework', '9.0.1');
|
|
@ -11,7 +11,7 @@ using EllieBot.Db;
|
|||
namespace EllieBot.Migrations.Sqlite
|
||||
{
|
||||
[DbContext(typeof(SqliteContext))]
|
||||
[Migration("20250202124903_init")]
|
||||
[Migration("20250226215220_init")]
|
||||
partial class init
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
@ -657,31 +657,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.ToTable("DiscordUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ItemType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("XpSettingsId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("XpSettingsId");
|
||||
|
||||
b.ToTable("ExcludedItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -2499,9 +2474,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ServerExcluded")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
|
@ -2571,6 +2543,12 @@ namespace EllieBot.Migrations.Sqlite
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Bait")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Pole")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Skill")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -2585,6 +2563,62 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.ToTable("UserFishStats");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.ChannelXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("ChannelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("GuildId", "ChannelId", "RateType");
|
||||
|
||||
b.ToTable("ChannelXpConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.GuildXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("XpTemplateUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("GuildId", "RateType");
|
||||
|
||||
b.ToTable("GuildXpConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Services.GreetSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -2752,13 +2786,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.Navigation("Club");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.XpSettings", null)
|
||||
.WithMany("ExclusionList")
|
||||
.HasForeignKey("XpSettingsId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.GuildFilterConfig", null)
|
||||
|
@ -3023,11 +3050,9 @@ namespace EllieBot.Migrations.Sqlite
|
|||
{
|
||||
b.Navigation("CurrencyRewards");
|
||||
|
||||
b.Navigation("ExclusionList");
|
||||
|
||||
b.Navigation("RoleRewards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -186,6 +186,24 @@ namespace EllieBot.Migrations.Sqlite
|
|||
table.UniqueConstraint("AK_ButtonRole_RoleId_MessageId", x => new { x.RoleId, x.MessageId });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ChannelXpConfig",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
RateType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ChannelId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
XpAmount = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
Cooldown = table.Column<float>(type: "REAL", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ChannelXpConfig", x => x.Id);
|
||||
table.UniqueConstraint("AK_ChannelXpConfig_GuildId_ChannelId_RateType", x => new { x.GuildId, x.ChannelId, x.RateType });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "CommandAlias",
|
||||
columns: table => new
|
||||
|
@ -486,6 +504,24 @@ namespace EllieBot.Migrations.Sqlite
|
|||
table.PrimaryKey("PK_GuildFilterConfig", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "GuildXpConfig",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
RateType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
XpAmount = table.Column<long>(type: "INTEGER", nullable: false),
|
||||
Cooldown = table.Column<float>(type: "REAL", nullable: false),
|
||||
XpTemplateUrl = table.Column<string>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_GuildXpConfig", x => x.Id);
|
||||
table.UniqueConstraint("AK_GuildXpConfig_GuildId_RateType", x => new { x.GuildId, x.RateType });
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "HoneyPotChannels",
|
||||
columns: table => new
|
||||
|
@ -1035,7 +1071,9 @@ namespace EllieBot.Migrations.Sqlite
|
|||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
UserId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
Skill = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
Skill = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
Pole = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
Bait = table.Column<int>(type: "INTEGER", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
|
@ -1120,7 +1158,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
GuildId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ServerExcluded = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
|
@ -1475,27 +1512,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ExcludedItem",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
XpSettingsId = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
ItemId = table.Column<ulong>(type: "INTEGER", nullable: false),
|
||||
ItemType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
DateAdded = table.Column<DateTime>(type: "TEXT", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ExcludedItem", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_ExcludedItem_XpSettings_XpSettingsId",
|
||||
column: x => x.XpSettingsId,
|
||||
principalTable: "XpSettings",
|
||||
principalColumn: "Id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "XpCurrencyReward",
|
||||
columns: table => new
|
||||
|
@ -1829,11 +1845,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
table: "DiscordUser",
|
||||
column: "Username");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ExcludedItem_XpSettingsId",
|
||||
table: "ExcludedItem",
|
||||
column: "XpSettingsId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_FeedSub_GuildId_Url",
|
||||
table: "FeedSub",
|
||||
|
@ -2312,6 +2323,9 @@ namespace EllieBot.Migrations.Sqlite
|
|||
migrationBuilder.DropTable(
|
||||
name: "ButtonRole");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ChannelXpConfig");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ClubApplicants");
|
||||
|
||||
|
@ -2333,9 +2347,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
migrationBuilder.DropTable(
|
||||
name: "DiscordPermOverrides");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "ExcludedItem");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Expressions");
|
||||
|
||||
|
@ -2378,6 +2389,9 @@ namespace EllieBot.Migrations.Sqlite
|
|||
migrationBuilder.DropTable(
|
||||
name: "GuildColors");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "GuildXpConfig");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "HoneyPotChannels");
|
||||
|
||||
|
@ -2553,4 +2567,4 @@ namespace EllieBot.Migrations.Sqlite
|
|||
name: "DiscordUser");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -654,31 +654,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.ToTable("DiscordUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("DateAdded")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<ulong>("ItemId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("ItemType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("XpSettingsId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("XpSettingsId");
|
||||
|
||||
b.ToTable("ExcludedItem");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FeedSub", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -2496,9 +2471,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("ServerExcluded")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
|
@ -2568,6 +2540,12 @@ namespace EllieBot.Migrations.Sqlite
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Bait")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("Pole")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("Skill")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
|
@ -2582,6 +2560,62 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.ToTable("UserFishStats");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.ChannelXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<ulong>("ChannelId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("GuildId", "ChannelId", "RateType");
|
||||
|
||||
b.ToTable("ChannelXpConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Modules.Xp.GuildXpConfig", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<float>("Cooldown")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RateType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<long>("XpAmount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("XpTemplateUrl")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasAlternateKey("GuildId", "RateType");
|
||||
|
||||
b.ToTable("GuildXpConfig");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Services.GreetSettings", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -2749,13 +2783,6 @@ namespace EllieBot.Migrations.Sqlite
|
|||
b.Navigation("Club");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.ExcludedItem", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.XpSettings", null)
|
||||
.WithMany("ExclusionList")
|
||||
.HasForeignKey("XpSettingsId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("EllieBot.Db.Models.FilterChannelId", b =>
|
||||
{
|
||||
b.HasOne("EllieBot.Db.Models.GuildFilterConfig", null)
|
||||
|
@ -3020,11 +3047,9 @@ namespace EllieBot.Migrations.Sqlite
|
|||
{
|
||||
b.Navigation("CurrencyRewards");
|
||||
|
||||
b.Navigation("ExclusionList");
|
||||
|
||||
b.Navigation("RoleRewards");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,4 +11,5 @@ public sealed class UserXpBatch
|
|||
public ulong GuildId { get; set; }
|
||||
public string Username { get; set; } = string.Empty;
|
||||
public string AvatarId { get; set; } = string.Empty;
|
||||
public long XpToGain { get; set; } = 0;
|
||||
}
|
|
@ -53,91 +53,6 @@ public partial class Xp : EllieModule<XpService>
|
|||
}
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task XpExclude(Server _)
|
||||
{
|
||||
var ex = await _service.ToggleExcludeServerAsync(ctx.Guild.Id);
|
||||
|
||||
if (ex)
|
||||
await Response().Confirm(strs.excluded(Format.Bold(ctx.Guild.ToString()))).SendAsync();
|
||||
else
|
||||
await Response().Confirm(strs.not_excluded(Format.Bold(ctx.Guild.ToString()))).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.ManageRoles)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpExclude(Role _, [Leftover] IRole role)
|
||||
{
|
||||
var ex = await _service.ToggleExcludeRoleAsync(ctx.Guild.Id, role.Id);
|
||||
|
||||
if (ex)
|
||||
await Response().Confirm(strs.excluded(Format.Bold(role.ToString()))).SendAsync();
|
||||
else
|
||||
await Response().Confirm(strs.not_excluded(Format.Bold(role.ToString()))).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[UserPerm(GuildPerm.ManageChannels)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpExclude(Channel _, [Leftover] IChannel? channel = null)
|
||||
{
|
||||
if (channel is null)
|
||||
channel = ctx.Channel;
|
||||
|
||||
var ex = await _service.ToggleExcludeChannelAsync(ctx.Guild.Id, channel.Id);
|
||||
|
||||
if (ex)
|
||||
await Response().Confirm(strs.excluded(Format.Bold(channel.ToString()))).SendAsync();
|
||||
else
|
||||
await Response().Confirm(strs.not_excluded(Format.Bold(channel.ToString()))).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpExclusionList()
|
||||
{
|
||||
var serverExcluded = _service.IsServerExcluded(ctx.Guild.Id);
|
||||
var roles = _service.GetExcludedRoles(ctx.Guild.Id)
|
||||
.Select(x => ctx.Guild.GetRole(x))
|
||||
.Where(x => x is not null)
|
||||
.Select(x => $"`role` {x.Mention}")
|
||||
.ToList();
|
||||
|
||||
var chans = (await _service.GetExcludedChannels(ctx.Guild.Id)
|
||||
.Select(x => ctx.Guild.GetChannelAsync(x))
|
||||
.WhenAll()).Where(x => x is not null)
|
||||
.Select(x => $"`channel` <#{x.Id}>")
|
||||
.ToList();
|
||||
|
||||
var rolesStr = roles.Any() ? string.Join("\n", roles) + "\n" : string.Empty;
|
||||
var chansStr = chans.Count > 0 ? string.Join("\n", chans) + "\n" : string.Empty;
|
||||
var desc = Format.Code(serverExcluded
|
||||
? GetText(strs.server_is_excluded)
|
||||
: GetText(strs.server_is_not_excluded));
|
||||
|
||||
desc += "\n\n" + rolesStr + chansStr;
|
||||
|
||||
var lines = desc.Split('\n');
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(lines)
|
||||
.PageSize(15)
|
||||
.CurrentPage(0)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var embed = CreateEmbed()
|
||||
.WithTitle(GetText(strs.exclusion_list))
|
||||
.WithDescription(string.Join('\n', items))
|
||||
.WithOkColor();
|
||||
|
||||
return embed;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[EllieOptions<LbOpts>]
|
||||
[Priority(0)]
|
||||
|
|
172
src/EllieBot/Modules/Xp/XpRate/GuildConfigXpService.cs
Normal file
172
src/EllieBot/Modules/Xp/XpRate/GuildConfigXpService.cs
Normal file
|
@ -0,0 +1,172 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
using LinqToDB;
|
||||
using LinqToDB.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using EllieBot.Common.ModuleBehaviors;
|
||||
using EllieBot.Modules.Xp.Services;
|
||||
|
||||
namespace EllieBot.Modules.Xp;
|
||||
|
||||
using GuildXpRates = (IReadOnlyList<GuildXpConfig> GuildRates, IReadOnlyList<ChannelXpConfig> ChannelRates);
|
||||
|
||||
public class GuildConfigXpService(DbService db, ShardData shardData, XpConfigService xcs) : IReadyExecutor, IEService
|
||||
{
|
||||
private ConcurrentDictionary<(XpRateType RateType, ulong GuildId), XpRate> _guildRates = new();
|
||||
private ConcurrentDictionary<ulong, ConcurrentDictionary<(XpRateType, ulong), XpRate>> _channelRates = new();
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
await using var uow = db.GetDbContext();
|
||||
_guildRates = await uow.GetTable<GuildXpConfig>()
|
||||
.AsNoTracking()
|
||||
.Where(x => Queries.GuildOnShard(x.GuildId, shardData.TotalShards, shardData.ShardId))
|
||||
.ToListAsyncLinqToDB()
|
||||
.Fmap(list =>
|
||||
list
|
||||
.ToDictionary(
|
||||
x => (x.RateType, x.GuildId),
|
||||
x => new XpRate(x.RateType, x.XpAmount, x.Cooldown))
|
||||
.ToConcurrent());
|
||||
|
||||
_channelRates = await uow.GetTable<ChannelXpConfig>()
|
||||
.AsNoTracking()
|
||||
.Where(x => Queries.GuildOnShard(x.GuildId, shardData.TotalShards, shardData.ShardId))
|
||||
.ToListAsyncLinqToDB()
|
||||
.Fmap(x =>
|
||||
x.GroupBy(x => x.GuildId)
|
||||
.ToDictionary(
|
||||
x => x.Key,
|
||||
x => x.ToDictionary(
|
||||
y => (y.RateType, y.ChannelId),
|
||||
y => new XpRate(y.RateType, y.XpAmount, y.Cooldown))
|
||||
.ToConcurrent())
|
||||
.ToConcurrent());
|
||||
}
|
||||
|
||||
public async Task<GuildXpRates> GetGuildXpRatesAsync(ulong guildId)
|
||||
{
|
||||
await using var uow = db.GetDbContext();
|
||||
var guildConfig = await uow.GetTable<GuildXpConfig>()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
var channelRates = await uow.GetTable<ChannelXpConfig>()
|
||||
.AsNoTracking()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
return (guildConfig, channelRates);
|
||||
}
|
||||
|
||||
public async Task SetGuildXpRateAsync(ulong guildId, XpRateType type, long amount, float cooldown)
|
||||
{
|
||||
AmountAndCooldownChecks(amount, cooldown);
|
||||
|
||||
if (type == XpRateType.Voice)
|
||||
cooldown = 1.0f;
|
||||
|
||||
await using var uow = db.GetDbContext();
|
||||
await uow.GetTable<GuildXpConfig>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
RateType = type,
|
||||
XpAmount = amount,
|
||||
Cooldown = cooldown,
|
||||
},
|
||||
(_) => new()
|
||||
{
|
||||
Cooldown = cooldown,
|
||||
XpAmount = amount,
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
RateType = type,
|
||||
});
|
||||
}
|
||||
|
||||
public async Task SetChannelXpRateAsync(ulong guildId,
|
||||
XpRateType type,
|
||||
ulong channelId,
|
||||
long amount,
|
||||
float cooldown)
|
||||
{
|
||||
AmountAndCooldownChecks(amount, cooldown);
|
||||
|
||||
if (type == XpRateType.Voice)
|
||||
cooldown = 1.0f;
|
||||
|
||||
await using var uow = db.GetDbContext();
|
||||
await uow.GetTable<ChannelXpConfig>()
|
||||
.InsertOrUpdateAsync(() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ChannelId = channelId,
|
||||
XpAmount = amount,
|
||||
Cooldown = cooldown,
|
||||
RateType = type
|
||||
},
|
||||
(_) => new()
|
||||
{
|
||||
Cooldown = cooldown,
|
||||
XpAmount = amount,
|
||||
},
|
||||
() => new()
|
||||
{
|
||||
GuildId = guildId,
|
||||
ChannelId = channelId,
|
||||
RateType = type,
|
||||
});
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void AmountAndCooldownChecks(long amount, float cooldown)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(amount, nameof(amount));
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThan(amount, 1000, nameof(amount));
|
||||
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(cooldown, nameof(cooldown));
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThan(cooldown, 1440, nameof(cooldown));
|
||||
}
|
||||
|
||||
public async Task<bool> ResetGuildXpRateAsync(ulong guildId)
|
||||
{
|
||||
await using var uow = db.GetDbContext();
|
||||
var deleted = await uow.GetTable<GuildXpConfig>()
|
||||
.Where(x => x.GuildId == guildId)
|
||||
.DeleteAsync();
|
||||
return deleted > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> ResetChannelXpRateAsync(ulong guildId, ulong channelId)
|
||||
{
|
||||
await using var uow = db.GetDbContext();
|
||||
var deleted = await uow.GetTable<ChannelXpConfig>()
|
||||
.Where(x => x.GuildId == guildId && x.ChannelId == channelId)
|
||||
.DeleteAsync();
|
||||
return deleted > 0;
|
||||
}
|
||||
|
||||
public XpRate GetXpRate(XpRateType type, ulong guildId, ulong channelId)
|
||||
{
|
||||
if (_channelRates.TryGetValue(guildId, out var guildChannelRates))
|
||||
{
|
||||
if (guildChannelRates.TryGetValue((type, channelId), out var rate))
|
||||
return rate;
|
||||
}
|
||||
|
||||
if (_guildRates.TryGetValue((type, guildId), out var guildRate))
|
||||
return guildRate;
|
||||
|
||||
var conf = xcs.Data;
|
||||
|
||||
return type switch
|
||||
{
|
||||
XpRateType.Image => new XpRate(XpRateType.Image, conf.TextXpFromImage, conf.TextXpCooldown / 60.0f),
|
||||
XpRateType.Voice => new XpRate(XpRateType.Voice, conf.VoiceXpPerMinute, 1.0f),
|
||||
_ => new XpRate(XpRateType.Text, conf.TextXpPerMessage, conf.TextXpCooldown / 60.0f),
|
||||
};
|
||||
}
|
||||
}
|
7
src/EllieBot/Modules/Xp/XpRate/XpRate.cs
Normal file
7
src/EllieBot/Modules/Xp/XpRate/XpRate.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace EllieBot.Modules.Xp;
|
||||
|
||||
public readonly record struct XpRate(XpRateType Type, long Amount, float Cooldown)
|
||||
{
|
||||
public bool IsExcluded()
|
||||
=> Amount == 0 || Cooldown == 0;
|
||||
}
|
116
src/EllieBot/Modules/Xp/XpRate/XpRateCommands.cs
Normal file
116
src/EllieBot/Modules/Xp/XpRate/XpRateCommands.cs
Normal file
|
@ -0,0 +1,116 @@
|
|||
namespace EllieBot.Modules.Xp;
|
||||
|
||||
public partial class Xp
|
||||
{
|
||||
[RequireUserPermission(GuildPermission.ManageGuild)]
|
||||
public class XpRateCommands : EllieModule<GuildConfigXpService>
|
||||
{
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpRate()
|
||||
{
|
||||
var rates = await _service.GetGuildXpRatesAsync(ctx.Guild.Id);
|
||||
if (!rates.GuildRates.Any() && !rates.ChannelRates.Any())
|
||||
{
|
||||
await Response().Pending(strs.xp_rate_none).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await Response()
|
||||
.Paginated()
|
||||
.Items(rates.ChannelRates.GroupBy(x => x.ChannelId).ToList())
|
||||
.PageSize(5)
|
||||
.Page((items, _) =>
|
||||
{
|
||||
var eb = CreateEmbed()
|
||||
.WithOkColor();
|
||||
|
||||
if (rates.GuildRates is not { Count: <= 0 })
|
||||
{
|
||||
eb.AddField(GetText(strs.xp_rate_server),
|
||||
rates.GuildRates
|
||||
.Select(x => GetText(strs.xp_rate_str(x.RateType, x.XpAmount, x.Cooldown)))
|
||||
.Join('\n'));
|
||||
}
|
||||
|
||||
if (items.Any())
|
||||
{
|
||||
var channelRates = items
|
||||
.Select(x => $"""
|
||||
<#{x.Key}>
|
||||
{x.Select(c => $"- {GetText(strs.xp_rate_str(c.RateType, c.XpAmount, c.Cooldown))}").Join('\n')}
|
||||
""")
|
||||
.Join('\n');
|
||||
|
||||
eb.AddField(GetText(strs.xp_rate_channels), channelRates);
|
||||
}
|
||||
|
||||
return eb;
|
||||
})
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpRate(XpRateType type, int amount, float minutes)
|
||||
{
|
||||
if (amount is < 0 or > 1000)
|
||||
{
|
||||
await Response().Error(strs.xp_rate_amount_invalid).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (minutes is < 0 or > 1440)
|
||||
{
|
||||
await Response().Error(strs.xp_rate_cooldown_invalid).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await _service.SetGuildXpRateAsync(ctx.Guild.Id, type, amount, (int)Math.Ceiling(minutes));
|
||||
await Response().Confirm(strs.xp_rate_server_set(amount, minutes)).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpRate(IMessageChannel channel, XpRateType type, int amount, float minutes)
|
||||
{
|
||||
if (amount is < 0 or > 1000)
|
||||
{
|
||||
await Response().Error(strs.xp_rate_amount_invalid).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
if (minutes is < 0 or > 1440)
|
||||
{
|
||||
await Response().Error(strs.xp_rate_cooldown_invalid).SendAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
await _service.SetChannelXpRateAsync(ctx.Guild.Id, type, channel.Id, amount, (int)Math.Ceiling(minutes));
|
||||
await Response()
|
||||
.Confirm(strs.xp_rate_channel_set(Format.Bold(channel.ToString()), amount, minutes))
|
||||
.SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpRateReset()
|
||||
{
|
||||
await _service.ResetGuildXpRateAsync(ctx.Guild.Id);
|
||||
await Response().Confirm(strs.xp_rate_server_reset).SendAsync();
|
||||
}
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpRateReset(IMessageChannel channel)
|
||||
=> await XpRateReset(channel.Id);
|
||||
|
||||
[Cmd]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task XpRateReset(ulong channelId)
|
||||
{
|
||||
await _service.ResetChannelXpRateAsync(ctx.Guild.Id, channelId);
|
||||
await Response().Confirm(strs.xp_rate_channel_reset($"<#{channelId}>")).SendAsync();
|
||||
}
|
||||
}
|
||||
}
|
8
src/EllieBot/Modules/Xp/XpRate/XpRateType.cs
Normal file
8
src/EllieBot/Modules/Xp/XpRate/XpRateType.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace EllieBot.Modules.Xp;
|
||||
|
||||
public enum XpRateType
|
||||
{
|
||||
Text,
|
||||
Voice,
|
||||
Image,
|
||||
}
|
30
src/EllieBot/Modules/Xp/XpRate/db/ChannelXpConfig.cs
Normal file
30
src/EllieBot/Modules/Xp/XpRate/db/ChannelXpConfig.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace EllieBot.Modules.Xp;
|
||||
|
||||
public class ChannelXpConfig
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public XpRateType RateType { get; set; }
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public long XpAmount { get; set; }
|
||||
public float Cooldown { get; set; }
|
||||
}
|
||||
|
||||
public sealed class ChannelXpConfigEntity : IEntityTypeConfiguration<ChannelXpConfig>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<ChannelXpConfig> builder)
|
||||
{
|
||||
builder.HasAlternateKey(x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.ChannelId,
|
||||
x.RateType,
|
||||
});
|
||||
}
|
||||
}
|
30
src/EllieBot/Modules/Xp/XpRate/db/GuildXpConfig.cs
Normal file
30
src/EllieBot/Modules/Xp/XpRate/db/GuildXpConfig.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace EllieBot.Modules.Xp;
|
||||
|
||||
public class GuildXpConfig
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
public ulong GuildId { get; set; }
|
||||
public XpRateType RateType { get; set; }
|
||||
|
||||
public long XpAmount { get; set; }
|
||||
public float Cooldown { get; set; }
|
||||
public string? XpTemplateUrl { get; set; }
|
||||
}
|
||||
|
||||
public sealed class GuildXpConfigEntity : IEntityTypeConfiguration<GuildXpConfig>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<GuildXpConfig> builder)
|
||||
{
|
||||
builder.HasAlternateKey(x => new
|
||||
{
|
||||
x.GuildId,
|
||||
x.RateType,
|
||||
});
|
||||
}
|
||||
}
|
|
@ -32,11 +32,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
private readonly ICurrencyService _cs;
|
||||
private readonly IHttpClientFactory _httpFactory;
|
||||
private readonly XpConfigService _xpConfig;
|
||||
private readonly IPubSub _pubSub;
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _excludedRoles = new();
|
||||
private readonly ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> _excludedChannels = new();
|
||||
private readonly ConcurrentHashSet<ulong> _excludedServers;
|
||||
|
||||
private readonly DiscordSocketClient _client;
|
||||
|
||||
|
@ -45,8 +40,8 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
|
||||
private readonly INotifySubscriber _notifySub;
|
||||
private readonly IMemoryCache _memCache;
|
||||
private readonly ShardData _shardData;
|
||||
private readonly XpTemplateService _templateService;
|
||||
private readonly GuildConfigXpService _xpRateService;
|
||||
|
||||
private readonly QueueRunner _levelUpQueue = new QueueRunner(0, 100);
|
||||
|
||||
|
@ -65,7 +60,8 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
INotifySubscriber notifySub,
|
||||
IMemoryCache memCache,
|
||||
ShardData shardData,
|
||||
XpTemplateService templateService)
|
||||
XpTemplateService templateService,
|
||||
GuildConfigXpService xpRateService)
|
||||
{
|
||||
_db = db;
|
||||
_images = images;
|
||||
|
@ -74,47 +70,17 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
_cs = cs;
|
||||
_httpFactory = http;
|
||||
_xpConfig = xpConfig;
|
||||
_pubSub = pubSub;
|
||||
_notifySub = notifySub;
|
||||
_memCache = memCache;
|
||||
_shardData = shardData;
|
||||
_templateService = templateService;
|
||||
_excludedServers = [];
|
||||
_excludedChannels = new();
|
||||
_xpRateService = xpRateService;
|
||||
_client = client;
|
||||
_ps = ps;
|
||||
_c = c;
|
||||
|
||||
if (client.ShardId == 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnReadyAsync()
|
||||
{
|
||||
// initialize ignored
|
||||
await using (var ctx = _db.GetDbContext())
|
||||
{
|
||||
var xps = await ctx.GetTable<XpSettings>()
|
||||
.Where(x => Queries.GuildOnShard(x.GuildId, _shardData.TotalShards, _shardData.ShardId))
|
||||
.LoadWith(x => x.ExclusionList)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
foreach (var xp in xps)
|
||||
{
|
||||
if (xp.ServerExcluded)
|
||||
_excludedServers.Add(xp.GuildId);
|
||||
|
||||
foreach (var item in xp.ExclusionList)
|
||||
{
|
||||
if (item.ItemType == ExcludedItemType.Channel)
|
||||
_excludedChannels.GetOrAdd(xp.GuildId, static _ => []).Add(item.ItemId);
|
||||
else if (item.ItemType == ExcludedItemType.Role)
|
||||
_excludedRoles.GetOrAdd(xp.GuildId, static _ => []).Add(item.ItemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Task.WhenAll(UpdateTimer(), VoiceUpdateTimer(), _levelUpQueue.RunAsync());
|
||||
|
||||
return;
|
||||
|
@ -156,65 +122,66 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
/// <summary>
|
||||
/// The current batch of users that will gain xp
|
||||
/// </summary>
|
||||
private readonly ConcurrentHashSet<IGuildUser> _usersBatch = [];
|
||||
private readonly ConcurrentHashSet<XpQueueEntry> _usersBatch = [];
|
||||
|
||||
/// <summary>
|
||||
/// The current batch of users that will gain voice xp
|
||||
/// </summary>
|
||||
private readonly ConcurrentHashSet<IGuildUser> _voiceXpBatch = [];
|
||||
private readonly HashSet<IGuildUser> _voiceXpBatch = [];
|
||||
|
||||
private async Task UpdateVoiceXp()
|
||||
{
|
||||
var xpAmount = _xpConfig.Data.VoiceXpPerMinute;
|
||||
|
||||
if (xpAmount <= 0)
|
||||
return;
|
||||
|
||||
var oldBatch = _voiceXpBatch.ToArray();
|
||||
var oldBatch = _voiceXpBatch.ToHashSet();
|
||||
_voiceXpBatch.Clear();
|
||||
var validUsers = new HashSet<IGuildUser>();
|
||||
var validUsers = new List<XpQueueEntry>(oldBatch.Count);
|
||||
|
||||
var guilds = _client.Guilds;
|
||||
|
||||
foreach (var g in guilds)
|
||||
{
|
||||
if (IsServerExcluded(g.Id))
|
||||
continue;
|
||||
|
||||
foreach (var vc in g.VoiceChannels)
|
||||
{
|
||||
if (!IsVoiceChannelActive(vc))
|
||||
continue;
|
||||
|
||||
if (IsChannelExcluded(vc))
|
||||
var rate = _xpRateService.GetXpRate(XpRateType.Voice, g.Id, vc.Id);
|
||||
|
||||
if (rate.IsExcluded())
|
||||
continue;
|
||||
|
||||
foreach (var u in vc.ConnectedUsers)
|
||||
{
|
||||
if (IsServerOrRoleExcluded(u) || !UserParticipatingInVoiceChannel(u))
|
||||
if (!UserParticipatingInVoiceChannel(u))
|
||||
continue;
|
||||
|
||||
if (oldBatch.Contains(u))
|
||||
validUsers.Add(u);
|
||||
{
|
||||
validUsers.Add(new(u, rate.Amount));
|
||||
}
|
||||
|
||||
_voiceXpBatch.Add(u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await UpdateXpInternalAsync(validUsers.DistinctBy(x => x.Id).ToArray(), xpAmount);
|
||||
await UpdateXpInternalAsync(validUsers.ToArray());
|
||||
}
|
||||
|
||||
private async Task UpdateXp()
|
||||
{
|
||||
var xpAmount = _xpConfig.Data.TextXpPerMessage;
|
||||
// might want to lock this, but it's not a big deal
|
||||
|
||||
// or do something like this
|
||||
// foreach (var item in currentBatch)
|
||||
// _usersBatch.TryRemove(item);
|
||||
|
||||
var currentBatch = _usersBatch.ToArray();
|
||||
_usersBatch.Clear();
|
||||
|
||||
await UpdateXpInternalAsync(currentBatch, xpAmount);
|
||||
await UpdateXpInternalAsync(currentBatch);
|
||||
}
|
||||
|
||||
private async Task UpdateXpInternalAsync(IGuildUser[] currentBatch, int xpAmount)
|
||||
private async Task UpdateXpInternalAsync(XpQueueEntry[] currentBatch)
|
||||
{
|
||||
if (currentBatch.Length == 0)
|
||||
return;
|
||||
|
@ -227,16 +194,17 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
|
||||
await batchTable.BulkCopyAsync(currentBatch.Select(x => new UserXpBatch()
|
||||
{
|
||||
GuildId = x.GuildId,
|
||||
UserId = x.Id,
|
||||
Username = x.Username,
|
||||
AvatarId = x.DisplayAvatarId
|
||||
GuildId = x.User.GuildId,
|
||||
UserId = x.User.Id,
|
||||
Username = x.User.Username,
|
||||
AvatarId = x.User.DisplayAvatarId,
|
||||
XpToGain = x.Xp
|
||||
}));
|
||||
|
||||
await lctx.ExecuteAsync(
|
||||
$"""
|
||||
INSERT INTO UserXpStats (GuildId, UserId, Xp)
|
||||
SELECT "{tempTableName}"."GuildId", "{tempTableName}"."UserId", {xpAmount}
|
||||
SELECT "{tempTableName}"."GuildId", "{tempTableName}"."UserId", "XpToGain"
|
||||
FROM {tempTableName}
|
||||
WHERE TRUE
|
||||
ON CONFLICT (GuildId, UserId) DO UPDATE
|
||||
|
@ -251,9 +219,13 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
(batch, stats) => stats)
|
||||
.ToListAsyncLinqToDB();
|
||||
|
||||
var userToXp = currentBatch.ToDictionary(x => x.User.Id, x => x.Xp);
|
||||
foreach (var u in updated)
|
||||
{
|
||||
var oldStats = new LevelStats(u.Xp - xpAmount);
|
||||
if (!userToXp.TryGetValue(u.UserId, out var xpGained))
|
||||
continue;
|
||||
|
||||
var oldStats = new LevelStats(u.Xp - xpGained);
|
||||
var newStats = new LevelStats(u.Xp);
|
||||
|
||||
Log.Information("User {User} xp updated from {OldLevel} to {NewLevel}",
|
||||
|
@ -531,8 +503,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
{
|
||||
if (UserParticipatingInVoiceChannel(user))
|
||||
{
|
||||
count++;
|
||||
if (count >= 2)
|
||||
if (++count >= 2)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -543,27 +514,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
private static bool UserParticipatingInVoiceChannel(SocketGuildUser user)
|
||||
=> !user.IsDeafened && !user.IsMuted && !user.IsSelfDeafened && !user.IsSelfMuted;
|
||||
|
||||
private bool IsServerOrRoleExcluded(SocketGuildUser user)
|
||||
{
|
||||
if (_excludedServers.Contains(user.Guild.Id))
|
||||
return true;
|
||||
|
||||
if (_excludedRoles.TryGetValue(user.Guild.Id, out var roles) && user.Roles.Any(x => roles.Contains(x.Id)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool IsChannelExcluded(IGuildChannel channel)
|
||||
{
|
||||
if (_excludedChannels.TryGetValue(channel.Guild.Id, out var chans)
|
||||
&& (chans.Contains(channel.Id)
|
||||
|| (channel is SocketThreadChannel tc && chans.Contains(tc.ParentChannel.Id))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Task ExecOnNoCommandAsync(IGuild guild, IUserMessage arg)
|
||||
{
|
||||
if (arg.Author is not SocketGuildUser user || user.IsBot)
|
||||
|
@ -574,27 +524,36 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
if (IsChannelExcluded(gc))
|
||||
var isImage = arg.Attachments.Any(a => a.Height >= 16 && a.Width >= 16);
|
||||
var isText = arg.Content.Contains(' ') || arg.Content.Length >= 5;
|
||||
|
||||
var textRate = _xpRateService.GetXpRate(XpRateType.Text, guild.Id, gc.Id);
|
||||
|
||||
XpRate rate;
|
||||
if (isImage)
|
||||
{
|
||||
var imageRate = _xpRateService.GetXpRate(XpRateType.Image, guild.Id, gc.Id);
|
||||
if (imageRate.IsExcluded())
|
||||
return;
|
||||
|
||||
rate = imageRate;
|
||||
}
|
||||
else if (isText)
|
||||
{
|
||||
if (textRate.IsExcluded())
|
||||
return;
|
||||
|
||||
rate = textRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await TryAddUserGainedXpAsync(user.Id, rate.Cooldown))
|
||||
return;
|
||||
|
||||
if (IsServerOrRoleExcluded(user))
|
||||
return;
|
||||
|
||||
var xpConf = _xpConfig.Data;
|
||||
var xp = 0;
|
||||
if (arg.Attachments.Any(a => a.Height >= 128 && a.Width >= 128))
|
||||
xp = xpConf.TextXpFromImage;
|
||||
|
||||
if (arg.Content.Contains(' ') || arg.Content.Length >= 5)
|
||||
xp = Math.Max(xp, xpConf.TextXpPerMessage);
|
||||
|
||||
if (xp <= 0)
|
||||
return;
|
||||
|
||||
if (!await TryAddUserGainedXpAsync(user.Id, xpConf.TextXpCooldown))
|
||||
return;
|
||||
|
||||
_usersBatch.Add(user);
|
||||
_usersBatch.Add(new(user, rate.Amount));
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
@ -621,28 +580,9 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public bool IsServerExcluded(ulong id)
|
||||
=> _excludedServers.Contains(id);
|
||||
|
||||
public IEnumerable<ulong> GetExcludedRoles(ulong id)
|
||||
private Task<bool> TryAddUserGainedXpAsync(ulong userId, float cdInMinutes)
|
||||
{
|
||||
if (_excludedRoles.TryGetValue(id, out var val))
|
||||
return val.ToArray();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public IEnumerable<ulong> GetExcludedChannels(ulong id)
|
||||
{
|
||||
if (_excludedChannels.TryGetValue(id, out var val))
|
||||
return val.ToArray();
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private Task<bool> TryAddUserGainedXpAsync(ulong userId, int cdInSeconds)
|
||||
{
|
||||
if (cdInSeconds <= 0)
|
||||
if (cdInMinutes <= float.Epsilon)
|
||||
return Task.FromResult(true);
|
||||
|
||||
if (_memCache.TryGetValue(userId, out _))
|
||||
|
@ -651,7 +591,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
using var entry = _memCache.CreateEntry(userId);
|
||||
entry.Value = true;
|
||||
|
||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(cdInSeconds);
|
||||
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cdInMinutes);
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
@ -674,81 +614,6 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
guildRank);
|
||||
}
|
||||
|
||||
public async Task<bool> ToggleExcludeServerAsync(ulong id)
|
||||
{
|
||||
await using var uow = _db.GetDbContext();
|
||||
var xpSetting = await uow.XpSettingsFor(id);
|
||||
if (_excludedServers.Add(id))
|
||||
{
|
||||
xpSetting.ServerExcluded = true;
|
||||
await uow.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
_excludedServers.TryRemove(id);
|
||||
xpSetting.ServerExcluded = false;
|
||||
await uow.SaveChangesAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> ToggleExcludeRoleAsync(ulong guildId, ulong rId)
|
||||
{
|
||||
var roles = _excludedRoles.GetOrAdd(guildId, _ => []);
|
||||
await using var uow = _db.GetDbContext();
|
||||
var xpSetting = await uow.XpSettingsFor(guildId, set => set.LoadWith(x => x.ExclusionList));
|
||||
var excludeObj = new ExcludedItem
|
||||
{
|
||||
ItemId = rId,
|
||||
ItemType = ExcludedItemType.Role
|
||||
};
|
||||
|
||||
if (roles.Add(rId))
|
||||
{
|
||||
if (xpSetting.ExclusionList.Add(excludeObj))
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
roles.TryRemove(rId);
|
||||
|
||||
var toDelete = xpSetting.ExclusionList.FirstOrDefault(x => x.Equals(excludeObj));
|
||||
if (toDelete is not null)
|
||||
{
|
||||
uow.Remove(toDelete);
|
||||
await uow.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> ToggleExcludeChannelAsync(ulong guildId, ulong chId)
|
||||
{
|
||||
var channels = _excludedChannels.GetOrAdd(guildId, _ => []);
|
||||
await using var uow = _db.GetDbContext();
|
||||
var xpSetting = await uow.XpSettingsFor(guildId, set => set.LoadWith(x => x.ExclusionList));
|
||||
var excludeObj = new ExcludedItem
|
||||
{
|
||||
ItemId = chId,
|
||||
ItemType = ExcludedItemType.Channel
|
||||
};
|
||||
|
||||
if (channels.Add(chId))
|
||||
{
|
||||
if (xpSetting.ExclusionList.Add(excludeObj))
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
channels.TryRemove(chId);
|
||||
|
||||
if (xpSetting.ExclusionList.Remove(excludeObj))
|
||||
await uow.SaveChangesAsync();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<(Stream Image, IImageFormat Format)> GenerateXpImageAsync(IGuildUser user)
|
||||
{
|
||||
var stats = await GetUserStatsAsync(user);
|
||||
|
@ -1224,8 +1089,7 @@ public class XpService : IEService, IReadyExecutor, IExecNoCommand
|
|||
if (item is null || item.Price < 0)
|
||||
return BuyResult.UnknownItem;
|
||||
|
||||
if (item.Price > 0 &&
|
||||
!await _cs.RemoveAsync(userId, item.Price, new("xpshop", "buy", $"Background {key}")))
|
||||
if (item.Price > 0 && !await _cs.RemoveAsync(userId, item.Price, new("xpshop", "buy", $"Background {key}")))
|
||||
return BuyResult.InsufficientFunds;
|
||||
|
||||
|
||||
|
@ -1438,4 +1302,13 @@ public sealed class XpTemplateService : IEService, IReadyExecutor
|
|||
|
||||
public XpTemplate GetTemplate()
|
||||
=> _template;
|
||||
}
|
||||
|
||||
public readonly record struct XpQueueEntry(IGuildUser User, long Xp)
|
||||
{
|
||||
public bool Equals(XpQueueEntry? other)
|
||||
=> other?.User == User;
|
||||
|
||||
public override int GetHashCode()
|
||||
=> User.GetHashCode();
|
||||
}
|
|
@ -35,9 +35,9 @@ public class XpSvc : GrpcXp.GrpcXpBase, IGrpcSvc, IEService
|
|||
if (guild is null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "Guild not found"));
|
||||
|
||||
var excludedChannels = _xp.GetExcludedChannels(request.GuildId);
|
||||
var excludedRoles = _xp.GetExcludedRoles(request.GuildId);
|
||||
var isServerExcluded = _xp.IsServerExcluded(request.GuildId);
|
||||
var excludedChannels = new List<ulong>();
|
||||
var excludedRoles = new List<ulong>();
|
||||
var isServerExcluded = false;
|
||||
|
||||
var reply = new GetXpSettingsReply();
|
||||
|
||||
|
@ -82,59 +82,6 @@ public class XpSvc : GrpcXp.GrpcXpBase, IGrpcSvc, IEService
|
|||
return reply;
|
||||
}
|
||||
|
||||
public override async Task<AddExclusionReply> AddExclusion(AddExclusionRequest request, ServerCallContext context)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
||||
var success = false;
|
||||
var guild = _client.GetGuild(request.GuildId);
|
||||
|
||||
if (guild is null)
|
||||
throw new RpcException(new Status(StatusCode.NotFound, "Guild not found"));
|
||||
|
||||
if (request.Type == "Role")
|
||||
{
|
||||
if (guild.GetRole(request.Id) is null)
|
||||
return new()
|
||||
{
|
||||
Success = false
|
||||
};
|
||||
|
||||
success = await _xp.ToggleExcludeRoleAsync(request.GuildId, request.Id);
|
||||
}
|
||||
else if (request.Type == "Channel")
|
||||
{
|
||||
if (guild.GetTextChannel(request.Id) is null)
|
||||
return new()
|
||||
{
|
||||
Success = false
|
||||
};
|
||||
|
||||
success = await _xp.ToggleExcludeChannelAsync(request.GuildId, request.Id);
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Success = success
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<DeleteExclusionReply> DeleteExclusion(
|
||||
DeleteExclusionRequest request,
|
||||
ServerCallContext context)
|
||||
{
|
||||
var success = false;
|
||||
if (request.Type == "Role")
|
||||
success = await _xp.ToggleExcludeRoleAsync(request.GuildId, request.Id);
|
||||
else
|
||||
success = await _xp.ToggleExcludeChannelAsync(request.GuildId, request.Id);
|
||||
|
||||
return new DeleteExclusionReply
|
||||
{
|
||||
Success = success
|
||||
};
|
||||
}
|
||||
|
||||
public override async Task<AddRewardReply> AddReward(AddRewardRequest request, ServerCallContext context)
|
||||
{
|
||||
await Task.Yield();
|
||||
|
@ -267,15 +214,4 @@ public class XpSvc : GrpcXp.GrpcXpBase, IGrpcSvc, IEService
|
|||
|
||||
return reply;
|
||||
}
|
||||
|
||||
public override async Task<SetServerExclusionReply> SetServerExclusion(
|
||||
SetServerExclusionRequest request,
|
||||
ServerCallContext context)
|
||||
{
|
||||
var newValue = await _xp.ToggleExcludeServerAsync(request.GuildId);
|
||||
return new()
|
||||
{
|
||||
Success = newValue
|
||||
};
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ public abstract class EllieInteractionBase
|
|||
message = msg;
|
||||
|
||||
Client.InteractionCreated += OnInteraction;
|
||||
await Task.WhenAny(Task.Delay(30_000), _interactionCompletedSource.Task);
|
||||
await Task.WhenAny(Task.Delay(600_000), _interactionCompletedSource.Task);
|
||||
Client.InteractionCreated -= OnInteraction;
|
||||
|
||||
if (_clearAfter)
|
||||
|
@ -130,7 +130,7 @@ public sealed class EllieModalSubmitHandler
|
|||
message = msg;
|
||||
|
||||
Client.ModalSubmitted += OnInteraction;
|
||||
await Task.WhenAny(Task.Delay(300_000), _interactionCompletedSource.Task);
|
||||
await Task.WhenAny(Task.Delay(600_000), _interactionCompletedSource.Task);
|
||||
Client.ModalSubmitted -= OnInteraction;
|
||||
|
||||
await msg.ModifyAsync(m => m.Components = new ComponentBuilder().Build());
|
||||
|
|
|
@ -159,7 +159,7 @@ public partial class ResponseBuilder
|
|||
|
||||
await Task.WhenAll(left.RunAsync(msg), extra?.RunAsync(msg) ?? Task.CompletedTask, right.RunAsync(msg));
|
||||
|
||||
await Task.Delay(30_000);
|
||||
await Task.Delay(600_000);
|
||||
|
||||
await msg.ModifyAsync(mp => mp.Components = new ComponentBuilder().Build());
|
||||
}
|
||||
|
|
|
@ -1091,12 +1091,6 @@ experience:
|
|||
xptemplatereload:
|
||||
- xptempreload
|
||||
- xptr
|
||||
xpexclusionlist:
|
||||
- xpexclusionlist
|
||||
- xpexl
|
||||
xpexclude:
|
||||
- xpexclude
|
||||
- xpex
|
||||
xpleveluprewards:
|
||||
- xplvluprewards
|
||||
- xprews
|
||||
|
@ -1581,4 +1575,8 @@ fishlist:
|
|||
fishspot:
|
||||
- fishspot
|
||||
- fisp
|
||||
- fish?
|
||||
- fish?
|
||||
xprate:
|
||||
- xprate
|
||||
xpratereset:
|
||||
- xpratereset
|
|
@ -3517,28 +3517,6 @@ xptemplatereload:
|
|||
- ''
|
||||
params:
|
||||
- { }
|
||||
xpexclusionlist:
|
||||
desc: Shows the roles and channels excluded from the XP system on this server, as well as whether the whole server is excluded.
|
||||
ex:
|
||||
- ''
|
||||
params:
|
||||
- { }
|
||||
xpexclude:
|
||||
desc: Exclude a channel, role or current server from the xp system.
|
||||
ex:
|
||||
- Role Excluded-Role
|
||||
- Server
|
||||
params:
|
||||
- _:
|
||||
desc: "The ID of the server to exclude from the XP system."
|
||||
- _:
|
||||
desc: "The role that should not receive XP rewards."
|
||||
role:
|
||||
desc: "The role that should not receive XP rewards."
|
||||
- _:
|
||||
desc: "The ID of the channel to exclude from XP tracking."
|
||||
channel:
|
||||
desc: "The ID of the channel to exclude from XP tracking."
|
||||
xpleveluprewards:
|
||||
desc: Shows currently set level up rewards.
|
||||
ex:
|
||||
|
@ -4953,4 +4931,40 @@ fishspot:
|
|||
ex:
|
||||
- ''
|
||||
params:
|
||||
- { }
|
||||
- { }
|
||||
xprate:
|
||||
desc: |-
|
||||
Sets the xp rate for the server or the specified channel.
|
||||
First specify the type, amount, and then the cooldown in minutes.
|
||||
Provide no parameters to see the current rates.
|
||||
Cooldown has no effect on voice xp, as any amount is gained per minute.
|
||||
ex:
|
||||
- ''
|
||||
- 'text 3 5'
|
||||
- '#channel voice 50 1'
|
||||
params:
|
||||
- { }
|
||||
- type:
|
||||
desc: "The type of rate to set. One of: text, voice or image."
|
||||
amount:
|
||||
desc: "The amount of xp to give per message."
|
||||
minutes:
|
||||
desc: "The cooldown in minutes. Allows decimal values."
|
||||
- channel:
|
||||
desc: "The channel to set the rate for."
|
||||
type:
|
||||
desc: "The type of rate to set. One of: text, voice or image."
|
||||
amount:
|
||||
desc: "The amount of xp to give per message."
|
||||
minutes:
|
||||
desc: "The cooldown in minutes. Allows decimal values."
|
||||
xpratereset:
|
||||
desc: |-
|
||||
Resets the xp rate for the server or the specified channel.
|
||||
ex:
|
||||
- ''
|
||||
- '#channel'
|
||||
params:
|
||||
- { }
|
||||
- channel:
|
||||
desc: "The channel to reset the rate for."
|
|
@ -836,11 +836,6 @@
|
|||
"xpn_notif_dm": "In a direct message channel.",
|
||||
"xpn_notif_disabled": "Nowhere.",
|
||||
"xprewsreset_confirm": "Are you sure you want to delete ALL xp level up rewards from this server? This action is irreversible.",
|
||||
"excluded": "{0} has been excluded from the XP system on this server.",
|
||||
"not_excluded": "{0} is no longer excluded from the XP system on this server.",
|
||||
"exclusion_list": "Exclusion List",
|
||||
"server_is_excluded": "This server is excluded.",
|
||||
"server_is_not_excluded": "This server is not excluded.",
|
||||
"level_up_channel": "Congratulations {0}, You've reached level {1}!",
|
||||
"level_up_dm": "Congratulations {0}, You've reached level {1} on {2} server!",
|
||||
"level_up_global": "Congratulations {0}, You've reached global level {1}!",
|
||||
|
@ -1172,5 +1167,16 @@
|
|||
"fish_weather_forecast": "Forecast",
|
||||
"fish_tod": "Time of Day",
|
||||
"fish_skill_up": "Fishing skill increased to **{0} / {1}**",
|
||||
"fish_list_title": "Fishing"
|
||||
"fish_list_title": "Fishing",
|
||||
"xp_rate_none": "No xp rate overrides on this server.",
|
||||
"xp_rate_amount_invalid": "Amount must be between 0 and 1000.",
|
||||
"xp_rate_cooldown_invalid": "Cooldown must be between 0 and 1440.",
|
||||
"xp_rate_server": "Server xp rates",
|
||||
"xp_rate_str": "`{0}:` {1} xp every {2} min.",
|
||||
"xp_rate_channels": "Channel xp rates",
|
||||
"xp_rate_server_set": "Server xp rate set to **{0}** xp per every **{1}** min.",
|
||||
"xp_rate_channel_set": "Channel **{0}** xp rate set to **{1}** xp per every **{2}** min.",
|
||||
"xp_rate_server_reset": "Server xp rate has been reset to global defaults.",
|
||||
"xp_rate_channel_reset": "Channel {0} xp rate has been reset.",
|
||||
"xp_rate_no_gain": "No xp gain"
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue