Compare commits

..

18 Commits

Author SHA1 Message Date
Deserty0
aa621ece26 Merge remote-tracking branch 'upstream/master' into funnyfunnystuff 2025-08-23 19:44:16 +10:00
Deserty0
52880de47e должно теперь работать 2025-08-13 21:07:21 +10:00
Deserty0
eb289104ab Update DiscordAuthManager.cs 2025-08-13 05:40:08 +10:00
Deserty0
db49a55481 Update CCvars.CP14DiscordAuth.cs 2025-08-13 05:40:08 +10:00
Deserty0
f01725fdc7 Update CCvars.CP14DiscordAuth.cs 2025-08-13 05:15:57 +10:00
Deserty0
0a6a560066 Update DiscordAuthManager.cs 2025-08-13 05:04:38 +10:00
Deserty0
6f170bb45f lol 2025-08-13 04:55:57 +10:00
Deserty0
cec07307bf 123 2025-08-13 04:49:12 +10:00
Deserty0
bd80a1eb60 Update PanicBunkerTab.xaml 2025-08-13 04:49:12 +10:00
Deserty0
b0c2b92464 Update DiscordAuthManager.cs 2025-08-13 04:15:38 +10:00
Deserty0
35e5025d3e Update CCvars.CP14DiscordAuth.cs 2025-08-13 04:15:37 +10:00
Deserty0
146967b786 looool 2025-08-13 04:15:37 +10:00
Deserty0
4b68d79729 uaua 2025-08-13 04:15:37 +10:00
Deserty0
8899695ed5 Update DiscordAuthManager.cs 2025-08-13 04:15:37 +10:00
Deserty0
1d410590b6 Update DiscordAuthManager.cs 2025-08-13 04:15:37 +10:00
Deserty0
24eb9d7493 Update DiscordAuthManager.cs 2025-08-13 04:15:37 +10:00
Deserty0
565283ae26 Update DiscordAuthManager.cs 2025-08-13 04:15:36 +10:00
Deserty0
d55800c575 funny 2025-08-13 04:15:36 +10:00
4382 changed files with 268528 additions and 437734 deletions

4
.github/CODEOWNERS vendored
View File

@@ -1,2 +1,6 @@
# TheShuEd # TheShuEd
* @TheShuEd * @TheShuEd
# TornadoTechnology
*.cs @Tornado-Technology
*.xaml @Tornado-Technology

22
.github/FUNDING.yml vendored
View File

@@ -1,14 +1,14 @@
# These are supported funding model platforms # These are supported funding model platforms
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
#patreon: # Replace with a single Patreon username patreon: # Replace with a single Patreon username
#open_collective: # Replace with a single Open Collective username open_collective: # Replace with a single Open Collective username
#ko_fi: # Replace with a single Ko-fi username ko_fi: # Replace with a single Ko-fi username
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
#liberapay: # Replace with a single Liberapay username liberapay: # Replace with a single Liberapay username
#issuehunt: # Replace with a single IssueHunt username issuehunt: # Replace with a single IssueHunt username
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
#polar: # Replace with a single Polar username polar: # Replace with a single Polar username
#buy_me_a_coffee: # Replace with a single Buy Me a Coffee username buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
custom: ['https://boosty.to/theshued'] custom: ['https://boosty.to/theshued']

