diff --git a/Content.Server.Database/Content.Server.Database.csproj b/Content.Server.Database/Content.Server.Database.csproj
new file mode 100644
index 0000000000..469168a8e8
--- /dev/null
+++ b/Content.Server.Database/Content.Server.Database.csproj
@@ -0,0 +1,28 @@
+
+
+
+
+ $(TargetFramework)
+ 8
+ false
+ x64
+ false
+ ..\bin\Content.Server.Database\
+ true
+ enable
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
diff --git a/Content.Server.Database/Migrations/20200111103836_InitialCreate.Designer.cs b/Content.Server.Database/Migrations/20200111103836_InitialCreate.Designer.cs
new file mode 100644
index 0000000000..3d5f2d5b1d
--- /dev/null
+++ b/Content.Server.Database/Migrations/20200111103836_InitialCreate.Designer.cs
@@ -0,0 +1,109 @@
+//
+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
+{
+ [DbContext(typeof(PreferencesDbContext))]
+ [Migration("20200111103836_InitialCreate")]
+ partial class InitialCreate
+ {
+ 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("HumanoidProfileId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Age")
+ .HasColumnType("INTEGER");
+
+ b.Property("CharacterName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("EyeColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("FacialHairColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("FacialHairName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("HairColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("HairName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("PrefsId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Sex")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("SkinColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Slot")
+ .HasColumnType("INTEGER");
+
+ b.Property("SlotName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("HumanoidProfileId");
+
+ b.HasIndex("PrefsId");
+
+ b.ToTable("HumanoidProfile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Prefs", b =>
+ {
+ b.Property("PrefsId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("SelectedCharacterSlot")
+ .HasColumnType("INTEGER");
+
+ b.Property("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", null)
+ .WithMany("HumanoidProfiles")
+ .HasForeignKey("PrefsId");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Content.Server.Database/Migrations/20200111103836_InitialCreate.cs b/Content.Server.Database/Migrations/20200111103836_InitialCreate.cs
new file mode 100644
index 0000000000..1324d3ca88
--- /dev/null
+++ b/Content.Server.Database/Migrations/20200111103836_InitialCreate.cs
@@ -0,0 +1,71 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace Content.Server.Database.Migrations
+{
+ public partial class InitialCreate : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ "Preferences",
+ table => new
+ {
+ PrefsId = table.Column()
+ .Annotation("Sqlite:Autoincrement", true),
+ Username = table.Column(),
+ SelectedCharacterSlot = table.Column()
+ },
+ constraints: table => { table.PrimaryKey("PK_Preferences", x => x.PrefsId); });
+
+ migrationBuilder.CreateTable(
+ "HumanoidProfile",
+ table => new
+ {
+ HumanoidProfileId = table.Column()
+ .Annotation("Sqlite:Autoincrement", true),
+ Slot = table.Column(),
+ SlotName = table.Column(),
+ CharacterName = table.Column(),
+ Age = table.Column(),
+ Sex = table.Column(),
+ HairName = table.Column(),
+ HairColor = table.Column(),
+ FacialHairName = table.Column(),
+ FacialHairColor = table.Column(),
+ EyeColor = table.Column(),
+ SkinColor = table.Column(),
+ PrefsId = table.Column(nullable: true)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_HumanoidProfile", x => x.HumanoidProfileId);
+ table.ForeignKey(
+ "FK_HumanoidProfile_Preferences_PrefsId",
+ x => x.PrefsId,
+ "Preferences",
+ "PrefsId",
+ onDelete: ReferentialAction.Restrict);
+ });
+
+ migrationBuilder.CreateIndex(
+ "IX_HumanoidProfile_PrefsId",
+ "HumanoidProfile",
+ "PrefsId");
+
+ migrationBuilder.CreateIndex(
+ "IX_Preferences_Username",
+ "Preferences",
+ "Username",
+ unique: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ "HumanoidProfile");
+
+ migrationBuilder.DropTable(
+ "Preferences");
+ }
+ }
+}
diff --git a/Content.Server.Database/Migrations/PreferencesDbContextModelSnapshot.cs b/Content.Server.Database/Migrations/PreferencesDbContextModelSnapshot.cs
new file mode 100644
index 0000000000..1cdebf3e2e
--- /dev/null
+++ b/Content.Server.Database/Migrations/PreferencesDbContextModelSnapshot.cs
@@ -0,0 +1,105 @@
+//
+
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+
+namespace Content.Server.Database.Migrations
+{
+ [DbContext(typeof(PreferencesDbContext))]
+ internal class PreferencesDbContextModelSnapshot : ModelSnapshot
+ {
+ protected override void BuildModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.0");
+
+ modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
+ {
+ b.Property("HumanoidProfileId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Age")
+ .HasColumnType("INTEGER");
+
+ b.Property("CharacterName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("EyeColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("FacialHairColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("FacialHairName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("HairColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("HairName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("PrefsId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Sex")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("SkinColor")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("Slot")
+ .HasColumnType("INTEGER");
+
+ b.Property("SlotName")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("HumanoidProfileId");
+
+ b.HasIndex("PrefsId");
+
+ b.ToTable("HumanoidProfile");
+ });
+
+ modelBuilder.Entity("Content.Server.Database.Prefs", b =>
+ {
+ b.Property("PrefsId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("SelectedCharacterSlot")
+ .HasColumnType("INTEGER");
+
+ b.Property("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", null)
+ .WithMany("HumanoidProfiles")
+ .HasForeignKey("PrefsId");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs
new file mode 100644
index 0000000000..54b4fce67a
--- /dev/null
+++ b/Content.Server.Database/Model.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using Microsoft.EntityFrameworkCore;
+
+namespace Content.Server.Database
+{
+ public class PreferencesDbContext : DbContext
+ {
+ // This is used by the "dotnet ef" CLI tool.
+ public PreferencesDbContext() :
+ base(new DbContextOptionsBuilder().UseSqlite("Data Source=:memory:").Options)
+ {
+ }
+
+ public PreferencesDbContext(DbContextOptions options) : base(options)
+ {
+ }
+
+ public DbSet Preferences { get; set; } = null!;
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.Entity()
+ .HasIndex(p => p.Username)
+ .IsUnique();
+ }
+ }
+
+ public class Prefs
+ {
+ public int PrefsId { get; set; }
+ public string Username { get; set; } = null!;
+ public int SelectedCharacterSlot { get; set; }
+ public List HumanoidProfiles { get; } = new List();
+ }
+
+ public class HumanoidProfile
+ {
+ public int HumanoidProfileId { get; set; }
+ public int Slot { get; set; }
+ public string SlotName { get; set; } = null!;
+ public string CharacterName { get; set; } = null!;
+ public int Age { get; set; }
+ public string Sex { get; set; } = null!;
+ public string HairName { get; set; } = null!;
+ public string HairColor { get; set; } = null!;
+ public string FacialHairName { get; set; } = null!;
+ public string FacialHairColor { get; set; } = null!;
+ public string EyeColor { get; set; } = null!;
+ public string SkinColor { get; set; } = null!;
+ }
+}
diff --git a/Content.Server.Database/PrefsDb.cs b/Content.Server.Database/PrefsDb.cs
new file mode 100644
index 0000000000..506686dccc
--- /dev/null
+++ b/Content.Server.Database/PrefsDb.cs
@@ -0,0 +1,60 @@
+using System.Linq;
+using Microsoft.EntityFrameworkCore;
+
+namespace Content.Server.Database
+{
+ public class PrefsDb
+ {
+ private readonly PreferencesDbContext _prefsCtx;
+
+ public PrefsDb(string dbPath)
+ {
+ var optionsBuilder = new DbContextOptionsBuilder();
+ optionsBuilder.UseSqlite($"Data Source={dbPath}");
+
+ _prefsCtx = new PreferencesDbContext(optionsBuilder.Options);
+ _prefsCtx.Database.Migrate();
+ }
+
+ public Prefs GetPlayerPreferences(string username)
+ {
+ return _prefsCtx.Preferences.SingleOrDefault(p => p.Username == username);
+ }
+
+ public void 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;
+ _prefsCtx.SaveChanges();
+ }
+
+ public void SaveCharacterSlot(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);
+ }
+
+ public void DeleteCharacterSlot(string username, int slot)
+ {
+ var profile = _prefsCtx
+ .Preferences
+ .Single(p => p.Username == username)
+ .HumanoidProfiles
+ .RemoveAll(h => h.Slot == slot);
+ _prefsCtx.SaveChanges();
+ }
+ }
+}
diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj
index 7d7ba55760..948ae862a2 100644
--- a/Content.Server/Content.Server.csproj
+++ b/Content.Server/Content.Server.csproj
@@ -12,12 +12,11 @@
-
-
+
false
@@ -32,7 +31,4 @@
-
-
-
diff --git a/Content.Server/Preferences/Migrations/000_Initial.sql b/Content.Server/Preferences/Migrations/000_Initial.sql
deleted file mode 100644
index 00c261a696..0000000000
--- a/Content.Server/Preferences/Migrations/000_Initial.sql
+++ /dev/null
@@ -1,20 +0,0 @@
-CREATE TABLE IF NOT EXISTS "HumanoidCharacterProfiles" (
- "Id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
- "Player" INTEGER NOT NULL,
- "Slot" INTEGER NOT NULL,
- "Name" TEXT NOT NULL,
- "Age" INTEGER NOT NULL,
- "Sex" TEXT NOT NULL,
- "HairStyleName" TEXT NOT NULL,
- "HairColor" TEXT NOT NULL,
- "FacialHairStyleName" TEXT NOT NULL,
- "FacialHairColor" TEXT NOT NULL,
- "EyeColor" TEXT NOT NULL,
- "SkinColor" TEXT NOT NULL,
- FOREIGN KEY("Player") REFERENCES "PlayerPreferences"("Id")
-);
-CREATE TABLE IF NOT EXISTS "PlayerPreferences" (
- "Id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
- "Username" TEXT NOT NULL UNIQUE,
- "SelectedCharacterIndex" INTEGER NOT NULL
-);
diff --git a/Content.Server/Preferences/Migrations/MigrationManager.cs b/Content.Server/Preferences/Migrations/MigrationManager.cs
deleted file mode 100644
index 9057d102dc..0000000000
--- a/Content.Server/Preferences/Migrations/MigrationManager.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-using System.Collections.Generic;
-using System.Data;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text.RegularExpressions;
-using Dapper;
-using JetBrains.Annotations;
-using Microsoft.Data.Sqlite;
-using Robust.Shared.Log;
-
-namespace Content.Server.Preferences.Migrations
-{
- ///
- /// Ensures database schemas are up to date.
- ///
- public static class MigrationManager
- {
- ///
- /// Ensures the database schema for the given connection string is up to date.
- ///
- public static void PerformUpgrade(string connectionString)
- {
- using (var connection = new SqliteConnection(connectionString))
- {
- EnsureSchemaVersionTableExists(connection);
- foreach (var migrationToRun in MigrationsToRun(connection))
- {
- Logger.InfoS("db", "Running migration {0}", migrationToRun.Id);
- migrationToRun.Run(connection);
- }
- }
- }
-
- ///
- /// Generated for each SQL file found.
- ///
- private class Migration
- {
- public readonly string Id;
- private readonly string _sql;
-
- public Migration(string id, string sql)
- {
- Id = id;
- _sql = sql;
- }
-
- ///
- /// Executes the query in and logs this in the SchemaVersion table.
- ///
- public void Run(IDbConnection connection)
- {
- connection.Execute(_sql);
- InsertMigrationLog(connection, Id);
- }
- }
-
- private const string InsertMigrationLogQuery =
- @"INSERT INTO SchemaVersion (Id) VALUES (@Id)";
- ///
- /// Inserts a in the SchemaVersion table.
- ///
- private static void InsertMigrationLog(IDbConnection connection, string id)
- {
- Logger.InfoS("db", "Completing migration {0}", id);
- connection.Execute(InsertMigrationLogQuery, new {Id = id});
- }
-
- ///
- /// An entry in the SchemaVersion table.
- ///
- [UsedImplicitly]
- private class MigrationLog
- {
- public string Id;
- public string Timestamp;
- }
-
- private const string GetRanMigrationsQuery =
- @"SELECT Id, Timestamp FROM SchemaVersion ORDER BY Id COLLATE NOCASE";
- ///
- /// Fetches a collection of from the SchemaVersion table and returns it.
- ///
- private static IEnumerable RanMigrations(IDbConnection connection)
- {
- return connection.Query(GetRanMigrationsQuery);
- }
-
- ///
- /// Finds all available migrations, returns those that haven't been run yet.
- ///
- private static List MigrationsToRun(IDbConnection connection)
- {
- var discoveredMigrations = DiscoverMigrations(connection);
- if (discoveredMigrations.Count == 0)
- {
- // No migrations found.
- return null;
- }
-
- var ranMigrations = RanMigrations(connection);
-
- // Filter out migrations that have already been executed
- discoveredMigrations
- .RemoveAll(migration => ranMigrations.Any(ranMigration => migration.Id == ranMigration.Id));
- return discoveredMigrations;
- }
-
- ///
- /// Given an embedded resource's full path returns its contents as a string.
- ///
- private static string ResourceAssemblyToString(string resourceName)
- {
- using (var stream = Assembly.GetExecutingAssembly()
- .GetManifestResourceStream(resourceName))
- using (var reader = new StreamReader(stream))
- {
- return reader.ReadToEnd();
- }
- }
-
- ///
- /// Searches the current assembly for SQL migration files.
- /// TODO: Filter by subfolder so that different databases use different sets of migrations.
- ///
- [NotNull]
- private static List DiscoverMigrations(IDbConnection connection)
- {
- var results = new List();
- var assembly = Assembly.GetExecutingAssembly();
- foreach (var sqlResourceName in assembly
- .GetManifestResourceNames()
- .Where(IsValidMigrationFileName))
- {
- var splitName = sqlResourceName.Split('.');
- // The second to last string in the list is the actual file name without the final ".sql"
- var migrationId = splitName[splitName.Length - 2];
- var sqlContents = ResourceAssemblyToString(sqlResourceName);
- results.Add(new Migration(migrationId, sqlContents));
- }
-
- return results;
- }
-
- ///
- /// A valid file name is "000_Initial.sql". A dot (from the path, not to be included in the filename itself),
- /// three digits, a mandatory underscore, any number of characters, a mandatory ".sql".
- ///
- private static bool IsValidMigrationFileName(string name)
- {
- return Regex.IsMatch(name, @"\.\d\d\d_[a-zA-Z]+\.sql$");
- }
-
- private const string EnsureSchemaVersionTableExistsQuery =
- @"CREATE TABLE IF NOT EXISTS SchemaVersion (
- Id TEXT NOT NULL UNIQUE,
- Timestamp TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
- )";
-
- ///
- /// Creates the SchemaVersion table if it doesn't exist.
- ///
- private static void EnsureSchemaVersionTableExists(IDbConnection connection)
- {
- connection.Execute(EnsureSchemaVersionTableExistsQuery);
- }
- }
-}
diff --git a/Content.Server/Preferences/PreferencesDatabase.cs b/Content.Server/Preferences/PreferencesDatabase.cs
index 7e8eb0201c..e806fa27f9 100644
--- a/Content.Server/Preferences/PreferencesDatabase.cs
+++ b/Content.Server/Preferences/PreferencesDatabase.cs
@@ -1,171 +1,63 @@
using System;
using System.Linq;
-using Content.Server.Preferences.Migrations;
+using Content.Server.Database;
using Content.Shared.Preferences;
-using Dapper;
-using Microsoft.Data.Sqlite;
using Robust.Shared.Maths;
using static Content.Shared.Preferences.Sex;
namespace Content.Server.Preferences
{
///
- /// Provides methods to retrieve and update character preferences.
- /// Don't use this directly, go through instead.
+ /// Provides methods to retrieve and update character preferences.
+ /// Don't use this directly, go through instead.
///
public class PreferencesDatabase
{
- private readonly string _databaseFilePath;
private readonly int _maxCharacterSlots;
+ private readonly PrefsDb _prefsDb;
public PreferencesDatabase(string databaseFilePath, int maxCharacterSlots)
{
- _databaseFilePath = databaseFilePath;
_maxCharacterSlots = maxCharacterSlots;
- MigrationManager.PerformUpgrade(GetDbConnectionString());
- }
-
- private string GetDbConnectionString()
- {
- return new SqliteConnectionStringBuilder
- {
- DataSource = _databaseFilePath,
- }.ToString();
- }
-
- private SqliteConnection GetDbConnection()
- {
- var connectionString = GetDbConnectionString();
- var conn = new SqliteConnection(connectionString);
- conn.Open();
- return conn;
- }
-
- private const string PlayerPreferencesQuery =
- @"SELECT Id, SelectedCharacterIndex FROM PlayerPreferences WHERE Username=@Username";
-
- private const string HumanoidCharactersQuery =
- @"SELECT Slot, Name, Age, Sex, HairStyleName, HairColor, FacialHairStyleName, FacialHairColor, EyeColor, SkinColor
- FROM HumanoidCharacterProfiles
- WHERE Player = @Id";
-
- private sealed class PlayerPreferencesSql
- {
- public int Id { get; set; }
- public int SelectedCharacterIndex { get; set; }
+ _prefsDb = new PrefsDb(databaseFilePath);
}
public PlayerPreferences GetPlayerPreferences(string username)
{
- using (var connection = GetDbConnection())
- {
- var prefs = connection.QueryFirstOrDefault(
- PlayerPreferencesQuery,
- new {Username = username});
- if (prefs is null)
- {
- return null;
- }
+ var prefs = _prefsDb.GetPlayerPreferences(username);
+ if (prefs is null) return null;
- // Using Dapper for ICharacterProfile and ICharacterAppearance is annoying so
- // we do it manually
- var cmd = new SqliteCommand(HumanoidCharactersQuery, connection);
- cmd.Parameters.AddWithValue("@Id", prefs.Id);
- cmd.Prepare();
-
- var reader = cmd.ExecuteReader();
- var profiles = new ICharacterProfile[_maxCharacterSlots];
- while (reader.Read())
+ var profiles = new ICharacterProfile[_maxCharacterSlots];
+ foreach (var profile in prefs.HumanoidProfiles)
+ profiles[profile.Slot] = new HumanoidCharacterProfile
{
- profiles[reader.GetInt32(0)] = new HumanoidCharacterProfile
+ Name = profile.CharacterName,
+ Age = profile.Age,
+ Sex = profile.Sex == "Male" ? Male : Female,
+ CharacterAppearance = new HumanoidCharacterAppearance
{
- Name = reader.GetString(1),
- Age = reader.GetInt32(2),
- Sex = reader.GetString(3) == "Male" ? Male : Female,
- CharacterAppearance = new HumanoidCharacterAppearance
- {
- HairStyleName = reader.GetString(4),
- HairColor = Color.FromHex(reader.GetString(5)),
- FacialHairStyleName = reader.GetString(6),
- FacialHairColor = Color.FromHex(reader.GetString(7)),
- EyeColor = Color.FromHex(reader.GetString(8)),
- SkinColor = Color.FromHex(reader.GetString(9))
- }
- };
- }
-
- return new PlayerPreferences
- {
- SelectedCharacterIndex = prefs.SelectedCharacterIndex,
- Characters = profiles.ToList()
+ HairStyleName = profile.HairName,
+ HairColor = Color.FromHex(profile.HairColor),
+ FacialHairStyleName = profile.FacialHairName,
+ FacialHairColor = Color.FromHex(profile.FacialHairColor),
+ EyeColor = Color.FromHex(profile.EyeColor),
+ SkinColor = Color.FromHex(profile.SkinColor)
+ }
};
- }
+
+ return new PlayerPreferences
+ {
+ SelectedCharacterIndex = prefs.SelectedCharacterSlot,
+ Characters = profiles.ToList()
+ };
}
- private const string SaveSelectedCharacterIndexQuery =
- @"UPDATE PlayerPreferences
- SET SelectedCharacterIndex = @SelectedCharacterIndex
- WHERE Username = @Username;
-
- -- If no update happened (i.e. the row didn't exist) then insert one // https://stackoverflow.com/a/38463024
- INSERT INTO PlayerPreferences
- (SelectedCharacterIndex, Username)
- SELECT
- @SelectedCharacterIndex,
- @Username
- WHERE (SELECT Changes() = 0);";
-
public void SaveSelectedCharacterIndex(string username, int index)
{
index = index.Clamp(0, _maxCharacterSlots - 1);
- using (var connection = GetDbConnection())
- {
- connection.Execute(SaveSelectedCharacterIndexQuery,
- new {SelectedCharacterIndex = index, Username = username});
- }
+ _prefsDb.SaveSelectedCharacterIndex(username, index);
}
- private const string SaveCharacterSlotQuery =
- @"UPDATE HumanoidCharacterProfiles
- SET
- Name = @Name,
- Age = @Age,
- Sex = @Sex,
- HairStyleName = @HairStyleName,
- HairColor = @HairColor,
- FacialHairStyleName = @FacialHairStyleName,
- FacialHairColor = @FacialHairColor,
- EyeColor = @EyeColor,
- SkinColor = @SkinColor
- WHERE Slot = @Slot AND Player = (SELECT Id FROM PlayerPreferences WHERE Username = @Username);
-
- -- If no update happened (i.e. the row didn't exist) then insert one // https://stackoverflow.com/a/38463024
- INSERT INTO HumanoidCharacterProfiles
- (Slot,
- Player,
- Name,
- Age,
- Sex,
- HairStyleName,
- HairColor,
- FacialHairStyleName,
- FacialHairColor,
- EyeColor,
- SkinColor)
- SELECT
- @Slot,
- (SELECT Id FROM PlayerPreferences WHERE Username = @Username),
- @Name,
- @Age,
- @Sex,
- @HairStyleName,
- @HairColor,
- @FacialHairStyleName,
- @FacialHairColor,
- @EyeColor,
- @SkinColor
- WHERE (SELECT Changes() = 0);";
-
public void SaveCharacterSlot(string username, ICharacterProfile profile, int slot)
{
if (slot < 0 || slot >= _maxCharacterSlots)
@@ -177,44 +69,28 @@ namespace Content.Server.Preferences
}
if (!(profile is HumanoidCharacterProfile humanoid))
- {
// TODO: Handle other ICharacterProfile implementations properly
throw new NotImplementedException();
- }
var appearance = (HumanoidCharacterAppearance) humanoid.CharacterAppearance;
- using (var connection = GetDbConnection())
+ _prefsDb.SaveCharacterSlot(username, new HumanoidProfile
{
- connection.Execute(SaveCharacterSlotQuery, new
- {
- Name = humanoid.Name,
- Age = humanoid.Age,
- Sex = humanoid.Sex.ToString(),
- HairStyleName = appearance.HairStyleName,
- HairColor = appearance.HairColor.ToHex(),
- FacialHairStyleName = appearance.FacialHairStyleName,
- FacialHairColor = appearance.FacialHairColor.ToHex(),
- EyeColor = appearance.EyeColor.ToHex(),
- SkinColor = appearance.SkinColor.ToHex(),
- Slot = slot,
- Username = username
- });
- }
+ 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
+ });
}
- private const string DeleteCharacterSlotQuery =
- @"DELETE FROM HumanoidCharacterProfiles
- WHERE
- Player = (SELECT Id FROM PlayerPreferences WHERE Username = @Username)
- AND
- Slot = @Slot";
-
private void DeleteCharacterSlot(string username, int slot)
{
- using (var connection = GetDbConnection())
- {
- connection.Execute(DeleteCharacterSlotQuery, new {Username = username, Slot = slot});
- }
+ _prefsDb.DeleteCharacterSlot(username, slot);
}
}
}
diff --git a/SpaceStation14.sln b/SpaceStation14.sln
index 6f4a3a5fa5..cfb56ada0b 100644
--- a/SpaceStation14.sln
+++ b/SpaceStation14.sln
@@ -42,6 +42,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Benchmarks", "Conte
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenToolkit.GraphicsLibraryFramework", "RobustToolbox\OpenToolkit.GraphicsLibraryFramework\OpenToolkit.GraphicsLibraryFramework.csproj", "{4809F412-3132-419E-BF9D-CCF7593C3533}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Server.Database", "Content.Server.Database\Content.Server.Database.csproj", "{45C9B43F-305D-4651-9863-F6384CBC847F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -104,6 +106,10 @@ Global
{4809F412-3132-419E-BF9D-CCF7593C3533}.Debug|x64.Build.0 = Debug|x64
{4809F412-3132-419E-BF9D-CCF7593C3533}.Release|x64.ActiveCfg = Release|x64
{4809F412-3132-419E-BF9D-CCF7593C3533}.Release|x64.Build.0 = Release|x64
+ {45C9B43F-305D-4651-9863-F6384CBC847F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {45C9B43F-305D-4651-9863-F6384CBC847F}.Debug|x64.Build.0 = Debug|Any CPU
+ {45C9B43F-305D-4651-9863-F6384CBC847F}.Release|x64.ActiveCfg = Release|Any CPU
+ {45C9B43F-305D-4651-9863-F6384CBC847F}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 8ca2ed5f1d..523a83e417 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -21,5 +21,6 @@
True
True
True
+ True
True
True