Use async DB queries.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Client.Interfaces;
|
using Content.Client.Interfaces;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
@@ -17,6 +18,7 @@ namespace Content.Client
|
|||||||
[Dependency] private readonly IClientNetManager _netManager;
|
[Dependency] private readonly IClientNetManager _netManager;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
|
public event Action OnServerDataLoaded;
|
||||||
public GameSettings Settings { get; private set; }
|
public GameSettings Settings { get; private set; }
|
||||||
public PlayerPreferences Preferences { get; private set; }
|
public PlayerPreferences Preferences { get; private set; }
|
||||||
|
|
||||||
@@ -69,6 +71,8 @@ namespace Content.Client
|
|||||||
{
|
{
|
||||||
Preferences = message.Preferences;
|
Preferences = message.Preferences;
|
||||||
Settings = message.Settings;
|
Settings = message.Settings;
|
||||||
|
|
||||||
|
OnServerDataLoaded?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
using System;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
|
|
||||||
namespace Content.Client.Interfaces
|
namespace Content.Client.Interfaces
|
||||||
{
|
{
|
||||||
public interface IClientPreferencesManager
|
public interface IClientPreferencesManager
|
||||||
{
|
{
|
||||||
|
event Action OnServerDataLoaded;
|
||||||
|
|
||||||
|
bool ServerDataLoaded => Settings != null;
|
||||||
|
|
||||||
GameSettings Settings { get; }
|
GameSettings Settings { get; }
|
||||||
PlayerPreferences Preferences { get; }
|
PlayerPreferences Preferences { get; }
|
||||||
void Initialize();
|
void Initialize();
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ namespace Content.Client.UserInterface
|
|||||||
_createNewCharacterButton = new Button
|
_createNewCharacterButton = new Button
|
||||||
{
|
{
|
||||||
Text = "Create new slot...",
|
Text = "Create new slot...",
|
||||||
ToolTip = $"A maximum of {preferencesManager.Settings.MaxCharacterSlots} characters are allowed."
|
|
||||||
};
|
};
|
||||||
_createNewCharacterButton.OnPressed += args =>
|
_createNewCharacterButton.OnPressed += args =>
|
||||||
{
|
{
|
||||||
@@ -155,6 +154,8 @@ namespace Content.Client.UserInterface
|
|||||||
hBox.AddChild(_humanoidProfileEditor);
|
hBox.AddChild(_humanoidProfileEditor);
|
||||||
|
|
||||||
UpdateUI();
|
UpdateUI();
|
||||||
|
|
||||||
|
preferencesManager.OnServerDataLoaded += UpdateUI;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save() => _humanoidProfileEditor.Save();
|
public void Save() => _humanoidProfileEditor.Save();
|
||||||
@@ -164,6 +165,15 @@ namespace Content.Client.UserInterface
|
|||||||
var numberOfFullSlots = 0;
|
var numberOfFullSlots = 0;
|
||||||
var characterButtonsGroup = new ButtonGroup();
|
var characterButtonsGroup = new ButtonGroup();
|
||||||
_charactersVBox.RemoveAllChildren();
|
_charactersVBox.RemoveAllChildren();
|
||||||
|
|
||||||
|
if (!_preferencesManager.ServerDataLoaded)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createNewCharacterButton.ToolTip =
|
||||||
|
$"A maximum of {_preferencesManager.Settings.MaxCharacterSlots} characters are allowed.";
|
||||||
|
|
||||||
var characterIndex = 0;
|
var characterIndex = 0;
|
||||||
foreach (var character in _preferencesManager.Preferences.Characters)
|
foreach (var character in _preferencesManager.Preferences.Characters)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ namespace Content.Client.UserInterface
|
|||||||
public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IPrototypeManager prototypeManager)
|
public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IPrototypeManager prototypeManager)
|
||||||
{
|
{
|
||||||
_random = IoCManager.Resolve<IRobustRandom>();
|
_random = IoCManager.Resolve<IRobustRandom>();
|
||||||
Profile = (HumanoidCharacterProfile) preferencesManager.Preferences.SelectedCharacter;
|
|
||||||
CharacterSlot = preferencesManager.Preferences.SelectedCharacterIndex;
|
|
||||||
_preferencesManager = preferencesManager;
|
_preferencesManager = preferencesManager;
|
||||||
|
|
||||||
var margin = new MarginContainer
|
var margin = new MarginContainer
|
||||||
@@ -365,11 +364,23 @@ namespace Content.Client.UserInterface
|
|||||||
|
|
||||||
#endregion Save
|
#endregion Save
|
||||||
|
|
||||||
UpdateControls();
|
if (preferencesManager.ServerDataLoaded)
|
||||||
|
{
|
||||||
|
LoadServerData();
|
||||||
|
}
|
||||||
|
|
||||||
|
preferencesManager.OnServerDataLoaded += LoadServerData;
|
||||||
|
|
||||||
IsDirty = false;
|
IsDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadServerData()
|
||||||
|
{
|
||||||
|
Profile = (HumanoidCharacterProfile) _preferencesManager.Preferences.SelectedCharacter;
|
||||||
|
CharacterSlot = _preferencesManager.Preferences.SelectedCharacterIndex;
|
||||||
|
UpdateControls();
|
||||||
|
}
|
||||||
|
|
||||||
private void SetAge(int newAge)
|
private void SetAge(int newAge)
|
||||||
{
|
{
|
||||||
Profile = Profile?.WithAge(newAge);
|
Profile = Profile?.WithAge(newAge);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ namespace Content.Client.UserInterface
|
|||||||
private readonly IClientPreferencesManager _preferencesManager;
|
private readonly IClientPreferencesManager _preferencesManager;
|
||||||
private IEntity _previewDummy;
|
private IEntity _previewDummy;
|
||||||
private readonly Label _summaryLabel;
|
private readonly Label _summaryLabel;
|
||||||
|
private VBoxContainer _loaded;
|
||||||
|
private Label _unloaded;
|
||||||
|
|
||||||
public LobbyCharacterPreviewPanel(IEntityManager entityManager,
|
public LobbyCharacterPreviewPanel(IEntityManager entityManager,
|
||||||
IClientPreferencesManager preferencesManager)
|
IClientPreferencesManager preferencesManager)
|
||||||
@@ -50,9 +52,13 @@ namespace Content.Client.UserInterface
|
|||||||
var vBox = new VBoxContainer();
|
var vBox = new VBoxContainer();
|
||||||
|
|
||||||
vBox.AddChild(header);
|
vBox.AddChild(header);
|
||||||
vBox.AddChild(CharacterSetupButton);
|
|
||||||
|
|
||||||
vBox.AddChild(_summaryLabel);
|
_unloaded = new Label {Text = "Your character preferences have not yet loaded, please stand by."};
|
||||||
|
|
||||||
|
_loaded = new VBoxContainer {Visible = false};
|
||||||
|
|
||||||
|
_loaded.AddChild(CharacterSetupButton);
|
||||||
|
_loaded.AddChild(_summaryLabel);
|
||||||
|
|
||||||
var hBox = new HBoxContainer();
|
var hBox = new HBoxContainer();
|
||||||
hBox.AddChild(viewSouth);
|
hBox.AddChild(viewSouth);
|
||||||
@@ -60,11 +66,15 @@ namespace Content.Client.UserInterface
|
|||||||
hBox.AddChild(viewWest);
|
hBox.AddChild(viewWest);
|
||||||
hBox.AddChild(viewEast);
|
hBox.AddChild(viewEast);
|
||||||
|
|
||||||
vBox.AddChild(hBox);
|
_loaded.AddChild(hBox);
|
||||||
|
|
||||||
|
vBox.AddChild(_loaded);
|
||||||
|
vBox.AddChild(_unloaded);
|
||||||
AddChild(vBox);
|
AddChild(vBox);
|
||||||
|
|
||||||
UpdateUI();
|
UpdateUI();
|
||||||
|
|
||||||
|
_preferencesManager.OnServerDataLoaded += UpdateUI;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Button CharacterSetupButton { get; }
|
public Button CharacterSetupButton { get; }
|
||||||
@@ -89,6 +99,15 @@ namespace Content.Client.UserInterface
|
|||||||
|
|
||||||
public void UpdateUI()
|
public void UpdateUI()
|
||||||
{
|
{
|
||||||
|
if (!_preferencesManager.ServerDataLoaded)
|
||||||
|
{
|
||||||
|
_loaded.Visible = false;
|
||||||
|
_unloaded.Visible = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_loaded.Visible = true;
|
||||||
|
_unloaded.Visible = false;
|
||||||
if (!(_preferencesManager.Preferences.SelectedCharacter is HumanoidCharacterProfile selectedCharacter))
|
if (!(_preferencesManager.Preferences.SelectedCharacter is HumanoidCharacterProfile selectedCharacter))
|
||||||
{
|
{
|
||||||
_summaryLabel.Text = string.Empty;
|
_summaryLabel.Text = string.Empty;
|
||||||
@@ -102,6 +121,7 @@ namespace Content.Client.UserInterface
|
|||||||
GiveDummyJobClothes(_previewDummy, selectedCharacter);
|
GiveDummyJobClothes(_previewDummy, selectedCharacter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void GiveDummyJobClothes(IEntity dummy, HumanoidCharacterProfile profile)
|
public static void GiveDummyJobClothes(IEntity dummy, HumanoidCharacterProfile profile)
|
||||||
{
|
{
|
||||||
|
|||||||
154
Content.Server.Database/Migrations/Postgres/20200625230829_AddSlotPrefsIdIndex.Designer.cs
generated
Normal file
154
Content.Server.Database/Migrations/Postgres/20200625230829_AddSlotPrefsIdIndex.Designer.cs
generated
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
// <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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
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,7 +1,8 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
|
using Content.Server.Database;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations.Postgres
|
namespace Content.Server.Database.Migrations.Postgres
|
||||||
@@ -14,7 +15,7 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
|
||||||
.HasAnnotation("ProductVersion", "3.1.0")
|
.HasAnnotation("ProductVersion", "3.1.4")
|
||||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
||||||
@@ -76,6 +77,9 @@ namespace Content.Server.Database.Migrations.Postgres
|
|||||||
|
|
||||||
b.HasIndex("PrefsId");
|
b.HasIndex("PrefsId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PrefsId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
b.ToTable("HumanoidProfile");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
148
Content.Server.Database/Migrations/Sqlite/20200625230839_AddSlotPrefsIdIndex.Designer.cs
generated
Normal file
148
Content.Server.Database/Migrations/Sqlite/20200625230839_AddSlotPrefsIdIndex.Designer.cs
generated
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
// <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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
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,7 +1,8 @@
|
|||||||
// <auto-generated />
|
// <auto-generated />
|
||||||
|
using Content.Server.Database;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
namespace Content.Server.Database.Migrations
|
namespace Content.Server.Database.Migrations
|
||||||
{
|
{
|
||||||
@@ -12,7 +13,7 @@ namespace Content.Server.Database.Migrations
|
|||||||
{
|
{
|
||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "3.1.0");
|
.HasAnnotation("ProductVersion", "3.1.4");
|
||||||
|
|
||||||
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
modelBuilder.Entity("Content.Server.Database.HumanoidProfile", b =>
|
||||||
{
|
{
|
||||||
@@ -72,6 +73,9 @@ namespace Content.Server.Database.Migrations
|
|||||||
|
|
||||||
b.HasIndex("PrefsId");
|
b.HasIndex("PrefsId");
|
||||||
|
|
||||||
|
b.HasIndex("Slot", "PrefsId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
b.ToTable("HumanoidProfile");
|
b.ToTable("HumanoidProfile");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -53,12 +53,17 @@ namespace Content.Server.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DbSet<Prefs> Preferences { get; set; } = null!;
|
public DbSet<Prefs> Preferences { get; set; } = null!;
|
||||||
|
public DbSet<HumanoidProfile> HumanoidProfile { get; set; } = null!;
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
modelBuilder.Entity<Prefs>()
|
modelBuilder.Entity<Prefs>()
|
||||||
.HasIndex(p => p.Username)
|
.HasIndex(p => p.Username)
|
||||||
.IsUnique();
|
.IsUnique();
|
||||||
|
|
||||||
|
modelBuilder.Entity<HumanoidProfile>()
|
||||||
|
.HasIndex(p => new {p.Slot, p.PrefsId})
|
||||||
|
.IsUnique();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Content.Server.Database
|
namespace Content.Server.Database
|
||||||
@@ -20,16 +22,16 @@ namespace Content.Server.Database
|
|||||||
_prefsCtx.Database.Migrate();
|
_prefsCtx.Database.Migrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prefs GetPlayerPreferences(string username)
|
public async Task<Prefs?> GetPlayerPreferences(string username)
|
||||||
{
|
{
|
||||||
return _prefsCtx
|
return await _prefsCtx
|
||||||
.Preferences
|
.Preferences
|
||||||
.Include(p => p.HumanoidProfiles)
|
.Include(p => p.HumanoidProfiles)
|
||||||
.ThenInclude(h => h.Jobs)
|
.ThenInclude(h => h.Jobs)
|
||||||
.SingleOrDefault(p => p.Username == username);
|
.SingleOrDefaultAsync(p => p.Username == username);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveSelectedCharacterIndex(string username, int slot)
|
public async Task SaveSelectedCharacterIndex(string username, int slot)
|
||||||
{
|
{
|
||||||
var prefs = _prefsCtx.Preferences.SingleOrDefault(p => p.Username == username);
|
var prefs = _prefsCtx.Preferences.SingleOrDefault(p => p.Username == username);
|
||||||
if (prefs is null)
|
if (prefs is null)
|
||||||
@@ -40,10 +42,10 @@ namespace Content.Server.Database
|
|||||||
});
|
});
|
||||||
else
|
else
|
||||||
prefs.SelectedCharacterSlot = slot;
|
prefs.SelectedCharacterSlot = slot;
|
||||||
_prefsCtx.SaveChanges();
|
await _prefsCtx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveCharacterSlot(string username, HumanoidProfile newProfile)
|
public async Task SaveCharacterSlotAsync(string username, HumanoidProfile newProfile)
|
||||||
{
|
{
|
||||||
var prefs = _prefsCtx
|
var prefs = _prefsCtx
|
||||||
.Preferences
|
.Preferences
|
||||||
@@ -53,17 +55,29 @@ namespace Content.Server.Database
|
|||||||
.SingleOrDefault(h => h.Slot == newProfile.Slot);
|
.SingleOrDefault(h => h.Slot == newProfile.Slot);
|
||||||
if (!(oldProfile is null)) prefs.HumanoidProfiles.Remove(oldProfile);
|
if (!(oldProfile is null)) prefs.HumanoidProfiles.Remove(oldProfile);
|
||||||
prefs.HumanoidProfiles.Add(newProfile);
|
prefs.HumanoidProfiles.Add(newProfile);
|
||||||
_prefsCtx.SaveChanges();
|
await _prefsCtx.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DeleteCharacterSlot(string username, int slot)
|
public async Task DeleteCharacterSlotAsync(string username, int slot)
|
||||||
{
|
{
|
||||||
var profile = _prefsCtx
|
var profile = _prefsCtx
|
||||||
.Preferences
|
.Preferences
|
||||||
.Single(p => p.Username == username)
|
.Single(p => p.Username == username)
|
||||||
.HumanoidProfiles
|
.HumanoidProfiles
|
||||||
.RemoveAll(h => h.Slot == slot);
|
.RemoveAll(h => h.Slot == slot);
|
||||||
_prefsCtx.SaveChanges();
|
await _prefsCtx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<string, HumanoidProfile>> GetProfilesForPlayersAsync(List<string> usernames)
|
||||||
|
{
|
||||||
|
return await _prefsCtx.HumanoidProfile
|
||||||
|
.Include(p => p.Jobs)
|
||||||
|
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,9 +82,9 @@ namespace Content.Server
|
|||||||
{
|
{
|
||||||
base.PostInit();
|
base.PostInit();
|
||||||
|
|
||||||
|
IoCManager.Resolve<IServerPreferencesManager>().FinishInit();
|
||||||
_gameTicker.Initialize();
|
_gameTicker.Initialize();
|
||||||
IoCManager.Resolve<ISandboxManager>().Initialize();
|
IoCManager.Resolve<ISandboxManager>().Initialize();
|
||||||
IoCManager.Resolve<IServerPreferencesManager>().FinishInit();
|
|
||||||
IoCManager.Resolve<RecipeManager>().Initialize();
|
IoCManager.Resolve<RecipeManager>().Initialize();
|
||||||
IoCManager.Resolve<BlackboardManager>().Initialize();
|
IoCManager.Resolve<BlackboardManager>().Initialize();
|
||||||
IoCManager.Resolve<IPDAUplinkManager>().Initialize();
|
IoCManager.Resolve<IPDAUplinkManager>().Initialize();
|
||||||
|
|||||||
@@ -19,7 +19,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<IPlayerSession, HumanoidCharacterProfile> profiles)
|
Dictionary<string, 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 +38,7 @@ namespace Content.Server.GameTicking
|
|||||||
var candidates = available
|
var candidates = available
|
||||||
.Select(player =>
|
.Select(player =>
|
||||||
{
|
{
|
||||||
var profile = profiles[player];
|
var profile = profiles[player.Name];
|
||||||
|
|
||||||
var availableJobs = profile.JobPriorities
|
var availableJobs = profile.JobPriorities
|
||||||
.Where(j =>
|
.Where(j =>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
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;
|
using Content.Server.GameObjects;
|
||||||
using Content.Server.GameObjects.Components.Access;
|
using Content.Server.GameObjects.Components.Access;
|
||||||
using Content.Server.GameObjects.Components.Markers;
|
using Content.Server.GameObjects.Components.Markers;
|
||||||
@@ -205,7 +206,7 @@ namespace Content.Server.GameTicking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartRound(bool force = false)
|
public async 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!");
|
||||||
@@ -227,7 +228,18 @@ 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 = readyPlayers.ToDictionary(p => p, GetPlayerProfile);
|
var profiles = (await _prefsManager.GetSelectedProfilesForPlayersAsync(
|
||||||
|
readyPlayers
|
||||||
|
.Select(p => p.Name).ToList()))
|
||||||
|
.ToDictionary(p => p.Key, p => (HumanoidCharacterProfile) p.Value);
|
||||||
|
|
||||||
|
foreach (var readyPlayer in readyPlayers)
|
||||||
|
{
|
||||||
|
if (!profiles.ContainsKey(readyPlayer.Name))
|
||||||
|
{
|
||||||
|
profiles.Add(readyPlayer.Name, HumanoidCharacterProfile.Default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var assignedJobs = AssignJobs(readyPlayers, profiles);
|
var assignedJobs = AssignJobs(readyPlayers, profiles);
|
||||||
|
|
||||||
@@ -239,7 +251,7 @@ namespace Content.Server.GameTicking
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var profile = profiles[player];
|
var profile = profiles[player.Name];
|
||||||
if (profile.PreferenceUnavailable == PreferenceUnavailableMode.SpawnAsOverflow)
|
if (profile.PreferenceUnavailable == PreferenceUnavailableMode.SpawnAsOverflow)
|
||||||
{
|
{
|
||||||
assignedJobs.Add(player, OverflowJob);
|
assignedJobs.Add(player, OverflowJob);
|
||||||
@@ -259,7 +271,8 @@ namespace Content.Server.GameTicking
|
|||||||
{
|
{
|
||||||
SetStartPreset(_configurationManager.GetCVar<string>("game.fallbackpreset"));
|
SetStartPreset(_configurationManager.GetCVar<string>("game.fallbackpreset"));
|
||||||
var newPreset = MakeGamePreset();
|
var newPreset = MakeGamePreset();
|
||||||
_chatManager.DispatchServerAnnouncement($"Failed to start {preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}...");
|
_chatManager.DispatchServerAnnouncement(
|
||||||
|
$"Failed to start {preset.ModeTitle} mode! Defaulting to {newPreset.ModeTitle}...");
|
||||||
if (!newPreset.Start(readyPlayers, force))
|
if (!newPreset.Start(readyPlayers, force))
|
||||||
{
|
{
|
||||||
throw new ApplicationException("Fallback preset failed to start!");
|
throw new ApplicationException("Fallback preset failed to start!");
|
||||||
@@ -278,8 +291,9 @@ namespace Content.Server.GameTicking
|
|||||||
IoCManager.Resolve<IServerNetManager>().ServerSendToAll(msg);
|
IoCManager.Resolve<IServerNetManager>().ServerSendToAll(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HumanoidCharacterProfile GetPlayerProfile(IPlayerSession p) =>
|
private async Task<HumanoidCharacterProfile> GetPlayerProfileAsync(IPlayerSession p) =>
|
||||||
(HumanoidCharacterProfile) _prefsManager.GetPreferences(p.SessionId.Username).SelectedCharacter;
|
(HumanoidCharacterProfile) (await _prefsManager.GetPreferencesAsync(p.SessionId.Username))
|
||||||
|
.SelectedCharacter;
|
||||||
|
|
||||||
public void EndRound()
|
public void EndRound()
|
||||||
{
|
{
|
||||||
@@ -297,17 +311,19 @@ namespace Content.Server.GameTicking
|
|||||||
|
|
||||||
//Generate a list of basic player info to display in the end round summary.
|
//Generate a list of basic player info to display in the end round summary.
|
||||||
var listOfPlayerInfo = new List<RoundEndPlayerInfo>();
|
var listOfPlayerInfo = new List<RoundEndPlayerInfo>();
|
||||||
foreach(var ply in _playerManager.GetAllPlayers().OrderBy(p => p.Name))
|
foreach (var ply in _playerManager.GetAllPlayers().OrderBy(p => p.Name))
|
||||||
{
|
{
|
||||||
var mind = ply.ContentData().Mind;
|
var mind = ply.ContentData().Mind;
|
||||||
if(mind != null)
|
if (mind != null)
|
||||||
{
|
{
|
||||||
var antag = mind.AllRoles.Any(role => role.Antag);
|
var antag = mind.AllRoles.Any(role => role.Antag);
|
||||||
var playerEndRoundInfo = new RoundEndPlayerInfo()
|
var playerEndRoundInfo = new RoundEndPlayerInfo()
|
||||||
{
|
{
|
||||||
PlayerOOCName = ply.Name,
|
PlayerOOCName = ply.Name,
|
||||||
PlayerICName = mind.CurrentEntity.Name,
|
PlayerICName = mind.CurrentEntity.Name,
|
||||||
Role = antag ? mind.AllRoles.First(role => role.Antag).Name : mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("Unknown"),
|
Role = antag
|
||||||
|
? mind.AllRoles.First(role => role.Antag).Name
|
||||||
|
: mind.AllRoles.FirstOrDefault()?.Name ?? Loc.GetString("Unknown"),
|
||||||
Antag = antag
|
Antag = antag
|
||||||
};
|
};
|
||||||
listOfPlayerInfo.Add(playerEndRoundInfo);
|
listOfPlayerInfo.Add(playerEndRoundInfo);
|
||||||
@@ -725,14 +741,14 @@ namespace Content.Server.GameTicking
|
|||||||
}, _updateShutdownCts.Token);
|
}, _updateShutdownCts.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SpawnPlayer(IPlayerSession session, string jobId = null, bool lateJoin = true)
|
private async void SpawnPlayer(IPlayerSession session, string jobId = null, bool lateJoin = true)
|
||||||
{
|
{
|
||||||
var character = (HumanoidCharacterProfile) _prefsManager
|
|
||||||
.GetPreferences(session.SessionId.Username)
|
|
||||||
.SelectedCharacter;
|
|
||||||
|
|
||||||
_playerJoinGame(session);
|
_playerJoinGame(session);
|
||||||
|
|
||||||
|
var character = (HumanoidCharacterProfile) (await _prefsManager
|
||||||
|
.GetPreferencesAsync(session.SessionId.Username))
|
||||||
|
.SelectedCharacter;
|
||||||
|
|
||||||
var data = session.ContentData();
|
var data = session.ContentData();
|
||||||
data.WipeMind();
|
data.WipeMind();
|
||||||
data.Mind = new Mind(session.SessionId)
|
data.Mind = new Mind(session.SessionId)
|
||||||
@@ -785,15 +801,16 @@ namespace Content.Server.GameTicking
|
|||||||
accessTags.UnionWith(jobPrototype.Access);
|
accessTags.UnionWith(jobPrototype.Access);
|
||||||
pdaComponent.SetPDAOwner(mob);
|
pdaComponent.SetPDAOwner(mob);
|
||||||
var mindComponent = mob.GetComponent<MindComponent>();
|
var mindComponent = mob.GetComponent<MindComponent>();
|
||||||
if (mindComponent.HasMind)//Redundancy checks.
|
if (mindComponent.HasMind) //Redundancy checks.
|
||||||
{
|
{
|
||||||
if (mindComponent.Mind.AllRoles.Any(role => role.Antag)) //Give antags a new uplinkaccount.
|
if (mindComponent.Mind.AllRoles.Any(role => role.Antag)) //Give antags a new uplinkaccount.
|
||||||
{
|
{
|
||||||
var uplinkAccount = new UplinkAccount(mob.Uid, 20); //TODO: make me into a variable based on server pop or something.
|
var uplinkAccount =
|
||||||
|
new UplinkAccount(mob.Uid,
|
||||||
|
20); //TODO: make me into a variable based on server pop or something.
|
||||||
pdaComponent.InitUplinkAccount(uplinkAccount);
|
pdaComponent.InitUplinkAccount(uplinkAccount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddManifestEntry(string characterName, string jobId)
|
private void AddManifestEntry(string characterName, string jobId)
|
||||||
@@ -801,13 +818,14 @@ namespace Content.Server.GameTicking
|
|||||||
_manifest.Add(new ManifestEntry(characterName, jobId));
|
_manifest.Add(new ManifestEntry(characterName, jobId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _spawnObserver(IPlayerSession session)
|
private async void _spawnObserver(IPlayerSession session)
|
||||||
{
|
{
|
||||||
var name = _prefsManager
|
_playerJoinGame(session);
|
||||||
.GetPreferences(session.SessionId.Username)
|
|
||||||
|
var name = (await _prefsManager
|
||||||
|
.GetPreferencesAsync(session.SessionId.Username))
|
||||||
.SelectedCharacter.Name;
|
.SelectedCharacter.Name;
|
||||||
|
|
||||||
_playerJoinGame(session);
|
|
||||||
var data = session.ContentData();
|
var data = session.ContentData();
|
||||||
data.WipeMind();
|
data.WipeMind();
|
||||||
data.Mind = new Mind(session.SessionId);
|
data.Mind = new Mind(session.SessionId);
|
||||||
@@ -868,7 +886,7 @@ namespace Content.Server.GameTicking
|
|||||||
return _localization.GetString(@"Hi and welcome to [color=white]Space Station 14![/color]
|
return _localization.GetString(@"Hi and welcome to [color=white]Space Station 14![/color]
|
||||||
|
|
||||||
The current game mode is: [color=white]{0}[/color].
|
The current game mode is: [color=white]{0}[/color].
|
||||||
[color=yellow]{1}[/color]", gmTitle, desc );
|
[color=yellow]{1}[/color]", gmTitle, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateInfoText()
|
private void UpdateInfoText()
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Server.Interfaces.Player;
|
using Robust.Server.Interfaces.Player;
|
||||||
|
|
||||||
@@ -7,7 +9,8 @@ namespace Content.Server.Interfaces
|
|||||||
{
|
{
|
||||||
void FinishInit();
|
void FinishInit();
|
||||||
void OnClientConnected(IPlayerSession session);
|
void OnClientConnected(IPlayerSession session);
|
||||||
PlayerPreferences GetPreferences(string username);
|
Task<PlayerPreferences> GetPreferencesAsync(string username);
|
||||||
|
Task<IEnumerable<KeyValuePair<string, ICharacterProfile>>> GetSelectedProfilesForPlayersAsync(List<string> usernames);
|
||||||
void StartInit();
|
void StartInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
using Content.Shared.Preferences;
|
using Content.Shared.Preferences;
|
||||||
using Robust.Shared.Maths;
|
using Robust.Shared.Maths;
|
||||||
@@ -16,38 +19,28 @@ namespace Content.Server.Preferences
|
|||||||
private readonly int _maxCharacterSlots;
|
private readonly int _maxCharacterSlots;
|
||||||
private readonly PrefsDb _prefsDb;
|
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)
|
public PreferencesDatabase(IDatabaseConfiguration dbConfig, int maxCharacterSlots)
|
||||||
{
|
{
|
||||||
_maxCharacterSlots = maxCharacterSlots;
|
_maxCharacterSlots = maxCharacterSlots;
|
||||||
_prefsDb = new PrefsDb(dbConfig);
|
_prefsDb = new PrefsDb(dbConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerPreferences GetPlayerPreferences(string username)
|
public async Task<PlayerPreferences> GetPlayerPreferencesAsync(string username)
|
||||||
{
|
{
|
||||||
var prefs = _prefsDb.GetPlayerPreferences(username);
|
await _prefsSemaphore.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var prefs = await _prefsDb.GetPlayerPreferences(username);
|
||||||
if (prefs is null) return null;
|
if (prefs is null) return null;
|
||||||
|
|
||||||
var profiles = new ICharacterProfile[_maxCharacterSlots];
|
var profiles = new ICharacterProfile[_maxCharacterSlots];
|
||||||
foreach (var profile in prefs.HumanoidProfiles)
|
foreach (var profile in prefs.HumanoidProfiles)
|
||||||
{
|
{
|
||||||
var jobs = profile.Jobs.ToDictionary(j => j.JobName, j => (JobPriority) j.Priority);
|
profiles[profile.Slot] = ConvertProfiles(profile);
|
||||||
|
|
||||||
profiles[profile.Slot] = 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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PlayerPreferences
|
return new PlayerPreferences
|
||||||
@@ -56,20 +49,37 @@ namespace Content.Server.Preferences
|
|||||||
prefs.SelectedCharacterSlot
|
prefs.SelectedCharacterSlot
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
public void SaveSelectedCharacterIndex(string username, int index)
|
|
||||||
{
|
{
|
||||||
index = index.Clamp(0, _maxCharacterSlots - 1);
|
_prefsSemaphore.Release();
|
||||||
_prefsDb.SaveSelectedCharacterIndex(username, index);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveCharacterSlot(string username, ICharacterProfile profile, int slot)
|
public async Task SaveSelectedCharacterIndexAsync(string username, int index)
|
||||||
|
{
|
||||||
|
await _prefsSemaphore.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
index = index.Clamp(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)
|
if (slot < 0 || slot >= _maxCharacterSlots)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
await _prefsSemaphore.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
if (profile is null)
|
if (profile is null)
|
||||||
{
|
{
|
||||||
DeleteCharacterSlot(username, slot);
|
await DeleteCharacterSlotAsync(username, slot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,12 +107,55 @@ namespace Content.Server.Preferences
|
|||||||
.Where(j => j.Value != JobPriority.Never)
|
.Where(j => j.Value != JobPriority.Never)
|
||||||
.Select(j => new Job {JobName = j.Key, Priority = (DbJobPriority) j.Value})
|
.Select(j => new Job {JobName = j.Key, Priority = (DbJobPriority) j.Value})
|
||||||
);
|
);
|
||||||
_prefsDb.SaveCharacterSlot(username, entity);
|
await _prefsDb.SaveCharacterSlotAsync(username, entity);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_prefsSemaphore.Release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteCharacterSlot(string username, int slot)
|
|
||||||
|
private async Task DeleteCharacterSlotAsync(string username, int slot)
|
||||||
{
|
{
|
||||||
_prefsDb.DeleteCharacterSlot(username, 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);
|
||||||
|
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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
@@ -82,20 +83,22 @@ namespace Content.Server.Preferences
|
|||||||
_preferencesDb = _prefsDbLoadTask.Result;
|
_preferencesDb = _prefsDbLoadTask.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleSelectCharacterMessage(MsgSelectCharacter message)
|
private async void HandleSelectCharacterMessage(MsgSelectCharacter message)
|
||||||
{
|
{
|
||||||
_preferencesDb.SaveSelectedCharacterIndex(message.MsgChannel.SessionId.Username, message.SelectedCharacterIndex);
|
await _preferencesDb.SaveSelectedCharacterIndexAsync(message.MsgChannel.SessionId.Username,
|
||||||
|
message.SelectedCharacterIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleUpdateCharacterMessage(MsgUpdateCharacter message)
|
private async void HandleUpdateCharacterMessage(MsgUpdateCharacter message)
|
||||||
{
|
{
|
||||||
_preferencesDb.SaveCharacterSlot(message.MsgChannel.SessionId.Username, message.Profile, message.Slot);
|
await _preferencesDb.SaveCharacterSlotAsync(message.MsgChannel.SessionId.Username, message.Profile,
|
||||||
|
message.Slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnClientConnected(IPlayerSession session)
|
public async void OnClientConnected(IPlayerSession session)
|
||||||
{
|
{
|
||||||
var msg = _netManager.CreateNetMessage<MsgPreferencesAndSettings>();
|
var msg = _netManager.CreateNetMessage<MsgPreferencesAndSettings>();
|
||||||
msg.Preferences = GetPreferences(session.SessionId.Username);
|
msg.Preferences = await GetPreferencesAsync(session.SessionId.Username);
|
||||||
msg.Settings = new GameSettings
|
msg.Settings = new GameSettings
|
||||||
{
|
{
|
||||||
MaxCharacterSlots = _configuration.GetCVar<int>("game.maxcharacterslots")
|
MaxCharacterSlots = _configuration.GetCVar<int>("game.maxcharacterslots")
|
||||||
@@ -106,26 +109,31 @@ namespace Content.Server.Preferences
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the requested <see cref="PlayerPreferences"/> or null if not found.
|
/// Returns the requested <see cref="PlayerPreferences"/> or null if not found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private PlayerPreferences GetFromSql(string username)
|
private async Task<PlayerPreferences> GetFromSql(string username)
|
||||||
{
|
{
|
||||||
return _preferencesDb.GetPlayerPreferences(username);
|
return await _preferencesDb.GetPlayerPreferencesAsync(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <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 PlayerPreferences GetPreferences(string username)
|
public async Task<PlayerPreferences> GetPreferencesAsync(string username)
|
||||||
{
|
{
|
||||||
var prefs = GetFromSql(username);
|
var prefs = await GetFromSql(username);
|
||||||
if (prefs is null)
|
if (prefs is null)
|
||||||
{
|
{
|
||||||
_preferencesDb.SaveSelectedCharacterIndex(username, 0);
|
await _preferencesDb.SaveSelectedCharacterIndexAsync(username, 0);
|
||||||
_preferencesDb.SaveCharacterSlot(username, HumanoidCharacterProfile.Default(), 0);
|
await _preferencesDb.SaveCharacterSlotAsync(username, HumanoidCharacterProfile.Default(), 0);
|
||||||
prefs = GetFromSql(username);
|
prefs = await GetFromSql(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefs;
|
return prefs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<KeyValuePair<string, ICharacterProfile>>> GetSelectedProfilesForPlayersAsync(List<string> usernames)
|
||||||
|
{
|
||||||
|
return await _preferencesDb.GetSelectedProfilesForPlayersAsync(usernames);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Database;
|
using Content.Server.Database;
|
||||||
using Content.Server.Preferences;
|
using Content.Server.Preferences;
|
||||||
using Content.Shared;
|
using Content.Shared;
|
||||||
@@ -44,64 +45,64 @@ namespace Content.Tests.Server.Preferences
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestUserDoesNotExist()
|
public async Task TestUserDoesNotExist()
|
||||||
{
|
{
|
||||||
var db = GetDb();
|
var db = GetDb();
|
||||||
Assert.Null(db.GetPlayerPreferences("[The database should be empty so any string should do]"));
|
Assert.Null(await db.GetPlayerPreferencesAsync("[The database should be empty so any string should do]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestUserDoesExist()
|
public async Task TestUserDoesExist()
|
||||||
{
|
{
|
||||||
var db = GetDb();
|
var db = GetDb();
|
||||||
const string username = "bobby";
|
const string username = "bobby";
|
||||||
db.SaveSelectedCharacterIndex(username, 0);
|
await db.SaveSelectedCharacterIndexAsync(username, 0);
|
||||||
var prefs = db.GetPlayerPreferences(username);
|
var prefs = await db.GetPlayerPreferencesAsync(username);
|
||||||
Assert.NotNull(prefs);
|
Assert.NotNull(prefs);
|
||||||
Assert.Zero(prefs.SelectedCharacterIndex);
|
Assert.Zero(prefs.SelectedCharacterIndex);
|
||||||
Assert.That(prefs.Characters.ToList().TrueForAll(character => character is null));
|
Assert.That(prefs.Characters.ToList().TrueForAll(character => character is null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestUpdateCharacter()
|
public async Task TestUpdateCharacter()
|
||||||
{
|
{
|
||||||
var db = GetDb();
|
var db = GetDb();
|
||||||
const string username = "charlie";
|
const string username = "charlie";
|
||||||
const int slot = 0;
|
const int slot = 0;
|
||||||
var originalProfile = CharlieCharlieson();
|
var originalProfile = CharlieCharlieson();
|
||||||
db.SaveSelectedCharacterIndex(username, slot);
|
await db.SaveSelectedCharacterIndexAsync(username, slot);
|
||||||
db.SaveCharacterSlot(username, originalProfile, slot);
|
await db.SaveCharacterSlotAsync(username, originalProfile, slot);
|
||||||
var prefs = db.GetPlayerPreferences(username);
|
var prefs = await db.GetPlayerPreferencesAsync(username);
|
||||||
Assert.That(prefs.Characters.ElementAt(slot).MemberwiseEquals(originalProfile));
|
Assert.That(prefs.Characters.ElementAt(slot).MemberwiseEquals(originalProfile));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestDeleteCharacter()
|
public async Task TestDeleteCharacter()
|
||||||
{
|
{
|
||||||
var db = GetDb();
|
var db = GetDb();
|
||||||
const string username = "charlie";
|
const string username = "charlie";
|
||||||
const int slot = 0;
|
const int slot = 0;
|
||||||
db.SaveSelectedCharacterIndex(username, slot);
|
await db.SaveSelectedCharacterIndexAsync(username, slot);
|
||||||
db.SaveCharacterSlot(username, CharlieCharlieson(), slot);
|
await db.SaveCharacterSlotAsync(username, CharlieCharlieson(), slot);
|
||||||
db.SaveCharacterSlot(username, null, slot);
|
await db.SaveCharacterSlotAsync(username, null, slot);
|
||||||
var prefs = db.GetPlayerPreferences(username);
|
var prefs = await db.GetPlayerPreferencesAsync(username);
|
||||||
Assert.That(prefs.Characters.ToList().TrueForAll(character => character is null));
|
Assert.That(prefs.Characters.ToList().TrueForAll(character => character is null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestInvalidSlot()
|
public async Task TestInvalidSlot()
|
||||||
{
|
{
|
||||||
var db = GetDb();
|
var db = GetDb();
|
||||||
const string username = "charlie";
|
const string username = "charlie";
|
||||||
const int slot = -1;
|
const int slot = -1;
|
||||||
|
|
||||||
db.SaveSelectedCharacterIndex(username, slot);
|
await db.SaveSelectedCharacterIndexAsync(username, slot);
|
||||||
db.SaveCharacterSlot(username, CharlieCharlieson(), slot);
|
await db.SaveCharacterSlotAsync(username, CharlieCharlieson(), slot);
|
||||||
var prefs = db.GetPlayerPreferences(username);
|
var prefs = await db.GetPlayerPreferencesAsync(username);
|
||||||
Assert.AreEqual(prefs.SelectedCharacterIndex, 0);
|
Assert.AreEqual(prefs.SelectedCharacterIndex, 0);
|
||||||
|
|
||||||
db.SaveSelectedCharacterIndex(username, MaxCharacterSlots);
|
await db.SaveSelectedCharacterIndexAsync(username, MaxCharacterSlots);
|
||||||
prefs = db.GetPlayerPreferences(username);
|
prefs = await db.GetPlayerPreferencesAsync(username);
|
||||||
Assert.AreEqual(prefs.SelectedCharacterIndex, MaxCharacterSlots - 1);
|
Assert.AreEqual(prefs.SelectedCharacterIndex, MaxCharacterSlots - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user