Role bans (#6703)
This commit is contained in:
1041
Content.Server.Database/Migrations/Postgres/20220214061058_RoleBans.Designer.cs
generated
Normal file
1041
Content.Server.Database/Migrations/Postgres/20220214061058_RoleBans.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Postgres
|
||||
{
|
||||
public partial class RoleBans : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "server_role_unban",
|
||||
columns: table => new
|
||||
{
|
||||
role_unban_id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
ban_id = table.Column<int>(type: "integer", nullable: false),
|
||||
unbanning_admin = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
unban_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_server_role_unban", x => x.role_unban_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_server_role_unban_server_ban_ban_id",
|
||||
column: x => x.ban_id,
|
||||
principalTable: "server_ban",
|
||||
principalColumn: "server_ban_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "server_role_ban",
|
||||
columns: table => new
|
||||
{
|
||||
server_role_ban_id = table.Column<int>(type: "integer", nullable: false)
|
||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||
user_id = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
address = table.Column<ValueTuple<IPAddress, int>>(type: "inet", nullable: true),
|
||||
hwid = table.Column<byte[]>(type: "bytea", nullable: true),
|
||||
ban_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
expiration_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
reason = table.Column<string>(type: "text", nullable: false),
|
||||
banning_admin = table.Column<Guid>(type: "uuid", nullable: true),
|
||||
unban_id = table.Column<int>(type: "integer", nullable: true),
|
||||
role_id = table.Column<string>(type: "text", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_server_role_ban", x => x.server_role_ban_id);
|
||||
table.CheckConstraint("CK_server_role_ban_AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||
table.ForeignKey(
|
||||
name: "FK_server_role_ban_server_role_unban__unban_id",
|
||||
column: x => x.unban_id,
|
||||
principalTable: "server_role_unban",
|
||||
principalColumn: "role_unban_id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_server_role_ban__unban_id",
|
||||
table: "server_role_ban",
|
||||
column: "unban_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_server_role_unban_ban_id",
|
||||
table: "server_role_unban",
|
||||
column: "ban_id");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "server_role_ban");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "server_role_unban");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -646,6 +646,94 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
b.ToTable("server_ban_hit", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("server_role_ban_id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<ValueTuple<IPAddress, int>?>("Address")
|
||||
.HasColumnType("inet")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("BanTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("ban_time");
|
||||
|
||||
b.Property<Guid?>("BanningAdmin")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("banning_admin");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<byte[]>("HWId")
|
||||
.HasColumnType("bytea")
|
||||
.HasColumnName("hwid");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text")
|
||||
.HasColumnName("role_id");
|
||||
|
||||
b.Property<int?>("UnbanId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("unban_id");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_role_ban");
|
||||
|
||||
b.HasIndex("UnbanId")
|
||||
.HasDatabaseName("IX_server_role_ban__unban_id");
|
||||
|
||||
b.ToTable("server_role_ban", (string)null);
|
||||
|
||||
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("role_unban_id");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("BanId")
|
||||
.HasColumnType("integer")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<DateTime>("UnbanTime")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("unban_time");
|
||||
|
||||
b.Property<Guid?>("UnbanningAdmin")
|
||||
.HasColumnType("uuid")
|
||||
.HasColumnName("unbanning_admin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_role_unban");
|
||||
|
||||
b.HasIndex("BanId")
|
||||
.HasDatabaseName("IX_server_role_unban_ban_id");
|
||||
|
||||
b.ToTable("server_role_unban", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -842,6 +930,28 @@ namespace Content.Server.Database.Migrations.Postgres
|
||||
b.Navigation("Connection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerRoleUnban", "Unban")
|
||||
.WithMany()
|
||||
.HasForeignKey("UnbanId")
|
||||
.HasConstraintName("FK_server_role_ban_server_role_unban__unban_id");
|
||||
|
||||
b.Navigation("Unban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerBan", "Ban")
|
||||
.WithMany()
|
||||
.HasForeignKey("BanId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_server_role_unban_server_ban_ban_id");
|
||||
|
||||
b.Navigation("Ban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerBan", "Ban")
|
||||
|
||||
990
Content.Server.Database/Migrations/Sqlite/20220214060745_RoleBans.Designer.cs
generated
Normal file
990
Content.Server.Database/Migrations/Sqlite/20220214060745_RoleBans.Designer.cs
generated
Normal file
@@ -0,0 +1,990 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Content.Server.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
[DbContext(typeof(SqliteServerDbContext))]
|
||||
[Migration("20220214060745_RoleBans")]
|
||||
partial class RoleBans
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "6.0.0");
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<int?>("AdminRankId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("title");
|
||||
|
||||
b.HasKey("UserId")
|
||||
.HasName("PK_admin");
|
||||
|
||||
b.HasIndex("AdminRankId")
|
||||
.HasDatabaseName("IX_admin_admin_rank_id");
|
||||
|
||||
b.ToTable("admin", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_flag_id");
|
||||
|
||||
b.Property<Guid>("AdminId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("admin_id");
|
||||
|
||||
b.Property<string>("Flag")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("flag");
|
||||
|
||||
b.Property<bool>("Negative")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("negative");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_admin_flag");
|
||||
|
||||
b.HasIndex("AdminId")
|
||||
.HasDatabaseName("IX_admin_flag_admin_id");
|
||||
|
||||
b.HasIndex("Flag", "AdminId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("admin_flag", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_log_id");
|
||||
|
||||
b.Property<int>("RoundId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("round_id");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("date");
|
||||
|
||||
b.Property<sbyte>("Impact")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("impact");
|
||||
|
||||
b.Property<string>("Json")
|
||||
.IsRequired()
|
||||
.HasColumnType("jsonb")
|
||||
.HasColumnName("json");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("message");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("type");
|
||||
|
||||
b.HasKey("Id", "RoundId")
|
||||
.HasName("PK_admin_log");
|
||||
|
||||
b.HasIndex("RoundId")
|
||||
.HasDatabaseName("IX_admin_log_round_id");
|
||||
|
||||
b.HasIndex("Type")
|
||||
.HasDatabaseName("IX_admin_log_type");
|
||||
|
||||
b.ToTable("admin_log", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminLogEntity", b =>
|
||||
{
|
||||
b.Property<int>("Uid")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("uid");
|
||||
|
||||
b.Property<int?>("AdminLogId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_log_id");
|
||||
|
||||
b.Property<int?>("AdminLogRoundId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_log_round_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.HasKey("Uid")
|
||||
.HasName("PK_admin_log_entity");
|
||||
|
||||
b.HasIndex("AdminLogId", "AdminLogRoundId")
|
||||
.HasDatabaseName("IX_admin_log_entity_admin_log_id_admin_log_round_id");
|
||||
|
||||
b.ToTable("admin_log_entity", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b =>
|
||||
{
|
||||
b.Property<Guid>("PlayerUserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("player_user_id");
|
||||
|
||||
b.Property<int>("LogId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("log_id");
|
||||
|
||||
b.Property<int>("RoundId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("round_id");
|
||||
|
||||
b.HasKey("PlayerUserId", "LogId", "RoundId")
|
||||
.HasName("PK_admin_log_player");
|
||||
|
||||
b.HasIndex("LogId", "RoundId");
|
||||
|
||||
b.ToTable("admin_log_player", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_admin_rank");
|
||||
|
||||
b.ToTable("admin_rank", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_flag_id");
|
||||
|
||||
b.Property<int>("AdminRankId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("admin_rank_id");
|
||||
|
||||
b.Property<string>("Flag")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("flag");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_admin_rank_flag");
|
||||
|
||||
b.HasIndex("AdminRankId")
|
||||
.HasDatabaseName("IX_admin_rank_flag_admin_rank_id");
|
||||
|
||||
b.HasIndex("Flag", "AdminRankId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("admin_rank_flag", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("antag_id");
|
||||
|
||||
b.Property<string>("AntagName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("antag_name");
|
||||
|
||||
b.Property<int>("ProfileId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_antag");
|
||||
|
||||
b.HasIndex("ProfileId", "AntagName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("antag", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("assigned_user_id_id");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_name");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_assigned_user_id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("UserName")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("assigned_user_id", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("connection_log_id");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<byte?>("Denied")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("denied");
|
||||
|
||||
b.Property<byte[]>("HWId")
|
||||
.HasColumnType("BLOB")
|
||||
.HasColumnName("hwid");
|
||||
|
||||
b.Property<DateTime>("Time")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("time");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_name");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_connection_log");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("connection_log", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("job_id");
|
||||
|
||||
b.Property<string>("JobName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("job_name");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("priority");
|
||||
|
||||
b.Property<int>("ProfileId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_job");
|
||||
|
||||
b.HasIndex("ProfileId")
|
||||
.HasDatabaseName("IX_job_profile_id");
|
||||
|
||||
b.HasIndex("ProfileId", "JobName")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex(new[] { "ProfileId" }, "IX_job_one_high_priority")
|
||||
.IsUnique()
|
||||
.HasFilter("priority = 3");
|
||||
|
||||
b.ToTable("job", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Player", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("player_id");
|
||||
|
||||
b.Property<DateTime>("FirstSeenTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("first_seen_time");
|
||||
|
||||
b.Property<string>("LastSeenAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("last_seen_address");
|
||||
|
||||
b.Property<byte[]>("LastSeenHWId")
|
||||
.HasColumnType("BLOB")
|
||||
.HasColumnName("last_seen_hwid");
|
||||
|
||||
b.Property<DateTime>("LastSeenTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("last_seen_time");
|
||||
|
||||
b.Property<string>("LastSeenUserName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("last_seen_user_name");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_player");
|
||||
|
||||
b.HasAlternateKey("UserId")
|
||||
.HasName("ak_player_user_id");
|
||||
|
||||
b.HasIndex("LastSeenUserName");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("player", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("preference_id");
|
||||
|
||||
b.Property<string>("AdminOOCColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("admin_ooc_color");
|
||||
|
||||
b.Property<int>("SelectedCharacterSlot")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("selected_character_slot");
|
||||
|
||||
b.Property<Guid>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_preference");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("preference", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("profile_id");
|
||||
|
||||
b.Property<int>("Age")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("age");
|
||||
|
||||
b.Property<string>("Backpack")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("backpack");
|
||||
|
||||
b.Property<string>("CharacterName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("char_name");
|
||||
|
||||
b.Property<string>("Clothing")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("clothing");
|
||||
|
||||
b.Property<string>("EyeColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("eye_color");
|
||||
|
||||
b.Property<string>("FacialHairColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("facial_hair_color");
|
||||
|
||||
b.Property<string>("FacialHairName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("facial_hair_name");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("gender");
|
||||
|
||||
b.Property<string>("HairColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("hair_color");
|
||||
|
||||
b.Property<string>("HairName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("hair_name");
|
||||
|
||||
b.Property<int>("PreferenceId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("preference_id");
|
||||
|
||||
b.Property<int>("PreferenceUnavailable")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("pref_unavailable");
|
||||
|
||||
b.Property<string>("Sex")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("sex");
|
||||
|
||||
b.Property<string>("SkinColor")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("skin_color");
|
||||
|
||||
b.Property<int>("Slot")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("slot");
|
||||
|
||||
b.Property<string>("Species")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("species");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_profile");
|
||||
|
||||
b.HasIndex("PreferenceId")
|
||||
.HasDatabaseName("IX_profile_preference_id");
|
||||
|
||||
b.HasIndex("Slot", "PreferenceId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("profile", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("round_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_round");
|
||||
|
||||
b.ToTable("round", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("server_ban_id");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("BanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("ban_time");
|
||||
|
||||
b.Property<Guid?>("BanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("banning_admin");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<byte[]>("HWId")
|
||||
.HasColumnType("BLOB")
|
||||
.HasColumnName("hwid");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_ban");
|
||||
|
||||
b.HasIndex("Address");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("server_ban", (string)null);
|
||||
|
||||
b.HasCheckConstraint("HaveEitherAddressOrUserIdOrHWId", "address IS NOT NULL OR user_id IS NOT NULL OR hwid IS NOT NULL");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerBanHit", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("server_ban_hit_id");
|
||||
|
||||
b.Property<int>("BanId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<int>("ConnectionId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("connection_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_ban_hit");
|
||||
|
||||
b.HasIndex("BanId")
|
||||
.HasDatabaseName("IX_server_ban_hit_ban_id");
|
||||
|
||||
b.HasIndex("ConnectionId")
|
||||
.HasDatabaseName("IX_server_ban_hit_connection_id");
|
||||
|
||||
b.ToTable("server_ban_hit", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("server_role_ban_id");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("BanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("ban_time");
|
||||
|
||||
b.Property<Guid?>("BanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("banning_admin");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<byte[]>("HWId")
|
||||
.HasColumnType("BLOB")
|
||||
.HasColumnName("hwid");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("role_id");
|
||||
|
||||
b.Property<int?>("UnbanId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("unban_id");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_role_ban");
|
||||
|
||||
b.HasIndex("UnbanId")
|
||||
.HasDatabaseName("IX_server_role_ban__unban_id");
|
||||
|
||||
b.ToTable("server_role_ban", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("role_unban_id");
|
||||
|
||||
b.Property<int>("BanId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<DateTime>("UnbanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unban_time");
|
||||
|
||||
b.Property<Guid?>("UnbanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unbanning_admin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_role_unban");
|
||||
|
||||
b.HasIndex("BanId")
|
||||
.HasDatabaseName("IX_server_role_unban_ban_id");
|
||||
|
||||
b.ToTable("server_role_unban", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("unban_id");
|
||||
|
||||
b.Property<int>("BanId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<DateTime>("UnbanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unban_time");
|
||||
|
||||
b.Property<Guid?>("UnbanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unbanning_admin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_unban");
|
||||
|
||||
b.HasIndex("BanId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("server_unban", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Whitelist", b =>
|
||||
{
|
||||
b.Property<Guid>("UserId")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("UserId")
|
||||
.HasName("PK_whitelist");
|
||||
|
||||
b.ToTable("whitelist", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PlayerRound", b =>
|
||||
{
|
||||
b.Property<int>("PlayersId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("players_id");
|
||||
|
||||
b.Property<int>("RoundsId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("rounds_id");
|
||||
|
||||
b.HasKey("PlayersId", "RoundsId")
|
||||
.HasName("PK_player_round");
|
||||
|
||||
b.HasIndex("RoundsId")
|
||||
.HasDatabaseName("IX_player_round_rounds_id");
|
||||
|
||||
b.ToTable("player_round", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.AdminRank", "AdminRank")
|
||||
.WithMany("Admins")
|
||||
.HasForeignKey("AdminRankId")
|
||||
.OnDelete(DeleteBehavior.SetNull)
|
||||
.HasConstraintName("FK_admin_admin_rank_admin_rank_id");
|
||||
|
||||
b.Navigation("AdminRank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminFlag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Admin", "Admin")
|
||||
.WithMany("Flags")
|
||||
.HasForeignKey("AdminId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_admin_flag_admin_admin_id");
|
||||
|
||||
b.Navigation("Admin");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Round", "Round")
|
||||
.WithMany("AdminLogs")
|
||||
.HasForeignKey("RoundId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_admin_log_round_round_id");
|
||||
|
||||
b.Navigation("Round");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminLogEntity", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.AdminLog", null)
|
||||
.WithMany("Entities")
|
||||
.HasForeignKey("AdminLogId", "AdminLogRoundId")
|
||||
.HasConstraintName("FK_admin_log_entity_admin_log_admin_log_id_admin_log_round_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminLogPlayer", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Player", "Player")
|
||||
.WithMany("AdminLogs")
|
||||
.HasForeignKey("PlayerUserId")
|
||||
.HasPrincipalKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_admin_log_player_player_player_user_id");
|
||||
|
||||
b.HasOne("Content.Server.Database.AdminLog", "Log")
|
||||
.WithMany("Players")
|
||||
.HasForeignKey("LogId", "RoundId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_admin_log_player_admin_log_log_id_round_id");
|
||||
|
||||
b.Navigation("Log");
|
||||
|
||||
b.Navigation("Player");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRankFlag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.AdminRank", "Rank")
|
||||
.WithMany("Flags")
|
||||
.HasForeignKey("AdminRankId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_admin_rank_flag_admin_rank_admin_rank_id");
|
||||
|
||||
b.Navigation("Rank");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
.WithMany("Antags")
|
||||
.HasForeignKey("ProfileId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_antag_profile_profile_id");
|
||||
|
||||
b.Navigation("Profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||
.WithMany("Jobs")
|
||||
.HasForeignKey("ProfileId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_job_profile_profile_id");
|
||||
|
||||
b.Navigation("Profile");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||
.WithMany("Profiles")
|
||||
.HasForeignKey("PreferenceId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_profile_preference_preference_id");
|
||||
|
||||
b.Navigation("Preference");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerBanHit", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerBan", "Ban")
|
||||
.WithMany("BanHits")
|
||||
.HasForeignKey("BanId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_server_ban_hit_server_ban_ban_id");
|
||||
|
||||
b.HasOne("Content.Server.Database.ConnectionLog", "Connection")
|
||||
.WithMany("BanHits")
|
||||
.HasForeignKey("ConnectionId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_server_ban_hit_connection_log_connection_id");
|
||||
|
||||
b.Navigation("Ban");
|
||||
|
||||
b.Navigation("Connection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerRoleUnban", "Unban")
|
||||
.WithMany()
|
||||
.HasForeignKey("UnbanId")
|
||||
.HasConstraintName("FK_server_role_ban_server_role_unban__unban_id");
|
||||
|
||||
b.Navigation("Unban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerBan", "Ban")
|
||||
.WithMany()
|
||||
.HasForeignKey("BanId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_server_role_unban_server_ban_ban_id");
|
||||
|
||||
b.Navigation("Ban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerBan", "Ban")
|
||||
.WithOne("Unban")
|
||||
.HasForeignKey("Content.Server.Database.ServerUnban", "BanId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_server_unban_server_ban_ban_id");
|
||||
|
||||
b.Navigation("Ban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("PlayerRound", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.Player", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("PlayersId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_player_round_player_players_id");
|
||||
|
||||
b.HasOne("Content.Server.Database.Round", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoundsId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_player_round_round_rounds_id");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Admin", b =>
|
||||
{
|
||||
b.Navigation("Flags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminLog", b =>
|
||||
{
|
||||
b.Navigation("Entities");
|
||||
|
||||
b.Navigation("Players");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.AdminRank", b =>
|
||||
{
|
||||
b.Navigation("Admins");
|
||||
|
||||
b.Navigation("Flags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ConnectionLog", b =>
|
||||
{
|
||||
b.Navigation("BanHits");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Player", b =>
|
||||
{
|
||||
b.Navigation("AdminLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||
{
|
||||
b.Navigation("Profiles");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||
{
|
||||
b.Navigation("Antags");
|
||||
|
||||
b.Navigation("Jobs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.Round", b =>
|
||||
{
|
||||
b.Navigation("AdminLogs");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerBan", b =>
|
||||
{
|
||||
b.Navigation("BanHits");
|
||||
|
||||
b.Navigation("Unban");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Content.Server.Database.Migrations.Sqlite
|
||||
{
|
||||
public partial class RoleBans : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "server_role_unban",
|
||||
columns: table => new
|
||||
{
|
||||
role_unban_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
ban_id = table.Column<int>(type: "INTEGER", nullable: false),
|
||||
unbanning_admin = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
unban_time = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_server_role_unban", x => x.role_unban_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_server_role_unban_server_ban_ban_id",
|
||||
column: x => x.ban_id,
|
||||
principalTable: "server_ban",
|
||||
principalColumn: "server_ban_id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "server_role_ban",
|
||||
columns: table => new
|
||||
{
|
||||
server_role_ban_id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||
.Annotation("Sqlite:Autoincrement", true),
|
||||
user_id = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
address = table.Column<string>(type: "TEXT", nullable: true),
|
||||
hwid = table.Column<byte[]>(type: "BLOB", nullable: true),
|
||||
ban_time = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||
expiration_time = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||
reason = table.Column<string>(type: "TEXT", nullable: false),
|
||||
banning_admin = table.Column<Guid>(type: "TEXT", nullable: true),
|
||||
unban_id = table.Column<int>(type: "INTEGER", nullable: true),
|
||||
role_id = table.Column<string>(type: "TEXT", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_server_role_ban", x => x.server_role_ban_id);
|
||||
table.ForeignKey(
|
||||
name: "FK_server_role_ban_server_role_unban__unban_id",
|
||||
column: x => x.unban_id,
|
||||
principalTable: "server_role_unban",
|
||||
principalColumn: "role_unban_id");
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_server_role_ban__unban_id",
|
||||
table: "server_role_ban",
|
||||
column: "unban_id");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_server_role_unban_ban_id",
|
||||
table: "server_role_unban",
|
||||
column: "ban_id");
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "server_role_ban");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "server_role_unban");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -603,6 +603,88 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
b.ToTable("server_ban_hit", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("server_role_ban_id");
|
||||
|
||||
b.Property<string>("Address")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("address");
|
||||
|
||||
b.Property<DateTime>("BanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("ban_time");
|
||||
|
||||
b.Property<Guid?>("BanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("banning_admin");
|
||||
|
||||
b.Property<DateTime?>("ExpirationTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("expiration_time");
|
||||
|
||||
b.Property<byte[]>("HWId")
|
||||
.HasColumnType("BLOB")
|
||||
.HasColumnName("hwid");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<string>("RoleId")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("role_id");
|
||||
|
||||
b.Property<int?>("UnbanId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("unban_id");
|
||||
|
||||
b.Property<Guid?>("UserId")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_role_ban");
|
||||
|
||||
b.HasIndex("UnbanId")
|
||||
.HasDatabaseName("IX_server_role_ban__unban_id");
|
||||
|
||||
b.ToTable("server_role_ban", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("role_unban_id");
|
||||
|
||||
b.Property<int>("BanId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("ban_id");
|
||||
|
||||
b.Property<DateTime>("UnbanTime")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unban_time");
|
||||
|
||||
b.Property<Guid?>("UnbanningAdmin")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("unbanning_admin");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("PK_server_role_unban");
|
||||
|
||||
b.HasIndex("BanId")
|
||||
.HasDatabaseName("IX_server_role_unban_ban_id");
|
||||
|
||||
b.ToTable("server_role_unban", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -797,6 +879,28 @@ namespace Content.Server.Database.Migrations.Sqlite
|
||||
b.Navigation("Connection");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleBan", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerRoleUnban", "Unban")
|
||||
.WithMany()
|
||||
.HasForeignKey("UnbanId")
|
||||
.HasConstraintName("FK_server_role_ban_server_role_unban__unban_id");
|
||||
|
||||
b.Navigation("Unban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerRoleUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerBan", "Ban")
|
||||
.WithMany()
|
||||
.HasForeignKey("BanId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired()
|
||||
.HasConstraintName("FK_server_role_unban_server_ban_ban_id");
|
||||
|
||||
b.Navigation("Ban");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Content.Server.Database.ServerUnban", b =>
|
||||
{
|
||||
b.HasOne("Content.Server.Database.ServerBan", "Ban")
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace Content.Server.Database
|
||||
public DbSet<ServerUnban> Unban { get; set; } = default!;
|
||||
public DbSet<ConnectionLog> ConnectionLog { get; set; } = default!;
|
||||
public DbSet<ServerBanHit> ServerBanHit { get; set; } = default!;
|
||||
public DbSet<ServerRoleBan> RoleBan { get; set; } = default!;
|
||||
public DbSet<ServerRoleUnban> RoleUnban { get; set; } = default!;
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
@@ -387,4 +389,37 @@ namespace Content.Server.Database
|
||||
public ServerBan Ban { get; set; } = null!;
|
||||
public ConnectionLog Connection { get; set; } = null!;
|
||||
}
|
||||
|
||||
[Table("server_role_ban")]
|
||||
public sealed class ServerRoleBan
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public Guid? UserId { get; set; }
|
||||
[Column(TypeName = "inet")] public (IPAddress, int)? Address { get; set; }
|
||||
public byte[]? HWId { get; set; }
|
||||
|
||||
public DateTime BanTime { get; set; }
|
||||
|
||||
public DateTime? ExpirationTime { get; set; }
|
||||
|
||||
public string Reason { get; set; } = null!;
|
||||
public Guid? BanningAdmin { get; set; }
|
||||
|
||||
public ServerRoleUnban? Unban { get; set; }
|
||||
|
||||
public string RoleId { get; set; } = null!;
|
||||
}
|
||||
|
||||
[Table("server_role_unban")]
|
||||
public sealed class ServerRoleUnban
|
||||
{
|
||||
[Column("role_unban_id")] public int Id { get; set; }
|
||||
|
||||
public int BanId { get; set; }
|
||||
public ServerBan Ban { get; set; } = null!;
|
||||
|
||||
public Guid? UnbanningAdmin { get; set; }
|
||||
|
||||
public DateTime UnbanTime { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,14 +41,15 @@ namespace Content.Server.Database
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
// ReSharper disable once CommentTypo
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
// ReSharper disable StringLiteralTypo
|
||||
// Enforce that an address cannot be IPv6-mapped IPv4.
|
||||
// So that IPv4 addresses are consistent between separate-socket and dual-stack socket modes.
|
||||
modelBuilder.Entity<ServerBan>()
|
||||
.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||
|
||||
// ReSharper disable once StringLiteralTypo
|
||||
modelBuilder.Entity<ServerRoleBan>()
|
||||
.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||
|
||||
modelBuilder.Entity<Player>()
|
||||
.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4",
|
||||
"NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||
@@ -56,6 +57,7 @@ namespace Content.Server.Database
|
||||
modelBuilder.Entity<ConnectionLog>()
|
||||
.HasCheckConstraint("AddressNotIPv6MappedIPv4",
|
||||
"NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||
// ReSharper restore StringLiteralTypo
|
||||
|
||||
foreach(var entity in modelBuilder.Model.GetEntityTypes())
|
||||
{
|
||||
|
||||
@@ -58,6 +58,12 @@ namespace Content.Server.Database
|
||||
.HasColumnType("TEXT")
|
||||
.HasConversion(ipMaskConverter);
|
||||
|
||||
modelBuilder
|
||||
.Entity<ServerRoleBan>()
|
||||
.Property(e => e.Address)
|
||||
.HasColumnType("TEXT")
|
||||
.HasConversion(ipMaskConverter);
|
||||
|
||||
var jsonConverter = new ValueConverter<JsonDocument, string>(
|
||||
v => JsonDocumentToString(v),
|
||||
v => StringToJsonDocument(v));
|
||||
|
||||
49
Content.Server/Administration/Commands/JobBanCommand.cs
Normal file
49
Content.Server/Administration/Commands/JobBanCommand.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Ban)]
|
||||
public sealed class JobBanCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "jobban";
|
||||
public string Description => "Bans a player from a job";
|
||||
public string Help => $"Usage: {Command} <name or user ID> <job> <reason> [duration in minutes, leave out or 0 for permanent ban]";
|
||||
|
||||
public async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
string target;
|
||||
string job;
|
||||
string reason;
|
||||
uint minutes;
|
||||
|
||||
switch (args.Length)
|
||||
{
|
||||
case 3:
|
||||
target = args[0];
|
||||
job = args[1];
|
||||
reason = args[2];
|
||||
minutes = 0;
|
||||
break;
|
||||
case 4:
|
||||
target = args[0];
|
||||
job = args[1];
|
||||
reason = args[2];
|
||||
|
||||
if (!uint.TryParse(args[3], out minutes))
|
||||
{
|
||||
shell.WriteLine($"{args[3]} is not a valid amount of minutes.\n{Help}");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
shell.WriteLine($"Invalid amount of arguments.");
|
||||
shell.WriteLine(Help);
|
||||
return;
|
||||
}
|
||||
|
||||
IoCManager.Resolve<RoleBanManager>().CreateJobBan(shell, target, job, reason, minutes);
|
||||
}
|
||||
}
|
||||
84
Content.Server/Administration/Commands/RoleBanListCommand.cs
Normal file
84
Content.Server/Administration/Commands/RoleBanListCommand.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System.Text;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.Administration.Commands;
|
||||
|
||||
[AdminCommand(AdminFlags.Ban)]
|
||||
public sealed class RoleBanListCommand : IConsoleCommand
|
||||
{
|
||||
public string Command => "rolebanlist";
|
||||
public string Description => "Lists the user's role bans";
|
||||
public string Help => "Usage: <name or user ID> [include unbanned]";
|
||||
|
||||
public async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 1 && args.Length != 2)
|
||||
{
|
||||
shell.WriteLine($"Invalid amount of args. {Help}");
|
||||
return;
|
||||
}
|
||||
|
||||
var includeUnbanned = true;
|
||||
if (args.Length == 2 && !bool.TryParse(args[1], out includeUnbanned))
|
||||
{
|
||||
shell.WriteLine($"Argument two ({args[1]}) is not a boolean.");
|
||||
return;
|
||||
}
|
||||
|
||||
var dbMan = IoCManager.Resolve<IServerDbManager>();
|
||||
|
||||
var target = args[0];
|
||||
|
||||
var locator = IoCManager.Resolve<IPlayerLocator>();
|
||||
var located = await locator.LookupIdByNameOrIdAsync(target);
|
||||
if (located == null)
|
||||
{
|
||||
shell.WriteError("Unable to find a player with that name or id.");
|
||||
return;
|
||||
}
|
||||
|
||||
var targetUid = located.UserId;
|
||||
var targetHWid = located.LastHWId;
|
||||
var targetAddress = located.LastAddress;
|
||||
|
||||
var bans = await dbMan.GetServerRoleBansAsync(targetAddress, targetUid, targetHWid, includeUnbanned);
|
||||
|
||||
if (bans.Count == 0)
|
||||
{
|
||||
shell.WriteLine("That user has no bans in their record.");
|
||||
return;
|
||||
}
|
||||
|
||||
var bansString = new StringBuilder("Bans in record:\n");
|
||||
|
||||
foreach (var ban in bans)
|
||||
{
|
||||
bansString
|
||||
.Append("Ban ID: ")
|
||||
.Append(ban.Id)
|
||||
.Append("\n")
|
||||
.Append("Banned on ")
|
||||
.Append(ban.BanTime);
|
||||
|
||||
if (ban.ExpirationTime != null)
|
||||
{
|
||||
bansString
|
||||
.Append(" until ")
|
||||
.Append(ban.ExpirationTime.Value);
|
||||
}
|
||||
|
||||
bansString
|
||||
.Append(".")
|
||||
.Append("\n");
|
||||
|
||||
bansString
|
||||
.Append("Reason: ")
|
||||
.Append(ban.Reason)
|
||||
.Append('\n');
|
||||
}
|
||||
|
||||
shell.WriteLine(bansString.ToString());
|
||||
}
|
||||
}
|
||||
183
Content.Server/Administration/Managers/RoleBanManager.cs
Normal file
183
Content.Server/Administration/Managers/RoleBanManager.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Administration.Managers;
|
||||
|
||||
public sealed class RoleBanManager
|
||||
{
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IPlayerLocator _playerLocator = default!;
|
||||
|
||||
private const string JobPrefix = "Job:";
|
||||
|
||||
private readonly Dictionary<NetUserId, HashSet<ServerRoleBanDef>> _cachedRoleBans = new();
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
}
|
||||
|
||||
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
{
|
||||
if (e.NewStatus != SessionStatus.Connected
|
||||
|| _cachedRoleBans.ContainsKey(e.Session.UserId))
|
||||
return;
|
||||
|
||||
var netChannel = e.Session.ConnectedClient;
|
||||
await CacheDbRoleBans(e.Session.UserId, netChannel.RemoteEndPoint.Address, netChannel.UserData.HWId);
|
||||
}
|
||||
|
||||
private async Task<bool> AddRoleBan(ServerRoleBanDef banDef)
|
||||
{
|
||||
if (banDef.UserId != null)
|
||||
{
|
||||
if (!_cachedRoleBans.TryGetValue(banDef.UserId.Value, out var roleBans))
|
||||
{
|
||||
roleBans = new HashSet<ServerRoleBanDef>();
|
||||
_cachedRoleBans.Add(banDef.UserId.Value, roleBans);
|
||||
}
|
||||
if (!roleBans.Contains(banDef))
|
||||
roleBans.Add(banDef);
|
||||
}
|
||||
|
||||
await _db.AddServerRoleBanAsync(banDef);
|
||||
return true;
|
||||
}
|
||||
|
||||
public HashSet<string>? GetRoleBans(NetUserId playerUserId)
|
||||
{
|
||||
return _cachedRoleBans.TryGetValue(playerUserId, out var roleBans) ? roleBans.Select(banDef => banDef.Role).ToHashSet() : null;
|
||||
}
|
||||
|
||||
private async Task CacheDbRoleBans(NetUserId userId, IPAddress? address = null, ImmutableArray<byte>? hwId = null)
|
||||
{
|
||||
var roleBans = await _db.GetServerRoleBansAsync(address, userId, hwId, false);
|
||||
|
||||
var userRoleBans = new HashSet<ServerRoleBanDef>();
|
||||
foreach (var ban in roleBans)
|
||||
{
|
||||
userRoleBans.Add(ban);
|
||||
}
|
||||
|
||||
_cachedRoleBans[userId] = userRoleBans;
|
||||
}
|
||||
|
||||
public void Restart()
|
||||
{
|
||||
// Clear out players that have disconnected.
|
||||
var toRemove = new List<NetUserId>();
|
||||
foreach (var player in _cachedRoleBans.Keys)
|
||||
{
|
||||
if (!_playerManager.TryGetSessionById(player, out _))
|
||||
toRemove.Add(player);
|
||||
}
|
||||
|
||||
foreach (var player in toRemove)
|
||||
{
|
||||
_cachedRoleBans.Remove(player);
|
||||
}
|
||||
|
||||
// Check for expired bans
|
||||
foreach (var (_, roleBans) in _cachedRoleBans)
|
||||
{
|
||||
roleBans.RemoveWhere(ban => DateTimeOffset.Now > ban.ExpirationTime);
|
||||
}
|
||||
}
|
||||
|
||||
#region Job Bans
|
||||
public async void CreateJobBan(IConsoleShell shell, string target, string job, string reason, uint minutes)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex(job, out JobPrototype? _))
|
||||
{
|
||||
shell.WriteLine($"Job {job} does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
job = string.Concat(JobPrefix, job);
|
||||
CreateRoleBan(shell, target, job, reason, minutes);
|
||||
}
|
||||
|
||||
public HashSet<string>? GetJobBans(NetUserId playerUserId)
|
||||
{
|
||||
if (!_cachedRoleBans.TryGetValue(playerUserId, out var roleBans))
|
||||
return null;
|
||||
return roleBans
|
||||
.Where(ban => ban.Role.StartsWith(JobPrefix))
|
||||
.Select(ban => ban.Role[JobPrefix.Length..])
|
||||
.ToHashSet();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
private async void CreateRoleBan(IConsoleShell shell, string target, string role, string reason, uint minutes)
|
||||
{
|
||||
var located = await _playerLocator.LookupIdByNameOrIdAsync(target);
|
||||
if (located == null)
|
||||
{
|
||||
shell.WriteError("Unable to find a player with that name.");
|
||||
return;
|
||||
}
|
||||
|
||||
var targetUid = located.UserId;
|
||||
var targetHWid = located.LastHWId;
|
||||
var targetAddress = located.LastAddress;
|
||||
|
||||
DateTimeOffset? expires = null;
|
||||
if (minutes > 0)
|
||||
{
|
||||
expires = DateTimeOffset.Now + TimeSpan.FromMinutes(minutes);
|
||||
}
|
||||
|
||||
(IPAddress, int)? addressRange = null;
|
||||
if (targetAddress != null)
|
||||
{
|
||||
if (targetAddress.IsIPv4MappedToIPv6)
|
||||
targetAddress = targetAddress.MapToIPv4();
|
||||
|
||||
// Ban /64 for IPv4, /32 for IPv4.
|
||||
var cidr = targetAddress.AddressFamily == AddressFamily.InterNetworkV6 ? 64 : 32;
|
||||
addressRange = (targetAddress, cidr);
|
||||
}
|
||||
|
||||
var player = shell.Player as IPlayerSession;
|
||||
var banDef = new ServerRoleBanDef(
|
||||
null,
|
||||
targetUid,
|
||||
addressRange,
|
||||
targetHWid,
|
||||
DateTimeOffset.Now,
|
||||
expires,
|
||||
reason,
|
||||
player?.UserId,
|
||||
null,
|
||||
role);
|
||||
|
||||
if (!await AddRoleBan(banDef))
|
||||
{
|
||||
shell.WriteLine($"{target} already has a role ban for {role}");
|
||||
return;
|
||||
}
|
||||
|
||||
var response = new StringBuilder($"Role banned {target} with reason \"{reason}\"");
|
||||
|
||||
response.Append(expires == null ?
|
||||
" permanently."
|
||||
: $" until {expires}");
|
||||
|
||||
shell.WriteLine(response.ToString());
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -306,6 +306,37 @@ namespace Content.Server.Database
|
||||
public abstract Task AddServerUnbanAsync(ServerUnbanDef serverUnban);
|
||||
#endregion
|
||||
|
||||
#region Role Bans
|
||||
/*
|
||||
* ROLE BANS
|
||||
*/
|
||||
/// <summary>
|
||||
/// Looks up a role ban by id.
|
||||
/// This will return a pardoned role ban as well.
|
||||
/// </summary>
|
||||
/// <param name="id">The role ban id to look for.</param>
|
||||
/// <returns>The role ban with the given id or null if none exist.</returns>
|
||||
public abstract Task<ServerRoleBanDef?> GetServerRoleBanAsync(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up an user's role ban history.
|
||||
/// This will return pardoned role bans based on the <see cref="includeUnbanned"/> bool.
|
||||
/// Requires one of <see cref="address"/>, <see cref="userId"/>, or <see cref="hwId"/> to not be null.
|
||||
/// </summary>
|
||||
/// <param name="address">The IP address of the user.</param>
|
||||
/// <param name="userId">The NetUserId of the user.</param>
|
||||
/// <param name="hwId">The Hardware Id of the user.</param>
|
||||
/// <param name="includeUnbanned">Whether expired and pardoned bans are included.</param>
|
||||
/// <returns>The user's role ban history.</returns>
|
||||
public abstract Task<List<ServerRoleBanDef>> GetServerRoleBansAsync(IPAddress? address,
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId,
|
||||
bool includeUnbanned);
|
||||
|
||||
public abstract Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan);
|
||||
public abstract Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverRoleUnban);
|
||||
#endregion
|
||||
|
||||
#region Player Records
|
||||
/*
|
||||
* PLAYER RECORDS
|
||||
|
||||
@@ -90,6 +90,35 @@ namespace Content.Server.Database
|
||||
Task AddServerUnbanAsync(ServerUnbanDef serverBan);
|
||||
#endregion
|
||||
|
||||
#region Role Bans
|
||||
/// <summary>
|
||||
/// Looks up a role ban by id.
|
||||
/// This will return a pardoned role ban as well.
|
||||
/// </summary>
|
||||
/// <param name="id">The role ban id to look for.</param>
|
||||
/// <returns>The role ban with the given id or null if none exist.</returns>
|
||||
Task<ServerRoleBanDef?> GetServerRoleBanAsync(int id);
|
||||
|
||||
/// <summary>
|
||||
/// Looks up an user's role ban history.
|
||||
/// This will return pardoned role bans based on the <see cref="includeUnbanned"/> bool.
|
||||
/// Requires one of <see cref="address"/>, <see cref="userId"/>, or <see cref="hwId"/> to not be null.
|
||||
/// </summary>
|
||||
/// <param name="address">The IP address of the user.</param>
|
||||
/// <param name="userId">The NetUserId of the user.</param>
|
||||
/// <param name="hwId">The Hardware Id of the user.</param>
|
||||
/// <param name="includeUnbanned">Whether expired and pardoned bans are included.</param>
|
||||
/// <returns>The user's role ban history.</returns>
|
||||
Task<List<ServerRoleBanDef>> GetServerRoleBansAsync(
|
||||
IPAddress? address,
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId,
|
||||
bool includeUnbanned = true);
|
||||
|
||||
Task AddServerRoleBanAsync(ServerRoleBanDef serverBan);
|
||||
Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverBan);
|
||||
#endregion
|
||||
|
||||
#region Player Records
|
||||
Task UpdatePlayerRecordAsync(
|
||||
NetUserId userId,
|
||||
@@ -264,6 +293,32 @@ namespace Content.Server.Database
|
||||
return _db.AddServerUnbanAsync(serverUnban);
|
||||
}
|
||||
|
||||
#region Role Ban
|
||||
public Task<ServerRoleBanDef?> GetServerRoleBanAsync(int id)
|
||||
{
|
||||
return _db.GetServerRoleBanAsync(id);
|
||||
}
|
||||
|
||||
public Task<List<ServerRoleBanDef>> GetServerRoleBansAsync(
|
||||
IPAddress? address,
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId,
|
||||
bool includeUnbanned = true)
|
||||
{
|
||||
return _db.GetServerRoleBansAsync(address, userId, hwId, includeUnbanned);
|
||||
}
|
||||
|
||||
public Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan)
|
||||
{
|
||||
return _db.AddServerRoleBanAsync(serverRoleBan);
|
||||
}
|
||||
|
||||
public Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverRoleUnban)
|
||||
{
|
||||
return _db.AddServerRoleUnbanAsync(serverRoleUnban);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public Task UpdatePlayerRecordAsync(
|
||||
NetUserId userId,
|
||||
string userName,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Collections.Immutable;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
@@ -34,6 +32,7 @@ namespace Content.Server.Database
|
||||
});
|
||||
}
|
||||
|
||||
#region Ban
|
||||
public override async Task<ServerBanDef?> GetServerBanAsync(int id)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
@@ -52,9 +51,9 @@ namespace Content.Server.Database
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId)
|
||||
{
|
||||
if (address == null && userId == null)
|
||||
if (address == null && userId == null && hwId == null)
|
||||
{
|
||||
throw new ArgumentException("Address and userId cannot both be null");
|
||||
throw new ArgumentException("Address, userId, and hwId cannot all be null");
|
||||
}
|
||||
|
||||
await using var db = await GetDbImpl();
|
||||
@@ -73,7 +72,7 @@ namespace Content.Server.Database
|
||||
{
|
||||
if (address == null && userId == null && hwId == null)
|
||||
{
|
||||
throw new ArgumentException("Address and userId cannot both be null");
|
||||
throw new ArgumentException("Address, userId, and hwId cannot all be null");
|
||||
}
|
||||
|
||||
await using var db = await GetDbImpl();
|
||||
@@ -225,6 +224,191 @@ namespace Content.Server.Database
|
||||
|
||||
await db.PgDbContext.SaveChangesAsync();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Role Ban
|
||||
public override async Task<ServerRoleBanDef?> GetServerRoleBanAsync(int id)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
var query = db.PgDbContext.RoleBan
|
||||
.Include(p => p.Unban)
|
||||
.Where(p => p.Id == id);
|
||||
|
||||
var ban = await query.SingleOrDefaultAsync();
|
||||
|
||||
return ConvertRoleBan(ban);
|
||||
|
||||
}
|
||||
|
||||
public override async Task<List<ServerRoleBanDef>> GetServerRoleBansAsync(IPAddress? address,
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId,
|
||||
bool includeUnbanned)
|
||||
{
|
||||
if (address == null && userId == null && hwId == null)
|
||||
{
|
||||
throw new ArgumentException("Address, userId, and hwId cannot all be null");
|
||||
}
|
||||
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
var query = MakeRoleBanLookupQuery(address, userId, hwId, db, includeUnbanned)
|
||||
.OrderByDescending(b => b.BanTime);
|
||||
|
||||
return await QueryRoleBans(query);
|
||||
}
|
||||
|
||||
private static async Task<List<ServerRoleBanDef>> QueryRoleBans(IQueryable<ServerRoleBan> query)
|
||||
{
|
||||
var queryRoleBans = await query.ToArrayAsync();
|
||||
var bans = new List<ServerRoleBanDef>(queryRoleBans.Length);
|
||||
|
||||
foreach (var ban in queryRoleBans)
|
||||
{
|
||||
var banDef = ConvertRoleBan(ban);
|
||||
|
||||
if (banDef != null)
|
||||
{
|
||||
bans.Add(banDef);
|
||||
}
|
||||
}
|
||||
|
||||
return bans;
|
||||
}
|
||||
|
||||
private static IQueryable<ServerRoleBan> MakeRoleBanLookupQuery(
|
||||
IPAddress? address,
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId,
|
||||
DbGuardImpl db,
|
||||
bool includeUnbanned)
|
||||
{
|
||||
IQueryable<ServerRoleBan>? query = null;
|
||||
|
||||
if (userId is { } uid)
|
||||
{
|
||||
var newQ = db.PgDbContext.RoleBan
|
||||
.Include(p => p.Unban)
|
||||
.Where(b => b.UserId == uid.UserId);
|
||||
|
||||
query = query == null ? newQ : query.Union(newQ);
|
||||
}
|
||||
|
||||
if (address != null)
|
||||
{
|
||||
var newQ = db.PgDbContext.RoleBan
|
||||
.Include(p => p.Unban)
|
||||
.Where(b => b.Address != null && EF.Functions.ContainsOrEqual(b.Address.Value, address));
|
||||
|
||||
query = query == null ? newQ : query.Union(newQ);
|
||||
}
|
||||
|
||||
if (hwId != null)
|
||||
{
|
||||
var newQ = db.PgDbContext.RoleBan
|
||||
.Include(p => p.Unban)
|
||||
.Where(b => b.HWId!.SequenceEqual(hwId.Value.ToArray()));
|
||||
|
||||
query = query == null ? newQ : query.Union(newQ);
|
||||
}
|
||||
|
||||
if (!includeUnbanned)
|
||||
{
|
||||
query = query?.Where(p =>
|
||||
p.Unban == null && (p.ExpirationTime == null || p.ExpirationTime.Value > DateTime.Now));
|
||||
}
|
||||
|
||||
query = query!.Distinct();
|
||||
return query;
|
||||
}
|
||||
|
||||
private static ServerRoleBanDef? ConvertRoleBan(ServerRoleBan? ban)
|
||||
{
|
||||
if (ban == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NetUserId? uid = null;
|
||||
if (ban.UserId is {} guid)
|
||||
{
|
||||
uid = new NetUserId(guid);
|
||||
}
|
||||
|
||||
NetUserId? aUid = null;
|
||||
if (ban.BanningAdmin is {} aGuid)
|
||||
{
|
||||
aUid = new NetUserId(aGuid);
|
||||
}
|
||||
|
||||
var unbanDef = ConvertRoleUnban(ban.Unban);
|
||||
|
||||
return new ServerRoleBanDef(
|
||||
ban.Id,
|
||||
uid,
|
||||
ban.Address,
|
||||
ban.HWId == null ? null : ImmutableArray.Create(ban.HWId),
|
||||
ban.BanTime,
|
||||
ban.ExpirationTime,
|
||||
ban.Reason,
|
||||
aUid,
|
||||
unbanDef,
|
||||
ban.RoleId);
|
||||
}
|
||||
|
||||
private static ServerRoleUnbanDef? ConvertRoleUnban(ServerRoleUnban? unban)
|
||||
{
|
||||
if (unban == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NetUserId? aUid = null;
|
||||
if (unban.UnbanningAdmin is {} aGuid)
|
||||
{
|
||||
aUid = new NetUserId(aGuid);
|
||||
}
|
||||
|
||||
return new ServerRoleUnbanDef(
|
||||
unban.Id,
|
||||
aUid,
|
||||
unban.UnbanTime);
|
||||
}
|
||||
|
||||
public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverRoleBan)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
db.PgDbContext.RoleBan.Add(new ServerRoleBan
|
||||
{
|
||||
Address = serverRoleBan.Address,
|
||||
HWId = serverRoleBan.HWId?.ToArray(),
|
||||
Reason = serverRoleBan.Reason,
|
||||
BanningAdmin = serverRoleBan.BanningAdmin?.UserId,
|
||||
BanTime = serverRoleBan.BanTime.UtcDateTime,
|
||||
ExpirationTime = serverRoleBan.ExpirationTime?.UtcDateTime,
|
||||
UserId = serverRoleBan.UserId?.UserId,
|
||||
RoleId = serverRoleBan.Role,
|
||||
});
|
||||
|
||||
await db.PgDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public override async Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverRoleUnban)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
db.PgDbContext.RoleUnban.Add(new ServerRoleUnban
|
||||
{
|
||||
BanId = serverRoleUnban.BanId,
|
||||
UnbanningAdmin = serverRoleUnban.UnbanningAdmin?.UserId,
|
||||
UnbanTime = serverRoleUnban.UnbanTime.UtcDateTime
|
||||
});
|
||||
|
||||
await db.PgDbContext.SaveChangesAsync();
|
||||
}
|
||||
#endregion
|
||||
|
||||
protected override PlayerRecord MakePlayerRecord(Player record)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Content.Server.Database
|
||||
}
|
||||
}
|
||||
|
||||
#region Ban
|
||||
public override async Task<ServerBanDef?> GetServerBanAsync(int id)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
@@ -159,6 +160,162 @@ namespace Content.Server.Database
|
||||
|
||||
await db.SqliteDbContext.SaveChangesAsync();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Role Ban
|
||||
public override async Task<ServerRoleBanDef?> GetServerRoleBanAsync(int id)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
var ban = await db.SqliteDbContext.RoleBan
|
||||
.Include(p => p.Unban)
|
||||
.Where(p => p.Id == id)
|
||||
.SingleOrDefaultAsync();
|
||||
|
||||
return ConvertRoleBan(ban);
|
||||
}
|
||||
|
||||
public override async Task<List<ServerRoleBanDef>> GetServerRoleBansAsync(IPAddress? address,
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId,
|
||||
bool includeUnbanned)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
// SQLite can't do the net masking stuff we need to match IP address ranges.
|
||||
// So just pull down the whole list into memory.
|
||||
var queryBans = await GetAllRoleBans(db.SqliteDbContext, includeUnbanned);
|
||||
|
||||
return queryBans
|
||||
.Where(b => BanMatches(b, address, userId, hwId))
|
||||
.Select(ConvertRoleBan)
|
||||
.ToList()!;
|
||||
}
|
||||
|
||||
private static async Task<List<ServerRoleBan>> GetAllRoleBans(
|
||||
SqliteServerDbContext db,
|
||||
bool includeUnbanned)
|
||||
{
|
||||
IQueryable<ServerRoleBan> query = db.RoleBan.Include(p => p.Unban);
|
||||
if (!includeUnbanned)
|
||||
{
|
||||
query = query.Where(p =>
|
||||
p.Unban == null && (p.ExpirationTime == null || p.ExpirationTime.Value > DateTime.UtcNow));
|
||||
}
|
||||
|
||||
return await query.ToListAsync();
|
||||
}
|
||||
|
||||
private static bool BanMatches(
|
||||
ServerRoleBan ban,
|
||||
IPAddress? address,
|
||||
NetUserId? userId,
|
||||
ImmutableArray<byte>? hwId)
|
||||
{
|
||||
if (address != null && ban.Address is not null && IPAddressExt.IsInSubnet(address, ban.Address.Value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userId is { } id && ban.UserId == id.UserId)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hwId is { } hwIdVar && hwIdVar.AsSpan().SequenceEqual(ban.HWId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override async Task AddServerRoleBanAsync(ServerRoleBanDef serverBan)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
db.SqliteDbContext.RoleBan.Add(new ServerRoleBan
|
||||
{
|
||||
Address = serverBan.Address,
|
||||
Reason = serverBan.Reason,
|
||||
BanningAdmin = serverBan.BanningAdmin?.UserId,
|
||||
HWId = serverBan.HWId?.ToArray(),
|
||||
BanTime = serverBan.BanTime.UtcDateTime,
|
||||
ExpirationTime = serverBan.ExpirationTime?.UtcDateTime,
|
||||
UserId = serverBan.UserId?.UserId,
|
||||
RoleId = serverBan.Role,
|
||||
});
|
||||
|
||||
await db.SqliteDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public override async Task AddServerRoleUnbanAsync(ServerRoleUnbanDef serverUnban)
|
||||
{
|
||||
await using var db = await GetDbImpl();
|
||||
|
||||
db.SqliteDbContext.RoleUnban.Add(new ServerRoleUnban
|
||||
{
|
||||
BanId = serverUnban.BanId,
|
||||
UnbanningAdmin = serverUnban.UnbanningAdmin?.UserId,
|
||||
UnbanTime = serverUnban.UnbanTime.UtcDateTime
|
||||
});
|
||||
|
||||
await db.SqliteDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private static ServerRoleBanDef? ConvertRoleBan(ServerRoleBan? ban)
|
||||
{
|
||||
if (ban == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NetUserId? uid = null;
|
||||
if (ban.UserId is { } guid)
|
||||
{
|
||||
uid = new NetUserId(guid);
|
||||
}
|
||||
|
||||
NetUserId? aUid = null;
|
||||
if (ban.BanningAdmin is { } aGuid)
|
||||
{
|
||||
aUid = new NetUserId(aGuid);
|
||||
}
|
||||
|
||||
var unban = ConvertRoleUnban(ban.Unban);
|
||||
|
||||
return new ServerRoleBanDef(
|
||||
ban.Id,
|
||||
uid,
|
||||
ban.Address,
|
||||
ban.HWId == null ? null : ImmutableArray.Create(ban.HWId),
|
||||
ban.BanTime,
|
||||
ban.ExpirationTime,
|
||||
ban.Reason,
|
||||
aUid,
|
||||
unban,
|
||||
ban.RoleId);
|
||||
}
|
||||
|
||||
private static ServerRoleUnbanDef? ConvertRoleUnban(ServerRoleUnban? unban)
|
||||
{
|
||||
if (unban == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
NetUserId? aUid = null;
|
||||
if (unban.UnbanningAdmin is { } aGuid)
|
||||
{
|
||||
aUid = new NetUserId(aGuid);
|
||||
}
|
||||
|
||||
return new ServerRoleUnbanDef(
|
||||
unban.Id,
|
||||
aUid,
|
||||
unban.UnbanTime);
|
||||
}
|
||||
#endregion
|
||||
|
||||
protected override PlayerRecord MakePlayerRecord(Player record)
|
||||
{
|
||||
|
||||
56
Content.Server/Database/ServerRoleBanDef.cs
Normal file
56
Content.Server/Database/ServerRoleBanDef.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Net;
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Server.Database;
|
||||
|
||||
public sealed class ServerRoleBanDef
|
||||
{
|
||||
public int? Id { get; }
|
||||
public NetUserId? UserId { get; }
|
||||
public (IPAddress address, int cidrMask)? Address { get; }
|
||||
public ImmutableArray<byte>? HWId { get; }
|
||||
|
||||
public DateTimeOffset BanTime { get; }
|
||||
public DateTimeOffset? ExpirationTime { get; }
|
||||
public string Reason { get; }
|
||||
public NetUserId? BanningAdmin { get; }
|
||||
public ServerRoleUnbanDef? Unban { get; }
|
||||
public string Role { get; }
|
||||
|
||||
public ServerRoleBanDef(
|
||||
int? id,
|
||||
NetUserId? userId,
|
||||
(IPAddress, int)? address,
|
||||
ImmutableArray<byte>? hwId,
|
||||
DateTimeOffset banTime,
|
||||
DateTimeOffset? expirationTime,
|
||||
string reason,
|
||||
NetUserId? banningAdmin,
|
||||
ServerRoleUnbanDef? unban,
|
||||
string role)
|
||||
{
|
||||
if (userId == null && address == null && hwId == null)
|
||||
{
|
||||
throw new ArgumentException("Must have at least one of banned user, banned address or hardware ID");
|
||||
}
|
||||
|
||||
if (address is {} addr && addr.Item1.IsIPv4MappedToIPv6)
|
||||
{
|
||||
// Fix IPv6-mapped IPv4 addresses
|
||||
// So that IPv4 addresses are consistent between separate-socket and dual-stack socket modes.
|
||||
address = (addr.Item1.MapToIPv4(), addr.Item2 - 96);
|
||||
}
|
||||
|
||||
Id = id;
|
||||
UserId = userId;
|
||||
Address = address;
|
||||
HWId = hwId;
|
||||
BanTime = banTime;
|
||||
ExpirationTime = expirationTime;
|
||||
Reason = reason;
|
||||
BanningAdmin = banningAdmin;
|
||||
Unban = unban;
|
||||
Role = role;
|
||||
}
|
||||
}
|
||||
19
Content.Server/Database/ServerRoleUnbanDef.cs
Normal file
19
Content.Server/Database/ServerRoleUnbanDef.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using Robust.Shared.Network;
|
||||
|
||||
namespace Content.Server.Database;
|
||||
|
||||
public sealed class ServerRoleUnbanDef
|
||||
{
|
||||
public int BanId { get; }
|
||||
|
||||
public NetUserId? UnbanningAdmin { get; }
|
||||
|
||||
public DateTimeOffset UnbanTime { get; }
|
||||
|
||||
public ServerRoleUnbanDef(int banId, NetUserId? unbanningAdmin, DateTimeOffset unbanTime)
|
||||
{
|
||||
BanId = banId;
|
||||
UnbanningAdmin = unbanningAdmin;
|
||||
UnbanTime = unbanTime;
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,7 @@ namespace Content.Server.Entry
|
||||
IoCManager.Resolve<IGameMapManager>().Initialize();
|
||||
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<GameTicker>().PostInitialize();
|
||||
IoCManager.Resolve<IBqlQueryManager>().DoAutoRegistrations();
|
||||
IoCManager.Resolve<RoleBanManager>().Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Shared.CCVar;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.MobState.Components;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
@@ -18,6 +19,56 @@ namespace Content.Server.GameTicking
|
||||
|
||||
private GamePresetPrototype? _preset;
|
||||
|
||||
private bool StartPreset(IPlayerSession[] origReadyPlayers, bool force)
|
||||
{
|
||||
var startAttempt = new RoundStartAttemptEvent(origReadyPlayers, force);
|
||||
RaiseLocalEvent(startAttempt);
|
||||
|
||||
if (!startAttempt.Cancelled)
|
||||
return true;
|
||||
|
||||
var presetTitle = _preset != null ? Loc.GetString(_preset.ModeTitle) : string.Empty;
|
||||
|
||||
void FailedPresetRestart()
|
||||
{
|
||||
SendServerMessage(Loc.GetString("game-ticker-start-round-cannot-start-game-mode-restart",
|
||||
("failedGameMode", presetTitle)));
|
||||
RestartRound();
|
||||
DelayStart(TimeSpan.FromSeconds(PresetFailedCooldownIncrease));
|
||||
}
|
||||
|
||||
if (_configurationManager.GetCVar(CCVars.GameLobbyFallbackEnabled))
|
||||
{
|
||||
var oldPreset = _preset;
|
||||
ClearGameRules();
|
||||
SetGamePreset(_configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset));
|
||||
AddGamePresetRules();
|
||||
StartGamePresetRules();
|
||||
|
||||
startAttempt.Uncancel();
|
||||
RaiseLocalEvent(startAttempt);
|
||||
|
||||
_chatManager.DispatchServerAnnouncement(
|
||||
Loc.GetString("game-ticker-start-round-cannot-start-game-mode-fallback",
|
||||
("failedGameMode", presetTitle),
|
||||
("fallbackMode", Loc.GetString(_preset!.ModeTitle))));
|
||||
|
||||
if (startAttempt.Cancelled)
|
||||
{
|
||||
FailedPresetRestart();
|
||||
}
|
||||
|
||||
RefreshLateJoinAllowed();
|
||||
}
|
||||
else
|
||||
{
|
||||
FailedPresetRestart();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void InitializeGamePreset()
|
||||
{
|
||||
SetGamePreset(_configurationManager.GetCVar(CCVars.GameLobbyDefaultPreset));
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
@@ -7,12 +6,10 @@ using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Station;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameTicking
|
||||
{
|
||||
@@ -25,17 +22,18 @@ namespace Content.Server.GameTicking
|
||||
[ViewVariables]
|
||||
private readonly Dictionary<string, int> _spawnedPositions = new();
|
||||
|
||||
private Dictionary<IPlayerSession, (string, StationId)> AssignJobs(List<IPlayerSession> available,
|
||||
private Dictionary<IPlayerSession, (string, StationId)> AssignJobs(List<IPlayerSession> availablePlayers,
|
||||
Dictionary<NetUserId, HumanoidCharacterProfile> profiles)
|
||||
{
|
||||
var assigned = new Dictionary<IPlayerSession, (string, StationId)>();
|
||||
|
||||
List<(IPlayerSession, List<string>)> GetPlayersJobCandidates(bool heads, JobPriority i)
|
||||
{
|
||||
return available.Select(player =>
|
||||
return availablePlayers.Select(player =>
|
||||
{
|
||||
var profile = profiles[player.UserId];
|
||||
|
||||
var roleBans = _roleBanManager.GetJobBans(player.UserId);
|
||||
var availableJobs = profile.JobPriorities
|
||||
.Where(j =>
|
||||
{
|
||||
@@ -53,6 +51,7 @@ namespace Content.Server.GameTicking
|
||||
|
||||
return priority == i;
|
||||
})
|
||||
.Where(p => roleBans != null && !roleBans.Contains(p.Key))
|
||||
.Select(j => j.Key)
|
||||
.ToList();
|
||||
|
||||
@@ -85,7 +84,7 @@ namespace Content.Server.GameTicking
|
||||
}
|
||||
}
|
||||
|
||||
available.RemoveAll(a => assigned.ContainsKey(a));
|
||||
availablePlayers.RemoveAll(a => assigned.ContainsKey(a));
|
||||
}
|
||||
|
||||
// Current strategy is to fill each station one by one.
|
||||
@@ -106,14 +105,17 @@ namespace Content.Server.GameTicking
|
||||
return assigned;
|
||||
}
|
||||
|
||||
private string? PickBestAvailableJob(HumanoidCharacterProfile profile, StationId station)
|
||||
private string? PickBestAvailableJob(IPlayerSession playerSession, HumanoidCharacterProfile profile,
|
||||
StationId station)
|
||||
{
|
||||
var available = _stationSystem.StationInfo[station].JobList;
|
||||
|
||||
bool TryPick(JobPriority priority, [NotNullWhen(true)] out string? jobId)
|
||||
{
|
||||
var roleBans = _roleBanManager.GetJobBans(playerSession.UserId);
|
||||
var filtered = profile.JobPriorities
|
||||
.Where(p => p.Value == priority)
|
||||
.Where(p => roleBans != null && !roleBans.Contains(p.Key))
|
||||
.Select(p => p.Key)
|
||||
.ToList();
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Content.Server.GameTicking
|
||||
[ViewVariables]
|
||||
public int RoundId { get; private set; }
|
||||
|
||||
private void PreRoundSetup()
|
||||
private void LoadMaps()
|
||||
{
|
||||
AddGamePresetRules();
|
||||
|
||||
@@ -192,6 +192,14 @@ namespace Content.Server.GameTicking
|
||||
|
||||
StartGamePresetRules();
|
||||
|
||||
RoundLengthMetric.Set(0);
|
||||
|
||||
var playerIds = _playersInLobby.Keys.Select(player => player.UserId.UserId).ToArray();
|
||||
RoundId = await _db.AddNewRound(playerIds);
|
||||
|
||||
var startingEvent = new RoundStartingEvent();
|
||||
RaiseLocalEvent(startingEvent);
|
||||
|
||||
List<IPlayerSession> readyPlayers;
|
||||
if (LobbyEnabled)
|
||||
{
|
||||
@@ -203,13 +211,13 @@ namespace Content.Server.GameTicking
|
||||
readyPlayers = _playersInLobby.Keys.ToList();
|
||||
}
|
||||
|
||||
RoundLengthMetric.Set(0);
|
||||
|
||||
var playerIds = _playersInLobby.Keys.Select(player => player.UserId.UserId).ToArray();
|
||||
RoundId = await _db.AddNewRound(playerIds);
|
||||
|
||||
var startingEvent = new RoundStartingEvent();
|
||||
RaiseLocalEvent(startingEvent);
|
||||
readyPlayers.RemoveAll(p =>
|
||||
{
|
||||
if (_roleBanManager.GetRoleBans(p.UserId) != null)
|
||||
return false;
|
||||
Logger.ErrorS("RoleBans", $"Role bans for player {p} {p.UserId} have not been loaded yet.");
|
||||
return true;
|
||||
});
|
||||
|
||||
// Get the profiles for each player for easier lookup.
|
||||
var profiles = _prefsManager.GetSelectedProfilesForPlayers(
|
||||
@@ -227,106 +235,13 @@ namespace Content.Server.GameTicking
|
||||
|
||||
var origReadyPlayers = readyPlayers.ToArray();
|
||||
|
||||
var startAttempt = new RoundStartAttemptEvent(origReadyPlayers, force);
|
||||
RaiseLocalEvent(startAttempt);
|
||||
|
||||
var presetTitle = _preset != null ? Loc.GetString(_preset.ModeTitle) : string.Empty;
|
||||
|
||||
void FailedPresetRestart()
|
||||
{
|
||||
SendServerMessage(Loc.GetString("game-ticker-start-round-cannot-start-game-mode-restart",
|
||||
("failedGameMode", presetTitle)));
|
||||
RestartRound();
|
||||
DelayStart(TimeSpan.FromSeconds(PresetFailedCooldownIncrease));
|
||||
}
|
||||
|
||||
if (startAttempt.Cancelled)
|
||||
{
|
||||
if (_configurationManager.GetCVar(CCVars.GameLobbyFallbackEnabled))
|
||||
{
|
||||
var oldPreset = _preset;
|
||||
ClearGameRules();
|
||||
SetGamePreset(_configurationManager.GetCVar(CCVars.GameLobbyFallbackPreset));
|
||||
AddGamePresetRules();
|
||||
StartGamePresetRules();
|
||||
|
||||
startAttempt.Uncancel();
|
||||
RaiseLocalEvent(startAttempt);
|
||||
|
||||
_chatManager.DispatchServerAnnouncement(
|
||||
Loc.GetString("game-ticker-start-round-cannot-start-game-mode-fallback",
|
||||
("failedGameMode", presetTitle),
|
||||
("fallbackMode", Loc.GetString(_preset!.ModeTitle))));
|
||||
|
||||
if (startAttempt.Cancelled)
|
||||
{
|
||||
FailedPresetRestart();
|
||||
}
|
||||
|
||||
RefreshLateJoinAllowed();
|
||||
}
|
||||
else
|
||||
{
|
||||
FailedPresetRestart();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!StartPreset(origReadyPlayers, force))
|
||||
return;
|
||||
|
||||
// MapInitialize *before* spawning players, our codebase is too shit to do it afterwards...
|
||||
_mapManager.DoMapInitialize(DefaultMap);
|
||||
|
||||
// Allow game rules to spawn players by themselves if needed. (For example, nuke ops or wizard)
|
||||
RaiseLocalEvent(new RulePlayerSpawningEvent(readyPlayers, profiles, force));
|
||||
|
||||
var assignedJobs = AssignJobs(readyPlayers, profiles);
|
||||
|
||||
// For players without jobs, give them the overflow job if they have that set...
|
||||
foreach (var player in origReadyPlayers)
|
||||
{
|
||||
if (assignedJobs.ContainsKey(player))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = profiles[player.UserId];
|
||||
if (profile.PreferenceUnavailable == PreferenceUnavailableMode.SpawnAsOverflow)
|
||||
{
|
||||
// Pick a random station
|
||||
var stations = _stationSystem.StationInfo.Keys.ToList();
|
||||
_robustRandom.Shuffle(stations);
|
||||
|
||||
if (stations.Count == 0)
|
||||
{
|
||||
assignedJobs.Add(player, (FallbackOverflowJob, StationId.Invalid));
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var station in stations)
|
||||
{
|
||||
// Pick a random overflow job from that station
|
||||
var overflows = _stationSystem.StationInfo[station].MapPrototype.OverflowJobs.Clone();
|
||||
_robustRandom.Shuffle(overflows);
|
||||
|
||||
// Stations with no overflow slots should simply get skipped over.
|
||||
if (overflows.Count == 0)
|
||||
continue;
|
||||
|
||||
// If the overflow exists, put them in as it.
|
||||
assignedJobs.Add(player, (overflows[0], stations[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn everybody in!
|
||||
foreach (var (player, (job, station)) in assignedJobs)
|
||||
{
|
||||
SpawnPlayer(player, profiles[player.UserId], station, job, false);
|
||||
}
|
||||
|
||||
RefreshLateJoinAllowed();
|
||||
|
||||
// Allow rules to add roles to players who have been spawned in. (For example, on-station traitors)
|
||||
RaiseLocalEvent(new RulePlayerJobsAssignedEvent(assignedJobs.Keys.ToArray(), profiles, force));
|
||||
SpawnPlayers(readyPlayers, origReadyPlayers, profiles, force);
|
||||
|
||||
_roundStartDateTime = DateTime.UtcNow;
|
||||
RunLevel = GameRunLevel.InRound;
|
||||
@@ -458,7 +373,7 @@ namespace Content.Server.GameTicking
|
||||
RunLevel = GameRunLevel.PreRoundLobby;
|
||||
LobbySong = _robustRandom.Pick(_lobbyMusicCollection.PickFiles).ToString();
|
||||
ResettingCleanup();
|
||||
PreRoundSetup();
|
||||
LoadMaps();
|
||||
|
||||
if (!LobbyEnabled)
|
||||
{
|
||||
@@ -508,6 +423,8 @@ namespace Content.Server.GameTicking
|
||||
|
||||
_mapManager.Restart();
|
||||
|
||||
_roleBanManager.Restart();
|
||||
|
||||
// Clear up any game rules.
|
||||
ClearGameRules();
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Content.Server.Access.Systems;
|
||||
@@ -22,13 +20,10 @@ using Content.Shared.Roles;
|
||||
using Content.Shared.Species;
|
||||
using Content.Shared.Station;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameTicking
|
||||
{
|
||||
@@ -48,6 +43,71 @@ namespace Content.Server.GameTicking
|
||||
// Mainly to avoid allocations.
|
||||
private readonly List<EntityCoordinates> _possiblePositions = new();
|
||||
|
||||
private void SpawnPlayers(List<IPlayerSession> readyPlayers, IPlayerSession[] origReadyPlayers,
|
||||
Dictionary<NetUserId, HumanoidCharacterProfile> profiles, bool force)
|
||||
{
|
||||
// Allow game rules to spawn players by themselves if needed. (For example, nuke ops or wizard)
|
||||
RaiseLocalEvent(new RulePlayerSpawningEvent(readyPlayers, profiles, force));
|
||||
|
||||
var assignedJobs = AssignJobs(readyPlayers, profiles);
|
||||
|
||||
AssignOverflowJobs(assignedJobs, origReadyPlayers, profiles);
|
||||
|
||||
// Spawn everybody in!
|
||||
foreach (var (player, (job, station)) in assignedJobs)
|
||||
{
|
||||
SpawnPlayer(player, profiles[player.UserId], station, job, false);
|
||||
}
|
||||
|
||||
RefreshLateJoinAllowed();
|
||||
|
||||
// Allow rules to add roles to players who have been spawned in. (For example, on-station traitors)
|
||||
RaiseLocalEvent(new RulePlayerJobsAssignedEvent(assignedJobs.Keys.ToArray(), profiles, force));
|
||||
}
|
||||
|
||||
private void AssignOverflowJobs(IDictionary<IPlayerSession, (string, StationId)> assignedJobs,
|
||||
IPlayerSession[] origReadyPlayers, IReadOnlyDictionary<NetUserId, HumanoidCharacterProfile> profiles)
|
||||
{
|
||||
// For players without jobs, give them the overflow job if they have that set...
|
||||
foreach (var player in origReadyPlayers)
|
||||
{
|
||||
if (assignedJobs.ContainsKey(player))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var profile = profiles[player.UserId];
|
||||
if (profile.PreferenceUnavailable != PreferenceUnavailableMode.SpawnAsOverflow)
|
||||
continue;
|
||||
|
||||
// Pick a random station
|
||||
var stations = _stationSystem.StationInfo.Keys.ToList();
|
||||
|
||||
if (stations.Count == 0)
|
||||
{
|
||||
assignedJobs.Add(player, (FallbackOverflowJob, StationId.Invalid));
|
||||
continue;
|
||||
}
|
||||
|
||||
_robustRandom.Shuffle(stations);
|
||||
|
||||
foreach (var station in stations)
|
||||
{
|
||||
// Pick a random overflow job from that station
|
||||
var overflows = _stationSystem.StationInfo[station].MapPrototype.OverflowJobs.Clone();
|
||||
_robustRandom.Shuffle(overflows);
|
||||
|
||||
// Stations with no overflow slots should simply get skipped over.
|
||||
if (overflows.Count == 0)
|
||||
continue;
|
||||
|
||||
// If the overflow exists, put them in as it.
|
||||
assignedJobs.Add(player, (overflows[0], stations[0]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnPlayer(IPlayerSession player, StationId station, string? jobId = null, bool lateJoin = true)
|
||||
{
|
||||
var character = GetPlayerProfile(player);
|
||||
@@ -90,7 +150,7 @@ namespace Content.Server.GameTicking
|
||||
}
|
||||
|
||||
// Pick best job best on prefs.
|
||||
jobId ??= PickBestAvailableJob(character, station);
|
||||
jobId ??= PickBestAvailableJob(player, character, station);
|
||||
// If no job available, stay in lobby, or if no lobby spawn as observer
|
||||
if (jobId is null)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.CharacterAppearance.Systems;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Ghost;
|
||||
@@ -16,14 +17,12 @@ using Robust.Shared.Configuration;
|
||||
#if EXCEPTION_TOLERANCE
|
||||
using Robust.Shared.Exceptions;
|
||||
#endif
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.GameTicking
|
||||
{
|
||||
@@ -99,5 +98,6 @@ namespace Content.Server.GameTicking
|
||||
[Dependency] private readonly PDASystem _pdaSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly GhostSystem _ghosts = default!;
|
||||
[Dependency] private readonly RoleBanManager _roleBanManager = default!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace Content.Server.IoC
|
||||
IoCManager.Register<IGameMapManager, GameMapManager>();
|
||||
IoCManager.Register<IGamePrototypeLoadManager, GamePrototypeLoadManager>();
|
||||
IoCManager.Register<RulesManager, RulesManager>();
|
||||
IoCManager.Register<RoleBanManager, RoleBanManager>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user