38
.github/workflows/cla.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened,closed,synchronize]
paths:
- '**CP14**'
# explicitly configure permissions, in case your GITHUB_TOKEN workflow permissions are set to read-only in repository settings
permissions:
actions: write
contents: write # this can be 'read' if the signatures are in remote repository
pull-requests: write
statuses: write
jobs:
CLAAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: ((github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target') && github.actor != 'TheShuEd'
uses: contributor-assistant/github-action@v2.6.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# the below token should have repo scope and must be manually added by you in the repository's secret
# This token is required only if you have configured to store the signatures in a remote repository/organization
# PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
with:
path-to-signatures: 'signatures/version1/cla.json'
path-to-document: 'https://github.com/crystallpunk-14/crystall-punk-14/blob/master/CLA.md' # e.g. a CLA or a DCO document
# branch should not be protected
branch: 'master'
allowlist: TheShuEd,bot*
# the followings are the optional inputs - If the optional inputs are not given, then default values will be taken
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'

View File

@@ -34,7 +34,7 @@ jobs:
run: dotnet build Content.Packaging --configuration Release --no-restore /m run: dotnet build Content.Packaging --configuration Release --no-restore /m
- name: Package server - name: Package server
run: dotnet run --project Content.Packaging server --platform win-x64 --platform win-arm64 --platform linux-x64 --platform linux-arm64 --platform osx-x64 --platform osx-arm64 run: dotnet run --project Content.Packaging server --platform win-x64 --platform linux-x64 --platform osx-x64 --platform linux-arm64
- name: Package client - name: Package client
run: dotnet run --project Content.Packaging client --no-wipe-release run: dotnet run --project Content.Packaging client --no-wipe-release

View File

@@ -41,7 +41,7 @@ jobs:
run: dotnet build Content.Packaging --configuration Release --no-restore /m run: dotnet build Content.Packaging --configuration Release --no-restore /m
- name: Package server - name: Package server
run: dotnet run --project Content.Packaging server --platform win-x64 --platform win-arm64 --platform linux-x64 --platform linux-arm64 --platform osx-x64 --platform osx-arm64 run: dotnet run --project Content.Packaging server --platform win-x64 --platform linux-x64 --platform osx-x64 --platform linux-arm64
- name: Package client - name: Package client
run: dotnet run --project Content.Packaging client --no-wipe-release run: dotnet run --project Content.Packaging client --no-wipe-release

View File

@@ -60,7 +60,7 @@ jobs:
run: dotnet build Content.Packaging --configuration Release --no-restore /m run: dotnet build Content.Packaging --configuration Release --no-restore /m
- name: Package server - name: Package server
run: dotnet run --project Content.Packaging server --platform win-x64 --platform win-arm64 --platform linux-x64 --platform linux-arm64 --platform osx-x64 --platform osx-arm64 run: dotnet run --project Content.Packaging server --platform win-x64 --platform linux-x64 --platform osx-x64 --platform linux-arm64
- name: Package client - name: Package client
run: dotnet run --project Content.Packaging client --no-wipe-release run: dotnet run --project Content.Packaging client --no-wipe-release

View File

@@ -1,19 +1,17 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" # Installs git hooks, updates them, updates submodules, that kind of thing.
Installs git hooks, updates them, updates submodules, that kind of thing.
"""
import os
import shutil
import subprocess import subprocess
import sys import sys
import os
import shutil
import time import time
from pathlib import Path from pathlib import Path
from typing import List from typing import List
SOLUTION_PATH = Path("..") / "SpaceStation14.sln" SOLUTION_PATH = Path("..") / "SpaceStation14.sln"
# If this doesn't match the saved version we overwrite them all. # If this doesn't match the saved version we overwrite them all.
CURRENT_HOOKS_VERSION = "3" CURRENT_HOOKS_VERSION = "2"
QUIET = len(sys.argv) == 2 and sys.argv[1] == "--quiet" QUIET = len(sys.argv) == 2 and sys.argv[1] == "--quiet"
@@ -27,10 +25,12 @@ def run_command(command: List[str], capture: bool = False) -> subprocess.Complet
sys.stdout.flush() sys.stdout.flush()
completed = None
if capture: if capture:
completed = subprocess.run(command, stdout=subprocess.PIPE, text=True) completed = subprocess.run(command, cwd="..", stdout=subprocess.PIPE)
else: else:
completed = subprocess.run(command) completed = subprocess.run(command, cwd="..")
if completed.returncode != 0: if completed.returncode != 0:
print("Error: command exited with code {}!".format(completed.returncode)) print("Error: command exited with code {}!".format(completed.returncode))
@@ -43,7 +43,7 @@ def update_submodules():
Updates all submodules. Updates all submodules.
""" """
if 'GITHUB_ACTIONS' in os.environ: if ('GITHUB_ACTIONS' in os.environ):
return return
if os.path.isfile("DISABLE_SUBMODULE_AUTOUPDATE"): if os.path.isfile("DISABLE_SUBMODULE_AUTOUPDATE"):
@@ -76,21 +76,22 @@ def install_hooks():
print("No hooks change detected.") print("No hooks change detected.")
return return
with open("INSTALLED_HOOKS_VERSION", "w") as f:
f.write(CURRENT_HOOKS_VERSION)
print("Hooks need updating.") print("Hooks need updating.")
hooks_target_dir = Path(run_command(["git", "rev-parse", "--git-path", "hooks"], True).stdout.strip()) hooks_target_dir = Path("..")/".git"/"hooks"
hooks_source_dir = Path("hooks") hooks_source_dir = Path("hooks")
# Clear entire tree since we need to kill deleted files too. # Clear entire tree since we need to kill deleted files too.
for filename in os.listdir(hooks_target_dir): for filename in os.listdir(str(hooks_target_dir)):
os.remove(hooks_target_dir / filename) os.remove(str(hooks_target_dir/filename))
for filename in os.listdir(hooks_source_dir): for filename in os.listdir(str(hooks_source_dir)):
print("Copying hook {}".format(filename)) print("Copying hook {}".format(filename))
shutil.copy2(hooks_source_dir / filename, hooks_target_dir / filename) shutil.copy2(str(hooks_source_dir/filename),
str(hooks_target_dir/filename))
with open("INSTALLED_HOOKS_VERSION", "w") as f:
f.write(CURRENT_HOOKS_VERSION)
def reset_solution(): def reset_solution():
@@ -106,7 +107,8 @@ def reset_solution():
def check_for_zip_download(): def check_for_zip_download():
# Check if .git exists, # Check if .git exists,
if run_command(["git", "rev-parse"]).returncode != 0: cur_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
if not os.path.isdir(os.path.join(cur_dir, ".git")):
print("It appears that you downloaded this repository directly from GitHub. (Using the .zip download option) \n" print("It appears that you downloaded this repository directly from GitHub. (Using the .zip download option) \n"
"When downloading straight from GitHub, it leaves out important information that git needs to function. " "When downloading straight from GitHub, it leaves out important information that git needs to function. "
"Such as information to download the engine or even the ability to even be able to create contributions. \n" "Such as information to download the engine or even the ability to even be able to create contributions. \n"

View File

@@ -1,10 +1,10 @@
#!/bin/bash #!/bin/bash
gitroot=$(git rev-parse --show-toplevel) gitroot=`git rev-parse --show-toplevel`
cd "$gitroot/BuildChecker" || exit cd "$gitroot/BuildChecker"
if [[ $(uname) == MINGW* || $(uname) == CYGWIN* ]]; then if [[ `uname` == MINGW* || `uname` == CYGWIN* ]]; then
# Windows # Windows
py -3 git_helper.py --quiet py -3 git_helper.py --quiet
else else

View File

@@ -1,5 +1,5 @@
#!/bin/bash #!/bin/bash
# Just call post-checkout since it does the same thing. # Just call post-checkout since it does the same thing.
gitroot=$(git rev-parse --git-path hooks) gitroot=`git rev-parse --show-toplevel`
bash "$gitroot/post-checkout" bash "$gitroot/.git/hooks/post-checkout"

View File

@@ -1,174 +0,0 @@
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Diagnosers;
using Content.IntegrationTests;
using Content.IntegrationTests.Pair;
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Shared.Atmos.Components;
using Content.Shared.CCVar;
using Robust.Shared;
using Robust.Shared.Analyzers;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Benchmarks;
/// <summary>
/// Spawns N number of entities with a <see cref="DeltaPressureComponent"/> and
/// simulates them for a number of ticks M.
/// </summary>
[Virtual]
[GcServer(true)]
//[MemoryDiagnoser]
//[ThreadingDiagnoser]
public class DeltaPressureBenchmark
{
/// <summary>
/// Number of entities (windows, really) to spawn with a <see cref="DeltaPressureComponent"/>.
/// </summary>
[Params(1, 10, 100, 1000, 5000, 10000, 50000, 100000)]
public int EntityCount;
/// <summary>
/// Number of entities that each parallel processing job will handle.
/// </summary>
// [Params(1, 10, 100, 1000, 5000, 10000)] For testing how multithreading parameters affect performance (THESE TESTS TAKE 16+ HOURS TO RUN)
[Params(10)]
public int BatchSize;
/// <summary>
/// Number of entities to process per iteration in the DeltaPressure
/// processing loop.
/// </summary>
// [Params(100, 1000, 5000, 10000, 50000)]
[Params(1000)]
public int EntitiesPerIteration;
private readonly EntProtoId _windowProtoId = "Window";
private readonly EntProtoId _wallProtoId = "WallPlastitaniumIndestructible";
private TestPair _pair = default!;
private IEntityManager _entMan = default!;
private SharedMapSystem _map = default!;
private IRobustRandom _random = default!;
private IConfigurationManager _cvar = default!;
private ITileDefinitionManager _tileDefMan = default!;
private AtmosphereSystem _atmospereSystem = default!;
private Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent>
_testEnt;
[GlobalSetup]
public async Task SetupAsync()
{
ProgramShared.PathOffset = "../../../../";
PoolManager.Startup();
_pair = await PoolManager.GetServerClient();
var server = _pair.Server;
var mapdata = await _pair.CreateTestMap();
_entMan = server.ResolveDependency<IEntityManager>();
_map = _entMan.System<SharedMapSystem>();
_random = server.ResolveDependency<IRobustRandom>();
_cvar = server.ResolveDependency<IConfigurationManager>();
_tileDefMan = server.ResolveDependency<ITileDefinitionManager>();
_atmospereSystem = _entMan.System<AtmosphereSystem>();
_random.SetSeed(69420); // Randomness needs to be deterministic for benchmarking.
_cvar.SetCVar(CCVars.DeltaPressureParallelToProcessPerIteration, EntitiesPerIteration);
_cvar.SetCVar(CCVars.DeltaPressureParallelBatchSize, BatchSize);
var plating = _tileDefMan["Plating"].TileId;
/*
Basically, we want to have a 5-wide grid of tiles.
Edges are walled, and the length of the grid is determined by N + 2.
Windows should only touch the top and bottom walls, and each other.
*/
var length = EntityCount + 2; // ensures we can spawn exactly N windows between side walls
const int height = 5;
await server.WaitPost(() =>
{
// Fill required tiles (extend grid) with plating
for (var x = 0; x < length; x++)
{
for (var y = 0; y < height; y++)
{
_map.SetTile(mapdata.Grid, mapdata.Grid, new Vector2i(x, y), new Tile(plating));
}
}
// Spawn perimeter walls and windows row in the middle (y = 2)
const int midY = height / 2;
for (var x = 0; x < length; x++)
{
for (var y = 0; y < height; y++)
{
var coords = new EntityCoordinates(mapdata.Grid, x + 0.5f, y + 0.5f);
var isPerimeter = x == 0 || x == length - 1 || y == 0 || y == height - 1;
if (isPerimeter)
{
_entMan.SpawnEntity(_wallProtoId, coords);
continue;
}
// Spawn windows only on the middle row, spanning interior (excluding side walls)
if (y == midY)
{
_entMan.SpawnEntity(_windowProtoId, coords);
}
}
}
});
// Next we run the fixgridatmos command to ensure that we have some air on our grid.
// Wait a little bit as well.
// TODO: Unhardcode command magic string when fixgridatmos is an actual command we can ref and not just
// a stamp-on in AtmosphereSystem.
await _pair.WaitCommand("fixgridatmos " + mapdata.Grid.Owner, 1);
var uid = mapdata.Grid.Owner;
_testEnt = new Entity<GridAtmosphereComponent, GasTileOverlayComponent, MapGridComponent, TransformComponent>(
uid,
_entMan.GetComponent<GridAtmosphereComponent>(uid),
_entMan.GetComponent<GasTileOverlayComponent>(uid),
_entMan.GetComponent<MapGridComponent>(uid),
_entMan.GetComponent<TransformComponent>(uid));
}
[Benchmark]
public async Task PerformFullProcess()
{
await _pair.Server.WaitPost(() =>
{
while (!_atmospereSystem.RunProcessingStage(_testEnt, AtmosphereProcessingState.DeltaPressure)) { }
});
}
[Benchmark]
public async Task PerformSingleRunProcess()
{
await _pair.Server.WaitPost(() =>
{
_atmospereSystem.RunProcessingStage(_testEnt, AtmosphereProcessingState.DeltaPressure);
});
}
[GlobalCleanup]
public async Task CleanupAsync()
{
await _pair.DisposeAsync();
PoolManager.Shutdown();
}
}

View File

@@ -47,7 +47,7 @@ public class MapLoadBenchmark
PoolManager.Shutdown(); PoolManager.Shutdown();
} }
public static string[] MapsSource { get; } = { "Empty", "Saltern", "Box", "Bagel", "Dev", "CentComm", "Core", "TestTeg", "Packed", "Omega", "Reach", "Meta", "Marathon", "MeteorArena", "Fland", "Oasis", "Convex"}; public static readonly string[] MapsSource = { "Empty", "Saltern", "Box", "Bagel", "Dev", "CentComm", "Core", "TestTeg", "Packed", "Omega", "Reach", "Meta", "Marathon", "MeteorArena", "Fland", "Oasis", "Convex"};
[ParamsSource(nameof(MapsSource))] [ParamsSource(nameof(MapsSource))]
public string Map; public string Map;

View File

@@ -6,6 +6,7 @@ using BenchmarkDotNet.Attributes;
using Content.IntegrationTests; using Content.IntegrationTests;
using Content.IntegrationTests.Pair; using Content.IntegrationTests.Pair;
using Content.Server.Mind; using Content.Server.Mind;
using Content.Server.Warps;
using Content.Shared.Warps; using Content.Shared.Warps;
using Robust.Shared; using Robust.Shared;
using Robust.Shared.Analyzers; using Robust.Shared.Analyzers;

View File

@@ -29,7 +29,7 @@ namespace Content.Client.Access.UI
foreach (var access in accessLevels) foreach (var access in accessLevels)
{ {
if (!protoManager.Resolve(access, out var accessLevel)) if (!protoManager.TryIndex(access, out var accessLevel))
{ {
continue; continue;
} }

View File

@@ -57,7 +57,7 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
foreach (var accessGroup in _accessGroups) foreach (var accessGroup in _accessGroups)
{ {
if (!_protoManager.Resolve(accessGroup, out var accessGroupProto)) if (!_protoManager.TryIndex(accessGroup, out var accessGroupProto))
continue; continue;
_groupedAccessLevels.Add(accessGroupProto, new()); _groupedAccessLevels.Add(accessGroupProto, new());
@@ -65,13 +65,13 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
// Ensure that the 'general' access group is added to handle // Ensure that the 'general' access group is added to handle
// misc. access levels that aren't associated with any group // misc. access levels that aren't associated with any group
if (_protoManager.Resolve(GeneralAccessGroup, out var generalAccessProto)) if (_protoManager.TryIndex(GeneralAccessGroup, out var generalAccessProto))
_groupedAccessLevels.TryAdd(generalAccessProto, new()); _groupedAccessLevels.TryAdd(generalAccessProto, new());
// Assign known access levels with their associated groups // Assign known access levels with their associated groups
foreach (var accessLevel in _accessLevels) foreach (var accessLevel in _accessLevels)
{ {
if (!_protoManager.Resolve(accessLevel, out var accessLevelProto)) if (!_protoManager.TryIndex(accessLevel, out var accessLevelProto))
continue; continue;
var assigned = false; var assigned = false;

View File

@@ -4,7 +4,6 @@ using Content.Shared.Access.Systems;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Containers.ItemSlots; using Content.Shared.Containers.ItemSlots;
using Content.Shared.CrewManifest; using Content.Shared.CrewManifest;
using Content.Shared.Roles;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using static Content.Shared.Access.Components.IdCardConsoleComponent; using static Content.Shared.Access.Components.IdCardConsoleComponent;
@@ -75,7 +74,7 @@ namespace Content.Client.Access.UI
_window?.UpdateState(castState); _window?.UpdateState(castState);
} }
public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, ProtoId<JobPrototype> newJobPrototype) public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, string newJobPrototype)
{ {
if (newFullName.Length > _maxNameLength) if (newFullName.Length > _maxNameLength)
newFullName = newFullName[.._maxNameLength]; newFullName = newFullName[.._maxNameLength];

View File

@@ -123,7 +123,7 @@ namespace Content.Client.Access.UI
foreach (var group in job.AccessGroups) foreach (var group in job.AccessGroups)
{ {
if (!_prototypeManager.Resolve(group, out AccessGroupPrototype? groupPrototype)) if (!_prototypeManager.TryIndex(group, out AccessGroupPrototype? groupPrototype))
{ {
continue; continue;
} }

View File

@@ -0,0 +1,10 @@
using Content.Shared.Administration.Components;
using Robust.Shared.GameStates;
namespace Content.Client.Administration.Components;
[RegisterComponent]
public sealed partial class HeadstandComponent : SharedHeadstandComponent
{
}

View File

@@ -15,7 +15,6 @@ namespace Content.Client.Administration.Managers
[Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IClientNetManager _netMgr = default!; [Dependency] private readonly IClientNetManager _netMgr = default!;
[Dependency] private readonly IClientConGroupController _conGroup = default!; [Dependency] private readonly IClientConGroupController _conGroup = default!;
[Dependency] private readonly IClientConsoleHost _host = default!;
[Dependency] private readonly IResourceManager _res = default!; [Dependency] private readonly IResourceManager _res = default!;
[Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterface = default!; [Dependency] private readonly IUserInterfaceManager _userInterface = default!;
@@ -87,12 +86,12 @@ namespace Content.Client.Administration.Managers
private void UpdateMessageRx(MsgUpdateAdminStatus message) private void UpdateMessageRx(MsgUpdateAdminStatus message)
{ {
_availableCommands.Clear(); _availableCommands.Clear();
var host = IoCManager.Resolve<IClientConsoleHost>();
// Anything marked as Any we'll just add even if the server doesn't know about it. // Anything marked as Any we'll just add even if the server doesn't know about it.
foreach (var (command, instance) in _host.AvailableCommands) foreach (var (command, instance) in host.AvailableCommands)
{ {
if (Attribute.GetCustomAttribute(instance.GetType(), typeof(AnyCommandAttribute)) == null) if (Attribute.GetCustomAttribute(instance.GetType(), typeof(AnyCommandAttribute)) == null) continue;
continue;
_availableCommands.Add(command); _availableCommands.Add(command);
} }

View File

@@ -0,0 +1,7 @@
using Content.Shared.Administration;
namespace Content.Client.Administration.Systems;
public sealed class AdminFrozenSystem : SharedAdminFrozenSystem
{
}

View File

@@ -1,4 +1,4 @@
using Content.Shared.Administration.Components; using Content.Client.Administration.Components;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
namespace Content.Client.Administration.Systems; namespace Content.Client.Administration.Systems;

View File

@@ -12,7 +12,7 @@ public sealed partial class AdminMenuWindow : DefaultWindow
public AdminMenuWindow() public AdminMenuWindow()
{ {
MinSize = new Vector2(650, 250); MinSize = new Vector2(650, 280);
Title = Loc.GetString("admin-menu-title"); Title = Loc.GetString("admin-menu-title");
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
MasterTabContainer.SetTabTitle((int) TabIndex.Admin, Loc.GetString("admin-menu-admin-tab")); MasterTabContainer.SetTabTitle((int) TabIndex.Admin, Loc.GetString("admin-menu-admin-tab"));

View File

@@ -316,9 +316,8 @@ public sealed partial class BanPanel : DefaultWindow
}; };
// This is adding the icon before the role name // This is adding the icon before the role name
// TODO: This should not be using raw strings for prototypes as it means it won't be validated at all. // Yeah, this is sus, but having to split the functions up and stuff is worse imo.
// I know the ban manager is doing the same thing, but that should not leak into UI code. if (_protoMan.TryIndex<JobPrototype>(role, out var jobPrototype) && _protoMan.TryIndex(jobPrototype.Icon, out var iconProto))
if (_protoMan.TryIndex<JobPrototype>(role, out var jobPrototype) && _protoMan.Resolve(jobPrototype.Icon, out var iconProto))
{ {
var jobIconTexture = new TextureRect var jobIconTexture = new TextureRect
{ {

View File

@@ -57,43 +57,12 @@ public sealed partial class ObjectsTab : Control
private void TeleportTo(NetEntity nent) private void TeleportTo(NetEntity nent)
{ {
var selection = _selections[ObjectTypeOptions.SelectedId]; _console.ExecuteCommand($"tpto {nent}");
switch (selection)
{
case ObjectsTabSelection.Grids:
{
// directly teleport to the entity
_console.ExecuteCommand($"tpto {nent}");
}
break;
case ObjectsTabSelection.Maps:
{
// teleport to the map, not to the map entity (which is in nullspace)
if (!_entityManager.TryGetEntity(nent, out var map) || !_entityManager.TryGetComponent<MapComponent>(map, out var mapComp))
break;
_console.ExecuteCommand($"tp 0 0 {mapComp.MapId}");
break;
}
case ObjectsTabSelection.Stations:
{
// teleport to the station's largest grid, not to the station entity (which is in nullspace)
if (!_entityManager.TryGetEntity(nent, out var station))
break;
var largestGrid = _entityManager.EntitySysManager.GetEntitySystem<StationSystem>().GetLargestGrid(station.Value);
if (largestGrid == null)
break;
_console.ExecuteCommand($"tpto {largestGrid.Value}");
break;
}
default:
throw new NotImplementedException();
}
} }
private void Delete(NetEntity nent) private void Delete(NetEntity nent)
{ {
_console.ExecuteCommand($"delete {nent}"); _console.ExecuteCommand($"delete {nent}");
RefreshObjectList();
} }
public void RefreshObjectList() public void RefreshObjectList()
@@ -107,24 +76,28 @@ public sealed partial class ObjectsTab : Control
switch (selection) switch (selection)
{ {
case ObjectsTabSelection.Stations: case ObjectsTabSelection.Stations:
entities.AddRange(_entityManager.EntitySysManager.GetEntitySystem<StationSystem>().GetStationNames()); entities.AddRange(_entityManager.EntitySysManager.GetEntitySystem<StationSystem>().Stations);
break; break;
case ObjectsTabSelection.Grids: case ObjectsTabSelection.Grids:
{
var query = _entityManager.AllEntityQueryEnumerator<MapGridComponent, MetaDataComponent>();
while (query.MoveNext(out var uid, out _, out var metadata))
{ {
var query = _entityManager.AllEntityQueryEnumerator<MapGridComponent, MetaDataComponent>(); entities.Add((metadata.EntityName, _entityManager.GetNetEntity(uid)));
while (query.MoveNext(out var uid, out _, out var metadata))
entities.Add((metadata.EntityName, _entityManager.GetNetEntity(uid)));
break;
} }
break;
}
case ObjectsTabSelection.Maps: case ObjectsTabSelection.Maps:
{
var query = _entityManager.AllEntityQueryEnumerator<MapComponent, MetaDataComponent>();
while (query.MoveNext(out var uid, out _, out var metadata))
{ {
var query = _entityManager.AllEntityQueryEnumerator<MapComponent, MetaDataComponent>(); entities.Add((metadata.EntityName, _entityManager.GetNetEntity(uid)));
while (query.MoveNext(out var uid, out _, out var metadata))
entities.Add((metadata.EntityName, _entityManager.GetNetEntity(uid)));
break;
} }
break;
}
default: default:
throw new ArgumentOutOfRangeException(nameof(selection), selection, null); throw new ArgumentOutOfRangeException(nameof(selection), selection, null);
} }

View File

@@ -1,6 +1,5 @@
<PanelContainer xmlns="https://spacestation14.io" <PanelContainer xmlns="https://spacestation14.io"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls" xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Name="BackgroundColorPanel"> Name="BackgroundColorPanel">
<BoxContainer Orientation="Horizontal" <BoxContainer Orientation="Horizontal"
HorizontalExpand="True" HorizontalExpand="True"
@@ -21,7 +20,7 @@
HorizontalExpand="True" HorizontalExpand="True"
ClipText="True"/> ClipText="True"/>
<customControls:VSeparator/> <customControls:VSeparator/>
<controls:ConfirmButton Name="DeleteButton" <Button Name="DeleteButton"
Text="{Loc object-tab-entity-delete}" Text="{Loc object-tab-entity-delete}"
SizeFlagsStretchRatio="3" SizeFlagsStretchRatio="3"
HorizontalExpand="True" HorizontalExpand="True"

View File

@@ -27,7 +27,12 @@
<cc:CommandButton Name="ShowReasonButton" Command="panicbunker_show_reason" <cc:CommandButton Name="ShowReasonButton" Command="panicbunker_show_reason"
ToggleMode="True" Text="{Loc admin-ui-panic-bunker-show-reason}" ToggleMode="True" Text="{Loc admin-ui-panic-bunker-show-reason}"
ToolTip="{Loc admin-ui-panic-bunker-show-reason-tooltip}" /> ToolTip="{Loc admin-ui-panic-bunker-show-reason-tooltip}" />
<BoxContainer Orientation="Vertical" Margin="0 10 0 0"> <BoxContainer Orientation="Horizontal">
<Label Text="{Loc cp14-admin-ui-suspicious-warning-level-setting}" MinWidth="175" />
<OptionButton Name="SuspiciousWarningLevel" HorizontalAlignment="Left" Margin="4 0"
ToolTip="{Loc cp14-admin-ui-suspicious-warning-level-setting-desc}" />
</BoxContainer>
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal" Margin="2"> <BoxContainer Orientation="Horizontal" Margin="2">
<Label Text="{Loc admin-ui-panic-bunker-min-account-age}" MinWidth="175" /> <Label Text="{Loc admin-ui-panic-bunker-min-account-age}" MinWidth="175" />
<LineEdit Name="MinAccountAge" MinWidth="50" Margin="0 0 5 0" /> <LineEdit Name="MinAccountAge" MinWidth="50" Margin="0 0 5 0" />

View File

@@ -1,7 +1,9 @@
using Content.Shared.Administration.Events; using Content.Shared.Administration.Events;
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Console; using Robust.Shared.Console;
namespace Content.Client.Administration.UI.Tabs.PanicBunkerTab; namespace Content.Client.Administration.UI.Tabs.PanicBunkerTab;
@@ -10,9 +12,13 @@ namespace Content.Client.Administration.UI.Tabs.PanicBunkerTab;
public sealed partial class PanicBunkerTab : Control public sealed partial class PanicBunkerTab : Control
{ {
[Dependency] private readonly IConsoleHost _console = default!; [Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private string _minAccountAge; private string _minAccountAge;
private string _minOverallMinutes; private string _minOverallMinutes;
// CrystallEdge suspicious activity warning system
private List<SuspiciousWarningLevelSelection> _suspiciousWarningLevelSelections = [];
private string _currentSuspiciousWarningLevel = string.Empty;
public PanicBunkerTab() public PanicBunkerTab()
{ {
@@ -28,6 +34,21 @@ public sealed partial class PanicBunkerTab : Control
MinOverallMinutes.OnTextEntered += args => SendMinOverallMinutes(args.Text); MinOverallMinutes.OnTextEntered += args => SendMinOverallMinutes(args.Text);
MinOverallMinutes.OnFocusExit += args => SendMinOverallMinutes(args.Text); MinOverallMinutes.OnFocusExit += args => SendMinOverallMinutes(args.Text);
_minOverallMinutes = MinOverallMinutes.Text; _minOverallMinutes = MinOverallMinutes.Text;
// CrystallEdge suspicious activity warning system
foreach (var type in Enum.GetValues<SuspiciousWarningLevelSelection>())
{
_suspiciousWarningLevelSelections.Add(type);
SuspiciousWarningLevel.AddItem(GetLocalizedEnumValue(type));
}
UpdateSuspiciousWarningLevel();
SuspiciousWarningLevel.OnItemSelected += ev =>
{
SuspiciousWarningLevel.SelectId(ev.Id);
SendSuspiciousWarningLevel(_suspiciousWarningLevelSelections[ev.Id]);
};
} }
private void SendMinAccountAge(string text) private void SendMinAccountAge(string text)
@@ -74,4 +95,43 @@ public sealed partial class PanicBunkerTab : Control
MinOverallMinutes.Text = status.MinOverallMinutes.ToString(); MinOverallMinutes.Text = status.MinOverallMinutes.ToString();
_minOverallMinutes = MinOverallMinutes.Text; _minOverallMinutes = MinOverallMinutes.Text;
} }
// CrystallEdge suspicious activity warning system
private enum SuspiciousWarningLevelSelection
{
Disabled,
Low,
Medium,
High,
}
private string GetLocalizedEnumValue(SuspiciousWarningLevelSelection selection)
{
return selection switch
{
SuspiciousWarningLevelSelection.Disabled => Loc.GetString("cp14-admin-ui-suspicious-warning-level-disabled"),
SuspiciousWarningLevelSelection.Low => Loc.GetString("cp14-admin-ui-suspicious-warning-level-low"),
SuspiciousWarningLevelSelection.Medium => Loc.GetString("cp14-admin-ui-suspicious-warning-level-medium"),
SuspiciousWarningLevelSelection.High => Loc.GetString("cp14-admin-ui-suspicious-warning-level-high"),
_ => throw new ArgumentOutOfRangeException(nameof(selection), selection, null),
};
}
private void UpdateSuspiciousWarningLevel()
{
_currentSuspiciousWarningLevel = _cfg.GetCVar(CCVars.SuspiciousAccountsWarningLevel);
if (!Enum.TryParse(_currentSuspiciousWarningLevel, true, out SuspiciousWarningLevelSelection currentSuspiciousWarningSelection))
{
throw new ArgumentOutOfRangeException(nameof(_currentSuspiciousWarningLevel),
_currentSuspiciousWarningLevel,
null);
}
SuspiciousWarningLevel.SelectId((int)currentSuspiciousWarningSelection);
}
private void SendSuspiciousWarningLevel(SuspiciousWarningLevelSelection selection)
{
_console.ExecuteCommand($"cp14.suspicious-warning-level {Enum.GetName(selection)}");
}
} }

View File

@@ -1,5 +0,0 @@
using Content.Shared.Animals.Systems;
namespace Content.Client.Animals.Systems;
public sealed class ParrotMemorySystem : SharedParrotMemorySystem;

View File

@@ -1,40 +0,0 @@
using Robust.Client.Graphics;
using SixLabors.ImageSharp.PixelFormats;
namespace Content.Client.Anomaly;
/// <summary>
/// This component creates and handles the drawing of a ScreenTexture to be used on the Anomaly Scanner
/// for an indicator of Anomaly Severity.
/// </summary>
/// <remarks>
/// In the future I would like to make this a more generic "DynamicTextureComponent" that can contain a dictionary
/// of texture components like "Bar(offset, size, minimumValue, maximumValue, AppearanceKey, LayerMapKey)" that can
/// just draw a bar or other basic drawn element that will show up on a texture layer.
/// </remarks>
[RegisterComponent]
[Access(typeof(AnomalyScannerSystem))]
public sealed partial class AnomalyScannerScreenComponent : Component
{
/// <summary>
/// This is the texture drawn as a layer on the Anomaly Scanner device.
/// </summary>
public OwnedTexture? ScreenTexture;
/// <summary>
/// A small buffer that we can reuse to draw the severity bar.
/// </summary>
public Rgba32[]? BarBuf;
/// <summary>
/// The position of the top-left of the severity bar in pixels.
/// </summary>
[DataField(readOnly: true)]
public Vector2i Offset = new Vector2i(12, 17);
/// <summary>
/// The width and height of the severity bar in pixels.
/// </summary>
[DataField(readOnly: true)]
public Vector2i Size = new Vector2i(10, 3);
}

View File

@@ -1,110 +0,0 @@
using System.Numerics;
using Content.Shared.Anomaly;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Utility;
using SixLabors.ImageSharp.PixelFormats;
namespace Content.Client.Anomaly;
/// <inheritdoc cref="SharedAnomalyScannerSystem"/>
public sealed class AnomalyScannerSystem : SharedAnomalyScannerSystem
{
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
private const float MaxHueDegrees = 360f;
private const float GreenHueDegrees = 110f;
private const float RedHueDegrees = 0f;
private const float GreenHue = GreenHueDegrees / MaxHueDegrees;
private const float RedHue = RedHueDegrees / MaxHueDegrees;
// Just an array to initialize the pixels of a new OwnedTexture
private static readonly Rgba32[] EmptyTexture = new Rgba32[32*32];
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<AnomalyScannerScreenComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<AnomalyScannerScreenComponent, ComponentStartup>(OnComponentStartup);
SubscribeLocalEvent<AnomalyScannerScreenComponent, AppearanceChangeEvent>(OnScannerAppearanceChanged);
}
private void OnComponentInit(Entity<AnomalyScannerScreenComponent> ent, ref ComponentInit args)
{
if(!_sprite.TryGetLayer(ent.Owner, AnomalyScannerVisualLayers.Base, out var layer, true))
return;
// Allocate the OwnedTexture
ent.Comp.ScreenTexture = _clyde.CreateBlankTexture<Rgba32>(layer.PixelSize);
if (layer.PixelSize.X < ent.Comp.Offset.X + ent.Comp.Size.X ||
layer.PixelSize.Y < ent.Comp.Offset.Y + ent.Comp.Size.Y)
{
// If the bar doesn't fit, just bail here, ScreenTexture and BarBuf will remain null, and appearance updates
// will do nothing.
DebugTools.Assert(false, "AnomalyScannerScreenComponent: Bar does not fit within sprite");
return;
}
// Initialize the texture
ent.Comp.ScreenTexture.SetSubImage((0, 0), layer.PixelSize, new ReadOnlySpan<Rgba32>(EmptyTexture));
// Initialize bar drawing buffer
ent.Comp.BarBuf = new Rgba32[ent.Comp.Size.X * ent.Comp.Size.Y];
}
private void OnComponentStartup(Entity<AnomalyScannerScreenComponent> ent, ref ComponentStartup args)
{
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
_sprite.LayerSetTexture((ent, sprite), AnomalyScannerVisualLayers.Screen, ent.Comp.ScreenTexture);
}
private void OnScannerAppearanceChanged(Entity<AnomalyScannerScreenComponent> ent, ref AppearanceChangeEvent args)
{
if (args.Sprite is null || ent.Comp.ScreenTexture is null || ent.Comp.BarBuf is null)
return;
args.AppearanceData.TryGetValue(AnomalyScannerVisuals.AnomalySeverity, out var severityObj);
if (severityObj is not float severity)
severity = 0;
// Get the bar length
var barLength = (int)(severity * ent.Comp.Size.X);
// Calculate the bar color
// Hue "angle" of two colors to interpolate between depending on severity
// Just a lerp from Green hue at severity = 0.5 to Red hue at 1.0
var hue = Math.Clamp(2*GreenHue * (1 - severity), RedHue, GreenHue);
var color = new Rgba32(Color.FromHsv(new Vector4(hue, 1f, 1f, 1f)).RGBA);
var transparent = new Rgba32(0, 0, 0, 255);
for(var y = 0; y < ent.Comp.Size.Y; y++)
{
for (var x = 0; x < ent.Comp.Size.X; x++)
{
ent.Comp.BarBuf[y*ent.Comp.Size.X + x] = x < barLength ? color : transparent;
}
}
// Copy the buffer to the texture
try
{
ent.Comp.ScreenTexture.SetSubImage(
ent.Comp.Offset,
ent.Comp.Size,
new ReadOnlySpan<Rgba32>(ent.Comp.BarBuf)
);
}
catch (IndexOutOfRangeException)
{
Log.Warning($"Bar dimensions out of bounds with the texture on entity {ent.Owner}");
}
}
}

View File

@@ -7,7 +7,7 @@ using Robust.Shared.Timing;
namespace Content.Client.Anomaly; namespace Content.Client.Anomaly;
public sealed partial class AnomalySystem : SharedAnomalySystem public sealed class AnomalySystem : SharedAnomalySystem
{ {
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly FloatingVisualizerSystem _floating = default!; [Dependency] private readonly FloatingVisualizerSystem _floating = default!;
@@ -24,7 +24,6 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
SubscribeLocalEvent<AnomalySupercriticalComponent, ComponentShutdown>(OnShutdown); SubscribeLocalEvent<AnomalySupercriticalComponent, ComponentShutdown>(OnShutdown);
} }
private void OnStartup(EntityUid uid, AnomalyComponent component, ComponentStartup args) private void OnStartup(EntityUid uid, AnomalyComponent component, ComponentStartup args)
{ {
_floating.FloatAnimation(uid, component.FloatingOffset, component.AnimationKey, component.AnimationTime); _floating.FloatAnimation(uid, component.FloatingOffset, component.AnimationKey, component.AnimationTime);

View File

@@ -1,6 +1,6 @@
using Content.Shared.Anomaly.Components; using Content.Shared.Anomaly.Components;
using Content.Shared.Anomaly.Effects; using Content.Shared.Anomaly.Effects;
using Content.Shared.Humanoid; using Content.Shared.Body.Components;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
namespace Content.Client.Anomaly.Effects; namespace Content.Client.Anomaly.Effects;
@@ -25,8 +25,9 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap); var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap);
if (TryComp<HumanoidAppearanceComponent>(ent, out var humanoidAppearance) && if (TryComp<BodyComponent>(ent, out var body) &&
ent.Comp.SpeciesSprites.TryGetValue(humanoidAppearance.Species, out var speciesSprite)) body.Prototype is not null &&
ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite))
{ {
_sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite); _sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite);
} }

View File

@@ -134,7 +134,7 @@ public sealed class AlignAtmosPipeLayers : SnapgridCenter
var newProtoId = altPrototypes[(int)layer]; var newProtoId = altPrototypes[(int)layer];
if (!_protoManager.Resolve(newProtoId, out var newProto)) if (!_protoManager.TryIndex(newProtoId, out var newProto))
return; return;
if (newProto.Type != ConstructionType.Structure) if (newProto.Type != ConstructionType.Structure)

View File

@@ -1,11 +1,46 @@
using Content.Client.Atmos.Components; using Content.Client.Atmos.Components;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Content.Client.UserInterface.Systems.Storage.Controls;
using Content.Shared.Atmos.Piping; using Content.Shared.Atmos.Piping;
using Content.Shared.Hands;
using Content.Shared.Atmos.Components;
using Content.Shared.Item;
namespace Content.Client.Atmos.EntitySystems; namespace Content.Client.Atmos.EntitySystems;
public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisualsComponent> public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisualsComponent>
{ {
[Dependency] private readonly SharedItemSystem _itemSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PipeColorVisualsComponent, GetInhandVisualsEvent>(OnGetVisuals);
SubscribeLocalEvent<PipeColorVisualsComponent, BeforeRenderInGridEvent>(OnDrawInGrid);
}
/// <summary>
/// This method is used to display the color changes of the pipe on the screen..
/// </summary>
private void OnGetVisuals(Entity<PipeColorVisualsComponent> item, ref GetInhandVisualsEvent args)
{
foreach (var (_, layerData) in args.Layers)
{
if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor))
layerData.Color = pipeColor.Color;
}
}
/// <summary>
/// This method is used to change the pipe's color in a container grid.
/// </summary>
private void OnDrawInGrid(Entity<PipeColorVisualsComponent> item, ref BeforeRenderInGridEvent args)
{
if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor))
args.Color = pipeColor.Color;
}
protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args) protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args)
{ {
if (TryComp<SpriteComponent>(uid, out var sprite) if (TryComp<SpriteComponent>(uid, out var sprite)
@@ -15,6 +50,8 @@ public sealed class PipeColorVisualizerSystem : VisualizerSystem<PipeColorVisual
var layer = sprite[PipeVisualLayers.Pipe]; var layer = sprite[PipeVisualLayers.Pipe];
layer.Color = color.WithAlpha(layer.Color.A); layer.Color = color.WithAlpha(layer.Color.A);
} }
_itemSystem.VisualsChanged(uid);
} }
} }

View File

@@ -59,7 +59,7 @@ public sealed partial class PumpControl : BoxContainer
foreach (var value in Enum.GetValues<VentPumpDirection>()) foreach (var value in Enum.GetValues<VentPumpDirection>())
{ {
_pumpDirection.AddItem(Loc.GetString($"air-alarm-ui-pump-direction-{value.ToString().ToLower()}"), (int) value); _pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
} }
_pumpDirection.SelectId((int) _data.PumpDirection); _pumpDirection.SelectId((int) _data.PumpDirection);
@@ -72,7 +72,7 @@ public sealed partial class PumpControl : BoxContainer
foreach (var value in Enum.GetValues<VentPressureBound>()) foreach (var value in Enum.GetValues<VentPressureBound>())
{ {
_pressureCheck.AddItem(Loc.GetString($"air-alarm-ui-pressure-bound-{value.ToString().ToLower()}"), (int) value); _pressureCheck.AddItem(Loc.GetString($"{value}"), (int) value);
} }
_pressureCheck.SelectId((int) _data.PressureChecks); _pressureCheck.SelectId((int) _data.PressureChecks);

View File

@@ -27,15 +27,9 @@
</BoxContainer> </BoxContainer>
<!-- Lower row: every single gas --> <!-- Lower row: every single gas -->
<Collapsible Margin="2 2 2 2"> <Collapsible Margin="2 2 2 2">
<CollapsibleHeading Title="{Loc 'air-alarm-ui-widget-gas-filters'}" /> <CollapsibleHeading Title="Gas filters" />
<CollapsibleBody Margin="20 0 0 0"> <CollapsibleBody Margin="20 0 0 0">
<BoxContainer Orientation="Vertical"> <GridContainer HorizontalExpand="True" Name="CGasContainer" Columns="3" />
<BoxContainer Margin="2">
<Button Name="CSelectAll" Text="{Loc 'air-alarm-ui-scrubber-select-all-gases-label'}" />
<Button Name="CDeselectAll" Text="{Loc 'air-alarm-ui-scrubber-deselect-all-gases-label'}" />
</BoxContainer>
<GridContainer Name="CGasContainer" Columns="3" />
</BoxContainer>
</CollapsibleBody> </CollapsibleBody>
</Collapsible> </Collapsible>
</BoxContainer> </BoxContainer>

View File

@@ -1,21 +1,15 @@
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Atmos.Monitor.Components; using Content.Shared.Atmos.Monitor.Components;
using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Atmos.Piping.Unary.Components;
using Content.Shared.Atmos.Prototypes;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Atmos.Monitor.UI.Widgets; namespace Content.Client.Atmos.Monitor.UI.Widgets;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class ScrubberControl : BoxContainer public sealed partial class ScrubberControl : BoxContainer
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
private GasVentScrubberData _data; private GasVentScrubberData _data;
private string _address; private string _address;
@@ -28,18 +22,12 @@ public sealed partial class ScrubberControl : BoxContainer
private FloatSpinBox _volumeRate => CVolumeRate; private FloatSpinBox _volumeRate => CVolumeRate;
private CheckBox _wideNet => CWideNet; private CheckBox _wideNet => CWideNet;
private Button _copySettings => CCopySettings; private Button _copySettings => CCopySettings;
private Button _selectAll => CSelectAll;
private Button _deselectAll => CDeselectAll;
private GridContainer _gases => CGasContainer; private GridContainer _gases => CGasContainer;
private Dictionary<Gas, Button> _gasControls = new(); private Dictionary<Gas, Button> _gasControls = new();
public ScrubberControl(GasVentScrubberData data, string address) public ScrubberControl(GasVentScrubberData data, string address)
{ {
IoCManager.InjectDependencies(this);
var atmosphereSystem = _entMan.System<SharedAtmosphereSystem>();
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
Name = address; Name = address;
@@ -73,7 +61,7 @@ public sealed partial class ScrubberControl : BoxContainer
foreach (var value in Enum.GetValues<ScrubberPumpDirection>()) foreach (var value in Enum.GetValues<ScrubberPumpDirection>())
{ {
_pumpDirection.AddItem(Loc.GetString($"air-alarm-ui-pump-direction-{value.ToString().ToLower()}"), (int) value); _pumpDirection.AddItem(Loc.GetString($"{value}"), (int) value);
} }
_pumpDirection.SelectId((int) _data.PumpDirection); _pumpDirection.SelectId((int) _data.PumpDirection);
@@ -90,28 +78,12 @@ public sealed partial class ScrubberControl : BoxContainer
ScrubberDataCopied?.Invoke(_data); ScrubberDataCopied?.Invoke(_data);
}; };
var allGases = Enum.GetValues<Gas>(); foreach (var value in Enum.GetValues<Gas>())
_selectAll.OnPressed += _ =>
{ {
_data.FilterGases = new HashSet<Gas>(allGases);
ScrubberDataChanged?.Invoke(_address, _data);
};
_deselectAll.OnPressed += _ =>
{
_data.FilterGases = [];
ScrubberDataChanged?.Invoke(_address, _data);
};
foreach (var value in allGases)
{
ProtoId<GasPrototype> gasProtoId = atmosphereSystem.GetGas(value);
var gasName = _prototypeManager.Index(gasProtoId).Name;
var gasButton = new Button var gasButton = new Button
{ {
Name = value.ToString(), Name = value.ToString(),
Text = Loc.GetString(gasName), Text = Loc.GetString($"{value}"),
ToggleMode = true, ToggleMode = true,
HorizontalExpand = true, HorizontalExpand = true,
Pressed = _data.FilterGases.Contains(value) Pressed = _data.FilterGases.Contains(value)

View File

@@ -1,22 +1,16 @@
using Content.Client.Message; using Content.Client.Message;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Content.Shared.Atmos.EntitySystems;
using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor;
using Content.Shared.Atmos.Prototypes;
using Content.Shared.Temperature; using Content.Shared.Temperature;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Atmos.Monitor.UI.Widgets; namespace Content.Client.Atmos.Monitor.UI.Widgets;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class SensorInfo : BoxContainer public sealed partial class SensorInfo : BoxContainer
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
public Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? OnThresholdUpdate; public Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? OnThresholdUpdate;
public event Action<AtmosSensorData>? SensorDataCopied; public event Action<AtmosSensorData>? SensorDataCopied;
private string _address; private string _address;
@@ -29,9 +23,6 @@ public sealed partial class SensorInfo : BoxContainer
public SensorInfo(AtmosSensorData data, string address) public SensorInfo(AtmosSensorData data, string address)
{ {
IoCManager.InjectDependencies(this);
var atmosphereSystem = _entMan.System<SharedAtmosphereSystem>();
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
_address = address; _address = address;
@@ -54,12 +45,8 @@ public sealed partial class SensorInfo : BoxContainer
var label = new RichTextLabel(); var label = new RichTextLabel();
var fractionGas = amount / data.TotalMoles; var fractionGas = amount / data.TotalMoles;
ProtoId<GasPrototype> gasProtoId = atmosphereSystem.GetGas(gas);
var gasName = _prototypeManager.Index(gasProtoId).Name;
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
("gas", Loc.GetString(gasName)), ("gas", $"{gas}"),
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])), ("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
("amount", $"{amount:0.####}"), ("amount", $"{amount:0.####}"),
("percentage", $"{(100 * fractionGas):0.##}"))); ("percentage", $"{(100 * fractionGas):0.##}")));
@@ -67,7 +54,7 @@ public sealed partial class SensorInfo : BoxContainer
_gasLabels.Add(gas, label); _gasLabels.Add(gas, label);
var threshold = data.GasThresholds[gas]; var threshold = data.GasThresholds[gas];
var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title"), threshold, AtmosMonitorThresholdType.Gas, gas, 100); var gasThresholdControl = new ThresholdControl(Loc.GetString($"air-alarm-ui-thresholds-gas-title", ("gas", $"{gas}")), threshold, AtmosMonitorThresholdType.Gas, gas, 100);
gasThresholdControl.Margin = new Thickness(20, 2, 2, 2); gasThresholdControl.Margin = new Thickness(20, 2, 2, 2);
gasThresholdControl.ThresholdDataChanged += (type, alarmThreshold, arg3) => gasThresholdControl.ThresholdDataChanged += (type, alarmThreshold, arg3) =>
{ {
@@ -103,9 +90,6 @@ public sealed partial class SensorInfo : BoxContainer
public void ChangeData(AtmosSensorData data) public void ChangeData(AtmosSensorData data)
{ {
IoCManager.InjectDependencies(this);
var atmosphereSystem = _entMan.System<SharedAtmosphereSystem>();
SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState)); SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState));
AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator", AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator",
@@ -128,12 +112,8 @@ public sealed partial class SensorInfo : BoxContainer
} }
var fractionGas = amount / data.TotalMoles; var fractionGas = amount / data.TotalMoles;
ProtoId<GasPrototype> gasProtoId = atmosphereSystem.GetGas(gas);
var gasName = _prototypeManager.Index(gasProtoId).Name;
label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator", label.SetMarkup(Loc.GetString("air-alarm-ui-gases-indicator",
("gas", Loc.GetString(gasName)), ("gas", $"{gas}"),
("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])), ("color", AirAlarmWindow.ColorForThreshold(fractionGas, data.GasThresholds[gas])),
("amount", $"{amount:0.####}"), ("amount", $"{amount:0.####}"),
("percentage", $"{(100 * fractionGas):0.##}"))); ("percentage", $"{(100 * fractionGas):0.##}")));

View File

@@ -2,6 +2,6 @@
HorizontalExpand="True" Orientation="Vertical" HorizontalExpand="True" Orientation="Vertical"
Margin = "20 0 0 0" MinSize="160 0" > Margin = "20 0 0 0" MinSize="160 0" >
<Label Name="CBoundLabel" HorizontalAlignment="Center" /> <Label Name="CBoundLabel" HorizontalAlignment="Center" />
<CheckBox Name="CBoundEnabled" HorizontalAlignment="Center" Text="{Loc 'air-alarm-ui-widget-enable'}" Pressed="True" /> <CheckBox Name="CBoundEnabled" HorizontalAlignment="Center" Text="{Loc 'Enable'}" Pressed="True" />
<FloatSpinBox Name="CSpinner" /> <FloatSpinBox Name="CSpinner" />
</BoxContainer> </BoxContainer>

View File

@@ -6,7 +6,7 @@
<CollapsibleBody Margin="20 0 0 0"> <CollapsibleBody Margin="20 0 0 0">
<BoxContainer Orientation="Vertical"> <BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal"> <BoxContainer Orientation="Horizontal">
<CheckBox Name="CEnabled" Text="{Loc 'air-alarm-ui-widget-enable'}" /> <CheckBox Name="CEnabled" Text="{Loc 'Enabled'}" />
</BoxContainer> </BoxContainer>
<!-- Upper row: Danger bounds --> <!-- Upper row: Danger bounds -->
<BoxContainer Name="CDangerBounds" Orientation="Horizontal" Margin="0 0 0 2"/> <BoxContainer Name="CDangerBounds" Orientation="Horizontal" Margin="0 0 0 2"/>

View File

@@ -208,7 +208,7 @@ namespace Content.Client.Atmos.UI
}); });
presBox.AddChild(new Label presBox.AddChild(new Label
{ {
Text = Loc.GetString("gas-analyzer-window-pressure-val-text", ("pressure", $"{gasMix.Pressure:0.00}")), Text = Loc.GetString("gas-analyzer-window-pressure-val-text", ("pressure", $"{gasMix.Pressure:0.##}")),
Align = Label.AlignMode.Right, Align = Label.AlignMode.Right,
HorizontalExpand = true HorizontalExpand = true
}); });
@@ -232,8 +232,8 @@ namespace Content.Client.Atmos.UI
tempBox.AddChild(new Label tempBox.AddChild(new Label
{ {
Text = Loc.GetString("gas-analyzer-window-temperature-val-text", Text = Loc.GetString("gas-analyzer-window-temperature-val-text",
("tempK", $"{gasMix.Temperature:0.0}"), ("tempK", $"{gasMix.Temperature:0.#}"),
("tempC", $"{TemperatureHelpers.KelvinToCelsius(gasMix.Temperature):0.0}")), ("tempC", $"{TemperatureHelpers.KelvinToCelsius(gasMix.Temperature):0.#}")),
Align = Label.AlignMode.Right, Align = Label.AlignMode.Right,
HorizontalExpand = true HorizontalExpand = true
}); });

View File

@@ -3,13 +3,17 @@ using Content.Shared.CCVar;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Log;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Physics; using Robust.Shared.Physics;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Robust.Client.GameObjects;
using Robust.Shared.Audio.Effects;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -27,7 +31,6 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
[Dependency] private readonly SharedTransformSystem _xformSystem = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IOverlayManager _overlayManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
@@ -62,19 +65,18 @@ public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
get => _overlayEnabled; get => _overlayEnabled;
set set
{ {
if (_overlayEnabled == value) if (_overlayEnabled == value) return;
return;
_overlayEnabled = value; _overlayEnabled = value;
var overlayManager = IoCManager.Resolve<IOverlayManager>();
if (_overlayEnabled) if (_overlayEnabled)
{ {
_overlay = new AmbientSoundOverlay(EntityManager, this, EntityManager.System<EntityLookupSystem>()); _overlay = new AmbientSoundOverlay(EntityManager, this, EntityManager.System<EntityLookupSystem>());
_overlayManager.AddOverlay(_overlay); overlayManager.AddOverlay(_overlay);
} }
else else
{ {
_overlayManager.RemoveOverlay(_overlay!); overlayManager.RemoveOverlay(_overlay!);
_overlay = null; _overlay = null;
} }
} }

View File

@@ -3,8 +3,11 @@ using Content.Client.Gameplay;
using Content.Shared.Audio; using Content.Shared.Audio;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.GameTicking; using Content.Shared.GameTicking;
using Content.Shared.Random;
using Content.Shared.Random.Rules; using Content.Shared.Random.Rules;
using Robust.Client.GameObjects;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.State; using Robust.Client.State;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Audio.Components; using Robust.Shared.Audio.Components;
@@ -22,7 +25,6 @@ public sealed partial class ContentAudioSystem
{ {
[Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
@@ -59,7 +61,7 @@ public sealed partial class ContentAudioSystem
private void InitializeAmbientMusic() private void InitializeAmbientMusic()
{ {
Subs.CVar(_configManager, CCVars.AmbientMusicVolume, AmbienceCVarChanged, true); Subs.CVar(_configManager, CCVars.AmbientMusicVolume, AmbienceCVarChanged, true);
_sawmill = _logManager.GetSawmill("audio.ambience"); _sawmill = IoCManager.Resolve<ILogManager>().GetSawmill("audio.ambience");
// Reset audio // Reset audio
_nextAudio = TimeSpan.MaxValue; _nextAudio = TimeSpan.MaxValue;

View File

@@ -58,7 +58,7 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
_menu.SetAudioStream(jukebox.AudioStream); _menu.SetAudioStream(jukebox.AudioStream);
if (_protoManager.Resolve(jukebox.SelectedSongId, out var songProto)) if (_protoManager.TryIndex(jukebox.SelectedSongId, out var songProto))
{ {
var length = EntMan.System<AudioSystem>().GetAudioLength(songProto.Path.Path.ToString()); var length = EntMan.System<AudioSystem>().GetAudioLength(songProto.Path.Path.ToString());
_menu.SetSelectedSong(songProto.Name, (float) length.TotalSeconds); _menu.SetSelectedSong(songProto.Name, (float) length.TotalSeconds);

View File

@@ -39,7 +39,7 @@ public sealed class BarSignSystem : VisualizerSystem<BarSignComponent>
if (powered if (powered
&& sign.Current != null && sign.Current != null
&& _prototypeManager.Resolve(sign.Current, out var proto)) && _prototypeManager.TryIndex(sign.Current, out var proto))
{ {
SpriteSystem.LayerSetSprite((id, sprite), 0, proto.Icon); SpriteSystem.LayerSetSprite((id, sprite), 0, proto.Icon);
sprite.LayerSetShader(0, "unshaded"); sprite.LayerSetShader(0, "unshaded");

View File

@@ -35,7 +35,7 @@ public sealed class BarSignBoundUserInterface(EntityUid owner, Enum uiKey) : Bou
public void Update(ProtoId<BarSignPrototype>? sign) public void Update(ProtoId<BarSignPrototype>? sign)
{ {
if (_prototype.Resolve(sign, out var signPrototype)) if (_prototype.TryIndex(sign, out var signPrototype))
_menu?.UpdateState(signPrototype); _menu?.UpdateState(signPrototype);
} }

View File

@@ -1,8 +1,8 @@
using System.Numerics; using System.Numerics;
using Content.Shared.Body.Components;
using Content.Shared.CardboardBox; using Content.Shared.CardboardBox;
using Content.Shared.CardboardBox.Components; using Content.Shared.CardboardBox.Components;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Mobs.Components;
using Content.Shared.Movement.Components; using Content.Shared.Movement.Components;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
@@ -15,13 +15,13 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
[Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly SpriteSystem _sprite = default!; [Dependency] private readonly SpriteSystem _sprite = default!;
private EntityQuery<MobStateComponent> _mobStateQuery; private EntityQuery<BodyComponent> _bodyQuery;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_mobStateQuery = GetEntityQuery<MobStateComponent>(); _bodyQuery = GetEntityQuery<BodyComponent>();
SubscribeNetworkEvent<PlayBoxEffectMessage>(OnBoxEffect); SubscribeNetworkEvent<PlayBoxEffectMessage>(OnBoxEffect);
} }
@@ -66,8 +66,8 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
if (!_examine.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null)) if (!_examine.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null))
continue; continue;
// no effect for non-mobs that have MobMover, such as mechs and vehicles. // no effect for anything too exotic
if (!_mobStateQuery.HasComp(mob)) if (!_bodyQuery.HasComp(mob))
continue; continue;
var ent = Spawn(box.Effect, mapPos); var ent = Spawn(box.Effect, mapPos);

View File

@@ -29,7 +29,7 @@ public sealed partial class BountyEntry : BoxContainer
UntilNextSkip = untilNextSkip; UntilNextSkip = untilNextSkip;
if (!_prototype.Resolve<CargoBountyPrototype>(bounty.Bounty, out var bountyPrototype)) if (!_prototype.TryIndex<CargoBountyPrototype>(bounty.Bounty, out var bountyPrototype))
return; return;
var items = new List<string>(); var items = new List<string>();

View File

@@ -19,7 +19,7 @@ public sealed partial class BountyHistoryEntry : BoxContainer
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
if (!_prototype.Resolve(bounty.Bounty, out var bountyPrototype)) if (!_prototype.TryIndex(bounty.Bounty, out var bountyPrototype))
return; return;
var items = new List<string>(); var items = new List<string>();

View File

@@ -1,30 +0,0 @@
using Content.Shared.Changeling.Components;
using Content.Shared.Changeling.Systems;
using Robust.Client.GameObjects;
namespace Content.Client.Changeling.Systems;
public sealed class ChangelingIdentitySystem : SharedChangelingIdentitySystem
{
[Dependency] private readonly UserInterfaceSystem _ui = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ChangelingIdentityComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
}
private void OnAfterAutoHandleState(Entity<ChangelingIdentityComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateUi(ent);
}
public void UpdateUi(EntityUid uid)
{
if (_ui.TryGetOpenUi(uid, ChangelingTransformUiKey.Key, out var bui))
{
bui.Update();
}
}
}

View File

@@ -1,68 +0,0 @@
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.Changeling.Components;
using Content.Shared.Changeling.Systems;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Changeling.UI;
[UsedImplicitly]
public sealed partial class ChangelingTransformBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
{
private SimpleRadialMenu? _menu;
private static readonly Color SelectedOptionBackground = StyleNano.ButtonColorGoodDefault.WithAlpha(128);
private static readonly Color SelectedOptionHoverBackground = StyleNano.ButtonColorGoodHovered.WithAlpha(128);
protected override void Open()
{
base.Open();
_menu = this.CreateWindow<SimpleRadialMenu>();
Update();
_menu.OpenOverMouseScreenPosition();
}
public override void Update()
{
if (_menu == null)
return;
if (!EntMan.TryGetComponent<ChangelingIdentityComponent>(Owner, out var lingIdentity))
return;
var models = ConvertToButtons(lingIdentity.ConsumedIdentities, lingIdentity?.CurrentIdentity);
_menu.SetButtons(models);
}
private IEnumerable<RadialMenuOptionBase> ConvertToButtons(
IEnumerable<EntityUid> identities,
EntityUid? currentIdentity
)
{
var buttons = new List<RadialMenuOptionBase>();
foreach (var identity in identities)
{
if (!EntMan.TryGetComponent<MetaDataComponent>(identity, out var metadata))
continue;
var option = new RadialMenuActionOption<NetEntity>(SendIdentitySelect, EntMan.GetNetEntity(identity))
{
IconSpecifier = RadialMenuIconSpecifier.With(identity),
ToolTip = metadata.EntityName,
BackgroundColor = (currentIdentity == identity) ? SelectedOptionBackground : null,
HoverBackgroundColor = (currentIdentity == identity) ? SelectedOptionHoverBackground : null
};
buttons.Add(option);
}
return buttons;
}
private void SendIdentitySelect(NetEntity identityId)
{
SendPredictedMessage(new ChangelingTransformIdentitySelectMessage(identityId));
}
}

View File

@@ -27,7 +27,7 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
if (overrideIndicator != null) if (overrideIndicator != null)
currentTypingIndicator = overrideIndicator.Value; currentTypingIndicator = overrideIndicator.Value;
if (!_prototypeManager.Resolve(currentTypingIndicator, out var proto)) if (!_prototypeManager.TryIndex(currentTypingIndicator, out var proto))
{ {
Log.Error($"Unknown typing indicator id: {component.TypingIndicatorPrototype}"); Log.Error($"Unknown typing indicator id: {component.TypingIndicatorPrototype}");
return; return;

View File

@@ -2,6 +2,7 @@ using Content.Client.Chemistry.UI;
using Content.Client.Items; using Content.Client.Items;
using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.GameStates;
namespace Content.Client.Chemistry.EntitySystems; namespace Content.Client.Chemistry.EntitySystems;
@@ -10,7 +11,6 @@ public sealed class InjectorSystem : SharedInjectorSystem
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
Subs.ItemStatus<InjectorComponent>(ent => new InjectorStatusControl(ent, SolutionContainers));
Subs.ItemStatus<InjectorComponent>(ent => new InjectorStatusControl(ent, SolutionContainer));
} }
} }

View File

@@ -38,13 +38,13 @@ public sealed class InjectorStatusControl : Control
// only updates the UI if any of the details are different than they previously were // only updates the UI if any of the details are different than they previously were
if (PrevVolume == solution.Volume if (PrevVolume == solution.Volume
&& PrevMaxVolume == solution.MaxVolume && PrevMaxVolume == solution.MaxVolume
&& PrevTransferAmount == _parent.Comp.CurrentTransferAmount && PrevTransferAmount == _parent.Comp.TransferAmount
&& PrevToggleState == _parent.Comp.ToggleState) && PrevToggleState == _parent.Comp.ToggleState)
return; return;
PrevVolume = solution.Volume; PrevVolume = solution.Volume;
PrevMaxVolume = solution.MaxVolume; PrevMaxVolume = solution.MaxVolume;
PrevTransferAmount = _parent.Comp.CurrentTransferAmount; PrevTransferAmount = _parent.Comp.TransferAmount;
PrevToggleState = _parent.Comp.ToggleState; PrevToggleState = _parent.Comp.ToggleState;
// Update current volume and injector state // Update current volume and injector state
@@ -59,6 +59,6 @@ public sealed class InjectorStatusControl : Control
("currentVolume", solution.Volume), ("currentVolume", solution.Volume),
("totalVolume", solution.MaxVolume), ("totalVolume", solution.MaxVolume),
("modeString", modeStringLocalized), ("modeString", modeStringLocalized),
("transferVolume", _parent.Comp.CurrentTransferAmount))); ("transferVolume", _parent.Comp.TransferAmount)));
} }
} }

View File

@@ -1,5 +0,0 @@
using Content.Shared.Cloning;
namespace Content.Client.Cloning;
public sealed partial class CloningSystem : SharedCloningSystem;

View File

@@ -1,10 +1,12 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Numerics;
using Content.Client.DisplacementMap; using Content.Client.DisplacementMap;
using Content.Client.Inventory; using Content.Client.Inventory;
using Content.Shared.Clothing; using Content.Shared.Clothing;
using Content.Shared.Clothing.Components; using Content.Shared.Clothing.Components;
using Content.Shared.Clothing.EntitySystems; using Content.Shared.Clothing.EntitySystems;
using Content.Shared.DisplacementMap;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Content.Shared.Inventory; using Content.Shared.Inventory;
using Content.Shared.Inventory.Events; using Content.Shared.Inventory.Events;
@@ -12,6 +14,7 @@ using Content.Shared.Item;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.ResourceManagement; using Robust.Client.ResourceManagement;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using static Robust.Client.GameObjects.SpriteComponent; using static Robust.Client.GameObjects.SpriteComponent;
@@ -179,7 +182,6 @@ public sealed class ClientClothingSystem : ClothingSystem
var layer = new PrototypeLayerData(); var layer = new PrototypeLayerData();
layer.RsiPath = rsi.Path.ToString(); layer.RsiPath = rsi.Path.ToString();
layer.State = state; layer.State = state;
layer.Scale = clothing.Scale;
layers = new() { layer }; layers = new() { layer };
return true; return true;

View File

@@ -45,7 +45,7 @@ public sealed class ChameleonBoundUserInterface : BoundUserInterface
var newTargets = new List<EntProtoId>(); var newTargets = new List<EntProtoId>();
foreach (var target in targets) foreach (var target in targets)
{ {
if (string.IsNullOrEmpty(target) || !_proto.Resolve(target, out EntityPrototype? proto)) if (string.IsNullOrEmpty(target) || !_proto.TryIndex(target, out EntityPrototype? proto))
continue; continue;
if (!proto.TryGetComponent(out TagComponent? tag, EntMan.ComponentFactory) || !_tag.HasTag(tag, st.RequiredTag)) if (!proto.TryGetComponent(out TagComponent? tag, EntMan.ComponentFactory) || !_tag.HasTag(tag, st.RequiredTag))

View File

@@ -54,7 +54,7 @@ public sealed partial class ChameleonMenu : DefaultWindow
foreach (var id in _possibleIds) foreach (var id in _possibleIds)
{ {
if (!_prototypeManager.Resolve(id, out EntityPrototype? proto)) if (!_prototypeManager.TryIndex(id, out EntityPrototype? proto))
continue; continue;
var lowId = id.Id.ToLowerInvariant(); var lowId = id.Id.ToLowerInvariant();

View File

@@ -80,7 +80,7 @@ namespace Content.Client.Construction
{ {
foreach (var constructionProto in PrototypeManager.EnumeratePrototypes<ConstructionPrototype>()) foreach (var constructionProto in PrototypeManager.EnumeratePrototypes<ConstructionPrototype>())
{ {
if (!PrototypeManager.Resolve(constructionProto.Graph, out var graphProto)) if (!PrototypeManager.TryIndex(constructionProto.Graph, out var graphProto))
continue; continue;
if (constructionProto.TargetNode is not { } targetNodeId) if (constructionProto.TargetNode is not { } targetNodeId)
@@ -121,14 +121,17 @@ namespace Content.Client.Construction
// If we got the id of the prototype, we exit the “recursion” by clearing the stack. // If we got the id of the prototype, we exit the “recursion” by clearing the stack.
stack.Clear(); stack.Clear();
if (!PrototypeManager.Resolve(entityId, out var proto)) if (!PrototypeManager.TryIndex(constructionProto.ID, out ConstructionPrototype? recipe))
continue; continue;
var name = constructionProto.SetName.HasValue ? Loc.GetString(constructionProto.SetName) : proto.Name; if (!PrototypeManager.TryIndex(entityId, out var proto))
var desc = constructionProto.SetDescription.HasValue ? Loc.GetString(constructionProto.SetDescription) : proto.Description; continue;
constructionProto.Name = name; var name = recipe.SetName.HasValue ? Loc.GetString(recipe.SetName) : proto.Name;
constructionProto.Description = desc; var desc = recipe.SetDescription.HasValue ? Loc.GetString(recipe.SetDescription) : proto.Description;
recipe.Name = name;
recipe.Description = desc;
_recipesMetadataCache.Add(constructionProto.ID, entityId); _recipesMetadataCache.Add(constructionProto.ID, entityId);
} while (stack.Count > 0); } while (stack.Count > 0);
@@ -169,7 +172,7 @@ namespace Content.Client.Construction
"construction-ghost-examine-message", "construction-ghost-examine-message",
("name", component.Prototype.Name))); ("name", component.Prototype.Name)));
if (!PrototypeManager.Resolve(component.Prototype.Graph, out var graph)) if (!PrototypeManager.TryIndex(component.Prototype.Graph, out var graph))
return; return;
var startNode = graph.Nodes[component.Prototype.StartNode]; var startNode = graph.Nodes[component.Prototype.StartNode];

View File

@@ -528,7 +528,7 @@ namespace Content.Client.Construction.UI
foreach (var id in favorites) foreach (var id in favorites)
{ {
if (_prototypeManager.TryIndex(id, out ConstructionPrototype? recipe)) if (_prototypeManager.TryIndex(id, out ConstructionPrototype? recipe, logError: false))
_favoritedRecipes.Add(recipe); _favoritedRecipes.Add(recipe);
} }

View File

@@ -80,7 +80,7 @@ public sealed partial class CreditsWindow : DefaultWindow
private async void PopulateAttributions(BoxContainer attributionsContainer, int count) private async void PopulateAttributions(BoxContainer attributionsContainer, int count)
{ {
attributionsContainer.RemoveAllChildren(); attributionsContainer.DisposeAllChildren();
if (_attributions.Count == 0) if (_attributions.Count == 0)
{ {
@@ -253,8 +253,6 @@ public sealed partial class CreditsWindow : DefaultWindow
private void PopulateLicenses(BoxContainer licensesContainer) private void PopulateLicenses(BoxContainer licensesContainer)
{ {
licensesContainer.RemoveAllChildren();
foreach (var entry in CreditsManager.GetLicenses(_resourceManager).OrderBy(p => p.Name)) foreach (var entry in CreditsManager.GetLicenses(_resourceManager).OrderBy(p => p.Name))
{ {
licensesContainer.AddChild(new Label licensesContainer.AddChild(new Label
@@ -271,8 +269,6 @@ public sealed partial class CreditsWindow : DefaultWindow
private void PopulatePatrons(BoxContainer patronsContainer) private void PopulatePatrons(BoxContainer patronsContainer)
{ {
patronsContainer.RemoveAllChildren();
var patrons = LoadPatrons(); var patrons = LoadPatrons();
// Do not show "become a patron" button on Steam builds // Do not show "become a patron" button on Steam builds
@@ -322,8 +318,6 @@ public sealed partial class CreditsWindow : DefaultWindow
private void PopulateContributors(BoxContainer ss14ContributorsContainer) private void PopulateContributors(BoxContainer ss14ContributorsContainer)
{ {
ss14ContributorsContainer.RemoveAllChildren();
Button contributeButton; Button contributeButton;
ss14ContributorsContainer.AddChild(new BoxContainer ss14ContributorsContainer.AddChild(new BoxContainer
@@ -362,7 +356,6 @@ public sealed partial class CreditsWindow : DefaultWindow
AddSection(Loc.GetString("credits-window-contributors-section-title"), "GitHub.txt"); AddSection(Loc.GetString("credits-window-contributors-section-title"), "GitHub.txt");
AddSection(Loc.GetString("credits-window-codebases-section-title"), "SpaceStation13.txt"); AddSection(Loc.GetString("credits-window-codebases-section-title"), "SpaceStation13.txt");
AddSection(Loc.GetString("credits-window-original-remake-team-section-title"), "OriginalRemake.txt"); AddSection(Loc.GetString("credits-window-original-remake-team-section-title"), "OriginalRemake.txt");
AddSection(Loc.GetString("credits-window-immortals-title"), "Immortals.txt", true);
AddSection(Loc.GetString("credits-window-special-thanks-section-title"), "SpecialThanks.txt", true); AddSection(Loc.GetString("credits-window-special-thanks-section-title"), "SpecialThanks.txt", true);
var linkGithub = _cfg.GetCVar(CCVars.InfoLinksGithub); var linkGithub = _cfg.GetCVar(CCVars.InfoLinksGithub);

View File

@@ -150,7 +150,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
// If the damage container on our entity's DamageableComponent // If the damage container on our entity's DamageableComponent
// is not null, we can try to check through its groups. // is not null, we can try to check through its groups.
if (damageComponent.DamageContainerID != null if (damageComponent.DamageContainerID != null
&& _prototypeManager.Resolve<DamageContainerPrototype>(damageComponent.DamageContainerID, out var damageContainer)) && _prototypeManager.TryIndex<DamageContainerPrototype>(damageComponent.DamageContainerID, out var damageContainer))
{ {
// Are we using damage overlay sprites by group? // Are we using damage overlay sprites by group?
// Check if the container matches the supported groups, // Check if the container matches the supported groups,

View File

@@ -1,4 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.DisplacementMap; using Content.Shared.DisplacementMap;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
@@ -11,11 +10,6 @@ public sealed class DisplacementMapSystem : EntitySystem
[Dependency] private readonly ISerializationManager _serialization = default!; [Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly SpriteSystem _sprite = default!; [Dependency] private readonly SpriteSystem _sprite = default!;
private static string? BuildDisplacementLayerKey(object key)
{
return key.ToString() is null ? null : $"{key}-displacement";
}
/// <summary> /// <summary>
/// Attempting to apply a displacement map to a specific layer of SpriteComponent /// Attempting to apply a displacement map to a specific layer of SpriteComponent
/// </summary> /// </summary>
@@ -25,23 +19,22 @@ public sealed class DisplacementMapSystem : EntitySystem
/// <param name="key">Unique layer key, which will determine which layer to apply displacement map to</param> /// <param name="key">Unique layer key, which will determine which layer to apply displacement map to</param>
/// <param name="displacementKey">The key of the new displacement map layer added by this function.</param> /// <param name="displacementKey">The key of the new displacement map layer added by this function.</param>
/// <returns></returns> /// <returns></returns>
public bool TryAddDisplacement( public bool TryAddDisplacement(DisplacementData data,
DisplacementData data,
Entity<SpriteComponent> sprite, Entity<SpriteComponent> sprite,
int index, int index,
object key, object key,
[NotNullWhen(true)] out string? displacementKey out string displacementKey)
)
{ {
displacementKey = BuildDisplacementLayerKey(key); displacementKey = $"{key}-displacement";
if (displacementKey is null)
if (key.ToString() is null)
return false; return false;
EnsureDisplacementIsNotOnSprite(sprite, key); if (data.ShaderOverride != null)
if (data.ShaderOverride is not null)
sprite.Comp.LayerSetShader(index, data.ShaderOverride); sprite.Comp.LayerSetShader(index, data.ShaderOverride);
_sprite.RemoveLayer(sprite.AsNullable(), displacementKey, false);
//allows you not to write it every time in the YML //allows you not to write it every time in the YML
foreach (var pair in data.SizeMaps) foreach (var pair in data.SizeMaps)
{ {
@@ -77,11 +70,7 @@ public sealed class DisplacementMapSystem : EntitySystem
} }
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true); var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
displacementLayer.CopyToShaderParameters!.LayerKey = key.ToString() ?? "this is impossible";
// This previously assigned a string reading "this is impossible" if key.ToString eval'd to false.
// However, for the sake of sanity, we've changed this to assert non-null - !.
// If this throws an error, we're not sorry. Nanotrasen thanks you for your service fixing this bug.
displacementLayer.CopyToShaderParameters!.LayerKey = key.ToString()!;
_sprite.AddLayer(sprite.AsNullable(), displacementLayer, index); _sprite.AddLayer(sprite.AsNullable(), displacementLayer, index);
_sprite.LayerMapSet(sprite.AsNullable(), displacementKey, index); _sprite.LayerMapSet(sprite.AsNullable(), displacementKey, index);
@@ -89,18 +78,14 @@ public sealed class DisplacementMapSystem : EntitySystem
return true; return true;
} }
/// <summary> /// <inheritdoc cref="TryAddDisplacement"/>
/// Ensures that the displacement map associated with the given layer key is not in the Sprite's LayerMap. [Obsolete("Use the Entity<SpriteComponent> overload")]
/// </summary> public bool TryAddDisplacement(DisplacementData data,
/// <param name="sprite">The sprite to remove the displacement layer from.</param> SpriteComponent sprite,
/// <param name="key">The key of the layer that is referenced by the displacement layer we want to remove.</param> int index,
/// <param name="logMissing">Whether to report an error if the displacement map isn't on the sprite.</param> object key,
public void EnsureDisplacementIsNotOnSprite(Entity<SpriteComponent> sprite, object key) out string displacementKey)
{ {
var displacementLayerKey = BuildDisplacementLayerKey(key); return TryAddDisplacement(data, (sprite.Owner, sprite), index, key, out displacementKey);
if (displacementLayerKey is null)
return;
_sprite.RemoveLayer(sprite.AsNullable(), displacementLayerKey, false);
} }
} }

View File

@@ -142,7 +142,7 @@ public sealed class DoorSystem : SharedDoorSystem
private void UpdateSpriteLayers(Entity<SpriteComponent> sprite, string targetProto) private void UpdateSpriteLayers(Entity<SpriteComponent> sprite, string targetProto)
{ {
if (!_prototypeManager.Resolve(targetProto, out var target)) if (!_prototypeManager.TryIndex(targetProto, out var target))
return; return;
if (!target.TryGetComponent(out SpriteComponent? targetSprite, _componentFactory)) if (!target.TryGetComponent(out SpriteComponent? targetSprite, _componentFactory))

View File

@@ -1,6 +1,5 @@
using Content.Shared.Drunk; using Content.Shared.Drunk;
using Content.Shared.StatusEffect; using Content.Shared.StatusEffect;
using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Enums; using Robust.Shared.Enums;
@@ -44,21 +43,19 @@ public sealed class DrunkOverlay : Overlay
if (playerEntity == null) if (playerEntity == null)
return; return;
var statusSys = _sysMan.GetEntitySystem<Shared.StatusEffectNew.StatusEffectsSystem>(); if (!_entityManager.HasComponent<DrunkComponent>(playerEntity)
if (!statusSys.TryGetMaxTime<DrunkStatusEffectComponent>(playerEntity.Value, out var status)) || !_entityManager.TryGetComponent<StatusEffectsComponent>(playerEntity, out var status))
return; return;
var time = status.Item2; var statusSys = _sysMan.GetEntitySystem<StatusEffectsSystem>();
if (!statusSys.TryGetTime(playerEntity.Value, SharedDrunkSystem.DrunkKey, out var time, status))
return;
var power = SharedDrunkSystem.MagicNumber; var curTime = _timing.CurTime;
var timeLeft = (float) (time.Value.Item2 - curTime).TotalSeconds;
if (time != null)
{
var curTime = _timing.CurTime;
power = (float) (time - curTime).Value.TotalSeconds;
}
CurrentBoozePower += 8f * (power * 0.5f - CurrentBoozePower) * args.DeltaSeconds / (power+1); CurrentBoozePower += 8f * (0.5f*timeLeft - CurrentBoozePower) * args.DeltaSeconds / (timeLeft+1);
} }
protected override bool BeforeDraw(in OverlayDrawArgs args) protected override bool BeforeDraw(in OverlayDrawArgs args)

View File

@@ -1,5 +1,4 @@
using Content.Shared.Drunk; using Content.Shared.Drunk;
using Content.Shared.StatusEffectNew;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -17,41 +16,38 @@ public sealed class DrunkSystem : SharedDrunkSystem
{ {
base.Initialize(); base.Initialize();
SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectAppliedEvent>(OnStatusApplied); SubscribeLocalEvent<DrunkComponent, ComponentInit>(OnDrunkInit);
SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectRemovedEvent>(OnStatusRemoved); SubscribeLocalEvent<DrunkComponent, ComponentShutdown>(OnDrunkShutdown);
SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerAttachedEvent>>(OnPlayerAttached); SubscribeLocalEvent<DrunkComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<DrunkStatusEffectComponent, StatusEffectRelayedEvent<LocalPlayerDetachedEvent>>(OnPlayerDetached); SubscribeLocalEvent<DrunkComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);
_overlay = new(); _overlay = new();
} }
private void OnStatusApplied(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectAppliedEvent args) private void OnPlayerAttached(EntityUid uid, DrunkComponent component, LocalPlayerAttachedEvent args)
{
if (!_overlayMan.HasOverlay<DrunkOverlay>())
_overlayMan.AddOverlay(_overlay);
}
private void OnStatusRemoved(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
{
if (Status.HasEffectComp<DrunkStatusEffectComponent>(args.Target))
return;
if (_player.LocalEntity != args.Target)
return;
_overlay.CurrentBoozePower = 0;
_overlayMan.RemoveOverlay(_overlay);
}
private void OnPlayerAttached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
{ {
_overlayMan.AddOverlay(_overlay); _overlayMan.AddOverlay(_overlay);
} }
private void OnPlayerDetached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args) private void OnPlayerDetached(EntityUid uid, DrunkComponent component, LocalPlayerDetachedEvent args)
{ {
_overlay.CurrentBoozePower = 0; _overlay.CurrentBoozePower = 0;
_overlayMan.RemoveOverlay(_overlay); _overlayMan.RemoveOverlay(_overlay);
} }
private void OnDrunkInit(EntityUid uid, DrunkComponent component, ComponentInit args)
{
if (_player.LocalEntity == uid)
_overlayMan.AddOverlay(_overlay);
}
private void OnDrunkShutdown(EntityUid uid, DrunkComponent component, ComponentShutdown args)
{
if (_player.LocalEntity == uid)
{
_overlay.CurrentBoozePower = 0;
_overlayMan.RemoveOverlay(_overlay);
}
}
} }

View File

@@ -0,0 +1,7 @@
using Content.Shared.Explosion.EntitySystems;
namespace Content.Client.Explosion;
public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem
{
}

View File

@@ -0,0 +1,7 @@
using Content.Shared.Explosion;
using Content.Shared.Explosion.Components;
namespace Content.Client.Explosion;
[RegisterComponent, Access(typeof(TriggerSystem))]
public sealed partial class TriggerOnProximityComponent : SharedTriggerOnProximityComponent {}

View File

@@ -1,12 +1,11 @@
using Content.Shared.Trigger; using Content.Shared.Trigger;
using Content.Shared.Trigger.Components.Triggers;
using Robust.Client.Animations; using Robust.Client.Animations;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.Animations; using Robust.Shared.Animations;
namespace Content.Client.Trigger.Systems; namespace Content.Client.Explosion;
public sealed class ProximityTriggerAnimationSystem : EntitySystem public sealed partial class TriggerSystem
{ {
[Dependency] private readonly AnimationPlayerSystem _player = default!; [Dependency] private readonly AnimationPlayerSystem _player = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
@@ -19,7 +18,7 @@ public sealed class ProximityTriggerAnimationSystem : EntitySystem
private const string AnimKey = "proximity"; private const string AnimKey = "proximity";
private static readonly Animation FlasherAnimation = new Animation private static readonly Animation _flasherAnimation = new Animation
{ {
Length = TimeSpan.FromSeconds(0.6f), Length = TimeSpan.FromSeconds(0.6f),
AnimationTracks = { AnimationTracks = {
@@ -43,10 +42,8 @@ public sealed class ProximityTriggerAnimationSystem : EntitySystem
} }
}; };
public override void Initialize() private void InitializeProximity()
{ {
base.Initialize();
SubscribeLocalEvent<TriggerOnProximityComponent, ComponentInit>(OnProximityInit); SubscribeLocalEvent<TriggerOnProximityComponent, ComponentInit>(OnProximityInit);
SubscribeLocalEvent<TriggerOnProximityComponent, AppearanceChangeEvent>(OnProxAppChange); SubscribeLocalEvent<TriggerOnProximityComponent, AppearanceChangeEvent>(OnProxAppChange);
SubscribeLocalEvent<TriggerOnProximityComponent, AnimationCompletedEvent>(OnProxAnimation); SubscribeLocalEvent<TriggerOnProximityComponent, AnimationCompletedEvent>(OnProxAnimation);
@@ -97,7 +94,7 @@ public sealed class ProximityTriggerAnimationSystem : EntitySystem
break; break;
case ProximityTriggerVisuals.Active: case ProximityTriggerVisuals.Active:
if (_player.HasRunningAnimation(uid, player, AnimKey)) return; if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
_player.Play((uid, player), FlasherAnimation, AnimKey); _player.Play((uid, player), _flasherAnimation, AnimKey);
break; break;
case ProximityTriggerVisuals.Off: case ProximityTriggerVisuals.Off:
default: default:

View File

@@ -0,0 +1,10 @@
namespace Content.Client.Explosion;
public sealed partial class TriggerSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
InitializeProximity();
}
}

View File

@@ -1,5 +0,0 @@
using Content.Shared.Forensics.Systems;
namespace Content.Client.Forensics.Systems;
public sealed class ForensicsSystem : SharedForensicsSystem;

View File

@@ -34,8 +34,6 @@ namespace Content.Client.GameTicking.Managers
[ViewVariables] public TimeSpan StartTime { get; private set; } [ViewVariables] public TimeSpan StartTime { get; private set; }
[ViewVariables] public new bool Paused { get; private set; } [ViewVariables] public new bool Paused { get; private set; }
public override IReadOnlyList<(TimeSpan, string)> AllPreviousGameRules => new List<(TimeSpan, string)>();
[ViewVariables] public IReadOnlyDictionary<NetEntity, Dictionary<ProtoId<JobPrototype>, int?>> JobsAvailable => _jobsAvailable; [ViewVariables] public IReadOnlyDictionary<NetEntity, Dictionary<ProtoId<JobPrototype>, int?>> JobsAvailable => _jobsAvailable;
[ViewVariables] public IReadOnlyDictionary<NetEntity, string> StationNames => _stationNames; [ViewVariables] public IReadOnlyDictionary<NetEntity, string> StationNames => _stationNames;

View File

@@ -1,58 +1,25 @@
using Content.Client.UserInterface.Controls;
using Content.Shared.Ghost.Roles; using Content.Shared.Ghost.Roles;
using Content.Shared.Ghost.Roles.Components;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Client.Ghost; namespace Content.Client.Ghost;
public sealed class GhostRoleRadioBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey) public sealed class GhostRoleRadioBoundUserInterface : BoundUserInterface
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; private GhostRoleRadioMenu? _ghostRoleRadioMenu;
private SimpleRadialMenu? _ghostRoleRadioMenu; public GhostRoleRadioBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
IoCManager.InjectDependencies(this);
}
protected override void Open() protected override void Open()
{ {
base.Open(); base.Open();
_ghostRoleRadioMenu = this.CreateWindow<SimpleRadialMenu>(); _ghostRoleRadioMenu = this.CreateWindow<GhostRoleRadioMenu>();
_ghostRoleRadioMenu.SetEntity(Owner);
// The purpose of this radial UI is for ghost role radios that allow you to select _ghostRoleRadioMenu.SendGhostRoleRadioMessageAction += SendGhostRoleRadioMessage;
// more than one potential option, such as with kobolds/lizards.
// This means that it won't show anything if SelectablePrototypes is empty.
if (!EntMan.TryGetComponent<GhostRoleMobSpawnerComponent>(Owner, out var comp))
return;
var list = ConvertToButtons(comp.SelectablePrototypes);
_ghostRoleRadioMenu.SetButtons(list);
}
private IEnumerable<RadialMenuOptionBase> ConvertToButtons(List<ProtoId<GhostRolePrototype>> protoIds)
{
var list = new List<RadialMenuOptionBase>();
foreach (var ghostRoleProtoId in protoIds)
{
// For each prototype we find we want to create a button that uses the name of the ghost role
// as the hover tooltip, and the icon is taken from either the ghost role entityprototype
// or the indicated icon entityprototype.
if (!_prototypeManager.Resolve(ghostRoleProtoId, out var ghostRoleProto))
continue;
var option = new RadialMenuActionOption<ProtoId<GhostRolePrototype>>(SendGhostRoleRadioMessage, ghostRoleProtoId)
{
ToolTip = Loc.GetString(ghostRoleProto.Name),
// pick the icon if it exists, otherwise fallback to the ghost role's entity
IconSpecifier = ghostRoleProto.IconPrototype != null
&& _prototypeManager.Resolve(ghostRoleProto.IconPrototype, out var iconProto)
? RadialMenuIconSpecifier.With(iconProto)
: RadialMenuIconSpecifier.With(ghostRoleProto.EntityPrototype)
};
list.Add(option);
}
return list;
} }
private void SendGhostRoleRadioMessage(ProtoId<GhostRolePrototype> protoId) private void SendGhostRoleRadioMessage(ProtoId<GhostRolePrototype> protoId)

View File

@@ -0,0 +1,8 @@
<ui:RadialMenu
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
CloseButtonStyleClass="RadialMenuCloseButton"
VerticalExpand="True"
HorizontalExpand="True">
<ui:RadialContainer Name="Main">
</ui:RadialContainer>
</ui:RadialMenu>

View File

@@ -0,0 +1,105 @@
using Content.Client.UserInterface.Controls;
using Content.Shared.Ghost.Roles;
using Content.Shared.Ghost.Roles.Components;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using System.Numerics;
namespace Content.Client.Ghost;
public sealed partial class GhostRoleRadioMenu : RadialMenu
{
[Dependency] private readonly EntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public event Action<ProtoId<GhostRolePrototype>>? SendGhostRoleRadioMessageAction;
public EntityUid Entity { get; set; }
public GhostRoleRadioMenu()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
}
public void SetEntity(EntityUid uid)
{
Entity = uid;
RefreshUI();
}
private void RefreshUI()
{
// The main control that will contain all the clickable options
var main = FindControl<RadialContainer>("Main");
// The purpose of this radial UI is for ghost role radios that allow you to select
// more than one potential option, such as with kobolds/lizards.
// This means that it won't show anything if SelectablePrototypes is empty.
if (!_entityManager.TryGetComponent<GhostRoleMobSpawnerComponent>(Entity, out var comp))
return;
foreach (var ghostRoleProtoString in comp.SelectablePrototypes)
{
// For each prototype we find we want to create a button that uses the name of the ghost role
// as the hover tooltip, and the icon is taken from either the ghost role entityprototype
// or the indicated icon entityprototype.
if (!_prototypeManager.TryIndex<GhostRolePrototype>(ghostRoleProtoString, out var ghostRoleProto))
continue;
var button = new GhostRoleRadioMenuButton()
{
SetSize = new Vector2(64, 64),
ToolTip = Loc.GetString(ghostRoleProto.Name),
ProtoId = ghostRoleProto.ID,
};
var entProtoView = new EntityPrototypeView()
{
SetSize = new Vector2(48, 48),
VerticalAlignment = VAlignment.Center,
HorizontalAlignment = HAlignment.Center,
Stretch = SpriteView.StretchMode.Fill
};
// pick the icon if it exists, otherwise fallback to the ghost role's entity
if (_prototypeManager.TryIndex(ghostRoleProto.IconPrototype, out var iconProto))
entProtoView.SetPrototype(iconProto);
else
entProtoView.SetPrototype(ghostRoleProto.EntityPrototype);
button.AddChild(entProtoView);
main.AddChild(button);
AddGhostRoleRadioMenuButtonOnClickActions(main);
}
}
private void AddGhostRoleRadioMenuButtonOnClickActions(Control control)
{
var mainControl = control as RadialContainer;
if (mainControl == null)
return;
foreach (var child in mainControl.Children)
{
var castChild = child as GhostRoleRadioMenuButton;
if (castChild == null)
continue;
castChild.OnButtonUp += _ =>
{
SendGhostRoleRadioMessageAction?.Invoke(castChild.ProtoId);
Close();
};
}
}
}
public sealed class GhostRoleRadioMenuButton : RadialMenuTextureButtonWithSector
{
public ProtoId<GhostRolePrototype> ProtoId { get; set; }
}

View File

@@ -136,7 +136,6 @@ namespace Content.Client.Ghost
//_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity); //Dont need in CP14 //_actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity); //Dont need in CP14
//CP14 //CP14
_actions.RemoveAction(uid, component.CP14ToggleRoofActionEntity); _actions.RemoveAction(uid, component.CP14ToggleRoofActionEntity);
_actions.RemoveAction(uid, component.CP14RespawnActionEntity);
//CP14 end //CP14 end
if (uid != _playerManager.LocalEntity) if (uid != _playerManager.LocalEntity)

View File

@@ -5,17 +5,14 @@ using Content.Client.Guidebook.Richtext;
using Content.Client.Message; using Content.Client.Message;
using Content.Client.UserInterface.ControlExtensions; using Content.Client.UserInterface.ControlExtensions;
using Content.Shared.Body.Prototypes; using Content.Shared.Body.Prototypes;
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent; using Content.Shared.Chemistry.Reagent;
using Content.Shared.Contraband;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -30,10 +27,8 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
[Dependency] private readonly IEntitySystemManager _systemManager = default!; [Dependency] private readonly IEntitySystemManager _systemManager = default!;
[Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IConfigurationManager _config = default!;
private readonly ChemistryGuideDataSystem _chemistryGuideData; private readonly ChemistryGuideDataSystem _chemistryGuideData;
private readonly ContrabandSystem _contraband;
private readonly ISawmill _sawmill; private readonly ISawmill _sawmill;
public IPrototype? RepresentedPrototype { get; private set; } public IPrototype? RepresentedPrototype { get; private set; }
@@ -44,7 +39,6 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
_sawmill = _logManager.GetSawmill("guidebook.reagent"); _sawmill = _logManager.GetSawmill("guidebook.reagent");
_chemistryGuideData = _systemManager.GetEntitySystem<ChemistryGuideDataSystem>(); _chemistryGuideData = _systemManager.GetEntitySystem<ChemistryGuideDataSystem>();
_contraband = _systemManager.GetEntitySystem<ContrabandSystem>();
MouseFilter = MouseFilterMode.Stop; MouseFilter = MouseFilterMode.Stop;
} }
@@ -210,25 +204,6 @@ public sealed partial class GuideReagentEmbed : BoxContainer, IDocumentTag, ISea
description.PushNewline(); description.PushNewline();
description.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-physical-description", description.AddMarkupOrThrow(Loc.GetString("guidebook-reagent-physical-description",
("description", reagent.LocalizedPhysicalDescription))); ("description", reagent.LocalizedPhysicalDescription)));
if (_config.GetCVar(CCVars.ContrabandExamine))
{
// Department-restricted text
if (reagent.AllowedJobs.Count > 0 || reagent.AllowedDepartments.Count > 0)
{
description.PushNewline();
description.AddMarkupPermissive(
_contraband.GenerateDepartmentExamineMessage(reagent.AllowedDepartments, reagent.AllowedJobs, ContrabandItemType.Reagent));
}
// Other contraband text
else if (reagent.ContrabandSeverity != null &&
_prototype.Resolve(reagent.ContrabandSeverity.Value, out var severity))
{
description.PushNewline();
description.AddMarkupPermissive(Loc.GetString(severity.ExamineText, ("type", ContrabandItemType.Reagent)));
}
}
ReagentDescription.SetMessage(description); ReagentDescription.SetMessage(description);
} }

View File

@@ -53,7 +53,7 @@ public sealed partial class DocumentParsingManager
public bool TryAddMarkup(Control control, ProtoId<GuideEntryPrototype> entryId, bool log = true) public bool TryAddMarkup(Control control, ProtoId<GuideEntryPrototype> entryId, bool log = true)
{ {
if (!_prototype.Resolve(entryId, out var entry)) if (!_prototype.TryIndex(entryId, out var entry))
return false; return false;
using var file = _resourceManager.ContentFileReadText(entry.Text); using var file = _resourceManager.ContentFileReadText(entry.Text);

View File

@@ -1,6 +1,5 @@
using Content.Shared.HotPotato; using Content.Shared.HotPotato;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Client.HotPotato; namespace Content.Client.HotPotato;
@@ -11,9 +10,6 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
private readonly EntProtoId _hotPotatoEffectId = "HotPotatoEffect";
// TODO: particle system
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);
@@ -27,7 +23,7 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem
if (_timing.CurTime < comp.TargetTime) if (_timing.CurTime < comp.TargetTime)
continue; continue;
comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown); comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown);
Spawn(_hotPotatoEffectId, _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f))); Spawn("HotPotatoEffect", _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f)));
} }
} }
} }

View File

@@ -300,26 +300,25 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
private void RemoveMarking(Marking marking, Entity<SpriteComponent> spriteEnt) private void RemoveMarking(Marking marking, Entity<SpriteComponent> spriteEnt)
{ {
if (!_markingManager.TryGetMarking(marking, out var prototype)) if (!_markingManager.TryGetMarking(marking, out var prototype))
{
return; return;
}
foreach (var sprite in prototype.Sprites) foreach (var sprite in prototype.Sprites)
{ {
if (sprite is not SpriteSpecifier.Rsi rsi) if (sprite is not SpriteSpecifier.Rsi rsi)
{
continue; continue;
}
var layerId = $"{marking.MarkingId}-{rsi.RsiState}"; var layerId = $"{marking.MarkingId}-{rsi.RsiState}";
if (!_sprite.LayerMapTryGet(spriteEnt.AsNullable(), layerId, out var index, false)) if (!_sprite.LayerMapTryGet(spriteEnt.AsNullable(), layerId, out var index, false))
{
continue; continue;
}
_sprite.LayerMapRemove(spriteEnt.AsNullable(), layerId); _sprite.LayerMapRemove(spriteEnt.AsNullable(), layerId);
_sprite.RemoveLayer(spriteEnt.AsNullable(), index); _sprite.RemoveLayer(spriteEnt.AsNullable(), index);
// If this marking is one that can be displaced, we need to remove the displacement as well; otherwise
// altering a marking at runtime can lead to the renderer falling over.
// The Vulps must be shaved.
// (https://github.com/space-wizards/space-station-14/issues/40135).
if (prototype.CanBeDisplaced)
_displacement.EnsureDisplacementIsNotOnSprite(spriteEnt, layerId);
} }
} }
@@ -358,7 +357,9 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
var sprite = entity.Comp2; var sprite = entity.Comp2;
if (!_sprite.LayerMapTryGet((entity.Owner, sprite), markingPrototype.BodyPart, out var targetLayer, false)) if (!_sprite.LayerMapTryGet((entity.Owner, sprite), markingPrototype.BodyPart, out var targetLayer, false))
{
return; return;
}
visible &= !IsHidden(humanoid, markingPrototype.BodyPart); visible &= !IsHidden(humanoid, markingPrototype.BodyPart);
visible &= humanoid.BaseLayers.TryGetValue(markingPrototype.BodyPart, out var setting) visible &= humanoid.BaseLayers.TryGetValue(markingPrototype.BodyPart, out var setting)
@@ -369,7 +370,9 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
var markingSprite = markingPrototype.Sprites[j]; var markingSprite = markingPrototype.Sprites[j];
if (markingSprite is not SpriteSpecifier.Rsi rsi) if (markingSprite is not SpriteSpecifier.Rsi rsi)
return; {
continue;
}
var layerId = $"{markingPrototype.ID}-{rsi.RsiState}"; var layerId = $"{markingPrototype.ID}-{rsi.RsiState}";
@@ -383,18 +386,26 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
_sprite.LayerSetVisible((entity.Owner, sprite), layerId, visible); _sprite.LayerSetVisible((entity.Owner, sprite), layerId, visible);
if (!visible || setting == null) // this is kinda implied if (!visible || setting == null) // this is kinda implied
{
continue; continue;
}
// Okay so if the marking prototype is modified but we load old marking data this may no longer be valid // Okay so if the marking prototype is modified but we load old marking data this may no longer be valid
// and we need to check the index is correct. // and we need to check the index is correct.
// So if that happens just default to white? // So if that happens just default to white?
if (colors != null && j < colors.Count) if (colors != null && j < colors.Count)
{
_sprite.LayerSetColor((entity.Owner, sprite), layerId, colors[j]); _sprite.LayerSetColor((entity.Owner, sprite), layerId, colors[j]);
}
else else
{
_sprite.LayerSetColor((entity.Owner, sprite), layerId, Color.White); _sprite.LayerSetColor((entity.Owner, sprite), layerId, Color.White);
}
if (humanoid.MarkingsDisplacement.TryGetValue(markingPrototype.BodyPart, out var displacementData) && markingPrototype.CanBeDisplaced) if (humanoid.MarkingsDisplacement.TryGetValue(markingPrototype.BodyPart, out var displacementData) && markingPrototype.CanBeDisplaced)
{
_displacement.TryAddDisplacement(displacementData, (entity.Owner, sprite), targetLayer + j + 1, layerId, out _); _displacement.TryAddDisplacement(displacementData, (entity.Owner, sprite), targetLayer + j + 1, layerId, out _);
}
} }
} }

View File

@@ -23,12 +23,10 @@ public sealed class ImplanterSystem : SharedImplanterSystem
{ {
if (_uiSystem.TryGetOpenUi<DeimplantBoundUserInterface>(uid, DeimplantUiKey.Key, out var bui)) if (_uiSystem.TryGetOpenUi<DeimplantBoundUserInterface>(uid, DeimplantUiKey.Key, out var bui))
{ {
// TODO: Don't use protoId for deimplanting
// and especially not raw strings!
Dictionary<string, string> implants = new(); Dictionary<string, string> implants = new();
foreach (var implant in component.DeimplantWhitelist) foreach (var implant in component.DeimplantWhitelist)
{ {
if (_proto.Resolve(implant, out var proto)) if (_proto.TryIndex(implant, out var proto))
implants.Add(proto.ID, proto.Name); implants.Add(proto.ID, proto.Name);
} }

View File

@@ -1,5 +0,0 @@
using Content.Shared.Implants;
namespace Content.Client.Implants;
public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem;

View File

@@ -62,7 +62,7 @@ public sealed partial class ChameleonControllerMenu : FancyWindow
// Go through every outfit and add them to the correct department. // Go through every outfit and add them to the correct department.
foreach (var outfit in _outfits) foreach (var outfit in _outfits)
{ {
_prototypeManager.Resolve(outfit.Job, out var jobProto); _prototypeManager.TryIndex(outfit.Job, out var jobProto);
var name = outfit.LoadoutName ?? outfit.Name ?? jobProto?.Name ?? "Prototype has no name or job."; var name = outfit.LoadoutName ?? outfit.Name ?? jobProto?.Name ?? "Prototype has no name or job.";

View File

@@ -49,7 +49,7 @@ public sealed class ImplanterStatusControl : Control
if (_parent.CurrentMode == ImplanterToggleMode.Draw) if (_parent.CurrentMode == ImplanterToggleMode.Draw)
{ {
string implantName = _parent.DeimplantChosen != null string implantName = _parent.DeimplantChosen != null
? (_prototype.Resolve(_parent.DeimplantChosen.Value, out EntityPrototype? implantProto) ? implantProto.Name : Loc.GetString("implanter-empty-text")) ? (_prototype.TryIndex(_parent.DeimplantChosen.Value, out EntityPrototype? implantProto) ? implantProto.Name : Loc.GetString("implanter-empty-text"))
: Loc.GetString("implanter-empty-text"); : Loc.GetString("implanter-empty-text");
_label.SetMarkup(Loc.GetString("implanter-label-draw", _label.SetMarkup(Loc.GetString("implanter-label-draw",

View File

@@ -294,6 +294,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem
SetMaster(uid, null); SetMaster(uid, null);
TrySetChannels(uid, data); TrySetChannels(uid, data);
instrument.MidiEventBuffer.Clear();
instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add; instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add;
return true; return true;
} }

View File

@@ -21,6 +21,7 @@ namespace Content.Client.Inventory
{ {
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!; [Dependency] private readonly IUserInterfaceManager _ui = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ClientClothingSystem _clothingVisualsSystem = default!; [Dependency] private readonly ClientClothingSystem _clothingVisualsSystem = default!;
[Dependency] private readonly ExamineSystem _examine = default!; [Dependency] private readonly ExamineSystem _examine = default!;
@@ -114,13 +115,6 @@ namespace Content.Client.Inventory
OnLinkInventorySlots?.Invoke(uid, component); OnLinkInventorySlots?.Invoke(uid, component);
} }
protected override void OnInit(Entity<InventoryComponent> ent, ref ComponentInit args)
{
base.OnInit(ent, ref args);
_clothingVisualsSystem.InitClothing(ent.Owner, ent.Comp);
}
public override void Shutdown() public override void Shutdown()
{ {
CommandBinds.Unregister<ClientInventorySystem>(); CommandBinds.Unregister<ClientInventorySystem>();
@@ -267,6 +261,7 @@ namespace Content.Client.Inventory
TryAddSlotData((ent.Owner, inventorySlots), (SlotData)slot); TryAddSlotData((ent.Owner, inventorySlots), (SlotData)slot);
} }
_clothingVisualsSystem.InitClothing(ent, ent.Comp);
if (ent.Owner == _playerManager.LocalEntity) if (ent.Owner == _playerManager.LocalEntity)
ReloadInventory(inventorySlots); ReloadInventory(inventorySlots);
} }

View File

@@ -0,0 +1,8 @@
using Content.Shared.Kitchen;
namespace Content.Client.Kitchen;
public sealed class KitchenSpikeSystem : SharedKitchenSpikeSystem
{
}

View File

@@ -30,10 +30,6 @@ namespace Content.Client.Lathe.UI
{ {
SendMessage(new LatheQueueRecipeMessage(recipe, amount)); SendMessage(new LatheQueueRecipeMessage(recipe, amount));
}; };
_menu.QueueDeleteAction += index => SendMessage(new LatheDeleteRequestMessage(index));
_menu.QueueMoveUpAction += index => SendMessage(new LatheMoveRequestMessage(index, -1));
_menu.QueueMoveDownAction += index => SendMessage(new LatheMoveRequestMessage(index, 1));
_menu.DeleteFabricatingAction += () => SendMessage(new LatheAbortFabricationMessage());
} }
protected override void UpdateState(BoundUserInterfaceState state) protected override void UpdateState(BoundUserInterfaceState state)

View File

@@ -1,7 +1,6 @@
<DefaultWindow <DefaultWindow
xmlns="https://spacestation14.io" xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client" xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:ui="clr-namespace:Content.Client.Materials.UI" xmlns:ui="clr-namespace:Content.Client.Materials.UI"
Title="{Loc 'lathe-menu-title'}" Title="{Loc 'lathe-menu-title'}"
MinSize="550 450" MinSize="550 450"
@@ -111,18 +110,6 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
Margin="130 0 0 0"> Margin="130 0 0 0">
</Label> </Label>
<Button
Name="DeleteFabricating"
Margin="0"
Text="✖"
SetSize="38 32"
HorizontalAlignment="Right"
ToolTip="{Loc 'lathe-menu-delete-fabricating-tooltip'}">
<Button.StyleClasses>
<system:String>Caution</system:String>
<system:String>OpenLeft</system:String>
</Button.StyleClasses>
</Button>
</PanelContainer> </PanelContainer>
</BoxContainer> </BoxContainer>
<ScrollContainer VerticalExpand="True" HScrollEnabled="False"> <ScrollContainer VerticalExpand="True" HScrollEnabled="False">

View File

@@ -11,7 +11,6 @@ using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.Lathe.UI; namespace Content.Client.Lathe.UI;
@@ -27,10 +26,6 @@ public sealed partial class LatheMenu : DefaultWindow
public event Action<BaseButton.ButtonEventArgs>? OnServerListButtonPressed; public event Action<BaseButton.ButtonEventArgs>? OnServerListButtonPressed;
public event Action<string, int>? RecipeQueueAction; public event Action<string, int>? RecipeQueueAction;
public event Action<int>? QueueDeleteAction;
public event Action<int>? QueueMoveUpAction;
public event Action<int>? QueueMoveDownAction;
public event Action? DeleteFabricatingAction;
public List<ProtoId<LatheRecipePrototype>> Recipes = new(); public List<ProtoId<LatheRecipePrototype>> Recipes = new();
@@ -55,21 +50,12 @@ public sealed partial class LatheMenu : DefaultWindow
}; };
AmountLineEdit.OnTextChanged += _ => AmountLineEdit.OnTextChanged += _ =>
{ {
if (int.TryParse(AmountLineEdit.Text, out var amount))
{
if (amount > LatheSystem.MaxItemsPerRequest)
AmountLineEdit.Text = LatheSystem.MaxItemsPerRequest.ToString();
else if (amount < 0)
AmountLineEdit.Text = "0";
}
PopulateRecipes(); PopulateRecipes();
}; };
FilterOption.OnItemSelected += OnItemSelected; FilterOption.OnItemSelected += OnItemSelected;
ServerListButton.OnPressed += a => OnServerListButtonPressed?.Invoke(a); ServerListButton.OnPressed += a => OnServerListButtonPressed?.Invoke(a);
DeleteFabricating.OnPressed += _ => DeleteFabricatingAction?.Invoke();
} }
public void SetEntity(EntityUid uid) public void SetEntity(EntityUid uid)
@@ -97,7 +83,7 @@ public sealed partial class LatheMenu : DefaultWindow
var recipesToShow = new List<LatheRecipePrototype>(); var recipesToShow = new List<LatheRecipePrototype>();
foreach (var recipe in Recipes) foreach (var recipe in Recipes)
{ {
if (!_prototypeManager.Resolve(recipe, out var proto)) if (!_prototypeManager.TryIndex(recipe, out var proto))
continue; continue;
// Category filtering // Category filtering
@@ -129,50 +115,21 @@ public sealed partial class LatheMenu : DefaultWindow
RecipeCount.Text = Loc.GetString("lathe-menu-recipe-count", ("count", recipesToShow.Count)); RecipeCount.Text = Loc.GetString("lathe-menu-recipe-count", ("count", recipesToShow.Count));
var sortedRecipesToShow = recipesToShow.OrderBy(_lathe.GetRecipeName); var sortedRecipesToShow = recipesToShow.OrderBy(_lathe.GetRecipeName);
RecipeList.Children.Clear();
// Get the existing list of queue controls
var oldChildCount = RecipeList.ChildCount;
_entityManager.TryGetComponent(Entity, out LatheComponent? lathe); _entityManager.TryGetComponent(Entity, out LatheComponent? lathe);
int idx = 0;
foreach (var prototype in sortedRecipesToShow) foreach (var prototype in sortedRecipesToShow)
{ {
var canProduce = _lathe.CanProduce(Entity, prototype, quantity, component: lathe); var canProduce = _lathe.CanProduce(Entity, prototype, quantity, component: lathe);
var tooltipFunction = () => GenerateTooltipText(prototype);
if (idx >= oldChildCount) var control = new RecipeControl(_lathe, prototype, () => GenerateTooltipText(prototype), canProduce, GetRecipeDisplayControl(prototype));
control.OnButtonPressed += s =>
{ {
var control = new RecipeControl(_lathe, prototype, tooltipFunction, canProduce, GetRecipeDisplayControl(prototype)); if (!int.TryParse(AmountLineEdit.Text, out var amount) || amount <= 0)
control.OnButtonPressed += s => amount = 1;
{ RecipeQueueAction?.Invoke(s, amount);
if (!int.TryParse(AmountLineEdit.Text, out var amount) || amount <= 0) };
amount = 1; RecipeList.AddChild(control);
RecipeQueueAction?.Invoke(s, amount);
};
RecipeList.AddChild(control);
}
else
{
var child = RecipeList.GetChild(idx) as RecipeControl;
if (child == null)
{
DebugTools.Assert($"Lathe menu recipe control at {idx} is not of type RecipeControl"); // Something's gone terribly wrong.
continue;
}
child.SetRecipe(prototype);
child.SetTooltipSupplier(tooltipFunction);
child.SetCanProduce(canProduce);
child.SetDisplayControl(GetRecipeDisplayControl(prototype));
}
idx++;
}
// Shrink list if new list is shorter than old list.
for (var childIdx = oldChildCount - 1; idx <= childIdx; childIdx--)
{
RecipeList.RemoveChild(childIdx);
} }
} }
@@ -183,7 +140,7 @@ public sealed partial class LatheMenu : DefaultWindow
foreach (var (id, amount) in prototype.Materials) foreach (var (id, amount) in prototype.Materials)
{ {
if (!_prototypeManager.Resolve(id, out var proto)) if (!_prototypeManager.TryIndex(id, out var proto))
continue; continue;
var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, multiplier); var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, multiplier);
@@ -266,53 +223,25 @@ public sealed partial class LatheMenu : DefaultWindow
/// Populates the build queue list with all queued items /// Populates the build queue list with all queued items
/// </summary> /// </summary>
/// <param name="queue"></param> /// <param name="queue"></param>
public void PopulateQueueList(IReadOnlyCollection<LatheRecipeBatch> queue) public void PopulateQueueList(IReadOnlyCollection<ProtoId<LatheRecipePrototype>> queue)
{ {
// Get the existing list of queue controls QueueList.DisposeAllChildren();
var oldChildCount = QueueList.ChildCount;
var idx = 0; var idx = 1;
foreach (var batch in queue) foreach (var recipeProto in queue)
{ {
var recipe = _prototypeManager.Index(batch.Recipe); var recipe = _prototypeManager.Index(recipeProto);
var queuedRecipeBox = new BoxContainer();
queuedRecipeBox.Orientation = BoxContainer.LayoutOrientation.Horizontal;
var itemName = _lathe.GetRecipeName(batch.Recipe); queuedRecipeBox.AddChild(GetRecipeDisplayControl(recipe));
string displayText;
if (batch.ItemsRequested > 1)
displayText = Loc.GetString("lathe-menu-item-batch", ("index", idx + 1), ("name", itemName), ("printed", batch.ItemsPrinted), ("total", batch.ItemsRequested));
else
displayText = Loc.GetString("lathe-menu-item-single", ("index", idx + 1), ("name", itemName));
if (idx >= oldChildCount) var queuedRecipeLabel = new Label();
{ queuedRecipeLabel.Text = $"{idx}. {_lathe.GetRecipeName(recipe)}";
var queuedRecipeBox = new QueuedRecipeControl(displayText, idx, GetRecipeDisplayControl(recipe)); queuedRecipeBox.AddChild(queuedRecipeLabel);
queuedRecipeBox.OnDeletePressed += s => QueueDeleteAction?.Invoke(s); QueueList.AddChild(queuedRecipeBox);
queuedRecipeBox.OnMoveUpPressed += s => QueueMoveUpAction?.Invoke(s);
queuedRecipeBox.OnMoveDownPressed += s => QueueMoveDownAction?.Invoke(s);
QueueList.AddChild(queuedRecipeBox);
}
else
{
var child = QueueList.GetChild(idx) as QueuedRecipeControl;
if (child == null)
{
DebugTools.Assert($"Lathe menu queued recipe control at {idx} is not of type QueuedRecipeControl"); // Something's gone terribly wrong.
continue;
}
child.SetDisplayText(displayText);
child.SetIndex(idx);
child.SetDisplayControl(GetRecipeDisplayControl(recipe));
}
idx++; idx++;
} }
// Shrink list if new list is shorter than old list.
for (var childIdx = oldChildCount - 1; idx <= childIdx; childIdx--)
{
QueueList.RemoveChild(childIdx);
}
} }
public void SetQueueInfo(ProtoId<LatheRecipePrototype>? recipeProto) public void SetQueueInfo(ProtoId<LatheRecipePrototype>? recipeProto)

View File

@@ -1,35 +0,0 @@
<Control xmlns="https://spacestation14.io"
xmlns:system="clr-namespace:System;assembly=System.Runtime">
<BoxContainer Orientation="Horizontal">
<BoxContainer
Name="RecipeDisplayContainer"
Margin="0 0 4 0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
MinSize="32 32"
/>
<Label Name="RecipeName" HorizontalExpand="True" />
<Button
Name="MoveUp"
Margin="0"
Text="⏶"
StyleClasses="OpenRight"
ToolTip="{Loc 'lathe-menu-move-up-tooltip'}"/>
<Button
Name="MoveDown"
Margin="0"
Text="⏷"
StyleClasses="OpenBoth"
ToolTip="{Loc 'lathe-menu-move-down-tooltip'}"/>
<Button
Name="Delete"
Margin="0"
Text="✖"
ToolTip="{Loc 'lathe-menu-delete-item-tooltip'}">
<Button.StyleClasses>
<system:String>Caution</system:String>
<system:String>OpenLeft</system:String>
</Button.StyleClasses>
</Button>
</BoxContainer>
</Control>

View File

@@ -1,56 +0,0 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Lathe.UI;
[GenerateTypedNameReferences]
public sealed partial class QueuedRecipeControl : Control
{
public Action<int>? OnDeletePressed;
public Action<int>? OnMoveUpPressed;
public Action<int>? OnMoveDownPressed;
private int _index;
public QueuedRecipeControl(string displayText, int index, Control displayControl)
{
RobustXamlLoader.Load(this);
SetDisplayText(displayText);
SetDisplayControl(displayControl);
SetIndex(index);
_index = index;
MoveUp.OnPressed += (_) =>
{
OnMoveUpPressed?.Invoke(_index);
};
MoveDown.OnPressed += (_) =>
{
OnMoveDownPressed?.Invoke(_index);
};
Delete.OnPressed += (_) =>
{
OnDeletePressed?.Invoke(_index);
};
}
public void SetDisplayText(string displayText)
{
RecipeName.Text = displayText;
}
public void SetDisplayControl(Control displayControl)
{
RecipeDisplayContainer.Children.Clear();
RecipeDisplayContainer.AddChild(displayControl);
}
public void SetIndex(int index)
{
_index = index;
}
}

View File

@@ -2,7 +2,6 @@ using Content.Shared.Research.Prototypes;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Lathe.UI; namespace Content.Client.Lathe.UI;
@@ -12,47 +11,20 @@ public sealed partial class RecipeControl : Control
public Action<string>? OnButtonPressed; public Action<string>? OnButtonPressed;
public Func<string> TooltipTextSupplier; public Func<string> TooltipTextSupplier;
private ProtoId<LatheRecipePrototype> _recipeId;
private LatheSystem _latheSystem;
public RecipeControl(LatheSystem latheSystem, LatheRecipePrototype recipe, Func<string> tooltipTextSupplier, bool canProduce, Control displayControl) public RecipeControl(LatheSystem latheSystem, LatheRecipePrototype recipe, Func<string> tooltipTextSupplier, bool canProduce, Control displayControl)
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
_latheSystem = latheSystem; RecipeName.Text = latheSystem.GetRecipeName(recipe);
_recipeId = recipe.ID; RecipeDisplayContainer.AddChild(displayControl);
Button.Disabled = !canProduce;
TooltipTextSupplier = tooltipTextSupplier; TooltipTextSupplier = tooltipTextSupplier;
SetRecipe(recipe); Button.TooltipSupplier = SupplyTooltip;
SetCanProduce(canProduce);
SetDisplayControl(displayControl);
Button.OnPressed += (_) => Button.OnPressed += (_) =>
{ {
OnButtonPressed?.Invoke(_recipeId); OnButtonPressed?.Invoke(recipe.ID);
}; };
Button.TooltipSupplier = SupplyTooltip;
}
public void SetRecipe(LatheRecipePrototype recipe)
{
RecipeName.Text = _latheSystem.GetRecipeName(recipe);
_recipeId = recipe.ID;
}
public void SetTooltipSupplier(Func<string> tooltipTextSupplier)
{
TooltipTextSupplier = tooltipTextSupplier;
}
public void SetCanProduce(bool canProduce)
{
Button.Disabled = !canProduce;
}
public void SetDisplayControl(Control displayControl)
{
RecipeDisplayContainer.Children.Clear();
RecipeDisplayContainer.AddChild(displayControl);
} }
private Control? SupplyTooltip(Control sender) private Control? SupplyTooltip(Control sender)

View File

@@ -1,46 +1,36 @@
using Content.Shared.Light.Components; using Content.Shared.Light.Components;
using Content.Shared.Light.EntitySystems;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
namespace Content.Client.Light.EntitySystems; namespace Content.Client.Light.Visualizers;
public sealed class LightBulbSystem : SharedLightBulbSystem public sealed class LightBulbSystem : VisualizerSystem<LightBulbComponent>
{ {
[Dependency] private readonly AppearanceSystem _appearance = default!; protected override void OnAppearanceChange(EntityUid uid, LightBulbComponent comp, ref AppearanceChangeEvent args)
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<LightBulbComponent, AppearanceChangeEvent>(OnAppearanceChange);
}
private void OnAppearanceChange(EntityUid uid, LightBulbComponent comp, ref AppearanceChangeEvent args)
{ {
if (args.Sprite == null) if (args.Sprite == null)
return; return;
// update sprite state // update sprite state
if (_appearance.TryGetData<LightBulbState>(uid, LightBulbVisuals.State, out var state, args.Component)) if (AppearanceSystem.TryGetData<LightBulbState>(uid, LightBulbVisuals.State, out var state, args.Component))
{ {
switch (state) switch (state)
{ {
case LightBulbState.Normal: case LightBulbState.Normal:
_sprite.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.NormalSpriteState); SpriteSystem.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.NormalSpriteState);
break; break;
case LightBulbState.Broken: case LightBulbState.Broken:
_sprite.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.BrokenSpriteState); SpriteSystem.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.BrokenSpriteState);
break; break;
case LightBulbState.Burned: case LightBulbState.Burned:
_sprite.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.BurnedSpriteState); SpriteSystem.LayerSetRsiState((uid, args.Sprite), LightBulbVisualLayers.Base, comp.BurnedSpriteState);
break; break;
} }
} }
// also update sprites color // also update sprites color
if (_appearance.TryGetData<Color>(uid, LightBulbVisuals.Color, out var color, args.Component)) if (AppearanceSystem.TryGetData<Color>(uid, LightBulbVisuals.Color, out var color, args.Component))
{ {
_sprite.SetColor((uid, args.Sprite), color); SpriteSystem.SetColor((uid, args.Sprite), color);
} }
} }
} }

View File

@@ -1,5 +0,0 @@
using Content.Shared.Light.EntitySystems;
namespace Content.Client.Light.EntitySystems;
public sealed class PoweredLightSystem : SharedPoweredLightSystem;

View File

@@ -72,7 +72,6 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
}); });
_configurationManager.OnValueChanged(CCVars.GameRoleTimers, _ => RefreshProfileEditor()); _configurationManager.OnValueChanged(CCVars.GameRoleTimers, _ => RefreshProfileEditor());
_configurationManager.OnValueChanged(CCVars.GameRoleLoadoutTimers, _ => RefreshProfileEditor());
_configurationManager.OnValueChanged(CCVars.GameRoleWhitelist, _ => RefreshProfileEditor()); _configurationManager.OnValueChanged(CCVars.GameRoleWhitelist, _ => RefreshProfileEditor());
} }
@@ -362,7 +361,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
{ {
foreach (var loadout in group) foreach (var loadout in group)
{ {
if (!_prototypeManager.Resolve(loadout.Prototype, out var loadoutProto)) if (!_prototypeManager.TryIndex(loadout.Prototype, out var loadoutProto))
continue; continue;
_spawn.EquipStartingGear(uid, loadoutProto); _spawn.EquipStartingGear(uid, loadoutProto);
@@ -385,14 +384,14 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
{ {
foreach (var loadout in loadouts) foreach (var loadout in loadouts)
{ {
if (!_prototypeManager.Resolve(loadout.Prototype, out var loadoutProto)) if (!_prototypeManager.TryIndex(loadout.Prototype, out var loadoutProto))
continue; continue;
// TODO: Need some way to apply starting gear to an entity and replace existing stuff coz holy fucking shit dude. // TODO: Need some way to apply starting gear to an entity and replace existing stuff coz holy fucking shit dude.
foreach (var slot in slots) foreach (var slot in slots)
{ {
// Try startinggear first // Try startinggear first
if (_prototypeManager.Resolve(loadoutProto.StartingGear, out var loadoutGear)) if (_prototypeManager.TryIndex(loadoutProto.StartingGear, out var loadoutGear))
{ {
var itemType = ((IEquipmentLoadout) loadoutGear).GetGear(slot.Name); var itemType = ((IEquipmentLoadout) loadoutGear).GetGear(slot.Name);
@@ -427,7 +426,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered<LobbyState
} }
} }
if (!_prototypeManager.Resolve(job.StartingGear, out var gear)) if (!_prototypeManager.TryIndex(job.StartingGear, out var gear))
return; return;
foreach (var slot in slots) foreach (var slot in slots)

View File

@@ -9,6 +9,7 @@ using Content.Client.Players.PlayTimeTracking;
using Content.Client.Sprite; using Content.Client.Sprite;
using Content.Client.Stylesheets; using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.Guidebook; using Content.Client.UserInterface.Systems.Guidebook;
using Content.Shared._CP14.Humanoid;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Clothing; using Content.Shared.Clothing;
using Content.Shared.GameTicking; using Content.Shared.GameTicking;
@@ -810,7 +811,7 @@ namespace Content.Client.Lobby.UI
if (_prototypeManager.HasIndex<GuideEntryPrototype>(species)) if (_prototypeManager.HasIndex<GuideEntryPrototype>(species))
page = new ProtoId<GuideEntryPrototype>(species.Id); // Gross. See above todo comment. page = new ProtoId<GuideEntryPrototype>(species.Id); // Gross. See above todo comment.
if (_prototypeManager.Resolve(DefaultSpeciesGuidebook, out var guideRoot)) if (_prototypeManager.TryIndex(DefaultSpeciesGuidebook, out var guideRoot))
{ {
var dict = new Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>(); var dict = new Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>();
dict.Add(DefaultSpeciesGuidebook, guideRoot); dict.Add(DefaultSpeciesGuidebook, guideRoot);
@@ -1020,7 +1021,7 @@ namespace Content.Client.Lobby.UI
_loadoutWindow = new LoadoutWindow(Profile, roleLoadout, roleLoadoutProto, _playerManager.LocalSession, collection) _loadoutWindow = new LoadoutWindow(Profile, roleLoadout, roleLoadoutProto, _playerManager.LocalSession, collection)
{ {
Title = Loc.GetString("loadout-window-title-loadout", ("job", $"{jobProto?.LocalizedName}")), Title = jobProto?.ID + "-loadout",
}; };
// Refresh the buttons etc. // Refresh the buttons etc.
@@ -1088,11 +1089,10 @@ namespace Content.Client.Lobby.UI
if (Profile is null) return; if (Profile is null) return;
var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration; var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration;
var strategy = _prototypeManager.Index(skin).Strategy;
switch (strategy.InputType) switch (skin)
{ {
case SkinColorationStrategyInput.Unary: case HumanoidSkinColor.HumanToned:
{ {
if (!Skin.Visible) if (!Skin.Visible)
{ {
@@ -1100,14 +1100,13 @@ namespace Content.Client.Lobby.UI
RgbSkinColorContainer.Visible = false; RgbSkinColorContainer.Visible = false;
} }
var color = strategy.FromUnary(Skin.Value); var color = SkinColor.HumanSkinTone((int) Skin.Value);
Markings.CurrentSkinColor = color; Markings.CurrentSkinColor = color;
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color)); Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));//
break; break;
} }
case SkinColorationStrategyInput.Color: case HumanoidSkinColor.Hues:
{ {
if (!RgbSkinColorContainer.Visible) if (!RgbSkinColorContainer.Visible)
{ {
@@ -1115,13 +1114,54 @@ namespace Content.Client.Lobby.UI
RgbSkinColorContainer.Visible = true; RgbSkinColorContainer.Visible = true;
} }
var color = strategy.ClosestSkinColor(_rgbSkinColorSelector.Color); Markings.CurrentSkinColor = _rgbSkinColorSelector.Color;
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(_rgbSkinColorSelector.Color));
break;
}
case HumanoidSkinColor.TintedHues:
{
if (!RgbSkinColorContainer.Visible)
{
Skin.Visible = false;
RgbSkinColorContainer.Visible = true;
}
var color = SkinColor.TintedHues(_rgbSkinColorSelector.Color);
Markings.CurrentSkinColor = color; Markings.CurrentSkinColor = color;
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color)); Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
break; break;
} }
case HumanoidSkinColor.VoxFeathers:
{
if (!RgbSkinColorContainer.Visible)
{
Skin.Visible = false;
RgbSkinColorContainer.Visible = true;
}
var color = SkinColor.ClosestVoxColor(_rgbSkinColorSelector.Color);
Markings.CurrentSkinColor = color;
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
break;
}
// CP14 - Custom HumanoidSkinColor - Start
case HumanoidSkinColor.TieflingHues:
{
if (!RgbSkinColorContainer.Visible)
{
Skin.Visible = false;
RgbSkinColorContainer.Visible = true;
}
var color = CP14SkinColor.MakeTieflingHueValid(_rgbSkinColorSelector.Color);
Markings.CurrentSkinColor = color;
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
break;
}
// CP14 - Custom HumanoidSkinColor - End
} }
ReloadProfilePreview(); ReloadProfilePreview();
@@ -1268,7 +1308,7 @@ namespace Content.Client.Lobby.UI
var sexes = new List<Sex>(); var sexes = new List<Sex>();
// add species sex options, default to just none if we are in bizzaro world and have no species // add species sex options, default to just none if we are in bizzaro world and have no species
if (_prototypeManager.Resolve<SpeciesPrototype>(Profile.Species, out var speciesProto)) if (_prototypeManager.TryIndex<SpeciesPrototype>(Profile.Species, out var speciesProto))
{ {
foreach (var sex in speciesProto.Sexes) foreach (var sex in speciesProto.Sexes)
{ {
@@ -1298,11 +1338,10 @@ namespace Content.Client.Lobby.UI
return; return;
var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration; var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration;
var strategy = _prototypeManager.Index(skin).Strategy;
switch (strategy.InputType) switch (skin)
{ {
case SkinColorationStrategyInput.Unary: case HumanoidSkinColor.HumanToned:
{ {
if (!Skin.Visible) if (!Skin.Visible)
{ {
@@ -1310,11 +1349,11 @@ namespace Content.Client.Lobby.UI
RgbSkinColorContainer.Visible = false; RgbSkinColorContainer.Visible = false;
} }
Skin.Value = strategy.ToUnary(Profile.Appearance.SkinColor); Skin.Value = SkinColor.HumanSkinToneFromColor(Profile.Appearance.SkinColor);
break; break;
} }
case SkinColorationStrategyInput.Color: case HumanoidSkinColor.Hues:
{ {
if (!RgbSkinColorContainer.Visible) if (!RgbSkinColorContainer.Visible)
{ {
@@ -1322,11 +1361,49 @@ namespace Content.Client.Lobby.UI
RgbSkinColorContainer.Visible = true; RgbSkinColorContainer.Visible = true;
} }
_rgbSkinColorSelector.Color = strategy.ClosestSkinColor(Profile.Appearance.SkinColor); // set the RGB values to the direct values otherwise
_rgbSkinColorSelector.Color = Profile.Appearance.SkinColor;
break;
}
case HumanoidSkinColor.TintedHues:
{
if (!RgbSkinColorContainer.Visible)
{
Skin.Visible = false;
RgbSkinColorContainer.Visible = true;
}
// set the RGB values to the direct values otherwise
_rgbSkinColorSelector.Color = Profile.Appearance.SkinColor;
break;
}
case HumanoidSkinColor.VoxFeathers:
{
if (!RgbSkinColorContainer.Visible)
{
Skin.Visible = false;
RgbSkinColorContainer.Visible = true;
}
_rgbSkinColorSelector.Color = SkinColor.ClosestVoxColor(Profile.Appearance.SkinColor);
break; break;
} }
// CP14 - Custom HumanoidSkinColor - Start
case HumanoidSkinColor.TieflingHues:
{
if (!RgbSkinColorContainer.Visible)
{
Skin.Visible = false;
RgbSkinColorContainer.Visible = true;
}
_rgbSkinColorSelector.Color = CP14SkinColor.MakeTieflingHueValid(Profile.Appearance.SkinColor);
break;
}
// CP14 - Custom HumanoidSkinColor - End
} }
} }
public void UpdateSpeciesGuidebookIcon() public void UpdateSpeciesGuidebookIcon()
@@ -1337,7 +1414,7 @@ namespace Content.Client.Lobby.UI
if (species is null) if (species is null)
return; return;
if (!_prototypeManager.Resolve<SpeciesPrototype>(species, out var speciesProto)) if (!_prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesProto))
return; return;
// Don't display the info button if no guide entry is found // Don't display the info button if no guide entry is found

View File

@@ -40,7 +40,7 @@ public sealed partial class LoadoutContainer : BoxContainer
SelectButton.TooltipSupplier = _ => tooltip; SelectButton.TooltipSupplier = _ => tooltip;
} }
if (_protoManager.Resolve(proto, out var loadProto)) if (_protoManager.TryIndex(proto, out var loadProto))
{ {
var ent = loadProto.DummyEntity ?? _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto); var ent = loadProto.DummyEntity ?? _entManager.System<LoadoutSystem>().GetFirstOrNull(loadProto);

View File

@@ -62,7 +62,7 @@ public sealed partial class LoadoutGroupContainer : BoxContainer
}); });
} }
if (protoMan.Resolve(loadout.Role, out var roleProto) && roleProto.Points != null && loadout.Points != null) if (protoMan.TryIndex(loadout.Role, out var roleProto) && roleProto.Points != null && loadout.Points != null)
{ {
RestrictionsContainer.AddChild(new Label() RestrictionsContainer.AddChild(new Label()
{ {

View File

@@ -68,7 +68,7 @@ public sealed partial class LoadoutWindow : FancyWindow
{ {
foreach (var group in proto.Groups) foreach (var group in proto.Groups)
{ {
if (!protoManager.Resolve(group, out var groupProto)) if (!protoManager.TryIndex(group, out var groupProto))
continue; continue;
if (groupProto.Hidden) if (groupProto.Hidden)

View File

@@ -64,9 +64,7 @@ public sealed partial class CrewMonitoringNavMapControl : NavMapControl
if (!LocalizedNames.TryGetValue(netEntity, out var name)) if (!LocalizedNames.TryGetValue(netEntity, out var name))
name = "Unknown"; name = "Unknown";
var message = name + "\n" + Loc.GetString("navmap-location", var message = name + "\nLocation: [x = " + MathF.Round(blip.Coordinates.X) + ", y = " + MathF.Round(blip.Coordinates.Y) + "]";
("x", MathF.Round(blip.Coordinates.X)),
("y", MathF.Round(blip.Coordinates.Y)));
_trackedEntityLabel.Text = message; _trackedEntityLabel.Text = message;
_trackedEntityPanel.Visible = true; _trackedEntityPanel.Visible = true;

Some files were not shown because too many files have changed in this diff Show More