Holy crap auth works (#2099)
* Holy crap auth works * Fix some usages of UserID instead of UserName * Refactor preferences. They be non-async now. Also faster. * Rename DbContext. * Guest username assignment. * Fix saving of profiles. * Don't store data for guests. * Fix generating invalid random colors. * Don't allow dumb garbage for char preferences. * Bans. * Lol forgot to fill out the command description. * Connection log. * Rename all the tables and columns to be snake_case. * Re-do migrations. * Fixing tests and warnings. * Update submodule
This commit is contained in:
committed by
GitHub
parent
8a33e0a9bd
commit
66c8a68891
@@ -28,7 +28,7 @@ namespace Content.Client.GameTicking
|
|||||||
[ViewVariables] public string ServerInfoBlob { get; private set; }
|
[ViewVariables] public string ServerInfoBlob { get; private set; }
|
||||||
[ViewVariables] public DateTime StartTime { get; private set; }
|
[ViewVariables] public DateTime StartTime { get; private set; }
|
||||||
[ViewVariables] public bool Paused { get; private set; }
|
[ViewVariables] public bool Paused { get; private set; }
|
||||||
[ViewVariables] public Dictionary<NetSessionId, PlayerStatus> Status { get; private set; }
|
[ViewVariables] public Dictionary<NetUserId, PlayerStatus> Status { get; private set; }
|
||||||
|
|
||||||
public event Action InfoBlobUpdated;
|
public event Action InfoBlobUpdated;
|
||||||
public event Action LobbyStatusUpdated;
|
public event Action LobbyStatusUpdated;
|
||||||
@@ -52,7 +52,7 @@ namespace Content.Client.GameTicking
|
|||||||
});
|
});
|
||||||
_netManager.RegisterNetMessage<MsgTickerLateJoinStatus>(nameof(MsgTickerLateJoinStatus), LateJoinStatus);
|
_netManager.RegisterNetMessage<MsgTickerLateJoinStatus>(nameof(MsgTickerLateJoinStatus), LateJoinStatus);
|
||||||
|
|
||||||
Status = new Dictionary<NetSessionId, PlayerStatus>();
|
Status = new Dictionary<NetUserId, PlayerStatus>();
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace Content.Client.Interfaces
|
|||||||
bool DisallowedLateJoin { get; }
|
bool DisallowedLateJoin { get; }
|
||||||
DateTime StartTime { get; }
|
DateTime StartTime { get; }
|
||||||
bool Paused { get; }
|
bool Paused { get; }
|
||||||
Dictionary<NetSessionId, PlayerStatus> Status { get; }
|
Dictionary<NetUserId, PlayerStatus> Status { get; }
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
event Action InfoBlobUpdated;
|
event Action InfoBlobUpdated;
|
||||||
|
|||||||
@@ -220,10 +220,10 @@ namespace Content.Client.State
|
|||||||
if (!_clientGameTicker.IsGameStarted)
|
if (!_clientGameTicker.IsGameStarted)
|
||||||
{
|
{
|
||||||
var status = PlayerStatus.NotReady;
|
var status = PlayerStatus.NotReady;
|
||||||
if (session.SessionId == _playerManager.LocalPlayer.SessionId)
|
if (session.UserId == _playerManager.LocalPlayer.UserId)
|
||||||
status = _clientGameTicker.AreWeReady ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
status = _clientGameTicker.AreWeReady ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
||||||
else
|
else
|
||||||
_clientGameTicker.Status.TryGetValue(session.SessionId, out status);
|
_clientGameTicker.Status.TryGetValue(session.UserId, out status);
|
||||||
|
|
||||||
readyState = status switch
|
readyState = status switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Content.Shared.Preferences.Appearance;
|
using Content.Shared.Preferences.Appearance;
|
||||||
using Content.Shared.Text;
|
using Content.Shared.Text;
|
||||||
using Robust.Shared.Interfaces.Random;
|
using Robust.Shared.Interfaces.Random;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.Client.UserInterface
|
namespace Content.Client.UserInterface
|
||||||
@@ -51,9 +53,9 @@ namespace Content.Client.UserInterface
|
|||||||
|
|
||||||
var newHairColor = _random.Pick(HairStyles.RealisticHairColors);
|
var newHairColor = _random.Pick(HairStyles.RealisticHairColors);
|
||||||
newHairColor = newHairColor
|
newHairColor = newHairColor
|
||||||
.WithRed(newHairColor.R + _random.Next(-25, 25) / 100f)
|
.WithRed(RandomizeColor(newHairColor.R))
|
||||||
.WithGreen(newHairColor.G + _random.Next(-25, 25) / 100f)
|
.WithGreen(RandomizeColor(newHairColor.G))
|
||||||
.WithBlue(newHairColor.B + _random.Next(-25, 25) / 100f);
|
.WithBlue(RandomizeColor(newHairColor.B));
|
||||||
|
|
||||||
Profile = Profile.WithCharacterAppearance(
|
Profile = Profile.WithCharacterAppearance(
|
||||||
Profile.Appearance
|
Profile.Appearance
|
||||||
@@ -62,6 +64,11 @@ namespace Content.Client.UserInterface
|
|||||||
.WithHairColor(newHairColor)
|
.WithHairColor(newHairColor)
|
||||||
.WithFacialHairColor(newHairColor));
|
.WithFacialHairColor(newHairColor));
|
||||||
UpdateHairPickers();
|
UpdateHairPickers();
|
||||||
|
|
||||||
|
float RandomizeColor(float channel)
|
||||||
|
{
|
||||||
|
return MathHelper.Clamp01(channel + _random.Next(-25, 25) / 100f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
playerEnt = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
|
playerEnt = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
|
||||||
visitEnt = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
|
visitEnt = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
|
||||||
|
|
||||||
mind = new Mind(player.SessionId);
|
mind = new Mind(player.UserId);
|
||||||
player.ContentData().Mind = mind;
|
player.ContentData().Mind = mind;
|
||||||
|
|
||||||
mind.TransferTo(playerEnt);
|
mind.TransferTo(playerEnt);
|
||||||
@@ -81,7 +81,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
playerEnt = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
|
playerEnt = entMgr.SpawnEntity(null, MapCoordinates.Nullspace);
|
||||||
|
|
||||||
mind = new Mind(player.SessionId);
|
mind = new Mind(player.UserId);
|
||||||
player.ContentData().Mind = mind;
|
player.ContentData().Mind = mind;
|
||||||
|
|
||||||
mind.TransferTo(playerEnt);
|
mind.TransferTo(playerEnt);
|
||||||
@@ -130,7 +130,7 @@ namespace Content.IntegrationTests.Tests
|
|||||||
|
|
||||||
playerEnt = entMgr.SpawnEntity(null, grid.ToCoordinates());
|
playerEnt = entMgr.SpawnEntity(null, grid.ToCoordinates());
|
||||||
|
|
||||||
mind = new Mind(player.SessionId);
|
mind = new Mind(player.UserId);
|
||||||
player.ContentData().Mind = mind;
|
player.ContentData().Mind = mind;
|
||||||
|
|
||||||
mind.TransferTo(playerEnt);
|
mind.TransferTo(playerEnt);
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
using Microsoft.Data.Sqlite;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Npgsql;
|
|
||||||
|
|
||||||
namespace Content.Server.Database
|
|
||||||
{
|
|
||||||
public interface IDatabaseConfiguration
|
|
||||||
{
|
|
||||||
DbContextOptions<PreferencesDbContext> Options { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PostgresConfiguration : IDatabaseConfiguration
|
|
||||||
{
|
|
||||||
private readonly string _database;
|
|
||||||
private readonly string _host;
|
|
||||||
private readonly string _password;
|
|
||||||
private readonly int _port;
|
|
||||||
private readonly string _username;
|
|
||||||
|
|
||||||
public PostgresConfiguration(string host,
|
|
||||||
int port,
|
|
||||||
string database,
|
|
||||||
string username,
|
|
||||||
string password)
|
|
||||||
{
|
|
||||||
_host = host;
|
|
||||||
_port = port;
|
|
||||||
_database = database;
|
|
||||||
_username = username;
|
|
||||||
_password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DbContextOptions<PreferencesDbContext> Options
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var optionsBuilder = new DbContextOptionsBuilder<PreferencesDbContext>();
|
|
||||||
var connectionString = new NpgsqlConnectionStringBuilder
|
|
||||||
{
|
|
||||||
Host = _host,
|
|
||||||
Port = _port,
|
|
||||||
Database = _database,
|
|
||||||
Username = _username,
|
|
||||||
Password = _password
|
|
||||||
}.ConnectionString;
|
|
||||||
optionsBuilder.UseNpgsql(connectionString);
|
|
||||||
return optionsBuilder.Options;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SqliteConfiguration : IDatabaseConfiguration
|
|
||||||
{
|
|
||||||
private readonly string? _databaseFilePath;
|
|
||||||
|
|
||||||
/// <param name="databaseFilePath">If null, an in-memory database is used.</param>
|
|
||||||
public SqliteConfiguration(string? databaseFilePath)
|
|
||||||
{
|
|
||||||
_databaseFilePath = databaseFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DbContextOptions<PreferencesDbContext> Options
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var optionsBuilder = new DbContextOptionsBuilder<PreferencesDbContext>();
|
|
||||||
SqliteConnection connection;
|
|
||||||
if (_databaseFilePath != null)
|
|
||||||
{
|
|
||||||
connection = new SqliteConnection($"Data Source={_databaseFilePath}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
connection = new SqliteConnection("Data Source=:memory:");
|
|
||||||
// When using an in-memory DB we have to open it manually
|
|
||||||
// so EFCore doesn't open, close and wipe it.
|
|
||||||
connection.Open();
|
|
||||||
}
|
|
||||||
|
|
||||||
optionsBuilder.UseSqlite(connection);
|
|
||||||
return optionsBuilder.Options;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -21,4 +21,9 @@
|
|||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Migrations\Postgres" />
|
||||||
|
<Folder Include="Migrations\Sqlite" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,151 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using Content.Server.Database;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
|
||||||
{
|
|
||||||
[DbContext(typeof(PostgresPreferencesDbContext))]
|
|
||||||
[Migration("20200124133512_InitialPg")]
|
|
||||||
partial class InitialPg
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.0")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
|
||||||
{
|
|
||||||
public partial class InitialPg : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Preferences",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
PrefsId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Username = table.Column<string>(nullable: false),
|
|
||||||
SelectedCharacterSlot = table.Column<int>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Preferences", x => x.PrefsId);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "HumanoidProfile",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
HumanoidProfileId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
Slot = table.Column<int>(nullable: false),
|
|
||||||
SlotName = table.Column<string>(nullable: false),
|
|
||||||
CharacterName = table.Column<string>(nullable: false),
|
|
||||||
Age = table.Column<int>(nullable: false),
|
|
||||||
Sex = table.Column<string>(nullable: false),
|
|
||||||
HairName = table.Column<string>(nullable: false),
|
|
||||||
HairColor = table.Column<string>(nullable: false),
|
|
||||||
FacialHairName = table.Column<string>(nullable: false),
|
|
||||||
FacialHairColor = table.Column<string>(nullable: false),
|
|
||||||
EyeColor = table.Column<string>(nullable: false),
|
|
||||||
SkinColor = table.Column<string>(nullable: false),
|
|
||||||
PreferenceUnavailable = table.Column<int>(nullable: false),
|
|
||||||
PrefsId = table.Column<int>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_HumanoidProfile", x => x.HumanoidProfileId);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_HumanoidProfile_Preferences_PrefsId",
|
|
||||||
column: x => x.PrefsId,
|
|
||||||
principalTable: "Preferences",
|
|
||||||
principalColumn: "PrefsId",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Job",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
JobId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
ProfileHumanoidProfileId = table.Column<int>(nullable: false),
|
|
||||||
JobName = table.Column<string>(nullable: false),
|
|
||||||
Priority = table.Column<int>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Job", x => x.JobId);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Job_HumanoidProfile_ProfileHumanoidProfileId",
|
|
||||||
column: x => x.ProfileHumanoidProfileId,
|
|
||||||
principalTable: "HumanoidProfile",
|
|
||||||
principalColumn: "HumanoidProfileId",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_HumanoidProfile_PrefsId",
|
|
||||||
table: "HumanoidProfile",
|
|
||||||
column: "PrefsId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Job_ProfileHumanoidProfileId",
|
|
||||||
table: "Job",
|
|
||||||
column: "ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Preferences_Username",
|
|
||||||
table: "Preferences",
|
|
||||||
column: "Username",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Job");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "HumanoidProfile");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Preferences");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using Content.Server.Database;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
|
||||||
{
|
|
||||||
[DbContext(typeof(PostgresPreferencesDbContext))]
|
|
||||||
[Migration("20200625230829_AddSlotPrefsIdIndex")]
|
|
||||||
partial class AddSlotPrefsIdIndex
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.4")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Slot", "PrefsId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
|
||||||
{
|
|
||||||
public partial class AddSlotPrefsIdIndex : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_HumanoidProfile_Slot_PrefsId",
|
|
||||||
table: "HumanoidProfile",
|
|
||||||
columns: new[] { "Slot", "PrefsId" },
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropIndex(
|
|
||||||
name: "IX_HumanoidProfile_Slot_PrefsId",
|
|
||||||
table: "HumanoidProfile");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using Content.Server.Database;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
|
||||||
{
|
|
||||||
[DbContext(typeof(PostgresPreferencesDbContext))]
|
|
||||||
[Migration("20200706172726_Antags")]
|
|
||||||
partial class Antags
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.4")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("AntagId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<string>("AntagName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("AntagId");
|
|
||||||
|
|
||||||
b.HasIndex("HumanoidProfileId", "AntagName")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Antag");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Slot", "PrefsId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Antags")
|
|
||||||
.HasForeignKey("HumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
|
||||||
{
|
|
||||||
public partial class Antags : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Antag",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
AntagId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
||||||
HumanoidProfileId = table.Column<int>(nullable: false),
|
|
||||||
AntagName = table.Column<string>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Antag", x => x.AntagId);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Antag_HumanoidProfile_HumanoidProfileId",
|
|
||||||
column: x => x.HumanoidProfileId,
|
|
||||||
principalTable: "HumanoidProfile",
|
|
||||||
principalColumn: "HumanoidProfileId",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Antag_HumanoidProfileId_AntagName",
|
|
||||||
table: "Antag",
|
|
||||||
columns: new[] { "HumanoidProfileId", "AntagName" },
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Antag");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
391
Content.Server.Database/Migrations/Postgres/20200929113117_Init.Designer.cs
generated
Normal file
391
Content.Server.Database/Migrations/Postgres/20200929113117_Init.Designer.cs
generated
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
[DbContext(typeof(PostgresServerDbContext))]
|
||||||
|
[Migration("20200929113117_Init")]
|
||||||
|
partial class Init
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<IPAddress>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresPlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<IPAddress>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("server_ban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<ValueTuple<IPAddress, int>?>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Address");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("server_ban");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("server_unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.PostgresServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.PostgresServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,285 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
public partial class Init : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "assigned_user_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
assigned_user_id_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
user_name = table.Column<string>(nullable: false),
|
||||||
|
user_id = table.Column<Guid>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_assigned_user_id", x => x.assigned_user_id_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "connection_log",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
connection_log_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
user_name = table.Column<string>(nullable: false),
|
||||||
|
time = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||||
|
address = table.Column<IPAddress>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_connection_log", x => x.connection_log_id);
|
||||||
|
table.CheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "player",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
player_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
first_seen_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||||
|
last_seen_user_name = table.Column<string>(nullable: false),
|
||||||
|
last_seen_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
|
||||||
|
last_seen_address = table.Column<IPAddress>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_player", x => x.player_id);
|
||||||
|
table.CheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "preference",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
preference_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
selected_character_slot = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_preference", x => x.preference_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "server_ban",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
server_ban_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
user_id = table.Column<Guid>(nullable: true),
|
||||||
|
address = table.Column<ValueTuple<IPAddress, int>>(type: "inet", 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>(nullable: false),
|
||||||
|
banning_admin = table.Column<Guid>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_server_ban", x => x.server_ban_id);
|
||||||
|
table.CheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
table.CheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
slot = table.Column<int>(nullable: false),
|
||||||
|
char_name = table.Column<string>(nullable: false),
|
||||||
|
age = table.Column<int>(nullable: false),
|
||||||
|
sex = table.Column<string>(nullable: false),
|
||||||
|
hair_name = table.Column<string>(nullable: false),
|
||||||
|
hair_color = table.Column<string>(nullable: false),
|
||||||
|
facial_hair_name = table.Column<string>(nullable: false),
|
||||||
|
facial_hair_color = table.Column<string>(nullable: false),
|
||||||
|
eye_color = table.Column<string>(nullable: false),
|
||||||
|
skin_color = table.Column<string>(nullable: false),
|
||||||
|
pref_unavailable = table.Column<int>(nullable: false),
|
||||||
|
preference_id = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile", x => x.profile_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_preference_preference_id",
|
||||||
|
column: x => x.preference_id,
|
||||||
|
principalTable: "preference",
|
||||||
|
principalColumn: "preference_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "server_unban",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
unban_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
ban_id = table.Column<int>(nullable: false),
|
||||||
|
unbanning_admin = table.Column<Guid>(nullable: true),
|
||||||
|
unban_time = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_server_unban", x => x.unban_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_server_unban_server_ban_ban_id",
|
||||||
|
column: x => x.ban_id,
|
||||||
|
principalTable: "server_ban",
|
||||||
|
principalColumn: "server_ban_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "antag",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
antag_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
profile_id = table.Column<int>(nullable: false),
|
||||||
|
antag_name = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_antag", x => x.antag_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_antag_profile_profile_id",
|
||||||
|
column: x => x.profile_id,
|
||||||
|
principalTable: "profile",
|
||||||
|
principalColumn: "profile_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "job",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
job_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
profile_id = table.Column<int>(nullable: false),
|
||||||
|
job_name = table.Column<string>(nullable: false),
|
||||||
|
priority = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_job", x => x.job_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_job_profile_profile_id",
|
||||||
|
column: x => x.profile_id,
|
||||||
|
principalTable: "profile",
|
||||||
|
principalColumn: "profile_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_antag_profile_id_antag_name",
|
||||||
|
table: "antag",
|
||||||
|
columns: new[] { "profile_id", "antag_name" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_assigned_user_id_user_id",
|
||||||
|
table: "assigned_user_id",
|
||||||
|
column: "user_id",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_assigned_user_id_user_name",
|
||||||
|
table: "assigned_user_id",
|
||||||
|
column: "user_name",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_connection_log_user_id",
|
||||||
|
table: "connection_log",
|
||||||
|
column: "user_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_job_profile_id",
|
||||||
|
table: "job",
|
||||||
|
column: "profile_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_player_user_id",
|
||||||
|
table: "player",
|
||||||
|
column: "user_id",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_preference_user_id",
|
||||||
|
table: "preference",
|
||||||
|
column: "user_id",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_preference_id",
|
||||||
|
table: "profile",
|
||||||
|
column: "preference_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_slot_preference_id",
|
||||||
|
table: "profile",
|
||||||
|
columns: new[] { "slot", "preference_id" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_server_ban_address",
|
||||||
|
table: "server_ban",
|
||||||
|
column: "address");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_server_ban_user_id",
|
||||||
|
table: "server_ban",
|
||||||
|
column: "user_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_server_unban_ban_id",
|
||||||
|
table: "server_unban",
|
||||||
|
column: "ban_id",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "antag");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "assigned_user_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "connection_log");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "job");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "player");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "server_unban");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "server_ban");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "preference");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
|
||||||
{
|
|
||||||
[DbContext(typeof(PostgresPreferencesDbContext))]
|
|
||||||
partial class PostgresPreferencesDbContextModelSnapshot : ModelSnapshot
|
|
||||||
{
|
|
||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.4")
|
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("AntagId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<string>("AntagName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("AntagId");
|
|
||||||
|
|
||||||
b.HasIndex("HumanoidProfileId", "AntagName")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Antag");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Slot", "PrefsId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("integer")
|
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("integer");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("text");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Antags")
|
|
||||||
.HasForeignKey("HumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,389 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
|
{
|
||||||
|
[DbContext(typeof(PostgresServerDbContext))]
|
||||||
|
partial class PostgresServerDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<IPAddress>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresPlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<IPAddress>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("server_ban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<ValueTuple<IPAddress, int>?>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("inet");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Address");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("server_ban");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
|
||||||
|
b.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("server_unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("text");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.PostgresServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.PostgresServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.PostgresServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
[DbContext(typeof(SqlitePreferencesDbContext))]
|
|
||||||
[Migration("20200118020532_initial")]
|
|
||||||
partial class initial
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.0");
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
public partial class initial : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Preferences",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
PrefsId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
Username = table.Column<string>(nullable: false),
|
|
||||||
SelectedCharacterSlot = table.Column<int>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Preferences", x => x.PrefsId);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "HumanoidProfile",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
HumanoidProfileId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
Slot = table.Column<int>(nullable: false),
|
|
||||||
SlotName = table.Column<string>(nullable: false),
|
|
||||||
CharacterName = table.Column<string>(nullable: false),
|
|
||||||
Age = table.Column<int>(nullable: false),
|
|
||||||
Sex = table.Column<string>(nullable: false),
|
|
||||||
HairName = table.Column<string>(nullable: false),
|
|
||||||
HairColor = table.Column<string>(nullable: false),
|
|
||||||
FacialHairName = table.Column<string>(nullable: false),
|
|
||||||
FacialHairColor = table.Column<string>(nullable: false),
|
|
||||||
EyeColor = table.Column<string>(nullable: false),
|
|
||||||
SkinColor = table.Column<string>(nullable: false),
|
|
||||||
PrefsId = table.Column<int>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_HumanoidProfile", x => x.HumanoidProfileId);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_HumanoidProfile_Preferences_PrefsId",
|
|
||||||
column: x => x.PrefsId,
|
|
||||||
principalTable: "Preferences",
|
|
||||||
principalColumn: "PrefsId",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_HumanoidProfile_PrefsId",
|
|
||||||
table: "HumanoidProfile",
|
|
||||||
column: "PrefsId");
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Preferences_Username",
|
|
||||||
table: "Preferences",
|
|
||||||
column: "Username",
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "HumanoidProfile");
|
|
||||||
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Preferences");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
[DbContext(typeof(SqlitePreferencesDbContext))]
|
|
||||||
[Migration("20200118195640_jobs")]
|
|
||||||
partial class jobs
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.0");
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
public partial class jobs : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Job",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
JobId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
ProfileHumanoidProfileId = table.Column<int>(nullable: false),
|
|
||||||
JobName = table.Column<string>(nullable: false),
|
|
||||||
Priority = table.Column<int>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Job", x => x.JobId);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Job_HumanoidProfile_ProfileHumanoidProfileId",
|
|
||||||
column: x => x.ProfileHumanoidProfileId,
|
|
||||||
principalTable: "HumanoidProfile",
|
|
||||||
principalColumn: "HumanoidProfileId",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Job_ProfileHumanoidProfileId",
|
|
||||||
table: "Job",
|
|
||||||
column: "ProfileHumanoidProfileId");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Job");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
[DbContext(typeof(SqlitePreferencesDbContext))]
|
|
||||||
[Migration("20200119103426_preferenceUnavailable")]
|
|
||||||
partial class preferenceUnavailable
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.0");
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
public partial class preferenceUnavailable : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.AddColumn<int>(
|
|
||||||
name: "PreferenceUnavailable",
|
|
||||||
table: "HumanoidProfile",
|
|
||||||
nullable: false,
|
|
||||||
defaultValue: 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropColumn(
|
|
||||||
name: "PreferenceUnavailable",
|
|
||||||
table: "HumanoidProfile");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using Content.Server.Database;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
[DbContext(typeof(SqlitePreferencesDbContext))]
|
|
||||||
[Migration("20200625230839_AddSlotPrefsIdIndex")]
|
|
||||||
partial class AddSlotPrefsIdIndex
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.4");
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Slot", "PrefsId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
public partial class AddSlotPrefsIdIndex : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_HumanoidProfile_Slot_PrefsId",
|
|
||||||
table: "HumanoidProfile",
|
|
||||||
columns: new[] { "Slot", "PrefsId" },
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropIndex(
|
|
||||||
name: "IX_HumanoidProfile_Slot_PrefsId",
|
|
||||||
table: "HumanoidProfile");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
using Content.Server.Database;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
[DbContext(typeof(SqlitePreferencesDbContext))]
|
|
||||||
[Migration("20200706172741_Antags")]
|
|
||||||
partial class Antags
|
|
||||||
{
|
|
||||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.4");
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("AntagId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("AntagName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("AntagId");
|
|
||||||
|
|
||||||
b.HasIndex("HumanoidProfileId", "AntagName")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Antag");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Slot", "PrefsId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Antags")
|
|
||||||
.HasForeignKey("HumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
public partial class Antags : Migration
|
|
||||||
{
|
|
||||||
protected override void Up(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.CreateTable(
|
|
||||||
name: "Antag",
|
|
||||||
columns: table => new
|
|
||||||
{
|
|
||||||
AntagId = table.Column<int>(nullable: false)
|
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
|
||||||
HumanoidProfileId = table.Column<int>(nullable: false),
|
|
||||||
AntagName = table.Column<string>(nullable: false)
|
|
||||||
},
|
|
||||||
constraints: table =>
|
|
||||||
{
|
|
||||||
table.PrimaryKey("PK_Antag", x => x.AntagId);
|
|
||||||
table.ForeignKey(
|
|
||||||
name: "FK_Antag_HumanoidProfile_HumanoidProfileId",
|
|
||||||
column: x => x.HumanoidProfileId,
|
|
||||||
principalTable: "HumanoidProfile",
|
|
||||||
principalColumn: "HumanoidProfileId",
|
|
||||||
onDelete: ReferentialAction.Cascade);
|
|
||||||
});
|
|
||||||
|
|
||||||
migrationBuilder.CreateIndex(
|
|
||||||
name: "IX_Antag_HumanoidProfileId_AntagName",
|
|
||||||
table: "Antag",
|
|
||||||
columns: new[] { "HumanoidProfileId", "AntagName" },
|
|
||||||
unique: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Down(MigrationBuilder migrationBuilder)
|
|
||||||
{
|
|
||||||
migrationBuilder.DropTable(
|
|
||||||
name: "Antag");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
361
Content.Server.Database/Migrations/Sqlite/20200929113112_Init.Designer.cs
generated
Normal file
361
Content.Server.Database/Migrations/Sqlite/20200929113112_Init.Designer.cs
generated
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
[DbContext(typeof(SqliteServerDbContext))]
|
||||||
|
[Migration("20200929113112_Init")]
|
||||||
|
partial class Init
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqlitePlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.SqliteServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.SqliteServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
258
Content.Server.Database/Migrations/Sqlite/20200929113112_Init.cs
Normal file
258
Content.Server.Database/Migrations/Sqlite/20200929113112_Init.cs
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
public partial class Init : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "assigned_user_id",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
assigned_user_id_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
user_name = table.Column<string>(nullable: false),
|
||||||
|
user_id = table.Column<Guid>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_assigned_user_id", x => x.assigned_user_id_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ban",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ban_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
user_id = table.Column<Guid>(nullable: true),
|
||||||
|
address = table.Column<string>(nullable: true),
|
||||||
|
ban_time = table.Column<DateTime>(nullable: false),
|
||||||
|
expiration_time = table.Column<DateTime>(nullable: true),
|
||||||
|
reason = table.Column<string>(nullable: false),
|
||||||
|
banning_admin = table.Column<Guid>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ban", x => x.ban_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "connection_log",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
connection_log_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
user_name = table.Column<string>(nullable: false),
|
||||||
|
time = table.Column<DateTime>(nullable: false),
|
||||||
|
address = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_connection_log", x => x.connection_log_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "player",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
player_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
first_seen_time = table.Column<DateTime>(nullable: false),
|
||||||
|
last_seen_user_name = table.Column<string>(nullable: false),
|
||||||
|
last_seen_time = table.Column<DateTime>(nullable: false),
|
||||||
|
last_seen_address = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_player", x => x.player_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "preference",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
preference_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
user_id = table.Column<Guid>(nullable: false),
|
||||||
|
selected_character_slot = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_preference", x => x.preference_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "unban",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
unban_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
ban_id = table.Column<int>(nullable: false),
|
||||||
|
unbanning_admin = table.Column<Guid>(nullable: true),
|
||||||
|
unban_time = table.Column<DateTime>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_unban", x => x.unban_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_unban_ban_ban_id",
|
||||||
|
column: x => x.ban_id,
|
||||||
|
principalTable: "ban",
|
||||||
|
principalColumn: "ban_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "profile",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
profile_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
slot = table.Column<int>(nullable: false),
|
||||||
|
char_name = table.Column<string>(nullable: false),
|
||||||
|
age = table.Column<int>(nullable: false),
|
||||||
|
sex = table.Column<string>(nullable: false),
|
||||||
|
hair_name = table.Column<string>(nullable: false),
|
||||||
|
hair_color = table.Column<string>(nullable: false),
|
||||||
|
facial_hair_name = table.Column<string>(nullable: false),
|
||||||
|
facial_hair_color = table.Column<string>(nullable: false),
|
||||||
|
eye_color = table.Column<string>(nullable: false),
|
||||||
|
skin_color = table.Column<string>(nullable: false),
|
||||||
|
pref_unavailable = table.Column<int>(nullable: false),
|
||||||
|
preference_id = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_profile", x => x.profile_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_profile_preference_preference_id",
|
||||||
|
column: x => x.preference_id,
|
||||||
|
principalTable: "preference",
|
||||||
|
principalColumn: "preference_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "antag",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
antag_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
profile_id = table.Column<int>(nullable: false),
|
||||||
|
antag_name = table.Column<string>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_antag", x => x.antag_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_antag_profile_profile_id",
|
||||||
|
column: x => x.profile_id,
|
||||||
|
principalTable: "profile",
|
||||||
|
principalColumn: "profile_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "job",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
job_id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
profile_id = table.Column<int>(nullable: false),
|
||||||
|
job_name = table.Column<string>(nullable: false),
|
||||||
|
priority = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_job", x => x.job_id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_job_profile_profile_id",
|
||||||
|
column: x => x.profile_id,
|
||||||
|
principalTable: "profile",
|
||||||
|
principalColumn: "profile_id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_antag_profile_id_antag_name",
|
||||||
|
table: "antag",
|
||||||
|
columns: new[] { "profile_id", "antag_name" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_assigned_user_id_user_id",
|
||||||
|
table: "assigned_user_id",
|
||||||
|
column: "user_id",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_assigned_user_id_user_name",
|
||||||
|
table: "assigned_user_id",
|
||||||
|
column: "user_name",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_job_profile_id",
|
||||||
|
table: "job",
|
||||||
|
column: "profile_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_preference_user_id",
|
||||||
|
table: "preference",
|
||||||
|
column: "user_id",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_preference_id",
|
||||||
|
table: "profile",
|
||||||
|
column: "preference_id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_profile_slot_preference_id",
|
||||||
|
table: "profile",
|
||||||
|
columns: new[] { "slot", "preference_id" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_unban_ban_id",
|
||||||
|
table: "unban",
|
||||||
|
column: "ban_id",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "antag");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "assigned_user_id");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "connection_log");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "job");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "player");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "unban");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "profile");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ban");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "preference");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
// <auto-generated />
|
|
||||||
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Sqlite
|
|
||||||
{
|
|
||||||
[DbContext(typeof(SqlitePreferencesDbContext))]
|
|
||||||
partial class SqlitePreferencesDbContextModelSnapshot : ModelSnapshot
|
|
||||||
{
|
|
||||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
|
||||||
{
|
|
||||||
#pragma warning disable 612, 618
|
|
||||||
modelBuilder
|
|
||||||
.HasAnnotation("ProductVersion", "3.1.4");
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("AntagId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("AntagName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("AntagId");
|
|
||||||
|
|
||||||
b.HasIndex("HumanoidProfileId", "AntagName")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Antag");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("HumanoidProfileId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("Age")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("CharacterName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("EyeColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("FacialHairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("HairName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("PreferenceUnavailable")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Sex")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("SkinColor")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Slot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("SlotName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("HumanoidProfileId");
|
|
||||||
|
|
||||||
b.HasIndex("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Slot", "PrefsId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("JobId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("JobName")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("Priority")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("ProfileHumanoidProfileId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.HasKey("JobId");
|
|
||||||
|
|
||||||
b.HasIndex("ProfileHumanoidProfileId");
|
|
||||||
|
|
||||||
b.ToTable("Job");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Prefs", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("PrefsId")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<int>("SelectedCharacterSlot")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Username")
|
|
||||||
.IsRequired()
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("PrefsId");
|
|
||||||
|
|
||||||
b.HasIndex("Username")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("Preferences");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Antags")
|
|
||||||
.HasForeignKey("HumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.Prefs", "Prefs")
|
|
||||||
.WithMany("HumanoidProfiles")
|
|
||||||
.HasForeignKey("PrefsId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Content.Server.Database.HumanoidProfile", "Profile")
|
|
||||||
.WithMany("Jobs")
|
|
||||||
.HasForeignKey("ProfileHumanoidProfileId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
});
|
|
||||||
#pragma warning restore 612, 618
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace Content.Server.Database.Migrations.Sqlite
|
||||||
|
{
|
||||||
|
[DbContext(typeof(SqliteServerDbContext))]
|
||||||
|
partial class SqliteServerDbContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.4");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("antag_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("AntagName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("antag_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId", "AntagName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("antag");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.AssignedUserId", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("assigned_user_id_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("UserName")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("assigned_user_id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("job_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("JobName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("job_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Priority")
|
||||||
|
.HasColumnName("priority")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProfileId")
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ProfileId");
|
||||||
|
|
||||||
|
b.ToTable("job");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Preference", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("SelectedCharacterSlot")
|
||||||
|
.HasColumnName("selected_character_slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("preference");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("profile_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Age")
|
||||||
|
.HasColumnName("age")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("CharacterName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("char_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("EyeColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("eye_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("FacialHairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("facial_hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("HairName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("hair_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceId")
|
||||||
|
.HasColumnName("preference_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("PreferenceUnavailable")
|
||||||
|
.HasColumnName("pref_unavailable")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Sex")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("sex")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("SkinColor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("skin_color")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Slot")
|
||||||
|
.HasColumnName("slot")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PreferenceId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PreferenceId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("profile");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteConnectionLog", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("connection_log_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Time")
|
||||||
|
.HasColumnName("time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("connection_log");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqlitePlayer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("player_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstSeenTime")
|
||||||
|
.HasColumnName("first_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenAddress")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastSeenTime")
|
||||||
|
.HasColumnName("last_seen_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("LastSeenUserName")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("last_seen_user_name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("player");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerBan", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Address")
|
||||||
|
.HasColumnName("address")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("BanTime")
|
||||||
|
.HasColumnName("ban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("BanningAdmin")
|
||||||
|
.HasColumnName("banning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("ExpirationTime")
|
||||||
|
.HasColumnName("expiration_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Reason")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnName("reason")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnName("user_id")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("ban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnName("unban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("BanId")
|
||||||
|
.HasColumnName("ban_id")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnbanTime")
|
||||||
|
.HasColumnName("unban_time")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UnbanningAdmin")
|
||||||
|
.HasColumnName("unbanning_admin")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BanId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("unban");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Antag", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Antags")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Job", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Profile", "Profile")
|
||||||
|
.WithMany("Jobs")
|
||||||
|
.HasForeignKey("ProfileId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.Profile", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.Preference", "Preference")
|
||||||
|
.WithMany("Profiles")
|
||||||
|
.HasForeignKey("PreferenceId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Content.Server.Database.SqliteServerUnban", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Content.Server.Database.SqliteServerBan", "Ban")
|
||||||
|
.WithOne("Unban")
|
||||||
|
.HasForeignKey("Content.Server.Database.SqliteServerUnban", "BanId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,42 +1,11 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Content.Server.Database
|
namespace Content.Server.Database
|
||||||
{
|
{
|
||||||
public class PostgresPreferencesDbContext : PreferencesDbContext
|
public abstract class ServerDbContext : DbContext
|
||||||
{
|
|
||||||
// This is used by the "dotnet ef" CLI tool.
|
|
||||||
public PostgresPreferencesDbContext()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
|
||||||
{
|
|
||||||
if(!InitializedWithOptions)
|
|
||||||
options.UseNpgsql("dummy connection string");
|
|
||||||
}
|
|
||||||
|
|
||||||
public PostgresPreferencesDbContext(DbContextOptions<PreferencesDbContext> options) : base(options)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SqlitePreferencesDbContext : PreferencesDbContext
|
|
||||||
{
|
|
||||||
public SqlitePreferencesDbContext()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
|
||||||
{
|
|
||||||
if (!InitializedWithOptions)
|
|
||||||
options.UseSqlite("dummy connection string");
|
|
||||||
}
|
|
||||||
|
|
||||||
public SqlitePreferencesDbContext(DbContextOptions<PreferencesDbContext> options) : base(options)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class PreferencesDbContext : DbContext
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The "dotnet ef" CLI tool uses the parameter-less constructor.
|
/// The "dotnet ef" CLI tool uses the parameter-less constructor.
|
||||||
@@ -44,70 +13,86 @@ namespace Content.Server.Database
|
|||||||
/// To use the context within the application, the options need to be passed the constructor instead.
|
/// To use the context within the application, the options need to be passed the constructor instead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly bool InitializedWithOptions;
|
protected readonly bool InitializedWithOptions;
|
||||||
public PreferencesDbContext()
|
|
||||||
|
public ServerDbContext()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
public PreferencesDbContext(DbContextOptions<PreferencesDbContext> options) : base(options)
|
|
||||||
|
public ServerDbContext(DbContextOptions<ServerDbContext> options) : base(options)
|
||||||
{
|
{
|
||||||
InitializedWithOptions = true;
|
InitializedWithOptions = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<Prefs> Preferences { get; set; } = null!;
|
public DbSet<Preference> Preference { get; set; } = null!;
|
||||||
public DbSet<HumanoidProfile> HumanoidProfile { get; set; } = null!;
|
public DbSet<Profile> Profile { get; set; } = null!;
|
||||||
|
public DbSet<AssignedUserId> AssignedUserId { get; set; } = null!;
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder.Entity<Prefs>()
|
modelBuilder.Entity<Preference>()
|
||||||
.HasIndex(p => p.Username)
|
.HasIndex(p => p.UserId)
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
modelBuilder.Entity<HumanoidProfile>()
|
modelBuilder.Entity<Profile>()
|
||||||
.HasIndex(p => new {p.Slot, p.PrefsId})
|
.HasIndex(p => new {p.Slot, PrefsId = p.PreferenceId})
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
modelBuilder.Entity<Antag>()
|
modelBuilder.Entity<Antag>()
|
||||||
.HasIndex(p => new {p.HumanoidProfileId , p.AntagName})
|
.HasIndex(p => new {HumanoidProfileId = p.ProfileId, p.AntagName})
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<AssignedUserId>()
|
||||||
|
.HasIndex(p => p.UserName)
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
// Can't have two usernames with the same user ID.
|
||||||
|
modelBuilder.Entity<AssignedUserId>()
|
||||||
|
.HasIndex(p => p.UserId)
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Prefs
|
[Table("preference")]
|
||||||
|
public class Preference
|
||||||
{
|
{
|
||||||
public int PrefsId { get; set; }
|
[Column("preference_id")] public int Id { get; set; }
|
||||||
public string Username { get; set; } = null!;
|
[Column("user_id")] public Guid UserId { get; set; }
|
||||||
public int SelectedCharacterSlot { get; set; }
|
[Column("selected_character_slot")] public int SelectedCharacterSlot { get; set; }
|
||||||
public List<HumanoidProfile> HumanoidProfiles { get; } = new List<HumanoidProfile>();
|
public List<Profile> Profiles { get; } = new List<Profile>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class HumanoidProfile
|
[Table("profile")]
|
||||||
|
public class Profile
|
||||||
{
|
{
|
||||||
public int HumanoidProfileId { get; set; }
|
[Column("profile_id")] public int Id { get; set; }
|
||||||
public int Slot { get; set; }
|
[Column("slot")] public int Slot { get; set; }
|
||||||
public string SlotName { get; set; } = null!;
|
[Column("char_name")] public string CharacterName { get; set; } = null!;
|
||||||
public string CharacterName { get; set; } = null!;
|
[Column("age")] public int Age { get; set; }
|
||||||
public int Age { get; set; }
|
[Column("sex")] public string Sex { get; set; } = null!;
|
||||||
public string Sex { get; set; } = null!;
|
[Column("hair_name")] public string HairName { get; set; } = null!;
|
||||||
public string HairName { get; set; } = null!;
|
[Column("hair_color")] public string HairColor { get; set; } = null!;
|
||||||
public string HairColor { get; set; } = null!;
|
[Column("facial_hair_name")] public string FacialHairName { get; set; } = null!;
|
||||||
public string FacialHairName { get; set; } = null!;
|
[Column("facial_hair_color")] public string FacialHairColor { get; set; } = null!;
|
||||||
public string FacialHairColor { get; set; } = null!;
|
[Column("eye_color")] public string EyeColor { get; set; } = null!;
|
||||||
public string EyeColor { get; set; } = null!;
|
[Column("skin_color")] public string SkinColor { get; set; } = null!;
|
||||||
public string SkinColor { get; set; } = null!;
|
|
||||||
public List<Job> Jobs { get; } = new List<Job>();
|
public List<Job> Jobs { get; } = new List<Job>();
|
||||||
public List<Antag> Antags { get; } = new List<Antag>();
|
public List<Antag> Antags { get; } = new List<Antag>();
|
||||||
public DbPreferenceUnavailableMode PreferenceUnavailable { get; set; }
|
|
||||||
|
|
||||||
public int PrefsId { get; set; }
|
[Column("pref_unavailable")] public DbPreferenceUnavailableMode PreferenceUnavailable { get; set; }
|
||||||
public Prefs Prefs { get; set; } = null!;
|
|
||||||
|
[Column("preference_id")] public int PreferenceId { get; set; }
|
||||||
|
public Preference Preference { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Table("job")]
|
||||||
public class Job
|
public class Job
|
||||||
{
|
{
|
||||||
public int JobId { get; set; }
|
[Column("job_id")] public int Id { get; set; }
|
||||||
public HumanoidProfile Profile { get; set; } = null!;
|
public Profile Profile { get; set; } = null!;
|
||||||
|
[Column("profile_id")] public int ProfileId { get; set; }
|
||||||
|
|
||||||
public string JobName { get; set; } = null!;
|
[Column("job_name")] public string JobName { get; set; } = null!;
|
||||||
public DbJobPriority Priority { get; set; }
|
[Column("priority")] public DbJobPriority Priority { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DbJobPriority
|
public enum DbJobPriority
|
||||||
@@ -119,13 +104,14 @@ namespace Content.Server.Database
|
|||||||
High = 3
|
High = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Table("antag")]
|
||||||
public class Antag
|
public class Antag
|
||||||
{
|
{
|
||||||
public int AntagId { get; set; }
|
[Column("antag_id")] public int Id { get; set; }
|
||||||
public HumanoidProfile Profile { get; set; } = null!;
|
public Profile Profile { get; set; } = null!;
|
||||||
public int HumanoidProfileId { get; set; }
|
[Column("profile_id")] public int ProfileId { get; set; }
|
||||||
|
|
||||||
public string AntagName { get; set; } = null!;
|
[Column("antag_name")] public string AntagName { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DbPreferenceUnavailableMode
|
public enum DbPreferenceUnavailableMode
|
||||||
@@ -134,4 +120,13 @@ namespace Content.Server.Database
|
|||||||
StayInLobby = 0,
|
StayInLobby = 0,
|
||||||
SpawnAsOverflow,
|
SpawnAsOverflow,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Table("assigned_user_id")]
|
||||||
|
public class AssignedUserId
|
||||||
|
{
|
||||||
|
[Column("assigned_user_id_id")] public int Id { get; set; }
|
||||||
|
[Column("user_name")] public string UserName { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("user_id")] public Guid UserId { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
144
Content.Server.Database/ModelPostgres.cs
Normal file
144
Content.Server.Database/ModelPostgres.cs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
public sealed class PostgresServerDbContext : ServerDbContext
|
||||||
|
{
|
||||||
|
// This is used by the "dotnet ef" CLI tool.
|
||||||
|
public PostgresServerDbContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<PostgresServerBan> Ban { get; set; } = default!;
|
||||||
|
public DbSet<PostgresServerUnban> Unban { get; set; } = default!;
|
||||||
|
public DbSet<PostgresPlayer> Player { get; set; } = default!;
|
||||||
|
public DbSet<PostgresConnectionLog> ConnectionLog { get; set; } = default!;
|
||||||
|
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||||
|
{
|
||||||
|
if (!InitializedWithOptions)
|
||||||
|
options.UseNpgsql("dummy connection string");
|
||||||
|
|
||||||
|
options.ReplaceService<IRelationalTypeMappingSource, CustomNpgsqlTypeMappingSource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostgresServerDbContext(DbContextOptions<ServerDbContext> options) : base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresServerBan>()
|
||||||
|
.HasIndex(p => p.UserId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresServerBan>()
|
||||||
|
.HasIndex(p => p.Address);
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresServerBan>()
|
||||||
|
.HasIndex(p => p.UserId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresServerUnban>()
|
||||||
|
.HasIndex(p => p.BanId)
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
// ReSharper disable once CommentTypo
|
||||||
|
// ReSharper disable once 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<PostgresServerBan>()
|
||||||
|
.HasCheckConstraint("AddressNotIPv6MappedIPv4", "NOT inet '::ffff:0.0.0.0/96' >>= address")
|
||||||
|
.HasCheckConstraint("HaveEitherAddressOrUserId", "address IS NOT NULL OR user_id IS NOT NULL");
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresPlayer>()
|
||||||
|
.HasIndex(p => p.UserId)
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
// ReSharper disable once StringLiteralTypo
|
||||||
|
modelBuilder.Entity<PostgresPlayer>()
|
||||||
|
.HasCheckConstraint("LastSeenAddressNotIPv6MappedIPv4",
|
||||||
|
"NOT inet '::ffff:0.0.0.0/96' >>= last_seen_address");
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresConnectionLog>()
|
||||||
|
.HasIndex(p => p.UserId);
|
||||||
|
|
||||||
|
modelBuilder.Entity<PostgresConnectionLog>()
|
||||||
|
.HasCheckConstraint("AddressNotIPv6MappedIPv4",
|
||||||
|
"NOT inet '::ffff:0.0.0.0/96' >>= address");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("server_ban")]
|
||||||
|
public class PostgresServerBan
|
||||||
|
{
|
||||||
|
[Column("server_ban_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("user_id")] public Guid? UserId { get; set; }
|
||||||
|
[Column("address", TypeName = "inet")] public (IPAddress, int)? Address { get; set; }
|
||||||
|
|
||||||
|
[Column("ban_time", TypeName = "timestamp with time zone")]
|
||||||
|
public DateTime BanTime { get; set; }
|
||||||
|
|
||||||
|
[Column("expiration_time", TypeName = "timestamp with time zone")]
|
||||||
|
public DateTime? ExpirationTime { get; set; }
|
||||||
|
|
||||||
|
[Column("reason")] public string Reason { get; set; } = null!;
|
||||||
|
[Column("banning_admin")] public Guid? BanningAdmin { get; set; }
|
||||||
|
|
||||||
|
public PostgresServerUnban? Unban { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("server_unban")]
|
||||||
|
public class PostgresServerUnban
|
||||||
|
{
|
||||||
|
[Column("unban_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("ban_id")] public int BanId { get; set; }
|
||||||
|
[Column("ban")] public PostgresServerBan Ban { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("unbanning_admin")] public Guid? UnbanningAdmin { get; set; }
|
||||||
|
|
||||||
|
[Column("unban_time", TypeName = "timestamp with time zone")]
|
||||||
|
public DateTime UnbanTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("player")]
|
||||||
|
public class PostgresPlayer
|
||||||
|
{
|
||||||
|
[Column("player_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
// Permanent data
|
||||||
|
[Column("user_id")] public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
[Column("first_seen_time", TypeName = "timestamp with time zone")]
|
||||||
|
public DateTime FirstSeenTime { get; set; }
|
||||||
|
|
||||||
|
// Data that gets updated on each join.
|
||||||
|
[Column("last_seen_user_name")] public string LastSeenUserName { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("last_seen_time", TypeName = "timestamp with time zone")]
|
||||||
|
public DateTime LastSeenTime { get; set; }
|
||||||
|
|
||||||
|
[Column("last_seen_address")] public IPAddress LastSeenAddress { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("connection_log")]
|
||||||
|
public class PostgresConnectionLog
|
||||||
|
{
|
||||||
|
[Column("connection_log_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("user_id")] public Guid UserId { get; set; }
|
||||||
|
[Column("user_name")] public string UserName { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("time", TypeName = "timestamp with time zone")]
|
||||||
|
public DateTime Time { get; set; }
|
||||||
|
|
||||||
|
[Column("address")] public IPAddress Address { get; set; } = null!;
|
||||||
|
}
|
||||||
|
}
|
||||||
82
Content.Server.Database/ModelSqlite.cs
Normal file
82
Content.Server.Database/ModelSqlite.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
public sealed class SqliteServerDbContext : ServerDbContext
|
||||||
|
{
|
||||||
|
public DbSet<SqliteServerBan> Ban { get; set; } = default!;
|
||||||
|
public DbSet<SqliteServerUnban> Unban { get; set; } = default!;
|
||||||
|
public DbSet<SqlitePlayer> Player { get; set; } = default!;
|
||||||
|
public DbSet<SqliteConnectionLog> ConnectionLog { get; set; } = default!;
|
||||||
|
|
||||||
|
public SqliteServerDbContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder options)
|
||||||
|
{
|
||||||
|
if (!InitializedWithOptions)
|
||||||
|
options.UseSqlite("dummy connection string");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SqliteServerDbContext(DbContextOptions<ServerDbContext> options) : base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("ban")]
|
||||||
|
public class SqliteServerBan
|
||||||
|
{
|
||||||
|
[Column("ban_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("user_id")] public Guid? UserId { get; set; }
|
||||||
|
[Column("address")] public string? Address { get; set; }
|
||||||
|
|
||||||
|
[Column("ban_time")] public DateTime BanTime { get; set; }
|
||||||
|
[Column("expiration_time")] public DateTime? ExpirationTime { get; set; }
|
||||||
|
[Column("reason")] public string Reason { get; set; } = null!;
|
||||||
|
[Column("banning_admin")] public Guid? BanningAdmin { get; set; }
|
||||||
|
|
||||||
|
public SqliteServerUnban? Unban { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("unban")]
|
||||||
|
public class SqliteServerUnban
|
||||||
|
{
|
||||||
|
[Column("unban_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("ban_id")] public int BanId { get; set; }
|
||||||
|
public SqliteServerBan Ban { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("unbanning_admin")] public Guid? UnbanningAdmin { get; set; }
|
||||||
|
[Column("unban_time")] public DateTime UnbanTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("player")]
|
||||||
|
public class SqlitePlayer
|
||||||
|
{
|
||||||
|
[Column("player_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
// Permanent data
|
||||||
|
[Column("user_id")] public Guid UserId { get; set; }
|
||||||
|
[Column("first_seen_time")] public DateTime FirstSeenTime { get; set; }
|
||||||
|
|
||||||
|
// Data that gets updated on each join.
|
||||||
|
[Column("last_seen_user_name")] public string LastSeenUserName { get; set; } = null!;
|
||||||
|
[Column("last_seen_time")] public DateTime LastSeenTime { get; set; }
|
||||||
|
[Column("last_seen_address")] public string LastSeenAddress { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Table("connection_log")]
|
||||||
|
public class SqliteConnectionLog
|
||||||
|
{
|
||||||
|
[Column("connection_log_id")] public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("user_id")] public Guid UserId { get; set; }
|
||||||
|
[Column("user_name")] public string UserName { get; set; } = null!;
|
||||||
|
[Column("time")] public DateTime Time { get; set; }
|
||||||
|
[Column("address")] public string Address { get; set; } = null!;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
Content.Server.Database/NpgsqlTypeMapping.cs
Normal file
68
Content.Server.Database/NpgsqlTypeMapping.cs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Infrastructure.Internal;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping;
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
// Taken from https://github.com/npgsql/efcore.pg/issues/1158
|
||||||
|
// To support inet -> (IPAddress, int) mapping.
|
||||||
|
#pragma warning disable EF1001
|
||||||
|
public class CustomNpgsqlTypeMappingSource : NpgsqlTypeMappingSource
|
||||||
|
#pragma warning restore EF1001
|
||||||
|
{
|
||||||
|
public CustomNpgsqlTypeMappingSource(
|
||||||
|
TypeMappingSourceDependencies dependencies,
|
||||||
|
RelationalTypeMappingSourceDependencies relationalDependencies,
|
||||||
|
ISqlGenerationHelper sqlGenerationHelper,
|
||||||
|
INpgsqlOptions? npgsqlOptions = null)
|
||||||
|
: base(dependencies, relationalDependencies, sqlGenerationHelper, npgsqlOptions)
|
||||||
|
{
|
||||||
|
StoreTypeMappings["inet"] =
|
||||||
|
new RelationalTypeMapping[]
|
||||||
|
{
|
||||||
|
new NpgsqlInetWithMaskTypeMapping(),
|
||||||
|
new NpgsqlInetTypeMapping()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basically copied from NpgsqlCidrTypeMapping
|
||||||
|
public class NpgsqlInetWithMaskTypeMapping : NpgsqlTypeMapping
|
||||||
|
{
|
||||||
|
public NpgsqlInetWithMaskTypeMapping() : base("inet", typeof((IPAddress, int)), NpgsqlTypes.NpgsqlDbType.Inet)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NpgsqlInetWithMaskTypeMapping(RelationalTypeMappingParameters parameters)
|
||||||
|
: base(parameters, NpgsqlTypes.NpgsqlDbType.Inet)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override RelationalTypeMapping Clone(RelationalTypeMappingParameters parameters)
|
||||||
|
=> new NpgsqlInetWithMaskTypeMapping(parameters);
|
||||||
|
|
||||||
|
protected override string GenerateNonNullSqlLiteral(object value)
|
||||||
|
{
|
||||||
|
var cidr = ((IPAddress Address, int Subnet)) value;
|
||||||
|
return $"INET '{cidr.Address}/{cidr.Subnet}'";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Expression GenerateCodeLiteral(object value)
|
||||||
|
{
|
||||||
|
var cidr = ((IPAddress Address, int Subnet)) value;
|
||||||
|
return Expression.New(
|
||||||
|
Constructor,
|
||||||
|
Expression.Call(ParseMethod, Expression.Constant(cidr.Address.ToString())),
|
||||||
|
Expression.Constant(cidr.Subnet));
|
||||||
|
}
|
||||||
|
|
||||||
|
static readonly MethodInfo ParseMethod = typeof(IPAddress).GetMethod("Parse", new[] {typeof(string)})!;
|
||||||
|
|
||||||
|
static readonly ConstructorInfo Constructor =
|
||||||
|
typeof((IPAddress, int)).GetConstructor(new[] {typeof(IPAddress), typeof(int)})!;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace Content.Server.Database
|
|
||||||
{
|
|
||||||
public class PrefsDb
|
|
||||||
{
|
|
||||||
private readonly PreferencesDbContext _prefsCtx;
|
|
||||||
|
|
||||||
public PrefsDb(IDatabaseConfiguration dbConfig)
|
|
||||||
{
|
|
||||||
_prefsCtx = dbConfig switch
|
|
||||||
{
|
|
||||||
SqliteConfiguration sqlite => (PreferencesDbContext) new SqlitePreferencesDbContext(
|
|
||||||
sqlite.Options),
|
|
||||||
PostgresConfiguration postgres => new PostgresPreferencesDbContext(postgres.Options),
|
|
||||||
_ => throw new NotImplementedException()
|
|
||||||
};
|
|
||||||
_prefsCtx.Database.Migrate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Prefs?> GetPlayerPreferences(string username)
|
|
||||||
{
|
|
||||||
return await _prefsCtx
|
|
||||||
.Preferences
|
|
||||||
.Include(p => p.HumanoidProfiles).ThenInclude(h => h.Jobs)
|
|
||||||
.Include(p => p.HumanoidProfiles).ThenInclude(h => h.Antags)
|
|
||||||
.SingleOrDefaultAsync(p => p.Username == username);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SaveSelectedCharacterIndex(string username, int slot)
|
|
||||||
{
|
|
||||||
var prefs = _prefsCtx.Preferences.SingleOrDefault(p => p.Username == username);
|
|
||||||
if (prefs is null)
|
|
||||||
_prefsCtx.Preferences.Add(new Prefs
|
|
||||||
{
|
|
||||||
Username = username,
|
|
||||||
SelectedCharacterSlot = slot
|
|
||||||
});
|
|
||||||
else
|
|
||||||
prefs.SelectedCharacterSlot = slot;
|
|
||||||
await _prefsCtx.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SaveCharacterSlotAsync(string username, HumanoidProfile newProfile)
|
|
||||||
{
|
|
||||||
var prefs = _prefsCtx
|
|
||||||
.Preferences
|
|
||||||
.Single(p => p.Username == username);
|
|
||||||
var oldProfile = prefs
|
|
||||||
.HumanoidProfiles
|
|
||||||
.SingleOrDefault(h => h.Slot == newProfile.Slot);
|
|
||||||
if (!(oldProfile is null)) prefs.HumanoidProfiles.Remove(oldProfile);
|
|
||||||
prefs.HumanoidProfiles.Add(newProfile);
|
|
||||||
await _prefsCtx.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteCharacterSlotAsync(string username, int slot)
|
|
||||||
{
|
|
||||||
var profile = _prefsCtx
|
|
||||||
.Preferences
|
|
||||||
.Single(p => p.Username == username)
|
|
||||||
.HumanoidProfiles
|
|
||||||
.RemoveAll(h => h.Slot == slot);
|
|
||||||
await _prefsCtx.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<Dictionary<string, HumanoidProfile>> GetProfilesForPlayersAsync(List<string> usernames)
|
|
||||||
{
|
|
||||||
return await _prefsCtx.HumanoidProfile
|
|
||||||
.Include(p => p.Jobs)
|
|
||||||
.Include(a => a.Antags)
|
|
||||||
.Join(_prefsCtx.Preferences,
|
|
||||||
profile => new {profile.Slot, profile.PrefsId},
|
|
||||||
prefs => new {Slot = prefs.SelectedCharacterSlot, prefs.PrefsId},
|
|
||||||
(profile, prefs) => new {prefs.Username, profile})
|
|
||||||
.Where(p => usernames.Contains(p.Username))
|
|
||||||
.ToDictionaryAsync(arg => arg.Username, arg => arg.profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
Content.Server.Database/add-migration.ps1
Executable file
12
Content.Server.Database/add-migration.ps1
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env pwsh
|
||||||
|
|
||||||
|
param([String]$name)
|
||||||
|
|
||||||
|
if ($name -eq "")
|
||||||
|
{
|
||||||
|
Write-Error "must specify migration name"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
dotnet ef migrations add --context SqliteServerDbContext -o Migrations/Sqlite $name
|
||||||
|
dotnet ef migrations add --context PostgresServerDbContext -o Migrations/Postgres $name
|
||||||
57
Content.Server/Administration/BanCommand.cs
Normal file
57
Content.Server/Administration/BanCommand.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Robust.Server.Interfaces.Console;
|
||||||
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Administration
|
||||||
|
{
|
||||||
|
public sealed class BanCommand : IClientCommand
|
||||||
|
{
|
||||||
|
public string Command => "ban";
|
||||||
|
public string Description => "Bans somebody";
|
||||||
|
public string Help => "Usage: <name or user ID> <reason> <duration in minutes, or 0 for permanent ban>";
|
||||||
|
|
||||||
|
public async void Execute(IConsoleShell shell, IPlayerSession? player, string[] args)
|
||||||
|
{
|
||||||
|
var plyMgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
|
var dbMan = IoCManager.Resolve<IServerDbManager>();
|
||||||
|
|
||||||
|
var target = args[0];
|
||||||
|
var reason = args[1];
|
||||||
|
var duration = int.Parse(args[2]);
|
||||||
|
NetUserId targetUid;
|
||||||
|
|
||||||
|
if (plyMgr.TryGetSessionByUsername(target, out var targetSession))
|
||||||
|
{
|
||||||
|
targetUid = targetSession.UserId;
|
||||||
|
}
|
||||||
|
else if (Guid.TryParse(target, out var targetGuid))
|
||||||
|
{
|
||||||
|
targetUid = new NetUserId(targetGuid);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shell.SendText(player, "Unable to find user with that name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTimeOffset? expires = null;
|
||||||
|
if (duration > 0)
|
||||||
|
{
|
||||||
|
expires = DateTimeOffset.Now + TimeSpan.FromMinutes(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
await dbMan.AddServerBanAsync(new ServerBanDef(targetUid, null, DateTimeOffset.Now, expires, reason, player?.UserId));
|
||||||
|
|
||||||
|
if (plyMgr.TryGetSessionById(targetUid, out var targetPlayer))
|
||||||
|
{
|
||||||
|
targetPlayer.ConnectedClient.Disconnect("You've been banned. Tough shit.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -165,10 +165,10 @@ namespace Content.Server.Chat
|
|||||||
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
|
||||||
msg.Channel = ChatChannel.OOC;
|
msg.Channel = ChatChannel.OOC;
|
||||||
msg.Message = message;
|
msg.Message = message;
|
||||||
msg.MessageWrap = $"OOC: {player.SessionId}: {{0}}";
|
msg.MessageWrap = $"OOC: {player.Name}: {{0}}";
|
||||||
_netManager.ServerSendToAll(msg);
|
_netManager.ServerSendToAll(msg);
|
||||||
|
|
||||||
_mommiLink.SendOOCMessage(player.SessionId.ToString(), message);
|
_mommiLink.SendOOCMessage(player.Name, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendDeadChat(IPlayerSession player, string message)
|
public void SendDeadChat(IPlayerSession player, string message)
|
||||||
@@ -210,7 +210,7 @@ namespace Content.Server.Chat
|
|||||||
|
|
||||||
msg.Channel = ChatChannel.AdminChat;
|
msg.Channel = ChatChannel.AdminChat;
|
||||||
msg.Message = message;
|
msg.Message = message;
|
||||||
msg.MessageWrap = $"{Loc.GetString("ADMIN")}: {player.SessionId}: {{0}}";
|
msg.MessageWrap = $"{Loc.GetString("ADMIN")}: {player.Name}: {{0}}";
|
||||||
_netManager.ServerSendToMany(msg, clients.ToList());
|
_netManager.ServerSendToMany(msg, clients.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
109
Content.Server/ConnectionManager.cs
Normal file
109
Content.Server/ConnectionManager.cs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Content.Server.Preferences;
|
||||||
|
using Content.Shared;
|
||||||
|
using Robust.Shared.Interfaces.Configuration;
|
||||||
|
using Robust.Shared.Interfaces.Network;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server
|
||||||
|
{
|
||||||
|
public interface IConnectionManager
|
||||||
|
{
|
||||||
|
void Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles various duties like guest username assignment, bans, connection logs, etc...
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ConnectionManager : IConnectionManager
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IServerNetManager _netMgr = default!;
|
||||||
|
[Dependency] private readonly IServerDbManager _db = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
_netMgr.Connecting += NetMgrOnConnecting;
|
||||||
|
_netMgr.AssignUserIdCallback = AssignUserIdCallback;
|
||||||
|
// Approval-based IP bans disabled because they don't play well with Happy Eyeballs.
|
||||||
|
// _netMgr.HandleApprovalCallback = HandleApproval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private async Task<NetApproval> HandleApproval(NetApprovalEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
var ban = await _db.GetServerBanByIpAsync(eventArgs.Connection.RemoteEndPoint.Address);
|
||||||
|
if (ban != null)
|
||||||
|
{
|
||||||
|
var expires = "This is a permanent ban.";
|
||||||
|
if (ban.ExpirationTime is { } expireTime)
|
||||||
|
{
|
||||||
|
var duration = expireTime - ban.BanTime;
|
||||||
|
var utc = expireTime.ToUniversalTime();
|
||||||
|
expires = $"This ban is for {duration.TotalMinutes} minutes and will expire at {utc:f} UTC.";
|
||||||
|
}
|
||||||
|
var reason = $@"You, or another user of this computer or connection is banned from playing here.
|
||||||
|
The ban reason is: ""{ban.Reason}""
|
||||||
|
{expires}";
|
||||||
|
return NetApproval.Deny(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NetApproval.Allow();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private async Task NetMgrOnConnecting(NetConnectingArgs e)
|
||||||
|
{
|
||||||
|
// Check if banned.
|
||||||
|
var addr = e.IP.Address;
|
||||||
|
var userId = e.UserId;
|
||||||
|
var ban = await _db.GetServerBanAsync(addr, userId);
|
||||||
|
if (ban != null)
|
||||||
|
{
|
||||||
|
var expires = "This is a permanent ban.";
|
||||||
|
if (ban.ExpirationTime is { } expireTime)
|
||||||
|
{
|
||||||
|
var duration = expireTime - ban.BanTime;
|
||||||
|
var utc = expireTime.ToUniversalTime();
|
||||||
|
expires = $"This ban is for {duration.TotalMinutes:N0} minutes and will expire at {utc:f} UTC.";
|
||||||
|
}
|
||||||
|
var reason = $@"You, or another user of this computer or connection, are banned from playing here.
|
||||||
|
The ban reason is: ""{ban.Reason}""
|
||||||
|
{expires}";
|
||||||
|
e.Deny(reason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ServerPreferencesManager.ShouldStorePrefs(e.AuthType))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _db.UpdatePlayerRecordAsync(userId, e.UserName, addr);
|
||||||
|
await _db.AddConnectionLogAsync(userId, e.UserName, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<NetUserId?> AssignUserIdCallback(string name)
|
||||||
|
{
|
||||||
|
if (!_cfg.GetCVar(CCVars.GamePersistGuests))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userId = await _db.GetAssignedUserIdAsync(name);
|
||||||
|
if (userId != null)
|
||||||
|
{
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
var assigned = new NetUserId(Guid.NewGuid());
|
||||||
|
await _db.AssignUserIdAsync(name, assigned);
|
||||||
|
return assigned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
Content.Server/Database/ServerBanDef.cs
Normal file
41
Content.Server/Database/ServerBanDef.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
public sealed class ServerBanDef
|
||||||
|
{
|
||||||
|
public NetUserId? UserId { get; }
|
||||||
|
public (IPAddress address, int cidrMask)? Address { get; }
|
||||||
|
|
||||||
|
public DateTimeOffset BanTime { get; }
|
||||||
|
public DateTimeOffset? ExpirationTime { get; }
|
||||||
|
public string Reason { get; }
|
||||||
|
public NetUserId? BanningAdmin { get; }
|
||||||
|
|
||||||
|
public ServerBanDef(NetUserId? userId, (IPAddress, int)? address, DateTimeOffset banTime, DateTimeOffset? expirationTime, string reason, NetUserId? banningAdmin)
|
||||||
|
{
|
||||||
|
if (userId == null && address == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Must have a banned user, banned address, or both.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserId = userId;
|
||||||
|
Address = address;
|
||||||
|
BanTime = banTime;
|
||||||
|
ExpirationTime = expirationTime;
|
||||||
|
Reason = reason;
|
||||||
|
BanningAdmin = banningAdmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
221
Content.Server/Database/ServerDbBase.cs
Normal file
221
Content.Server/Database/ServerDbBase.cs
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
public abstract class ServerDbBase
|
||||||
|
{
|
||||||
|
public async Task<PlayerPreferences?> GetPlayerPreferencesAsync(NetUserId userId)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
var prefs = await db.DbContext
|
||||||
|
.Preference
|
||||||
|
.Include(p => p.Profiles).ThenInclude(h => h.Jobs)
|
||||||
|
.Include(p => p.Profiles).ThenInclude(h => h.Antags)
|
||||||
|
.SingleOrDefaultAsync(p => p.UserId == userId.UserId);
|
||||||
|
|
||||||
|
if (prefs is null) return null;
|
||||||
|
|
||||||
|
var maxSlot = prefs.Profiles.Max(p => p.Slot)+1;
|
||||||
|
var profiles = new ICharacterProfile[maxSlot];
|
||||||
|
foreach (var profile in prefs.Profiles)
|
||||||
|
{
|
||||||
|
profiles[profile.Slot] = ConvertProfiles(profile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PlayerPreferences
|
||||||
|
(
|
||||||
|
profiles,
|
||||||
|
prefs.SelectedCharacterSlot
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
var prefs = await db.DbContext.Preference.SingleAsync(p => p.UserId == userId.UserId);
|
||||||
|
prefs.SelectedCharacterSlot = index;
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot)
|
||||||
|
{
|
||||||
|
if (profile is null)
|
||||||
|
{
|
||||||
|
await DeleteCharacterSlotAsync(userId, slot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await using var db = await GetDb();
|
||||||
|
if (!(profile is HumanoidCharacterProfile humanoid))
|
||||||
|
{
|
||||||
|
// TODO: Handle other ICharacterProfile implementations properly
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var entity = ConvertProfiles(humanoid, slot);
|
||||||
|
|
||||||
|
var prefs = await db.DbContext
|
||||||
|
.Preference
|
||||||
|
.Include(p => p.Profiles)
|
||||||
|
.SingleAsync(p => p.UserId == userId.UserId);
|
||||||
|
|
||||||
|
var oldProfile = prefs
|
||||||
|
.Profiles
|
||||||
|
.SingleOrDefault(h => h.Slot == entity.Slot);
|
||||||
|
|
||||||
|
if (!(oldProfile is null))
|
||||||
|
{
|
||||||
|
prefs.Profiles.Remove(oldProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
prefs.Profiles.Add(entity);
|
||||||
|
await db.DbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteCharacterSlotAsync(NetUserId userId, int slot)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
db.DbContext
|
||||||
|
.Preference
|
||||||
|
.Single(p => p.UserId == userId.UserId)
|
||||||
|
.Profiles
|
||||||
|
.RemoveAll(h => h.Slot == slot);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<PlayerPreferences> InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
var profile = ConvertProfiles((HumanoidCharacterProfile) defaultProfile, 0);
|
||||||
|
var prefs = new Preference
|
||||||
|
{
|
||||||
|
UserId = userId.UserId,
|
||||||
|
SelectedCharacterSlot = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
prefs.Profiles.Add(profile);
|
||||||
|
|
||||||
|
db.DbContext.Preference.Add(prefs);
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return new PlayerPreferences(new []{defaultProfile}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HumanoidCharacterProfile ConvertProfiles(Profile profile)
|
||||||
|
{
|
||||||
|
var jobs = profile.Jobs.ToDictionary(j => j.JobName, j => (JobPriority) j.Priority);
|
||||||
|
var antags = profile.Antags.Select(a => a.AntagName);
|
||||||
|
return new HumanoidCharacterProfile(
|
||||||
|
profile.CharacterName,
|
||||||
|
profile.Age,
|
||||||
|
profile.Sex == "Male" ? Sex.Male : Sex.Female,
|
||||||
|
new HumanoidCharacterAppearance
|
||||||
|
(
|
||||||
|
profile.HairName,
|
||||||
|
Color.FromHex(profile.HairColor),
|
||||||
|
profile.FacialHairName,
|
||||||
|
Color.FromHex(profile.FacialHairColor),
|
||||||
|
Color.FromHex(profile.EyeColor),
|
||||||
|
Color.FromHex(profile.SkinColor)
|
||||||
|
),
|
||||||
|
jobs,
|
||||||
|
(PreferenceUnavailableMode) profile.PreferenceUnavailable,
|
||||||
|
antags.ToList()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Profile ConvertProfiles(HumanoidCharacterProfile humanoid, int slot)
|
||||||
|
{
|
||||||
|
var appearance = (HumanoidCharacterAppearance) humanoid.CharacterAppearance;
|
||||||
|
|
||||||
|
var entity = new Profile
|
||||||
|
{
|
||||||
|
CharacterName = humanoid.Name,
|
||||||
|
Age = humanoid.Age,
|
||||||
|
Sex = humanoid.Sex.ToString(),
|
||||||
|
HairName = appearance.HairStyleName,
|
||||||
|
HairColor = appearance.HairColor.ToHex(),
|
||||||
|
FacialHairName = appearance.FacialHairStyleName,
|
||||||
|
FacialHairColor = appearance.FacialHairColor.ToHex(),
|
||||||
|
EyeColor = appearance.EyeColor.ToHex(),
|
||||||
|
SkinColor = appearance.SkinColor.ToHex(),
|
||||||
|
Slot = slot,
|
||||||
|
PreferenceUnavailable = (DbPreferenceUnavailableMode) humanoid.PreferenceUnavailable
|
||||||
|
};
|
||||||
|
entity.Jobs.AddRange(
|
||||||
|
humanoid.JobPriorities
|
||||||
|
.Where(j => j.Value != JobPriority.Never)
|
||||||
|
.Select(j => new Job {JobName = j.Key, Priority = (DbJobPriority) j.Value})
|
||||||
|
);
|
||||||
|
entity.Antags.AddRange(
|
||||||
|
humanoid.AntagPreferences
|
||||||
|
.Select(a => new Antag {AntagName = a})
|
||||||
|
);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<NetUserId?> GetAssignedUserIdAsync(string name)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
var assigned = await db.DbContext.AssignedUserId.SingleOrDefaultAsync(p => p.UserName == name);
|
||||||
|
return assigned?.UserId is { } g ? new NetUserId(g) : default(NetUserId?);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AssignUserIdAsync(string name, NetUserId netUserId)
|
||||||
|
{
|
||||||
|
await using var db = await GetDb();
|
||||||
|
|
||||||
|
db.DbContext.AssignedUserId.Add(new AssignedUserId
|
||||||
|
{
|
||||||
|
UserId = netUserId.UserId,
|
||||||
|
UserName = name
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.DbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BAN STUFF
|
||||||
|
*/
|
||||||
|
public abstract Task<ServerBanDef?> GetServerBanAsync(IPAddress? address, NetUserId? userId);
|
||||||
|
public abstract Task AddServerBanAsync(ServerBanDef serverBan);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PLAYER RECORDS
|
||||||
|
*/
|
||||||
|
public abstract Task UpdatePlayerRecord(NetUserId userId, string userName, IPAddress address);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CONNECTION LOG
|
||||||
|
*/
|
||||||
|
public abstract Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address);
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract Task<DbGuard> GetDb();
|
||||||
|
|
||||||
|
protected abstract class DbGuard : IAsyncDisposable
|
||||||
|
{
|
||||||
|
public abstract ServerDbContext DbContext { get; }
|
||||||
|
|
||||||
|
public abstract ValueTask DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
245
Content.Server/Database/ServerDbManager.cs
Normal file
245
Content.Server/Database/ServerDbManager.cs
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Shared;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Microsoft.Data.Sqlite;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Npgsql;
|
||||||
|
using Robust.Shared.Interfaces.Configuration;
|
||||||
|
using Robust.Shared.Interfaces.Log;
|
||||||
|
using Robust.Shared.Interfaces.Resources;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using MSLogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||||
|
using LogLevel = Robust.Shared.Log.LogLevel;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
public interface IServerDbManager
|
||||||
|
{
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
// Preferences
|
||||||
|
Task<PlayerPreferences> InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile);
|
||||||
|
Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index);
|
||||||
|
Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile profile, int slot);
|
||||||
|
Task<PlayerPreferences?> GetPlayerPreferencesAsync(NetUserId userId);
|
||||||
|
|
||||||
|
// Username assignment (for guest accounts, so they persist GUID)
|
||||||
|
Task AssignUserIdAsync(string name, NetUserId userId);
|
||||||
|
Task<NetUserId?> GetAssignedUserIdAsync(string name);
|
||||||
|
|
||||||
|
// Ban stuff
|
||||||
|
Task<ServerBanDef?> GetServerBanAsync(IPAddress? address, NetUserId? userId);
|
||||||
|
Task AddServerBanAsync(ServerBanDef serverBan);
|
||||||
|
|
||||||
|
// Player records
|
||||||
|
Task UpdatePlayerRecordAsync(NetUserId userId, string userName, IPAddress address);
|
||||||
|
|
||||||
|
// Connection log
|
||||||
|
Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class ServerDbManager : IServerDbManager
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
|
[Dependency] private readonly IResourceManager _res = default!;
|
||||||
|
[Dependency] private readonly ILogManager _logMgr = default!;
|
||||||
|
|
||||||
|
private ServerDbBase _db = default!;
|
||||||
|
private LoggingProvider _msLogProvider = default!;
|
||||||
|
private ILoggerFactory _msLoggerFactory = default!;
|
||||||
|
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
_msLogProvider = new LoggingProvider(_logMgr);
|
||||||
|
_msLoggerFactory = LoggerFactory.Create(builder =>
|
||||||
|
{
|
||||||
|
builder.AddProvider(_msLogProvider);
|
||||||
|
});
|
||||||
|
|
||||||
|
var engine = _cfg.GetCVar(CCVars.DatabaseEngine).ToLower();
|
||||||
|
switch (engine)
|
||||||
|
{
|
||||||
|
case "sqlite":
|
||||||
|
var options = CreateSqliteOptions();
|
||||||
|
_db = new ServerDbSqlite(options);
|
||||||
|
break;
|
||||||
|
case "postgres":
|
||||||
|
options = CreatePostgresOptions();
|
||||||
|
_db = new ServerDbPostgres(options);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidDataException("Unknown database engine {engine}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PlayerPreferences> InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile)
|
||||||
|
{
|
||||||
|
return _db.InitPrefsAsync(userId, defaultProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index)
|
||||||
|
{
|
||||||
|
return _db.SaveSelectedCharacterIndexAsync(userId, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile profile, int slot)
|
||||||
|
{
|
||||||
|
return _db.SaveCharacterSlotAsync(userId, profile, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<PlayerPreferences?> GetPlayerPreferencesAsync(NetUserId userId)
|
||||||
|
{
|
||||||
|
return _db.GetPlayerPreferencesAsync(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AssignUserIdAsync(string name, NetUserId userId)
|
||||||
|
{
|
||||||
|
return _db.AssignUserIdAsync(name, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<NetUserId?> GetAssignedUserIdAsync(string name)
|
||||||
|
{
|
||||||
|
return _db.GetAssignedUserIdAsync(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ServerBanDef?> GetServerBanAsync(IPAddress? address, NetUserId? userId)
|
||||||
|
{
|
||||||
|
return _db.GetServerBanAsync(address, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddServerBanAsync(ServerBanDef serverBan)
|
||||||
|
{
|
||||||
|
return _db.AddServerBanAsync(serverBan);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task UpdatePlayerRecordAsync(NetUserId userId, string userName, IPAddress address)
|
||||||
|
{
|
||||||
|
return _db.UpdatePlayerRecord(userId, userName, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address)
|
||||||
|
{
|
||||||
|
return _db.AddConnectionLogAsync(userId, userName, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DbContextOptions<ServerDbContext> CreatePostgresOptions()
|
||||||
|
{
|
||||||
|
var host = _cfg.GetCVar(CCVars.DatabasePgHost);
|
||||||
|
var port = _cfg.GetCVar(CCVars.DatabasePgPort);
|
||||||
|
var db = _cfg.GetCVar(CCVars.DatabasePgDatabase);
|
||||||
|
var user = _cfg.GetCVar(CCVars.DatabasePgUsername);
|
||||||
|
var pass = _cfg.GetCVar(CCVars.DatabasePgPassword);
|
||||||
|
|
||||||
|
var builder = new DbContextOptionsBuilder<ServerDbContext>();
|
||||||
|
var connectionString = new NpgsqlConnectionStringBuilder
|
||||||
|
{
|
||||||
|
Host = host,
|
||||||
|
Port = port,
|
||||||
|
Database = db,
|
||||||
|
Username = user,
|
||||||
|
Password = pass
|
||||||
|
}.ConnectionString;
|
||||||
|
builder.UseNpgsql(connectionString);
|
||||||
|
SetupLogging(builder);
|
||||||
|
return builder.Options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DbContextOptions<ServerDbContext> CreateSqliteOptions()
|
||||||
|
{
|
||||||
|
var builder = new DbContextOptionsBuilder<ServerDbContext>();
|
||||||
|
|
||||||
|
var configPreferencesDbPath = _cfg.GetCVar(CCVars.DatabaseSqliteDbPath);
|
||||||
|
var inMemory = _res.UserData.RootDir == null;
|
||||||
|
|
||||||
|
SqliteConnection connection;
|
||||||
|
if (!inMemory)
|
||||||
|
{
|
||||||
|
var finalPreferencesDbPath = Path.Combine(_res.UserData.RootDir!, configPreferencesDbPath);
|
||||||
|
connection = new SqliteConnection($"Data Source={finalPreferencesDbPath}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connection = new SqliteConnection("Data Source=:memory:");
|
||||||
|
// When using an in-memory DB we have to open it manually
|
||||||
|
// so EFCore doesn't open, close and wipe it.
|
||||||
|
connection.Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.UseSqlite(connection);
|
||||||
|
SetupLogging(builder);
|
||||||
|
return builder.Options;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupLogging(DbContextOptionsBuilder<ServerDbContext> builder)
|
||||||
|
{
|
||||||
|
builder.UseLoggerFactory(_msLoggerFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class LoggingProvider : ILoggerProvider
|
||||||
|
{
|
||||||
|
private readonly ILogManager _logManager;
|
||||||
|
|
||||||
|
public LoggingProvider(ILogManager logManager)
|
||||||
|
{
|
||||||
|
_logManager = logManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ILogger CreateLogger(string categoryName)
|
||||||
|
{
|
||||||
|
return new MSLogger(_logManager.GetSawmill("db.ef"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class MSLogger : ILogger
|
||||||
|
{
|
||||||
|
private readonly ISawmill _sawmill;
|
||||||
|
|
||||||
|
public MSLogger(ISawmill sawmill)
|
||||||
|
{
|
||||||
|
_sawmill = sawmill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<TState>(MSLogLevel logLevel, EventId eventId, TState state, Exception exception,
|
||||||
|
Func<TState, Exception, string> formatter)
|
||||||
|
{
|
||||||
|
var lvl = logLevel switch
|
||||||
|
{
|
||||||
|
MSLogLevel.Trace => LogLevel.Debug,
|
||||||
|
MSLogLevel.Debug => LogLevel.Debug,
|
||||||
|
// EFCore feels the need to log individual DB commands as "Information" so I'm slapping debug on it.
|
||||||
|
MSLogLevel.Information => LogLevel.Debug,
|
||||||
|
MSLogLevel.Warning => LogLevel.Warning,
|
||||||
|
MSLogLevel.Error => LogLevel.Error,
|
||||||
|
MSLogLevel.Critical => LogLevel.Fatal,
|
||||||
|
MSLogLevel.None => LogLevel.Debug,
|
||||||
|
_ => LogLevel.Debug
|
||||||
|
};
|
||||||
|
|
||||||
|
_sawmill.Log(lvl, formatter(state, exception));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled(MSLogLevel logLevel)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDisposable BeginScope<TState>(TState state)
|
||||||
|
{
|
||||||
|
// TODO: this
|
||||||
|
return null!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
184
Content.Server/Database/ServerDbPostgres.cs
Normal file
184
Content.Server/Database/ServerDbPostgres.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
public sealed class ServerDbPostgres : ServerDbBase
|
||||||
|
{
|
||||||
|
private readonly DbContextOptions<ServerDbContext> _options;
|
||||||
|
private readonly Task _dbReadyTask;
|
||||||
|
|
||||||
|
public ServerDbPostgres(DbContextOptions<ServerDbContext> options)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
|
||||||
|
_dbReadyTask = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await using var ctx = new PostgresServerDbContext(_options);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ctx.Database.MigrateAsync();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
await ctx.DisposeAsync();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<ServerBanDef?> GetServerBanAsync(IPAddress? address, NetUserId? userId)
|
||||||
|
{
|
||||||
|
if (address == null && userId == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Address and userId cannot both be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
var query = db.PgDbContext.Ban
|
||||||
|
.Include(p => p.Unban)
|
||||||
|
.Where(p => p.Unban == null && (p.ExpirationTime == null || p.ExpirationTime.Value > DateTime.Now));
|
||||||
|
|
||||||
|
if (userId is { } uid)
|
||||||
|
{
|
||||||
|
if (address == null)
|
||||||
|
{
|
||||||
|
// Only have a user ID.
|
||||||
|
query = query.Where(p => p.UserId == uid.UserId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Have both user ID and IP address.
|
||||||
|
query = query.Where(p =>
|
||||||
|
(p.Address != null && EF.Functions.ContainsOrEqual(p.Address.Value, address))
|
||||||
|
|| p.UserId == uid.UserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Only have a connecting address.
|
||||||
|
query = query.Where(
|
||||||
|
p => p.Address != null && EF.Functions.ContainsOrEqual(p.Address.Value, address));
|
||||||
|
}
|
||||||
|
|
||||||
|
var ban = await query.FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
return ConvertBan(ban);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerBanDef? ConvertBan(PostgresServerBan? 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ServerBanDef(
|
||||||
|
uid,
|
||||||
|
ban.Address,
|
||||||
|
ban.BanTime,
|
||||||
|
ban.ExpirationTime,
|
||||||
|
ban.Reason,
|
||||||
|
aUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task AddServerBanAsync(ServerBanDef serverBan)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
db.PgDbContext.Ban.Add(new PostgresServerBan
|
||||||
|
{
|
||||||
|
Address = serverBan.Address,
|
||||||
|
Reason = serverBan.Reason,
|
||||||
|
BanningAdmin = serverBan.BanningAdmin?.UserId,
|
||||||
|
BanTime = serverBan.BanTime.UtcDateTime,
|
||||||
|
ExpirationTime = serverBan.ExpirationTime?.UtcDateTime,
|
||||||
|
UserId = serverBan.UserId?.UserId
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.PgDbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task UpdatePlayerRecord(NetUserId userId, string userName, IPAddress address)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
var record = await db.PgDbContext.Player.SingleOrDefaultAsync(p => p.UserId == userId.UserId);
|
||||||
|
if (record == null)
|
||||||
|
{
|
||||||
|
db.PgDbContext.Player.Add(record = new PostgresPlayer
|
||||||
|
{
|
||||||
|
FirstSeenTime = DateTime.UtcNow,
|
||||||
|
UserId = userId.UserId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record.LastSeenTime = DateTime.UtcNow;
|
||||||
|
record.LastSeenAddress = address;
|
||||||
|
record.LastSeenUserName = userName;
|
||||||
|
|
||||||
|
await db.PgDbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
db.PgDbContext.ConnectionLog.Add(new PostgresConnectionLog
|
||||||
|
{
|
||||||
|
Address = address,
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
UserId = userId.UserId,
|
||||||
|
UserName = userName
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.PgDbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<DbGuardImpl> GetDbImpl()
|
||||||
|
{
|
||||||
|
await _dbReadyTask;
|
||||||
|
|
||||||
|
return new DbGuardImpl(new PostgresServerDbContext(_options));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<DbGuard> GetDb()
|
||||||
|
{
|
||||||
|
return await GetDbImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class DbGuardImpl : DbGuard
|
||||||
|
{
|
||||||
|
public DbGuardImpl(PostgresServerDbContext dbC)
|
||||||
|
{
|
||||||
|
PgDbContext = dbC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PostgresServerDbContext PgDbContext { get; }
|
||||||
|
public override ServerDbContext DbContext => PgDbContext;
|
||||||
|
|
||||||
|
public override ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
return DbContext.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
192
Content.Server/Database/ServerDbSqlite.cs
Normal file
192
Content.Server/Database/ServerDbSqlite.cs
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Preferences;
|
||||||
|
using Content.Server.Utility;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
namespace Content.Server.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides methods to retrieve and update character preferences.
|
||||||
|
/// Don't use this directly, go through <see cref="ServerPreferencesManager" /> instead.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ServerDbSqlite : ServerDbBase
|
||||||
|
{
|
||||||
|
// For SQLite we use a single DB context via SQLite.
|
||||||
|
// This doesn't allow concurrent access so that's what the semaphore is for.
|
||||||
|
// That said, this is bloody SQLite, I don't even think EFCore bothers to truly async it.
|
||||||
|
private readonly SemaphoreSlim _prefsSemaphore = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
|
private readonly Task _dbReadyTask;
|
||||||
|
private readonly SqliteServerDbContext _prefsCtx;
|
||||||
|
|
||||||
|
public ServerDbSqlite(DbContextOptions<ServerDbContext> options)
|
||||||
|
{
|
||||||
|
_prefsCtx = new SqliteServerDbContext(options);
|
||||||
|
|
||||||
|
_dbReadyTask = Task.Run(() => _prefsCtx.Database.Migrate());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<ServerBanDef?> GetServerBanAsync(IPAddress? address, NetUserId? userId)
|
||||||
|
{
|
||||||
|
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 bans = await db.SqliteDbContext.Ban
|
||||||
|
.Include(p => p.Unban)
|
||||||
|
.Where(p => p.Unban == null && (p.ExpirationTime == null || p.ExpirationTime.Value > DateTime.UtcNow))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
foreach (var ban in bans)
|
||||||
|
{
|
||||||
|
if (address != null && ban.Address != null && address.IsInSubnet(ban.Address))
|
||||||
|
{
|
||||||
|
return ConvertBan(ban);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userId is { } id && ban.UserId == id.UserId)
|
||||||
|
{
|
||||||
|
return ConvertBan(ban);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task AddServerBanAsync(ServerBanDef serverBan)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
string? addrStr = null;
|
||||||
|
if (serverBan.Address is { } addr)
|
||||||
|
{
|
||||||
|
addrStr = $"{addr.address}/{addr.cidrMask}";
|
||||||
|
}
|
||||||
|
|
||||||
|
db.SqliteDbContext.Ban.Add(new SqliteServerBan
|
||||||
|
{
|
||||||
|
Address = addrStr,
|
||||||
|
Reason = serverBan.Reason,
|
||||||
|
BanningAdmin = serverBan.BanningAdmin?.UserId,
|
||||||
|
BanTime = serverBan.BanTime.UtcDateTime,
|
||||||
|
ExpirationTime = serverBan.ExpirationTime?.UtcDateTime,
|
||||||
|
UserId = serverBan.UserId?.UserId
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.SqliteDbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task UpdatePlayerRecord(NetUserId userId, string userName, IPAddress address)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
var record = await db.SqliteDbContext.Player.SingleOrDefaultAsync(p => p.UserId == userId.UserId);
|
||||||
|
if (record == null)
|
||||||
|
{
|
||||||
|
db.SqliteDbContext.Player.Add(record = new SqlitePlayer
|
||||||
|
{
|
||||||
|
FirstSeenTime = DateTime.UtcNow,
|
||||||
|
UserId = userId.UserId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
record.LastSeenTime = DateTime.UtcNow;
|
||||||
|
record.LastSeenAddress = address.ToString();
|
||||||
|
record.LastSeenUserName = userName;
|
||||||
|
|
||||||
|
await db.SqliteDbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerBanDef? ConvertBan(SqliteServerBan? 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
(IPAddress, int)? addrTuple = null;
|
||||||
|
if (ban.Address != null)
|
||||||
|
{
|
||||||
|
var idx = ban.Address.IndexOf('/', StringComparison.Ordinal);
|
||||||
|
addrTuple = (IPAddress.Parse(ban.Address.AsSpan(0, idx)),
|
||||||
|
int.Parse(ban.Address.AsSpan(idx + 1), provider: CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ServerBanDef(
|
||||||
|
uid,
|
||||||
|
addrTuple,
|
||||||
|
ban.BanTime,
|
||||||
|
ban.ExpirationTime,
|
||||||
|
ban.Reason,
|
||||||
|
aUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task AddConnectionLogAsync(NetUserId userId, string userName, IPAddress address)
|
||||||
|
{
|
||||||
|
await using var db = await GetDbImpl();
|
||||||
|
|
||||||
|
db.SqliteDbContext.ConnectionLog.Add(new SqliteConnectionLog
|
||||||
|
{
|
||||||
|
Address = address.ToString(),
|
||||||
|
Time = DateTime.UtcNow,
|
||||||
|
UserId = userId.UserId,
|
||||||
|
UserName = userName
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.SqliteDbContext.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<DbGuardImpl> GetDbImpl()
|
||||||
|
{
|
||||||
|
await _dbReadyTask;
|
||||||
|
await _prefsSemaphore.WaitAsync();
|
||||||
|
|
||||||
|
return new DbGuardImpl(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task<DbGuard> GetDb()
|
||||||
|
{
|
||||||
|
return await GetDbImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class DbGuardImpl : DbGuard
|
||||||
|
{
|
||||||
|
private readonly ServerDbSqlite _db;
|
||||||
|
|
||||||
|
public DbGuardImpl(ServerDbSqlite db)
|
||||||
|
{
|
||||||
|
_db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ServerDbContext DbContext => _db._prefsCtx;
|
||||||
|
public SqliteServerDbContext SqliteDbContext => _db._prefsCtx;
|
||||||
|
|
||||||
|
public override ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
_db._prefsSemaphore.Release();
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Server.AI.Utility.Considerations;
|
using Content.Server.AI.Utility.Considerations;
|
||||||
using Content.Server.AI.WorldState;
|
using Content.Server.AI.WorldState;
|
||||||
using Content.Server.Body.Network;
|
using Content.Server.Body.Network;
|
||||||
|
using Content.Server.Database;
|
||||||
using Content.Server.GameObjects.Components.Mobs.Speech;
|
using Content.Server.GameObjects.Components.Mobs.Speech;
|
||||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
@@ -62,7 +63,9 @@ namespace Content.Server
|
|||||||
var logManager = IoCManager.Resolve<ILogManager>();
|
var logManager = IoCManager.Resolve<ILogManager>();
|
||||||
logManager.GetSawmill("Storage").Level = LogLevel.Info;
|
logManager.GetSawmill("Storage").Level = LogLevel.Info;
|
||||||
|
|
||||||
IoCManager.Resolve<IServerPreferencesManager>().StartInit();
|
IoCManager.Resolve<IConnectionManager>().Initialize();
|
||||||
|
IoCManager.Resolve<IServerDbManager>().Init();
|
||||||
|
IoCManager.Resolve<IServerPreferencesManager>().Init();
|
||||||
IoCManager.Resolve<INodeGroupFactory>().Initialize();
|
IoCManager.Resolve<INodeGroupFactory>().Initialize();
|
||||||
IoCManager.Resolve<ISandboxManager>().Initialize();
|
IoCManager.Resolve<ISandboxManager>().Initialize();
|
||||||
IoCManager.Resolve<IAccentManager>().Initialize();
|
IoCManager.Resolve<IAccentManager>().Initialize();
|
||||||
@@ -72,7 +75,6 @@ namespace Content.Server
|
|||||||
{
|
{
|
||||||
base.PostInit();
|
base.PostInit();
|
||||||
|
|
||||||
IoCManager.Resolve<IServerPreferencesManager>().FinishInit();
|
|
||||||
_gameTicker.Initialize();
|
_gameTicker.Initialize();
|
||||||
IoCManager.Resolve<RecipeManager>().Initialize();
|
IoCManager.Resolve<RecipeManager>().Initialize();
|
||||||
IoCManager.Resolve<BlackboardManager>().Initialize();
|
IoCManager.Resolve<BlackboardManager>().Initialize();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using Robust.Shared.GameObjects;
|
|||||||
using Robust.Shared.Interfaces.GameObjects;
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
@@ -144,7 +145,7 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
UserInterface?.Open(actor.playerSession);
|
UserInterface?.Open(actor.playerSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
||||||
{
|
{
|
||||||
if (!(obj.Message is CloningPodUiButtonPressedMessage message)) return;
|
if (!(obj.Message is CloningPodUiButtonPressedMessage message)) return;
|
||||||
|
|
||||||
@@ -167,11 +168,10 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
|
|
||||||
|
|
||||||
var mob = _entityManager.SpawnEntity("HumanMob_Content", Owner.Transform.MapPosition);
|
var mob = _entityManager.SpawnEntity("HumanMob_Content", Owner.Transform.MapPosition);
|
||||||
var client = _playerManager
|
var client = _playerManager.GetSessionByUserId(mind.UserId!.Value);
|
||||||
.GetPlayersBy(x => x.SessionId == mind.SessionId).First();
|
var profile = GetPlayerProfileAsync(client.UserId);
|
||||||
mob.GetComponent<HumanoidAppearanceComponent>()
|
mob.GetComponent<HumanoidAppearanceComponent>().UpdateFromProfile(profile);
|
||||||
.UpdateFromProfile(GetPlayerProfileAsync(client.Name).Result);
|
mob.Name = profile.Name;
|
||||||
mob.Name = GetPlayerProfileAsync(client.Name).Result.Name;
|
|
||||||
|
|
||||||
_bodyContainer.Insert(mob);
|
_bodyContainer.Insert(mob);
|
||||||
_capturedMind = mind;
|
_capturedMind = mind;
|
||||||
@@ -209,10 +209,9 @@ namespace Content.Server.GameObjects.Components.Medical
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<HumanoidCharacterProfile> GetPlayerProfileAsync(string username)
|
private HumanoidCharacterProfile GetPlayerProfileAsync(NetUserId userId)
|
||||||
{
|
{
|
||||||
return (HumanoidCharacterProfile) (await _prefsManager.GetPreferencesAsync(username))
|
return (HumanoidCharacterProfile) _prefsManager.GetPreferences(userId).SelectedCharacter;
|
||||||
.SelectedCharacter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleGhostReturn(GhostComponent.GhostReturnMessage message)
|
private void HandleGhostReturn(GhostComponent.GhostReturnMessage message)
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
{
|
{
|
||||||
public class SignalLinkerSystem : EntitySystem
|
public class SignalLinkerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
private Dictionary<NetSessionId, SignalTransmitterComponent> _transmitters;
|
private Dictionary<NetUserId, SignalTransmitterComponent> _transmitters;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
_transmitters = new Dictionary<NetSessionId, SignalTransmitterComponent>();
|
_transmitters = new Dictionary<NetUserId, SignalTransmitterComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SignalLinkerKeybind(NetSessionId id, bool? enable)
|
public void SignalLinkerKeybind(NetUserId id, bool? enable)
|
||||||
{
|
{
|
||||||
if (enable == null)
|
if (enable == null)
|
||||||
{
|
{
|
||||||
@@ -66,7 +66,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
|
|
||||||
private bool HandleUse(ICommonSession session, EntityCoordinates coords, EntityUid uid)
|
private bool HandleUse(ICommonSession session, EntityCoordinates coords, EntityUid uid)
|
||||||
{
|
{
|
||||||
if (!_transmitters.TryGetValue(session.SessionId, out var signalTransmitter))
|
if (!_transmitters.TryGetValue(session.UserId, out var signalTransmitter))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
|
|
||||||
if (entity.TryGetComponent<SignalTransmitterComponent>(out var transmitter))
|
if (entity.TryGetComponent<SignalTransmitterComponent>(out var transmitter))
|
||||||
{
|
{
|
||||||
_transmitters[session.SessionId] = transmitter.GetSignal(session.AttachedEntity);
|
_transmitters[session.UserId] = transmitter.GetSignal(session.AttachedEntity);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -129,7 +129,7 @@ namespace Content.Server.GameObjects.EntitySystems
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
system.SignalLinkerKeybind(player.SessionId, enable);
|
system.SignalLinkerKeybind(player.UserId, enable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking
|
namespace Content.Server.GameTicking
|
||||||
{
|
{
|
||||||
@@ -13,6 +14,6 @@ namespace Content.Server.GameTicking
|
|||||||
public virtual string ModeTitle => "Sandbox";
|
public virtual string ModeTitle => "Sandbox";
|
||||||
public virtual string Description => "Secret!";
|
public virtual string Description => "Secret!";
|
||||||
public virtual bool DisallowLateJoin => false;
|
public virtual bool DisallowLateJoin => false;
|
||||||
public Dictionary<string, HumanoidCharacterProfile> readyProfiles;
|
public Dictionary<NetUserId, HumanoidCharacterProfile> readyProfiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,11 +76,11 @@ namespace Content.Server.GameTicking.GamePresets
|
|||||||
|
|
||||||
foreach (var player in list)
|
foreach (var player in list)
|
||||||
{
|
{
|
||||||
if (!readyProfiles.ContainsKey(player.Name))
|
if (!readyProfiles.ContainsKey(player.UserId))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var profile = readyProfiles[player.Name];
|
var profile = readyProfiles[player.UserId];
|
||||||
if (profile.AntagPreferences.Contains(_prototypeManager.Index<AntagPrototype>(TraitorID).Name))
|
if (profile.AntagPreferences.Contains(_prototypeManager.Index<AntagPrototype>(TraitorID).Name))
|
||||||
{
|
{
|
||||||
prefList.Add(player);
|
prefList.Add(player);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using Content.Shared.Preferences;
|
|||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
@@ -19,7 +20,7 @@ namespace Content.Server.GameTicking
|
|||||||
private readonly Dictionary<string, int> _spawnedPositions = new Dictionary<string, int>();
|
private readonly Dictionary<string, int> _spawnedPositions = new Dictionary<string, int>();
|
||||||
|
|
||||||
private Dictionary<IPlayerSession, string> AssignJobs(List<IPlayerSession> available,
|
private Dictionary<IPlayerSession, string> AssignJobs(List<IPlayerSession> available,
|
||||||
Dictionary<string, HumanoidCharacterProfile> profiles)
|
Dictionary<NetUserId, HumanoidCharacterProfile> profiles)
|
||||||
{
|
{
|
||||||
// Calculate positions available round-start for each job.
|
// Calculate positions available round-start for each job.
|
||||||
var availablePositions = GetBasePositions(true);
|
var availablePositions = GetBasePositions(true);
|
||||||
@@ -38,7 +39,7 @@ namespace Content.Server.GameTicking
|
|||||||
var candidates = available
|
var candidates = available
|
||||||
.Select(player =>
|
.Select(player =>
|
||||||
{
|
{
|
||||||
var profile = profiles[player.Name];
|
var profile = profiles[player.UserId];
|
||||||
|
|
||||||
var availableJobs = profile.JobPriorities
|
var availableJobs = profile.JobPriorities
|
||||||
.Where(j =>
|
.Where(j =>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Content.Server.GameObjects.Components.Access;
|
using Content.Server.GameObjects.Components.Access;
|
||||||
using Content.Server.GameObjects.Components.GUI;
|
using Content.Server.GameObjects.Components.GUI;
|
||||||
using Content.Server.GameObjects.Components.Items.Storage;
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
@@ -34,7 +33,6 @@ using Robust.Server.Interfaces.Maps;
|
|||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Server.ServerStatus;
|
using Robust.Server.ServerStatus;
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.GameObjects.Systems;
|
using Robust.Shared.GameObjects.Systems;
|
||||||
@@ -222,7 +220,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void StartRound(bool force = false)
|
public void StartRound(bool force = false)
|
||||||
{
|
{
|
||||||
DebugTools.Assert(RunLevel == GameRunLevel.PreRoundLobby);
|
DebugTools.Assert(RunLevel == GameRunLevel.PreRoundLobby);
|
||||||
Logger.InfoS("ticker", "Starting round!");
|
Logger.InfoS("ticker", "Starting round!");
|
||||||
@@ -244,16 +242,16 @@ namespace Content.Server.GameTicking
|
|||||||
RoundLengthMetric.Set(0);
|
RoundLengthMetric.Set(0);
|
||||||
|
|
||||||
// Get the profiles for each player for easier lookup.
|
// Get the profiles for each player for easier lookup.
|
||||||
var profiles = (await _prefsManager.GetSelectedProfilesForPlayersAsync(
|
var profiles = _prefsManager.GetSelectedProfilesForPlayers(
|
||||||
readyPlayers
|
readyPlayers
|
||||||
.Select(p => p.Name).ToList()))
|
.Select(p => p.UserId).ToList())
|
||||||
.ToDictionary(p => p.Key, p => (HumanoidCharacterProfile) p.Value);
|
.ToDictionary(p => p.Key, p => (HumanoidCharacterProfile) p.Value);
|
||||||
|
|
||||||
foreach (var readyPlayer in readyPlayers)
|
foreach (var readyPlayer in readyPlayers)
|
||||||
{
|
{
|
||||||
if (!profiles.ContainsKey(readyPlayer.Name))
|
if (!profiles.ContainsKey(readyPlayer.UserId))
|
||||||
{
|
{
|
||||||
profiles.Add(readyPlayer.Name, HumanoidCharacterProfile.Default());
|
profiles.Add(readyPlayer.UserId, HumanoidCharacterProfile.Default());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,7 +265,7 @@ namespace Content.Server.GameTicking
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var profile = profiles[player.Name];
|
var profile = profiles[player.UserId];
|
||||||
if (profile.PreferenceUnavailable == PreferenceUnavailableMode.SpawnAsOverflow)
|
if (profile.PreferenceUnavailable == PreferenceUnavailableMode.SpawnAsOverflow)
|
||||||
{
|
{
|
||||||
assignedJobs.Add(player, OverflowJob);
|
assignedJobs.Add(player, OverflowJob);
|
||||||
@@ -277,7 +275,7 @@ namespace Content.Server.GameTicking
|
|||||||
// Spawn everybody in!
|
// Spawn everybody in!
|
||||||
foreach (var (player, job) in assignedJobs)
|
foreach (var (player, job) in assignedJobs)
|
||||||
{
|
{
|
||||||
SpawnPlayer(player, profiles[player.Name], job, false);
|
SpawnPlayer(player, profiles[player.UserId], job, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time to start the preset.
|
// Time to start the preset.
|
||||||
@@ -320,9 +318,10 @@ namespace Content.Server.GameTicking
|
|||||||
IoCManager.Resolve<IServerNetManager>().ServerSendToAll(msg);
|
IoCManager.Resolve<IServerNetManager>().ServerSendToAll(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<HumanoidCharacterProfile> GetPlayerProfileAsync(IPlayerSession p) =>
|
private HumanoidCharacterProfile GetPlayerProfile(IPlayerSession p)
|
||||||
(HumanoidCharacterProfile) (await _prefsManager.GetPreferencesAsync(p.SessionId.Username))
|
{
|
||||||
.SelectedCharacter;
|
return (HumanoidCharacterProfile) _prefsManager.GetPreferences(p.UserId).SelectedCharacter;
|
||||||
|
}
|
||||||
|
|
||||||
public void EndRound(string roundEndText = "")
|
public void EndRound(string roundEndText = "")
|
||||||
{
|
{
|
||||||
@@ -373,7 +372,7 @@ namespace Content.Server.GameTicking
|
|||||||
if (LobbyEnabled)
|
if (LobbyEnabled)
|
||||||
_playerJoinLobby(targetPlayer);
|
_playerJoinLobby(targetPlayer);
|
||||||
else
|
else
|
||||||
SpawnPlayerAsync(targetPlayer);
|
SpawnPlayer(targetPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MakeObserve(IPlayerSession player)
|
public void MakeObserve(IPlayerSession player)
|
||||||
@@ -389,13 +388,23 @@ namespace Content.Server.GameTicking
|
|||||||
{
|
{
|
||||||
if (!_playersInLobby.ContainsKey(player)) return;
|
if (!_playersInLobby.ContainsKey(player)) return;
|
||||||
|
|
||||||
SpawnPlayerAsync(player, jobId);
|
if (!_prefsManager.HavePreferencesLoaded(player))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SpawnPlayer(player, jobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleReady(IPlayerSession player, bool ready)
|
public void ToggleReady(IPlayerSession player, bool ready)
|
||||||
{
|
{
|
||||||
if (!_playersInLobby.ContainsKey(player)) return;
|
if (!_playersInLobby.ContainsKey(player)) return;
|
||||||
|
|
||||||
|
if (!_prefsManager.HavePreferencesLoaded(player))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var status = ready ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
var status = ready ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
||||||
_playersInLobby[player] = ready ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
_playersInLobby[player] = ready ? PlayerStatus.Ready : PlayerStatus.NotReady;
|
||||||
_netManager.ServerSendMessage(_getStatusMsg(player), player.ConnectedClient);
|
_netManager.ServerSendMessage(_getStatusMsg(player), player.ConnectedClient);
|
||||||
@@ -703,7 +712,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
case SessionStatus.Connected:
|
case SessionStatus.Connected:
|
||||||
{
|
{
|
||||||
_chatManager.DispatchServerAnnouncement($"Player {args.Session.SessionId} joined server!");
|
_chatManager.DispatchServerAnnouncement($"Player {args.Session.Name} joined server!");
|
||||||
|
|
||||||
if (LobbyEnabled && _roundStartCountdownHasNotStartedYetDueToNoPlayers)
|
if (LobbyEnabled && _roundStartCountdownHasNotStartedYetDueToNoPlayers)
|
||||||
{
|
{
|
||||||
@@ -716,6 +725,8 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
case SessionStatus.InGame:
|
case SessionStatus.InGame:
|
||||||
{
|
{
|
||||||
|
_prefsManager.OnClientConnected(session);
|
||||||
|
|
||||||
var data = session.ContentData();
|
var data = session.ContentData();
|
||||||
if (data.Mind == null)
|
if (data.Mind == null)
|
||||||
{
|
{
|
||||||
@@ -725,13 +736,14 @@ namespace Content.Server.GameTicking
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnPlayerAsync(session);
|
|
||||||
|
SpawnWaitPrefs();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (data.Mind.CurrentEntity == null)
|
if (data.Mind.CurrentEntity == null)
|
||||||
{
|
{
|
||||||
SpawnPlayerAsync(session);
|
SpawnWaitPrefs();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -747,11 +759,18 @@ namespace Content.Server.GameTicking
|
|||||||
{
|
{
|
||||||
if (_playersInLobby.ContainsKey(session)) _playersInLobby.Remove(session);
|
if (_playersInLobby.ContainsKey(session)) _playersInLobby.Remove(session);
|
||||||
|
|
||||||
_chatManager.DispatchServerAnnouncement($"Player {args.Session.SessionId} left server!");
|
_chatManager.DispatchServerAnnouncement($"Player {args.Session} left server!");
|
||||||
ServerEmptyUpdateRestartCheck();
|
ServerEmptyUpdateRestartCheck();
|
||||||
|
_prefsManager.OnClientDisconnected(session);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async void SpawnWaitPrefs()
|
||||||
|
{
|
||||||
|
await _prefsManager.WaitPreferencesLoaded(session);
|
||||||
|
SpawnPlayer(session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -785,11 +804,9 @@ namespace Content.Server.GameTicking
|
|||||||
}, _updateShutdownCts.Token);
|
}, _updateShutdownCts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SpawnPlayerAsync(IPlayerSession session, string jobId = null, bool lateJoin = true)
|
private void SpawnPlayer(IPlayerSession session, string jobId = null, bool lateJoin = true)
|
||||||
{
|
{
|
||||||
var character = (HumanoidCharacterProfile) (await _prefsManager
|
var character = GetPlayerProfile(session);
|
||||||
.GetPreferencesAsync(session.SessionId.Username))
|
|
||||||
.SelectedCharacter;
|
|
||||||
|
|
||||||
SpawnPlayer(session, character, jobId, lateJoin);
|
SpawnPlayer(session, character, jobId, lateJoin);
|
||||||
}
|
}
|
||||||
@@ -809,7 +826,7 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
var data = session.ContentData();
|
var data = session.ContentData();
|
||||||
data.WipeMind();
|
data.WipeMind();
|
||||||
data.Mind = new Mind(session.SessionId)
|
data.Mind = new Mind(session.UserId)
|
||||||
{
|
{
|
||||||
CharacterName = character.Name
|
CharacterName = character.Name
|
||||||
};
|
};
|
||||||
@@ -866,17 +883,15 @@ namespace Content.Server.GameTicking
|
|||||||
_manifest.Add(new ManifestEntry(characterName, jobId));
|
_manifest.Add(new ManifestEntry(characterName, jobId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void _spawnObserver(IPlayerSession session)
|
private void _spawnObserver(IPlayerSession session)
|
||||||
{
|
{
|
||||||
_playerJoinGame(session);
|
_playerJoinGame(session);
|
||||||
|
|
||||||
var name = (await _prefsManager
|
var name = GetPlayerProfile(session).Name;
|
||||||
.GetPreferencesAsync(session.SessionId.Username))
|
|
||||||
.SelectedCharacter.Name;
|
|
||||||
|
|
||||||
var data = session.ContentData();
|
var data = session.ContentData();
|
||||||
data.WipeMind();
|
data.WipeMind();
|
||||||
data.Mind = new Mind(session.SessionId);
|
data.Mind = new Mind(session.UserId);
|
||||||
|
|
||||||
var mob = _spawnObserverMob();
|
var mob = _spawnObserverMob();
|
||||||
mob.Name = name;
|
mob.Name = name;
|
||||||
@@ -888,7 +903,6 @@ namespace Content.Server.GameTicking
|
|||||||
{
|
{
|
||||||
_playersInLobby.Add(session, PlayerStatus.NotReady);
|
_playersInLobby.Add(session, PlayerStatus.NotReady);
|
||||||
|
|
||||||
_prefsManager.OnClientConnected(session);
|
|
||||||
_netManager.ServerSendMessage(_netManager.CreateNetMessage<MsgTickerJoinLobby>(), session.ConnectedClient);
|
_netManager.ServerSendMessage(_netManager.CreateNetMessage<MsgTickerJoinLobby>(), session.ConnectedClient);
|
||||||
_netManager.ServerSendMessage(_getStatusMsg(session), session.ConnectedClient);
|
_netManager.ServerSendMessage(_getStatusMsg(session), session.ConnectedClient);
|
||||||
_netManager.ServerSendMessage(GetInfoMsg(), session.ConnectedClient);
|
_netManager.ServerSendMessage(GetInfoMsg(), session.ConnectedClient);
|
||||||
@@ -907,11 +921,11 @@ namespace Content.Server.GameTicking
|
|||||||
private MsgTickerLobbyReady GetPlayerStatus()
|
private MsgTickerLobbyReady GetPlayerStatus()
|
||||||
{
|
{
|
||||||
var msg = _netManager.CreateNetMessage<MsgTickerLobbyReady>();
|
var msg = _netManager.CreateNetMessage<MsgTickerLobbyReady>();
|
||||||
msg.PlayerStatus = new Dictionary<NetSessionId, PlayerStatus>();
|
msg.PlayerStatus = new Dictionary<NetUserId, PlayerStatus>();
|
||||||
foreach (var player in _playersInLobby.Keys)
|
foreach (var player in _playersInLobby.Keys)
|
||||||
{
|
{
|
||||||
_playersInLobby.TryGetValue(player, out var status);
|
_playersInLobby.TryGetValue(player, out var status);
|
||||||
msg.PlayerStatus.Add(player.SessionId, status);
|
msg.PlayerStatus.Add(player.UserId, status);
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
@@ -919,9 +933,9 @@ namespace Content.Server.GameTicking
|
|||||||
private MsgTickerLobbyReady GetStatusSingle(IPlayerSession player, PlayerStatus status)
|
private MsgTickerLobbyReady GetStatusSingle(IPlayerSession player, PlayerStatus status)
|
||||||
{
|
{
|
||||||
var msg = _netManager.CreateNetMessage<MsgTickerLobbyReady>();
|
var msg = _netManager.CreateNetMessage<MsgTickerLobbyReady>();
|
||||||
msg.PlayerStatus = new Dictionary<NetSessionId, PlayerStatus>
|
msg.PlayerStatus = new Dictionary<NetUserId, PlayerStatus>
|
||||||
{
|
{
|
||||||
{ player.SessionId, status }
|
{ player.UserId, status }
|
||||||
};
|
};
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
@@ -967,7 +981,7 @@ The current game mode is: [color=white]{0}[/color].
|
|||||||
_netManager.ServerSendToMany(infoMsg, _playersInLobby.Keys.Select(p => p.ConnectedClient).ToList());
|
_netManager.ServerSendToMany(infoMsg, _playersInLobby.Keys.Select(p => p.ConnectedClient).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private GamePreset MakeGamePreset(Dictionary<string, HumanoidCharacterProfile> readyProfiles)
|
private GamePreset MakeGamePreset(Dictionary<NetUserId, HumanoidCharacterProfile> readyProfiles)
|
||||||
{
|
{
|
||||||
var preset = _dynamicTypeFactory.CreateInstance<GamePreset>(_presetType ?? typeof(PresetSandbox));
|
var preset = _dynamicTypeFactory.CreateInstance<GamePreset>(_presetType ?? typeof(PresetSandbox));
|
||||||
preset.readyProfiles = readyProfiles;
|
preset.readyProfiles = readyProfiles;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Content.Server.GameTicking
|
|||||||
{
|
{
|
||||||
// Always make sure the client has player data. Mind gets assigned on spawn.
|
// Always make sure the client has player data. Mind gets assigned on spawn.
|
||||||
if (session.Data.ContentDataUncast == null)
|
if (session.Data.ContentDataUncast == null)
|
||||||
session.Data.ContentDataUncast = new PlayerData(session.SessionId);
|
session.Data.ContentDataUncast = new PlayerData(session.UserId);
|
||||||
|
|
||||||
// timer time must be > tick length
|
// timer time must be > tick length
|
||||||
Timer.Spawn(0, args.Session.JoinGame);
|
Timer.Spawn(0, args.Session.JoinGame);
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ namespace Content.Server.GameTicking
|
|||||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
var ticker = IoCManager.Resolve<IGameTicker>();
|
var ticker = IoCManager.Resolve<IGameTicker>();
|
||||||
|
|
||||||
NetSessionId sessionId;
|
NetUserId userId;
|
||||||
if (args.Length == 0)
|
if (args.Length == 0)
|
||||||
{
|
{
|
||||||
if (player == null)
|
if (player == null)
|
||||||
@@ -139,16 +139,17 @@ namespace Content.Server.GameTicking
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionId = player.SessionId;
|
userId = player.UserId;
|
||||||
}
|
}
|
||||||
else
|
else if (!playerMgr.TryGetUserId(args[0], out userId))
|
||||||
{
|
{
|
||||||
sessionId = new NetSessionId(args[0]);
|
shell.SendText(player, "Unknown player");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!playerMgr.TryGetSessionById(sessionId, out var targetPlayer))
|
if (!playerMgr.TryGetSessionById(userId, out var targetPlayer))
|
||||||
{
|
{
|
||||||
if (!playerMgr.TryGetPlayerData(sessionId, out var data))
|
if (!playerMgr.TryGetPlayerData(userId, out var data))
|
||||||
{
|
{
|
||||||
shell.SendText(player, "Unknown player");
|
shell.SendText(player, "Unknown player");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2,15 +2,21 @@ using System.Collections.Generic;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
|
||||||
namespace Content.Server.Interfaces
|
namespace Content.Server.Interfaces
|
||||||
{
|
{
|
||||||
public interface IServerPreferencesManager
|
public interface IServerPreferencesManager
|
||||||
{
|
{
|
||||||
void FinishInit();
|
void Init();
|
||||||
|
|
||||||
void OnClientConnected(IPlayerSession session);
|
void OnClientConnected(IPlayerSession session);
|
||||||
Task<PlayerPreferences> GetPreferencesAsync(string username);
|
void OnClientDisconnected(IPlayerSession session);
|
||||||
Task<IEnumerable<KeyValuePair<string, ICharacterProfile>>> GetSelectedProfilesForPlayersAsync(List<string> usernames);
|
|
||||||
void StartInit();
|
bool HavePreferencesLoaded(IPlayerSession session);
|
||||||
|
Task WaitPreferencesLoaded(IPlayerSession session);
|
||||||
|
|
||||||
|
PlayerPreferences GetPreferences(NetUserId userId);
|
||||||
|
IEnumerable<KeyValuePair<NetUserId, ICharacterProfile>> GetSelectedProfilesForPlayers(List<NetUserId> userIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ namespace Content.Server.Mobs
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mgr = IoCManager.Resolve<IPlayerManager>();
|
var mgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
if (mgr.TryGetPlayerData(new NetSessionId(args[0]), out var data))
|
if (mgr.TryGetSessionByUsername(args[0], out var data))
|
||||||
{
|
{
|
||||||
var mind = data.ContentData().Mind;
|
var mind = data.ContentData().Mind;
|
||||||
|
|
||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
builder.AppendFormat("player: {0}, mob: {1}\nroles: ", mind.SessionId, mind.OwnedMob?.Owner?.Uid);
|
builder.AppendFormat("player: {0}, mob: {1}\nroles: ", mind.UserId, mind.OwnedMob?.Owner?.Uid);
|
||||||
foreach (var role in mind.AllRoles)
|
foreach (var role in mind.AllRoles)
|
||||||
{
|
{
|
||||||
builder.AppendFormat("{0} ", role.Name);
|
builder.AppendFormat("{0} ", role.Name);
|
||||||
@@ -68,7 +68,7 @@ namespace Content.Server.Mobs
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mgr = IoCManager.Resolve<IPlayerManager>();
|
var mgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
if (mgr.TryGetPlayerData(new NetSessionId(args[0]), out var data))
|
if (mgr.TryGetPlayerDataByUsername(args[0], out var data))
|
||||||
{
|
{
|
||||||
var mind = data.ContentData().Mind;
|
var mind = data.ContentData().Mind;
|
||||||
var role = new Job(mind, _prototypeManager.Index<JobPrototype>(args[1]));
|
var role = new Job(mind, _prototypeManager.Index<JobPrototype>(args[1]));
|
||||||
@@ -100,7 +100,7 @@ namespace Content.Server.Mobs
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mgr = IoCManager.Resolve<IPlayerManager>();
|
var mgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
if (mgr.TryGetPlayerData(new NetSessionId(args[0]), out var data))
|
if (mgr.TryGetPlayerDataByUsername(args[0], out var data))
|
||||||
{
|
{
|
||||||
var mind = data.ContentData().Mind;
|
var mind = data.ContentData().Mind;
|
||||||
var role = new Job(mind, _prototypeManager.Index<JobPrototype>(args[1]));
|
var role = new Job(mind, _prototypeManager.Index<JobPrototype>(args[1]));
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ namespace Content.Server.Mobs
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the new mind attached to a specific player session.
|
/// Creates the new mind attached to a specific player session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sessionId">The session ID of the owning player.</param>
|
/// <param name="userId">The session ID of the owning player.</param>
|
||||||
public Mind(NetSessionId sessionId)
|
public Mind(NetUserId userId)
|
||||||
{
|
{
|
||||||
SessionId = sessionId;
|
UserId = userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This session should be able to be changed, probably.
|
// TODO: This session should be able to be changed, probably.
|
||||||
@@ -41,7 +41,7 @@ namespace Content.Server.Mobs
|
|||||||
/// The session ID of the player owning this mind.
|
/// The session ID of the player owning this mind.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public NetSessionId? SessionId { get; private set; }
|
public NetUserId? UserId { get; private set; }
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public bool IsVisitingEntity => VisitingEntity != null;
|
public bool IsVisitingEntity => VisitingEntity != null;
|
||||||
@@ -83,12 +83,12 @@ namespace Content.Server.Mobs
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!SessionId.HasValue)
|
if (!UserId.HasValue)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
playerMgr.TryGetSessionById(SessionId.Value, out var ret);
|
playerMgr.TryGetSessionById(UserId.Value, out var ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -195,7 +195,7 @@ namespace Content.Server.Mobs
|
|||||||
VisitingEntity = null;
|
VisitingEntity = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeOwningPlayer(NetSessionId? newOwner)
|
public void ChangeOwningPlayer(NetUserId? newOwner)
|
||||||
{
|
{
|
||||||
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
var playerMgr = IoCManager.Resolve<IPlayerManager>();
|
||||||
PlayerData newOwnerData = null;
|
PlayerData newOwnerData = null;
|
||||||
@@ -216,12 +216,12 @@ namespace Content.Server.Mobs
|
|||||||
var oldSession = Session;
|
var oldSession = Session;
|
||||||
oldSession?.AttachToEntity(null);
|
oldSession?.AttachToEntity(null);
|
||||||
|
|
||||||
if (SessionId.HasValue)
|
if (UserId.HasValue)
|
||||||
{
|
{
|
||||||
playerMgr.GetPlayerData(SessionId.Value).ContentData().Mind = null;
|
playerMgr.GetPlayerData(UserId.Value).ContentData().Mind = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionId = newOwner;
|
UserId = newOwner;
|
||||||
if (!newOwner.HasValue)
|
if (!newOwner.HasValue)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Content.Server.Players
|
|||||||
/// The session ID of the player owning this data.
|
/// The session ID of the player owning this data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public NetSessionId SessionId { get; }
|
public NetUserId UserId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The currently occupied mind of the player owning this data.
|
/// The currently occupied mind of the player owning this data.
|
||||||
@@ -31,9 +31,9 @@ namespace Content.Server.Players
|
|||||||
Mind = null;
|
Mind = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerData(NetSessionId sessionId)
|
public PlayerData(NetUserId userId)
|
||||||
{
|
{
|
||||||
SessionId = sessionId;
|
UserId = userId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,167 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Content.Server.Database;
|
|
||||||
using Content.Shared.Preferences;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using static Content.Shared.Preferences.Sex;
|
|
||||||
|
|
||||||
namespace Content.Server.Preferences
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides methods to retrieve and update character preferences.
|
|
||||||
/// Don't use this directly, go through <see cref="ServerPreferencesManager" /> instead.
|
|
||||||
/// </summary>
|
|
||||||
public class PreferencesDatabase
|
|
||||||
{
|
|
||||||
private readonly int _maxCharacterSlots;
|
|
||||||
private readonly PrefsDb _prefsDb;
|
|
||||||
|
|
||||||
// We use a single DbContext for the entire DB connection, and EFCore doesn't allow concurrent access.
|
|
||||||
// So we need this semaphore to prevent bugs.
|
|
||||||
private readonly SemaphoreSlim _prefsSemaphore = new SemaphoreSlim(1, 1);
|
|
||||||
|
|
||||||
public PreferencesDatabase(IDatabaseConfiguration dbConfig, int maxCharacterSlots)
|
|
||||||
{
|
|
||||||
_maxCharacterSlots = maxCharacterSlots;
|
|
||||||
_prefsDb = new PrefsDb(dbConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<PlayerPreferences> GetPlayerPreferencesAsync(string username)
|
|
||||||
{
|
|
||||||
await _prefsSemaphore.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var prefs = await _prefsDb.GetPlayerPreferences(username);
|
|
||||||
if (prefs is null) return null;
|
|
||||||
|
|
||||||
var profiles = new ICharacterProfile[_maxCharacterSlots];
|
|
||||||
foreach (var profile in prefs.HumanoidProfiles)
|
|
||||||
{
|
|
||||||
profiles[profile.Slot] = ConvertProfiles(profile);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PlayerPreferences
|
|
||||||
(
|
|
||||||
profiles,
|
|
||||||
prefs.SelectedCharacterSlot
|
|
||||||
);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_prefsSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SaveSelectedCharacterIndexAsync(string username, int index)
|
|
||||||
{
|
|
||||||
await _prefsSemaphore.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
index = MathHelper.Clamp(index, 0, _maxCharacterSlots - 1);
|
|
||||||
await _prefsDb.SaveSelectedCharacterIndex(username, index);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_prefsSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task SaveCharacterSlotAsync(string username, ICharacterProfile profile, int slot)
|
|
||||||
{
|
|
||||||
if (slot < 0 || slot >= _maxCharacterSlots)
|
|
||||||
return;
|
|
||||||
|
|
||||||
await _prefsSemaphore.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (profile is null)
|
|
||||||
{
|
|
||||||
await DeleteCharacterSlotAsync(username, slot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(profile is HumanoidCharacterProfile humanoid))
|
|
||||||
// TODO: Handle other ICharacterProfile implementations properly
|
|
||||||
throw new NotImplementedException();
|
|
||||||
var appearance = (HumanoidCharacterAppearance) humanoid.CharacterAppearance;
|
|
||||||
var entity = new HumanoidProfile
|
|
||||||
{
|
|
||||||
SlotName = humanoid.Name,
|
|
||||||
CharacterName = humanoid.Name,
|
|
||||||
Age = humanoid.Age,
|
|
||||||
Sex = humanoid.Sex.ToString(),
|
|
||||||
HairName = appearance.HairStyleName,
|
|
||||||
HairColor = appearance.HairColor.ToHex(),
|
|
||||||
FacialHairName = appearance.FacialHairStyleName,
|
|
||||||
FacialHairColor = appearance.FacialHairColor.ToHex(),
|
|
||||||
EyeColor = appearance.EyeColor.ToHex(),
|
|
||||||
SkinColor = appearance.SkinColor.ToHex(),
|
|
||||||
Slot = slot,
|
|
||||||
PreferenceUnavailable = (DbPreferenceUnavailableMode) humanoid.PreferenceUnavailable
|
|
||||||
};
|
|
||||||
entity.Jobs.AddRange(
|
|
||||||
humanoid.JobPriorities
|
|
||||||
.Where(j => j.Value != JobPriority.Never)
|
|
||||||
.Select(j => new Job {JobName = j.Key, Priority = (DbJobPriority) j.Value})
|
|
||||||
);
|
|
||||||
entity.Antags.AddRange(
|
|
||||||
humanoid.AntagPreferences
|
|
||||||
.Select(a => new Antag {AntagName = a})
|
|
||||||
);
|
|
||||||
await _prefsDb.SaveCharacterSlotAsync(username, entity);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_prefsSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private async Task DeleteCharacterSlotAsync(string username, int slot)
|
|
||||||
{
|
|
||||||
await _prefsDb.DeleteCharacterSlotAsync(username, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IEnumerable<KeyValuePair<string, ICharacterProfile>>> GetSelectedProfilesForPlayersAsync(
|
|
||||||
List<string> usernames)
|
|
||||||
{
|
|
||||||
await _prefsSemaphore.WaitAsync();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var profiles = await _prefsDb.GetProfilesForPlayersAsync(usernames);
|
|
||||||
return profiles.Select(
|
|
||||||
p => new KeyValuePair<string, ICharacterProfile>(p.Key, ConvertProfiles(p.Value)));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_prefsSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HumanoidCharacterProfile ConvertProfiles(HumanoidProfile profile)
|
|
||||||
{
|
|
||||||
var jobs = profile.Jobs.ToDictionary(j => j.JobName, j => (JobPriority) j.Priority);
|
|
||||||
var antags = profile.Antags.Select(a => a.AntagName);
|
|
||||||
return new HumanoidCharacterProfile(
|
|
||||||
profile.CharacterName,
|
|
||||||
profile.Age,
|
|
||||||
profile.Sex == "Male" ? Male : Female,
|
|
||||||
new HumanoidCharacterAppearance
|
|
||||||
(
|
|
||||||
profile.HairName,
|
|
||||||
Color.FromHex(profile.HairColor),
|
|
||||||
profile.FacialHairName,
|
|
||||||
Color.FromHex(profile.FacialHairColor),
|
|
||||||
Color.FromHex(profile.EyeColor),
|
|
||||||
Color.FromHex(profile.SkinColor)
|
|
||||||
),
|
|
||||||
jobs,
|
|
||||||
(PreferenceUnavailableMode) profile.PreferenceUnavailable,
|
|
||||||
antags.ToList()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
using Content.Server.Interfaces;
|
using Content.Server.Interfaces;
|
||||||
|
using Content.Shared;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
using Robust.Shared.Interfaces.Configuration;
|
using Robust.Shared.Interfaces.Configuration;
|
||||||
using Robust.Shared.Interfaces.Network;
|
using Robust.Shared.Interfaces.Network;
|
||||||
using Robust.Shared.Interfaces.Resources;
|
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
namespace Content.Server.Preferences
|
namespace Content.Server.Preferences
|
||||||
{
|
{
|
||||||
@@ -20,119 +25,188 @@ namespace Content.Server.Preferences
|
|||||||
public class ServerPreferencesManager : SharedPreferencesManager, IServerPreferencesManager
|
public class ServerPreferencesManager : SharedPreferencesManager, IServerPreferencesManager
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IServerNetManager _netManager = default!;
|
[Dependency] private readonly IServerNetManager _netManager = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configuration = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IResourceManager _resourceManager = default!;
|
[Dependency] private readonly IServerDbManager _db = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _protos = default!;
|
||||||
|
|
||||||
private PreferencesDatabase _preferencesDb;
|
// Cache player prefs on the server so we don't need as much async hell related to them.
|
||||||
private Task<PreferencesDatabase> _prefsDbLoadTask;
|
private readonly Dictionary<NetUserId, PlayerPrefData> _cachedPlayerPrefs =
|
||||||
|
new Dictionary<NetUserId, PlayerPrefData>();
|
||||||
|
|
||||||
public void StartInit()
|
private int MaxCharacterSlots => _cfg.GetCVar(CCVars.GameMaxCharacterSlots);
|
||||||
|
|
||||||
|
public void Init()
|
||||||
{
|
{
|
||||||
_netManager.RegisterNetMessage<MsgPreferencesAndSettings>(nameof(MsgPreferencesAndSettings));
|
_netManager.RegisterNetMessage<MsgPreferencesAndSettings>(nameof(MsgPreferencesAndSettings));
|
||||||
_netManager.RegisterNetMessage<MsgSelectCharacter>(nameof(MsgSelectCharacter),
|
_netManager.RegisterNetMessage<MsgSelectCharacter>(nameof(MsgSelectCharacter),
|
||||||
HandleSelectCharacterMessage);
|
HandleSelectCharacterMessage);
|
||||||
_netManager.RegisterNetMessage<MsgUpdateCharacter>(nameof(MsgUpdateCharacter),
|
_netManager.RegisterNetMessage<MsgUpdateCharacter>(nameof(MsgUpdateCharacter),
|
||||||
HandleUpdateCharacterMessage);
|
HandleUpdateCharacterMessage);
|
||||||
|
|
||||||
_configuration.RegisterCVar("game.maxcharacterslots", 10);
|
|
||||||
_configuration.RegisterCVar("database.prefs_engine", "sqlite");
|
|
||||||
_configuration.RegisterCVar("database.prefs_sqlite_dbpath", "preferences.db");
|
|
||||||
_configuration.RegisterCVar("database.prefs_pg_host", "localhost");
|
|
||||||
_configuration.RegisterCVar("database.prefs_pg_port", 5432);
|
|
||||||
_configuration.RegisterCVar("database.prefs_pg_database", "ss14_prefs");
|
|
||||||
_configuration.RegisterCVar("database.prefs_pg_username", string.Empty);
|
|
||||||
_configuration.RegisterCVar("database.prefs_pg_password", string.Empty);
|
|
||||||
|
|
||||||
var engine = _configuration.GetCVar<string>("database.prefs_engine").ToLower();
|
|
||||||
IDatabaseConfiguration dbConfig;
|
|
||||||
switch (engine)
|
|
||||||
{
|
|
||||||
case "sqlite":
|
|
||||||
var configPreferencesDbPath = _configuration.GetCVar<string>("database.prefs_sqlite_dbpath");
|
|
||||||
var inMemory = _resourceManager.UserData.RootDir == null;
|
|
||||||
var finalPreferencesDbPath = inMemory ?
|
|
||||||
null :
|
|
||||||
Path.Combine(_resourceManager.UserData.RootDir, configPreferencesDbPath);
|
|
||||||
dbConfig = new SqliteConfiguration(finalPreferencesDbPath);
|
|
||||||
break;
|
|
||||||
case "postgres":
|
|
||||||
dbConfig = new PostgresConfiguration(
|
|
||||||
_configuration.GetCVar<string>("database.prefs_pg_host"),
|
|
||||||
_configuration.GetCVar<int>("database.prefs_pg_port"),
|
|
||||||
_configuration.GetCVar<string>("database.prefs_pg_database"),
|
|
||||||
_configuration.GetCVar<string>("database.prefs_pg_username"),
|
|
||||||
_configuration.GetCVar<string>("database.prefs_pg_password")
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException("Unknown database engine {engine}.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxCharacterSlots = _configuration.GetCVar<int>("game.maxcharacterslots");
|
|
||||||
|
|
||||||
// Actually loading the preferences database takes a while,
|
|
||||||
// because EFCore has to initialize and run migrations.
|
|
||||||
// We load it in the thread pool here and then fetch the .Result in FinishInit.
|
|
||||||
// This means it'll run in parallel with other loading like prototypes & map load.
|
|
||||||
_prefsDbLoadTask = Task.Run(() => new PreferencesDatabase(dbConfig, maxCharacterSlots));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FinishInit()
|
|
||||||
{
|
|
||||||
_preferencesDb = _prefsDbLoadTask.Result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void HandleSelectCharacterMessage(MsgSelectCharacter message)
|
private async void HandleSelectCharacterMessage(MsgSelectCharacter message)
|
||||||
{
|
{
|
||||||
await _preferencesDb.SaveSelectedCharacterIndexAsync(message.MsgChannel.SessionId.Username,
|
var index = message.SelectedCharacterIndex;
|
||||||
message.SelectedCharacterIndex);
|
var userId = message.MsgChannel.UserId;
|
||||||
|
|
||||||
|
if (!_cachedPlayerPrefs.TryGetValue(userId, out var prefsData) || !prefsData.PrefsLoaded.IsCompleted)
|
||||||
|
{
|
||||||
|
Logger.WarningS("prefs", $"User {userId} tried to modify preferences before they loaded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index < 0 || index >= MaxCharacterSlots)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var curPrefs = prefsData.Prefs!;
|
||||||
|
|
||||||
|
prefsData.Prefs = new PlayerPreferences(curPrefs.Characters, index);
|
||||||
|
|
||||||
|
if (ShouldStorePrefs(message.MsgChannel.AuthType))
|
||||||
|
{
|
||||||
|
await _db.SaveSelectedCharacterIndexAsync(message.MsgChannel.UserId, message.SelectedCharacterIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void HandleUpdateCharacterMessage(MsgUpdateCharacter message)
|
private async void HandleUpdateCharacterMessage(MsgUpdateCharacter message)
|
||||||
{
|
{
|
||||||
await _preferencesDb.SaveCharacterSlotAsync(message.MsgChannel.SessionId.Username, message.Profile,
|
var slot = message.Slot;
|
||||||
message.Slot);
|
var profile = message.Profile;
|
||||||
|
var userId = message.MsgChannel.UserId;
|
||||||
|
|
||||||
|
if (!_cachedPlayerPrefs.TryGetValue(userId, out var prefsData) || !prefsData.PrefsLoaded.IsCompleted)
|
||||||
|
{
|
||||||
|
Logger.WarningS("prefs", $"User {userId} tried to modify preferences before they loaded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot < 0 || slot >= MaxCharacterSlots)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var curPrefs = prefsData.Prefs!;
|
||||||
|
|
||||||
|
var arr = new ICharacterProfile[MaxCharacterSlots];
|
||||||
|
curPrefs.Characters.ToList().CopyTo(arr, 0);
|
||||||
|
|
||||||
|
arr[slot] = HumanoidCharacterProfile.EnsureValid((HumanoidCharacterProfile) profile, _protos);
|
||||||
|
|
||||||
|
prefsData.Prefs = new PlayerPreferences(arr, slot);
|
||||||
|
|
||||||
|
if (ShouldStorePrefs(message.MsgChannel.AuthType))
|
||||||
|
{
|
||||||
|
await _db.SaveCharacterSlotAsync(message.MsgChannel.UserId, message.Profile, message.Slot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void OnClientConnected(IPlayerSession session)
|
public async void OnClientConnected(IPlayerSession session)
|
||||||
{
|
{
|
||||||
|
if (!ShouldStorePrefs(session.ConnectedClient.AuthType))
|
||||||
|
{
|
||||||
|
// Don't store data for guests.
|
||||||
|
var prefsData = new PlayerPrefData
|
||||||
|
{
|
||||||
|
PrefsLoaded = Task.CompletedTask,
|
||||||
|
Prefs = new PlayerPreferences(
|
||||||
|
new ICharacterProfile[] {HumanoidCharacterProfile.Default()},
|
||||||
|
0)
|
||||||
|
};
|
||||||
|
|
||||||
|
_cachedPlayerPrefs[session.UserId] = prefsData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var prefsData = new PlayerPrefData();
|
||||||
|
var loadTask = LoadPrefs();
|
||||||
|
prefsData.PrefsLoaded = loadTask;
|
||||||
|
_cachedPlayerPrefs[session.UserId] = prefsData;
|
||||||
|
|
||||||
|
await loadTask;
|
||||||
|
|
||||||
|
async Task LoadPrefs()
|
||||||
|
{
|
||||||
|
var prefs = await GetOrCreatePreferencesAsync(session.UserId);
|
||||||
|
prefsData.Prefs = prefs;
|
||||||
|
|
||||||
var msg = _netManager.CreateNetMessage<MsgPreferencesAndSettings>();
|
var msg = _netManager.CreateNetMessage<MsgPreferencesAndSettings>();
|
||||||
msg.Preferences = await GetPreferencesAsync(session.SessionId.Username);
|
msg.Preferences = prefs;
|
||||||
msg.Settings = new GameSettings
|
msg.Settings = new GameSettings
|
||||||
{
|
{
|
||||||
MaxCharacterSlots = _configuration.GetCVar<int>("game.maxcharacterslots")
|
MaxCharacterSlots = MaxCharacterSlots
|
||||||
};
|
};
|
||||||
_netManager.ServerSendMessage(msg, session.ConnectedClient);
|
_netManager.ServerSendMessage(msg, session.ConnectedClient);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the requested <see cref="PlayerPreferences"/> or null if not found.
|
public void OnClientDisconnected(IPlayerSession session)
|
||||||
/// </summary>
|
|
||||||
private async Task<PlayerPreferences> GetFromSql(string username)
|
|
||||||
{
|
{
|
||||||
return await _preferencesDb.GetPlayerPreferencesAsync(username);
|
_cachedPlayerPrefs.Remove(session.UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HavePreferencesLoaded(IPlayerSession session)
|
||||||
|
{
|
||||||
|
return _cachedPlayerPrefs.ContainsKey(session.UserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task WaitPreferencesLoaded(IPlayerSession session)
|
||||||
|
{
|
||||||
|
return _cachedPlayerPrefs[session.UserId].PrefsLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves preferences for the given username from storage.
|
/// Retrieves preferences for the given username from storage.
|
||||||
/// Creates and saves default preferences if they are not found, then returns them.
|
/// Creates and saves default preferences if they are not found, then returns them.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<PlayerPreferences> GetPreferencesAsync(string username)
|
public PlayerPreferences GetPreferences(NetUserId userId)
|
||||||
{
|
{
|
||||||
var prefs = await GetFromSql(username);
|
var prefs = _cachedPlayerPrefs[userId].Prefs;
|
||||||
if (prefs is null)
|
if (prefs == null)
|
||||||
{
|
{
|
||||||
await _preferencesDb.SaveSelectedCharacterIndexAsync(username, 0);
|
throw new InvalidOperationException("Preferences for this player have not loaded yet.");
|
||||||
await _preferencesDb.SaveCharacterSlotAsync(username, HumanoidCharacterProfile.Default(), 0);
|
|
||||||
prefs = await GetFromSql(username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefs;
|
return prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<KeyValuePair<string, ICharacterProfile>>> GetSelectedProfilesForPlayersAsync(List<string> usernames)
|
private async Task<PlayerPreferences> GetOrCreatePreferencesAsync(NetUserId userId)
|
||||||
{
|
{
|
||||||
return await _preferencesDb.GetSelectedProfilesForPlayersAsync(usernames);
|
var prefs = await _db.GetPlayerPreferencesAsync(userId);
|
||||||
|
if (prefs is null)
|
||||||
|
{
|
||||||
|
return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Default());
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<KeyValuePair<NetUserId, ICharacterProfile>> GetSelectedProfilesForPlayers(
|
||||||
|
List<NetUserId> usernames)
|
||||||
|
{
|
||||||
|
return usernames
|
||||||
|
.Select(p => (_cachedPlayerPrefs[p].Prefs, p))
|
||||||
|
.Where(p => p.Prefs != null)
|
||||||
|
.Select(p =>
|
||||||
|
{
|
||||||
|
var idx = p.Prefs!.SelectedCharacterIndex;
|
||||||
|
return new KeyValuePair<NetUserId, ICharacterProfile>(p.p, p.Prefs!.GetProfile(idx));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool ShouldStorePrefs(LoginType loginType)
|
||||||
|
{
|
||||||
|
return loginType.HasStaticUserId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class PlayerPrefData
|
||||||
|
{
|
||||||
|
public Task PrefsLoaded = default!;
|
||||||
|
public PlayerPreferences? Prefs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.AI.WorldState;
|
|||||||
using Content.Server.Body.Network;
|
using Content.Server.Body.Network;
|
||||||
using Content.Server.Cargo;
|
using Content.Server.Cargo;
|
||||||
using Content.Server.Chat;
|
using Content.Server.Chat;
|
||||||
|
using Content.Server.Database;
|
||||||
using Content.Server.GameObjects.Components.Mobs.Speech;
|
using Content.Server.GameObjects.Components.Mobs.Speech;
|
||||||
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
|
||||||
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
using Content.Server.GameObjects.Components.Power.PowerNetComponents;
|
||||||
@@ -34,6 +35,7 @@ namespace Content.Server
|
|||||||
IoCManager.Register<ICargoOrderDataManager, CargoOrderDataManager>();
|
IoCManager.Register<ICargoOrderDataManager, CargoOrderDataManager>();
|
||||||
IoCManager.Register<IModuleManager, ServerModuleManager>();
|
IoCManager.Register<IModuleManager, ServerModuleManager>();
|
||||||
IoCManager.Register<IServerPreferencesManager, ServerPreferencesManager>();
|
IoCManager.Register<IServerPreferencesManager, ServerPreferencesManager>();
|
||||||
|
IoCManager.Register<IServerDbManager, ServerDbManager>();
|
||||||
IoCManager.Register<RecipeManager, RecipeManager>();
|
IoCManager.Register<RecipeManager, RecipeManager>();
|
||||||
IoCManager.Register<IPDAUplinkManager,PDAUplinkManager>();
|
IoCManager.Register<IPDAUplinkManager,PDAUplinkManager>();
|
||||||
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
||||||
@@ -43,6 +45,7 @@ namespace Content.Server
|
|||||||
IoCManager.Register<ConsiderationsManager, ConsiderationsManager>();
|
IoCManager.Register<ConsiderationsManager, ConsiderationsManager>();
|
||||||
IoCManager.Register<IBodyNetworkFactory, BodyNetworkFactory>();
|
IoCManager.Register<IBodyNetworkFactory, BodyNetworkFactory>();
|
||||||
IoCManager.Register<IAccentManager, AccentManager>();
|
IoCManager.Register<IAccentManager, AccentManager>();
|
||||||
|
IoCManager.Register<IConnectionManager, ConnectionManager>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
79
Content.Server/Utility/IPAddressExt.cs
Normal file
79
Content.Server/Utility/IPAddressExt.cs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
|
||||||
|
namespace Content.Server.Utility
|
||||||
|
{
|
||||||
|
public static class IPAddressExt
|
||||||
|
{
|
||||||
|
// Taken from https://stackoverflow.com/a/56461160/4678631
|
||||||
|
public static bool IsInSubnet(this IPAddress address, string subnetMask)
|
||||||
|
{
|
||||||
|
var slashIdx = subnetMask.IndexOf("/", StringComparison.Ordinal);
|
||||||
|
if (slashIdx == -1)
|
||||||
|
{
|
||||||
|
// We only handle netmasks in format "IP/PrefixLength".
|
||||||
|
throw new NotSupportedException("Only SubNetMasks with a given prefix length are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// First parse the address of the netmask before the prefix length.
|
||||||
|
var maskAddress = IPAddress.Parse(subnetMask.Substring(0, slashIdx));
|
||||||
|
|
||||||
|
if (maskAddress.AddressFamily != address.AddressFamily)
|
||||||
|
{
|
||||||
|
// We got something like an IPV4-Address for an IPv6-Mask. This is not valid.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now find out how long the prefix is.
|
||||||
|
int maskLength = int.Parse(subnetMask.Substring(slashIdx + 1));
|
||||||
|
|
||||||
|
if (maskAddress.AddressFamily == AddressFamily.InterNetwork)
|
||||||
|
{
|
||||||
|
// Convert the mask address to an unsigned integer.
|
||||||
|
var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray(), 0);
|
||||||
|
|
||||||
|
// And convert the IpAddress to an unsigned integer.
|
||||||
|
var ipAddressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray(), 0);
|
||||||
|
|
||||||
|
// Get the mask/network address as unsigned integer.
|
||||||
|
uint mask = uint.MaxValue << (32 - maskLength);
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/1499284/3085985
|
||||||
|
// Bitwise AND mask and MaskAddress, this should be the same as mask and IpAddress
|
||||||
|
// as the end of the mask is 0000 which leads to both addresses to end with 0000
|
||||||
|
// and to start with the prefix.
|
||||||
|
return (maskAddressBits & mask) == (ipAddressBits & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||||
|
{
|
||||||
|
// Convert the mask address to a BitArray.
|
||||||
|
var maskAddressBits = new BitArray(maskAddress.GetAddressBytes());
|
||||||
|
|
||||||
|
// And convert the IpAddress to a BitArray.
|
||||||
|
var ipAddressBits = new BitArray(address.GetAddressBytes());
|
||||||
|
|
||||||
|
if (maskAddressBits.Length != ipAddressBits.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Length of IP Address and Subnet Mask do not match.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the prefix bits.
|
||||||
|
for (int maskIndex = 0; maskIndex < maskLength; maskIndex++)
|
||||||
|
{
|
||||||
|
if (ipAddressBits[maskIndex] != maskAddressBits[maskIndex])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotSupportedException("Only InterNetworkV6 or InterNetwork address families are supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,5 +21,40 @@ namespace Content.Shared
|
|||||||
|
|
||||||
public static readonly CVarDef<bool>
|
public static readonly CVarDef<bool>
|
||||||
GameLobbyEnableWin = CVarDef.Create("game.enablewin", true, CVar.ARCHIVE);
|
GameLobbyEnableWin = CVarDef.Create("game.enablewin", true, CVar.ARCHIVE);
|
||||||
|
|
||||||
|
public static readonly CVarDef<int>
|
||||||
|
GameMaxCharacterSlots = CVarDef.Create("game.maxcharacterslots", 10, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When enabled, guests will be assigned permanent UIDs and will have their preferences stored.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly CVarDef<bool>
|
||||||
|
GamePersistGuests = CVarDef.Create("game.persistguests", true, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Database stuff
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static readonly CVarDef<string> DatabaseEngine =
|
||||||
|
CVarDef.Create("database.engine", "sqlite", CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<string> DatabaseSqliteDbPath =
|
||||||
|
CVarDef.Create("database.sqlite_dbpath", "preferences.db", CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<string> DatabasePgHost =
|
||||||
|
CVarDef.Create("database.pg_host", "localhost", CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<int> DatabasePgPort =
|
||||||
|
CVarDef.Create("database.pg_port", 5432, CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<string> DatabasePgDatabase =
|
||||||
|
CVarDef.Create("database.pg_database", "ss14", CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<string> DatabasePgUsername =
|
||||||
|
CVarDef.Create("database.pg_username", "", CVar.SERVERONLY);
|
||||||
|
|
||||||
|
public static readonly CVarDef<string> DatabasePgPassword =
|
||||||
|
CVarDef.Create("database.pg_password", "", CVar.SERVERONLY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using Content.Shared.Preferences.Appearance;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
@@ -72,6 +73,47 @@ namespace Content.Shared.Preferences
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance)
|
||||||
|
{
|
||||||
|
string hairStyleName;
|
||||||
|
if (!HairStyles.HairStylesMap.ContainsKey(appearance.HairStyleName))
|
||||||
|
{
|
||||||
|
hairStyleName = HairStyles.DefaultHairStyle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hairStyleName = appearance.HairStyleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
string facialHairStyleName;
|
||||||
|
if (!HairStyles.FacialHairStylesMap.ContainsKey(appearance.FacialHairStyleName))
|
||||||
|
{
|
||||||
|
facialHairStyleName = HairStyles.DefaultFacialHairStyle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
facialHairStyleName = appearance.FacialHairStyleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hairColor = ClampColor(appearance.HairColor);
|
||||||
|
var facialHairColor = ClampColor(appearance.FacialHairColor);
|
||||||
|
var eyeColor = ClampColor(appearance.EyeColor);
|
||||||
|
var skinColor = ClampColor(appearance.SkinColor);
|
||||||
|
|
||||||
|
return new HumanoidCharacterAppearance(
|
||||||
|
hairStyleName,
|
||||||
|
hairColor,
|
||||||
|
facialHairStyleName,
|
||||||
|
facialHairColor,
|
||||||
|
eyeColor,
|
||||||
|
skinColor);
|
||||||
|
|
||||||
|
static Color ClampColor(Color color)
|
||||||
|
{
|
||||||
|
return new Color(color.RByte, color.GByte, color.BByte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool MemberwiseEquals(ICharacterAppearance maybeOther)
|
public bool MemberwiseEquals(ICharacterAppearance maybeOther)
|
||||||
{
|
{
|
||||||
if (!(maybeOther is HumanoidCharacterAppearance other)) return false;
|
if (!(maybeOther is HumanoidCharacterAppearance other)) return false;
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Preferences
|
namespace Content.Shared.Preferences
|
||||||
@@ -12,6 +14,7 @@ namespace Content.Shared.Preferences
|
|||||||
private readonly List<string> _antagPreferences;
|
private readonly List<string> _antagPreferences;
|
||||||
public static int MinimumAge = 18;
|
public static int MinimumAge = 18;
|
||||||
public static int MaximumAge = 120;
|
public static int MaximumAge = 120;
|
||||||
|
public static int MaxNameLength = 32;
|
||||||
|
|
||||||
private HumanoidCharacterProfile(
|
private HumanoidCharacterProfile(
|
||||||
string name,
|
string name,
|
||||||
@@ -146,6 +149,69 @@ namespace Content.Shared.Preferences
|
|||||||
return new HumanoidCharacterProfile(Name, Age, Sex, Appearance, _jobPriorities, PreferenceUnavailable, list);
|
return new HumanoidCharacterProfile(Name, Age, Sex, Appearance, _jobPriorities, PreferenceUnavailable, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes this profile valid so there's no bad data like negative ages.
|
||||||
|
/// </summary>
|
||||||
|
public static HumanoidCharacterProfile EnsureValid(
|
||||||
|
HumanoidCharacterProfile profile,
|
||||||
|
IPrototypeManager prototypeManager)
|
||||||
|
{
|
||||||
|
var age = Math.Clamp(profile.Age, MinimumAge, MaximumAge);
|
||||||
|
var sex = profile.Sex switch
|
||||||
|
{
|
||||||
|
Sex.Male => Sex.Male,
|
||||||
|
Sex.Female => Sex.Female,
|
||||||
|
_ => Sex.Male // Invalid enum values.
|
||||||
|
};
|
||||||
|
|
||||||
|
string name;
|
||||||
|
if (string.IsNullOrEmpty(profile.Name))
|
||||||
|
{
|
||||||
|
name = "John Doe";
|
||||||
|
}
|
||||||
|
else if (profile.Name.Length > MaxNameLength)
|
||||||
|
{
|
||||||
|
name = profile.Name[..MaxNameLength];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = profile.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Avoid Z̨͇̙͉͎̭͔̼̿͋A͚̖̞̗̞͈̓̾̀ͩͩ̔L̟ͮ̈͝G̙O͍͎̗̺̺ͫ̀̽͊̓͝ͅ tier shenanigans.
|
||||||
|
// And other stuff like RTL overrides and such.
|
||||||
|
// Probably also emojis...
|
||||||
|
|
||||||
|
name = name.Trim();
|
||||||
|
|
||||||
|
var appearance = HumanoidCharacterAppearance.EnsureValid(profile.Appearance);
|
||||||
|
|
||||||
|
var prefsUnavailableMode = profile.PreferenceUnavailable switch
|
||||||
|
{
|
||||||
|
PreferenceUnavailableMode.StayInLobby => PreferenceUnavailableMode.StayInLobby,
|
||||||
|
PreferenceUnavailableMode.SpawnAsOverflow => PreferenceUnavailableMode.SpawnAsOverflow,
|
||||||
|
_ => PreferenceUnavailableMode.StayInLobby // Invalid enum values.
|
||||||
|
};
|
||||||
|
|
||||||
|
var priorities = profile.JobPriorities
|
||||||
|
.Where(p => prototypeManager.HasIndex<JobPrototype>(p.Key) && p.Value switch
|
||||||
|
{
|
||||||
|
JobPriority.Never => false, // Drop never since that's assumed default.
|
||||||
|
JobPriority.Low => true,
|
||||||
|
JobPriority.Medium => true,
|
||||||
|
JobPriority.High => true,
|
||||||
|
_ => false
|
||||||
|
})
|
||||||
|
.ToDictionary(p => p.Key, p => p.Value);
|
||||||
|
|
||||||
|
|
||||||
|
var antags = profile.AntagPreferences
|
||||||
|
.Where(prototypeManager.HasIndex<AntagPrototype>)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return new HumanoidCharacterProfile(name, age, sex, appearance, priorities, prefsUnavailableMode, antags);
|
||||||
|
}
|
||||||
|
|
||||||
public string Summary =>
|
public string Summary =>
|
||||||
$"{Name}, {Age} years old {Sex.ToString().ToLower()} human.";
|
$"{Name}, {Age} years old {Sex.ToString().ToLower()} human.";
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,11 @@ namespace Content.Shared.Preferences
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<ICharacterProfile> Characters => _characters.AsEnumerable();
|
public IEnumerable<ICharacterProfile> Characters => _characters.AsEnumerable();
|
||||||
|
|
||||||
|
public ICharacterProfile GetProfile(int index)
|
||||||
|
{
|
||||||
|
return _characters[index];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Index of the currently selected character.
|
/// Index of the currently selected character.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -193,23 +193,23 @@ namespace Content.Shared
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Status of the Player in the lobby (ready, observer, ...)
|
/// The Status of the Player in the lobby (ready, observer, ...)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<NetSessionId, PlayerStatus> PlayerStatus { get; set; }
|
public Dictionary<NetUserId, PlayerStatus> PlayerStatus { get; set; }
|
||||||
|
|
||||||
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
public override void ReadFromBuffer(NetIncomingMessage buffer)
|
||||||
{
|
{
|
||||||
PlayerStatus = new Dictionary<NetSessionId, PlayerStatus>();
|
PlayerStatus = new Dictionary<NetUserId, PlayerStatus>();
|
||||||
var length = buffer.ReadInt32();
|
var length = buffer.ReadInt32();
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
{
|
{
|
||||||
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
var serializer = IoCManager.Resolve<IRobustSerializer>();
|
||||||
var byteLength = buffer.ReadVariableInt32();
|
var byteLength = buffer.ReadVariableInt32();
|
||||||
NetSessionId sessionID;
|
NetUserId userId;
|
||||||
using (var stream = buffer.ReadAsStream(byteLength))
|
using (var stream = buffer.ReadAsStream(byteLength))
|
||||||
{
|
{
|
||||||
serializer.DeserializeDirect(stream, out sessionID);
|
serializer.DeserializeDirect(stream, out userId);
|
||||||
}
|
}
|
||||||
var status = (PlayerStatus)buffer.ReadByte();
|
var status = (PlayerStatus)buffer.ReadByte();
|
||||||
PlayerStatus.Add(sessionID, status);
|
PlayerStatus.Add(userId, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Content.Server.Database;
|
|
||||||
using Content.Server.Preferences;
|
|
||||||
using Content.Shared;
|
|
||||||
using Content.Shared.Preferences;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.UnitTesting;
|
|
||||||
|
|
||||||
namespace Content.Tests.Server.Preferences
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class PreferencesDatabaseTests : RobustUnitTest
|
|
||||||
{
|
|
||||||
private const int MaxCharacterSlots = 10;
|
|
||||||
|
|
||||||
private static HumanoidCharacterProfile CharlieCharlieson()
|
|
||||||
{
|
|
||||||
return new HumanoidCharacterProfile(
|
|
||||||
"Charlie Charlieson",
|
|
||||||
21,
|
|
||||||
Sex.Male,
|
|
||||||
new HumanoidCharacterAppearance(
|
|
||||||
"Afro",
|
|
||||||
Color.Aqua,
|
|
||||||
"Shaved",
|
|
||||||
Color.Aquamarine,
|
|
||||||
Color.Azure,
|
|
||||||
Color.Beige
|
|
||||||
),
|
|
||||||
new Dictionary<string, JobPriority>
|
|
||||||
{
|
|
||||||
{SharedGameTicker.OverflowJob, JobPriority.High}
|
|
||||||
},
|
|
||||||
PreferenceUnavailableMode.StayInLobby,
|
|
||||||
new List<string>{}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PreferencesDatabase GetDb()
|
|
||||||
{
|
|
||||||
return new PreferencesDatabase(new SqliteConfiguration(Path.GetTempFileName()), MaxCharacterSlots);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task TestUserDoesNotExist()
|
|
||||||
{
|
|
||||||
var db = GetDb();
|
|
||||||
Assert.Null(await db.GetPlayerPreferencesAsync("[The database should be empty so any string should do]"));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task TestUserDoesExist()
|
|
||||||
{
|
|
||||||
var db = GetDb();
|
|
||||||
const string username = "bobby";
|
|
||||||
await db.SaveSelectedCharacterIndexAsync(username, 0);
|
|
||||||
var prefs = await db.GetPlayerPreferencesAsync(username);
|
|
||||||
Assert.NotNull(prefs);
|
|
||||||
Assert.Zero(prefs.SelectedCharacterIndex);
|
|
||||||
Assert.That(prefs.Characters.ToList().TrueForAll(character => character is null));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task TestUpdateCharacter()
|
|
||||||
{
|
|
||||||
var db = GetDb();
|
|
||||||
const string username = "charlie";
|
|
||||||
const int slot = 0;
|
|
||||||
var originalProfile = CharlieCharlieson();
|
|
||||||
await db.SaveSelectedCharacterIndexAsync(username, slot);
|
|
||||||
await db.SaveCharacterSlotAsync(username, originalProfile, slot);
|
|
||||||
var prefs = await db.GetPlayerPreferencesAsync(username);
|
|
||||||
Assert.That(prefs.Characters.ElementAt(slot).MemberwiseEquals(originalProfile));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task TestDeleteCharacter()
|
|
||||||
{
|
|
||||||
var db = GetDb();
|
|
||||||
const string username = "charlie";
|
|
||||||
const int slot = 0;
|
|
||||||
await db.SaveSelectedCharacterIndexAsync(username, slot);
|
|
||||||
await db.SaveCharacterSlotAsync(username, CharlieCharlieson(), slot);
|
|
||||||
await db.SaveCharacterSlotAsync(username, null, slot);
|
|
||||||
var prefs = await db.GetPlayerPreferencesAsync(username);
|
|
||||||
Assert.That(prefs.Characters.ToList().TrueForAll(character => character is null));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public async Task TestInvalidSlot()
|
|
||||||
{
|
|
||||||
var db = GetDb();
|
|
||||||
const string username = "charlie";
|
|
||||||
const int slot = -1;
|
|
||||||
|
|
||||||
await db.SaveSelectedCharacterIndexAsync(username, slot);
|
|
||||||
await db.SaveCharacterSlotAsync(username, CharlieCharlieson(), slot);
|
|
||||||
var prefs = await db.GetPlayerPreferencesAsync(username);
|
|
||||||
Assert.That(prefs.SelectedCharacterIndex, Is.EqualTo(0));
|
|
||||||
|
|
||||||
await db.SaveSelectedCharacterIndexAsync(username, MaxCharacterSlots);
|
|
||||||
prefs = await db.GetPlayerPreferencesAsync(username);
|
|
||||||
Assert.That(prefs.SelectedCharacterIndex, Is.EqualTo(MaxCharacterSlots - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
92
Content.Tests/Server/Preferences/ServerDbSqliteTests.cs
Normal file
92
Content.Tests/Server/Preferences/ServerDbSqliteTests.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Database;
|
||||||
|
using Content.Shared;
|
||||||
|
using Content.Shared.Preferences;
|
||||||
|
using Microsoft.Data.Sqlite;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Network;
|
||||||
|
using Robust.UnitTesting;
|
||||||
|
|
||||||
|
namespace Content.Tests.Server.Preferences
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class ServerDbSqliteTests : RobustUnitTest
|
||||||
|
{
|
||||||
|
private const int MaxCharacterSlots = 10;
|
||||||
|
|
||||||
|
private static HumanoidCharacterProfile CharlieCharlieson()
|
||||||
|
{
|
||||||
|
return new HumanoidCharacterProfile(
|
||||||
|
"Charlie Charlieson",
|
||||||
|
21,
|
||||||
|
Sex.Male,
|
||||||
|
new HumanoidCharacterAppearance(
|
||||||
|
"Afro",
|
||||||
|
Color.Aqua,
|
||||||
|
"Shaved",
|
||||||
|
Color.Aquamarine,
|
||||||
|
Color.Azure,
|
||||||
|
Color.Beige
|
||||||
|
),
|
||||||
|
new Dictionary<string, JobPriority>
|
||||||
|
{
|
||||||
|
{SharedGameTicker.OverflowJob, JobPriority.High}
|
||||||
|
},
|
||||||
|
PreferenceUnavailableMode.StayInLobby,
|
||||||
|
new List<string> ()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServerDbSqlite GetDb()
|
||||||
|
{
|
||||||
|
var builder = new DbContextOptionsBuilder<ServerDbContext>();
|
||||||
|
var conn = new SqliteConnection("Data Source=:memory:");
|
||||||
|
conn.Open();
|
||||||
|
builder.UseSqlite(conn);
|
||||||
|
return new ServerDbSqlite(builder.Options);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestUserDoesNotExist()
|
||||||
|
{
|
||||||
|
var db = GetDb();
|
||||||
|
// Database should be empty so a new GUID should do it.
|
||||||
|
Assert.Null(await db.GetPlayerPreferencesAsync(NewUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestInitPrefs()
|
||||||
|
{
|
||||||
|
var db = GetDb();
|
||||||
|
var username = new NetUserId(new Guid("640bd619-fc8d-4fe2-bf3c-4a5fb17d6ddd"));
|
||||||
|
const int slot = 0;
|
||||||
|
var originalProfile = CharlieCharlieson();
|
||||||
|
await db.InitPrefsAsync(username, originalProfile);
|
||||||
|
var prefs = await db.GetPlayerPreferencesAsync(username);
|
||||||
|
Assert.That(prefs.Characters.ElementAt(slot).MemberwiseEquals(originalProfile));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TestDeleteCharacter()
|
||||||
|
{
|
||||||
|
var db = GetDb();
|
||||||
|
var username = new NetUserId(new Guid("640bd619-fc8d-4fe2-bf3c-4a5fb17d6ddd"));
|
||||||
|
await db.InitPrefsAsync(username, HumanoidCharacterProfile.Default());
|
||||||
|
await db.SaveCharacterSlotAsync(username, CharlieCharlieson(), 1);
|
||||||
|
await db.SaveSelectedCharacterIndexAsync(username, 1);
|
||||||
|
await db.SaveCharacterSlotAsync(username, null, 1);
|
||||||
|
var prefs = await db.GetPlayerPreferencesAsync(username);
|
||||||
|
Assert.That(prefs.Characters.Skip(1).All(character => character is null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static NetUserId NewUserId()
|
||||||
|
{
|
||||||
|
return new NetUserId(Guid.NewGuid());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
Content.Tests/Server/Utility/IPAddressExtTest.cs
Normal file
61
Content.Tests/Server/Utility/IPAddressExtTest.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System.Net;
|
||||||
|
using Content.Server.Utility;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace Content.Tests.Server.Utility
|
||||||
|
{
|
||||||
|
public class IPAddressExtTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[TestCase("192.168.5.85/24", "192.168.5.1")]
|
||||||
|
[TestCase("192.168.5.85/24", "192.168.5.254")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.128.240.48")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.128.240.49")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.128.240.50")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.128.240.51")]
|
||||||
|
public void IpV4SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress)
|
||||||
|
{
|
||||||
|
var ipAddressObj = IPAddress.Parse(ipAddress);
|
||||||
|
Assert.That(ipAddressObj.IsInSubnet(netMask), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase("192.168.5.85/24", "192.168.4.254")]
|
||||||
|
[TestCase("192.168.5.85/24", "191.168.5.254")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.128.240.47")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.128.240.52")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.128.239.50")]
|
||||||
|
[TestCase("10.128.240.50/30", "10.127.240.51")]
|
||||||
|
public void IpV4SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
|
||||||
|
{
|
||||||
|
var ipAddressObj = IPAddress.Parse(ipAddress);
|
||||||
|
Assert.That(ipAddressObj.IsInSubnet(netMask), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable StringLiteralTypo
|
||||||
|
[Test]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0001:0000:0000:0000")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFF0")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")]
|
||||||
|
public void IpV6SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress)
|
||||||
|
{
|
||||||
|
var ipAddressObj = IPAddress.Parse(ipAddress);
|
||||||
|
Assert.That(ipAddressObj.IsInSubnet(netMask), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFFF")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0000:0000:0000:0000")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0001:0000:0000:0000")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFF0")]
|
||||||
|
[TestCase("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0001")]
|
||||||
|
// ReSharper restore StringLiteralTypo
|
||||||
|
public void IpV6SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
|
||||||
|
{
|
||||||
|
var ipAddressObj = IPAddress.Parse(ipAddress);
|
||||||
|
Assert.That(ipAddressObj.IsInSubnet(netMask), Is.False);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Submodule RobustToolbox updated: ab86b59bc8...aa64528a03
@@ -39,15 +39,19 @@
|
|||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INVOCABLE_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INVOCABLE_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/OTHER_BRACES/@EntryValue">NEXT_LINE</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/OTHER_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/TYPE_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/TYPE_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CC/@EntryIndexedValue">CC</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GD/@EntryIndexedValue">GD</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GD/@EntryIndexedValue">GD</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GL/@EntryIndexedValue">GL</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GL/@EntryIndexedValue">GL</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KHR/@EntryIndexedValue">KHR</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=KHR/@EntryIndexedValue">KHR</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=MS/@EntryIndexedValue">MS</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OGL/@EntryIndexedValue">OGL</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OGL/@EntryIndexedValue">OGL</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OOC/@EntryIndexedValue">OOC</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OOC/@EntryIndexedValue">OOC</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OS/@EntryIndexedValue">OS</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=OS/@EntryIndexedValue">OS</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PCM/@EntryIndexedValue">PCM</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PCM/@EntryIndexedValue">PCM</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PNG/@EntryIndexedValue">PNG</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=PNG/@EntryIndexedValue">PNG</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RSI/@EntryIndexedValue">RSI</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RSI/@EntryIndexedValue">RSI</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SA/@EntryIndexedValue">SA</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UTF/@EntryIndexedValue">UTF</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UTF/@EntryIndexedValue">UTF</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UV/@EntryIndexedValue">UV</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UV/@EntryIndexedValue">UV</s:String>
|
||||||
|
|||||||
Reference in New Issue
Block a user