Merge remote-tracking branch 'space-wizards/master'

# Conflicts:
#	.github/workflows/publish.yml
#	Content.Client/Clothing/ClientClothingSystem.cs
#	Content.Client/Clothing/Systems/ChameleonClothingSystem.cs
#	Content.Client/Fax/UI/FaxWindow.xaml
#	Content.Client/Ghost/GhostSystem.cs
#	Content.Client/Holiday/HolidaySystem.cs
#	Content.Client/Humanoid/HumanoidAppearanceSystem.cs
#	Content.Client/Lobby/UI/Loadouts/LoadoutWindow.xaml.cs
#	Content.Client/Lobby/UI/LobbyGui.xaml
#	Content.Client/Lobby/UI/LobbyGui.xaml.cs
#	Content.Client/Mech/MechSystem.cs
#	Content.Client/Stealth/StealthSystem.cs
#	Content.Client/Weapons/Ranged/Systems/GunSystem.cs
#	Content.Server.Database/Migrations/Sqlite/SqliteServerDbContextModelSnapshot.cs
#	Content.Server/Bed/BedSystem.cs
#	Content.Server/Body/Systems/BodySystem.cs
#	Content.Server/Body/Systems/RespiratorSystem.cs
#	Content.Server/Cargo/Systems/CargoSystem.Orders.cs
#	Content.Server/Communications/CommunicationsConsoleComponent.cs
#	Content.Server/EntityEffects/Effects/AreaReactionEffect.cs
#	Content.Server/EntityEffects/Effects/MakeSentient.cs
#	Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustPests.cs
#	Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustToxins.cs
#	Content.Server/EntityEffects/Effects/PlantMetabolism/PlantAdjustWeeds.cs
#	Content.Server/EntityEffects/Effects/PlantMutateGases.cs
#	Content.Server/Fluids/EntitySystems/AbsorbentSystem.cs
#	Content.Server/GameTicking/GameTicker.Spawning.cs
#	Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs
#	Content.Server/IoC/ServerContentIoC.cs
#	Content.Server/Nutrition/EntitySystems/FoodSystem.cs
#	Content.Server/Power/EntitySystems/PowerNetSystem.cs
#	Content.Server/Preferences/Managers/ServerPreferencesManager.cs
#	Content.Server/RoundEnd/RoundEndSystem.cs
#	Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs
#	Content.Server/Station/Systems/StationSpawningSystem.cs
#	Content.Server/VoiceMask/VoiceMaskSystem.cs
#	Content.Server/Weapons/Ranged/Systems/GunSystem.cs
#	Content.Shared/Bed/Components/HealOnBuckleComponent.cs
#	Content.Shared/Clothing/EntitySystems/ClothingSystem.cs
#	Content.Shared/EntityEffects/Effects/ExplosionReactionEffect.cs
#	Content.Shared/Inventory/InventorySystem.Relay.cs
#	Content.Shared/Item/ItemToggle/Components/ComponentTogglerComponent.cs
#	Content.Shared/Preferences/HumanoidCharacterProfile.cs
#	Content.Shared/Preferences/Loadouts/RoleLoadout.cs
#	Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs
#	Content.Shared/Wieldable/SharedWieldableSystem.cs
#	Resources/Audio/Machines/attributions.yml
#	Resources/Locale/en-US/_strings/atmos/plaque-component.ftl
#	Resources/Locale/en-US/_strings/chat/chat-channel.ftl
#	Resources/Locale/en-US/_strings/components/screen-component.ftl
#	Resources/Locale/en-US/_strings/inventory/components/slot-block-component.ftl
#	Resources/Locale/en-US/_strings/mass-media/news-discord.ftl
#	Resources/Locale/en-US/_strings/objectives/commands/stripall.ftl
#	Resources/Locale/en-US/_strings/salvage/job-board.ftl
#	Resources/Locale/en-US/_strings/ui/spray-painter-window.ftl
#	Resources/Locale/en-US/_strings/ui/turret-controls.ftl
#	Resources/Maps/_Sunrise/Station/box.yml
#	Resources/Prototypes/Access/misc.yml
#	Resources/Prototypes/Catalog/Fills/Boxes/emergency.yml
#	Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml
#	Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
#	Resources/Prototypes/Catalog/Fills/Lockers/service.yml
#	Resources/Prototypes/Catalog/Fills/Lockers/suit_storage.yml
#	Resources/Prototypes/Entities/Clothing/Head/helmets.yml
#	Resources/Prototypes/Entities/Clothing/Masks/masks.yml
#	Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
#	Resources/Prototypes/Entities/Markers/Spawners/mobs.yml
#	Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
#	Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
#	Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
#	Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
#	Resources/Prototypes/Entities/Mobs/Player/dragon.yml
#	Resources/Prototypes/Entities/Mobs/Player/silicon.yml
#	Resources/Prototypes/Entities/Mobs/Species/arachnid.yml
#	Resources/Prototypes/Entities/Mobs/Species/moth.yml
#	Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml
#	Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml
#	Resources/Prototypes/LootTables/suspicion_loot_table.yml
#	Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml
#	Resources/Prototypes/Reagents/medicine.yml
#	Resources/Prototypes/Recipes/Lathes/Packs/science.yml
#	Resources/Prototypes/Recipes/Lathes/medical.yml
#	Resources/Prototypes/SoundCollections/NukeMusic.yml
#	Resources/ServerInfo/Guidebook/Cargo/Salvage.xml
#	Resources/Textures/Clothing/Hands/Gloves/KnuckleDusters/brassknuckleduster.rsi/equipped-OUTERCLOTHING-reptilian.png
#	Resources/Textures/Clothing/OuterClothing/Hardsuits/basic.rsi/meta.json
#	Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/meta.json
#	Resources/Textures/Clothing/OuterClothing/Suits/eva_emergency.rsi/meta.json
#	Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/meta.json
#	Resources/Textures/Effects/speech.rsi/alien3.png
#	Resources/Textures/Effects/speech.rsi/alienroyal3.png
#	Resources/Textures/Effects/speech.rsi/default3.png
#	Resources/Textures/Effects/speech.rsi/guardian3.png
#	Resources/Textures/Effects/speech.rsi/holo3.png
#	Resources/Textures/Effects/speech.rsi/lawyer3.png
#	Resources/Textures/Effects/speech.rsi/lizard3.png
#	Resources/Textures/Effects/speech.rsi/meta.json
#	Resources/Textures/Effects/speech.rsi/moth3.png
#	Resources/Textures/Effects/speech.rsi/robot3.png
#	Resources/Textures/Effects/speech.rsi/slime3.png
#	Resources/Textures/Effects/speech.rsi/spider3.png
#	Resources/Textures/Effects/speech.rsi/syndibot3.png
#	Resources/Textures/Interface/Misc/job_icons.rsi/meta.json
#	Resources/Textures/Mobs/Silicon/chassis.rsi/meta.json
#	Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_f.png
#	Resources/Textures/Mobs/Species/Reptilian/parts.rsi/head_m.png
#	Resources/Textures/Objects/Misc/id_cards.rsi/meta.json
#	Resources/Textures/Structures/Doors/Airlocks/Glass/external.rsi/emergency_unlit.png
#	Resources/Textures/Structures/Piping/disposal.rsi/meta.json
#	Resources/Textures/Tiles/attributions.yml
#	Resources/Textures/Tiles/steel_dirty.png
#	Resources/migration.yml
#	runclient-Tools.bat
#	runclient.bat
This commit is contained in:
Vigers Ray 2025-05-27 03:41:41 +03:00
commit d6c0a011b7
1712 changed files with 327602 additions and 284989 deletions

2
.github/CODEOWNERS vendored
View file

@ -8,7 +8,7 @@
/Resources/ServerInfo/ @nikthechampiongr @crazybrain23 /Resources/ServerInfo/ @nikthechampiongr @crazybrain23
/Resources/ServerInfo/Guidebook/ServerRules/ @nikthechampiongr @crazybrain23 /Resources/ServerInfo/Guidebook/ServerRules/ @nikthechampiongr @crazybrain23
/Resources/Prototypes/Maps/** @Emisse /Resources/Prototypes/Maps/** @Emisse @ArtisticRoomba
/Resources/Prototypes/Body/ @DrSmugleaf # suffering /Resources/Prototypes/Body/ @DrSmugleaf # suffering
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf /Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf

View file

@ -0,0 +1,54 @@
name: Trailing Whitespace Check
on:
pull_request:
types: [ opened, reopened, synchronize, ready_for_review ]
jobs:
build:
name: Trailing Whitespace Check
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- name: Get changed text files
id: changed-files
uses: tj-actions/changed-files@v46.0.5
with:
files: |
**.cs
**.yml
**.swsl
**.json
**.py
- name: Check for trailing whitespace and EOF newline
env:
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: |
has_trailing_whitespace=0
has_missing_eof_newline=0
for file in ${ALL_CHANGED_FILES}; do
echo "Checking $file"
# Check for trailing whitespace
if grep -qP '[ \t]+$' "$file"; then
echo "::error file=$file::Trailing whitespace found"
has_trailing_whitespace=1
fi
# Check for missing EOF newline
if [ -f "$file" ] && [ -s "$file" ]; then
last_char=$(tail -c 1 "$file")
if [ "$last_char" != "" ] && [ "$last_char" != $'\n' ]; then
echo "::error file=$file::Missing newline at end of file"
has_missing_eof_newline=1
fi
fi
done
if [ "$has_trailing_whitespace" -eq 1 ] || [ "$has_missing_eof_newline" -eq 1 ]; then
echo "Issues found: trailing whitespace or missing EOF newline."
echo "We recommend using an IDE to prevent this from happening."
exit 1
fi

View file

@ -2,6 +2,7 @@
concurrency: concurrency:
group: publish-testing group: publish-testing
cancel-in-progress: true
on: on:
workflow_dispatch: workflow_dispatch:

View file

@ -2,6 +2,7 @@ name: Publish
concurrency: concurrency:
group: publish group: publish
cancel-in-progress: true
on: on:
workflow_dispatch: workflow_dispatch:
@ -68,18 +69,21 @@ jobs:
DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_SUNRISE }} DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_SUNRISE }}
- name: Publish discord changelog (LUST) - name: Publish discord changelog (LUST)
continue-on-error: true
run: Tools/_sunrise/actions_changelogs_since_last_run.py run: Tools/_sunrise/actions_changelogs_since_last_run.py
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_LUST }} DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_LUST }}
- name: Publish discord changelog (FISH) - name: Publish discord changelog (FISH)
continue-on-error: true
run: Tools/_sunrise/actions_changelogs_since_last_run.py run: Tools/_sunrise/actions_changelogs_since_last_run.py
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_FISH }} DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_FISH }}
# - name: Publish changelog (RSS) # - name: Publish changelog (RSS)
# continue-on-error: true
# run: Tools/actions_changelog_rss.py # run: Tools/actions_changelog_rss.py
# env: # env:
# CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }} # CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }}

40
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,40 @@
# Space Station 14 Code of Conduct
Space Station 14's staff and community is made up volunteers from all over the world, working on every aspect of the project - including development, teaching, and hosting integral tools.
Diversity is one of our huge strengths, but it can also lead to communication issues and unhappiness. To that end, we have a few ground rules that we ask people to adhere to. This code applies equally to all levels of the project, from commenters to contributors to staff.
This isnt an exhaustive list of things that you cant do. Rather, take it in the spirit in which its intended - a guide to make it easier to enrich all of us and the technical communities in which we participate.
This code of conduct applies specifically to the Github repositories and its spaces managed by the Space Station 14 project or Space Wizards Federation. Some spaces, such as the Space Station 14 Discord or the official Wizard's Den game servers, have their own rules but are in spirit equal to what may be found in here.
If you believe someone is violating the code of conduct, we ask that you report it by contacting a Maintainer, Project Manager or Wizard staff member through [Discord](https://discord.ss14.io/), [the forums](https://forum.spacestation14.com/), or emailing [telecommunications@spacestation14.com](mailto:telecommunications@spacestation14.com).
- **Be friendly and patient.**
- **Be welcoming.** We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
- **Be considerate.** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and contributors, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language. We have contributors of all skill levels, some even making their first foray into a new field with this project, so keep that in mind when discussing someone's work.
- **Be respectful.** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. Its important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the Space Station 14 community should be respectful when dealing with other members as well as with people outside the Space Station 14 community. Assume contributions to the project, even those that do not end up being included, are made in good faith.
- **Be careful in the words that you choose.** We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
- Violent threats or language directed against another person.
- Discriminatory jokes and language.
- Posting sexually explicit or violent material.
- Posting (or threatening to post) other people's personally identifying information ("doxing").
- Personal insults, especially those using racist or sexist terms.
- Unwelcome sexual attention.
- Advocating for, or encouraging, any of the above behavior.
- Repeated harassment of others. In general, if someone asks you to stop, then stop.
- **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time and Space Station 14 is no exception. It is important that we resolve disagreements and differing views constructively. Remember that were different. The strength of Space Station 14 comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesnt mean that theyre wrong. Dont forget that it is human to make mistakes and blaming each other doesnt get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
Original text courtesy of the [Speak Up! project](http://web.archive.org/web/20141109123859/http://speakup.io/coc.html).
## On Comunity Moderation
Deviating from the Code of Conduct on the Github repository may result in moderative actions taken by project Maintainers. This can involve your content being edited or deleted, and may result in a temporary or permanent block from the repository.
This is to ensure Space Station 14 is a healthy community in which contributors feel encouraged and empowered to contribute, and to give you as a member of this community a chance to reflect on how you are interacting with it. While outright offensive and bigoted content will *always* be unacceptable on the repository, Maintainers are at liberty to take moderative actions against more ambiguous content that fail to provide constructive criticism, or that provides constructive criticism in a non-constructive manner. Examples of this include using hyperbole, bringing up PRs/changes unrelated to the discussion at hand, hostile tone, off-topic comments, creating PRs/Issues for the sole purpose of causing discussions, skirting the line of acceptable behavior, etc. Disagreeing with content or each other is fine and appreciated, but only as long as it's done with respect and in a constructive manner.
Maintainers are expected to adhere to the guidelines as listed in the [Github Moderation Guidelines](https://docs.spacestation14.com/en/general-development/github-moderation-guidelines.html), though may deviate should they feel it's in the best interest of the community. If you believe you had an action incorrectly applied against you, you are encouraged to contact staff via [Discord](https://discord.ss14.io/) or [the forums](https://forum.spacestation14.com/), [appeal your Github ban](https://forum.spacestation14.com/c/ban-appeals/appeals-github/38), or make a [staff complaint](https://forum.spacestation14.com/t/staff-complaint-instructions-and-info/31).
## Attribution
This Code of Conduct is an edited version of the [Django Code of Conduct](https://www.djangoproject.com/conduct/), licensed under CC BY 3.0, for the Space Station 14 Github repository.

View file

@ -29,7 +29,7 @@ namespace Content.Benchmarks;
[CategoriesColumn] [CategoriesColumn]
public class ComponentQueryBenchmark public class ComponentQueryBenchmark
{ {
public const string Map = "Maps/atlas.yml"; public const string Map = "Maps/saltern.yml";
private TestPair _pair = default!; private TestPair _pair = default!;
private IEntityManager _entMan = default!; private IEntityManager _entMan = default!;

View file

@ -1,15 +1,7 @@
using System; using System;
using System.Linq;
using System.Threading.Tasks;
using BenchmarkDotNet.Running; using BenchmarkDotNet.Running;
using Content.IntegrationTests;
using Content.Server.Maps;
#if DEBUG
using BenchmarkDotNet.Configs; using BenchmarkDotNet.Configs;
#else
using Robust.Benchmarks.Configs; using Robust.Benchmarks.Configs;
#endif
using Robust.Shared.Prototypes;
namespace Content.Benchmarks namespace Content.Benchmarks
{ {
@ -22,11 +14,15 @@ namespace Content.Benchmarks
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("\nWARNING: YOU ARE RUNNING A DEBUG BUILD, USE A RELEASE BUILD FOR AN ACCURATE BENCHMARK"); Console.WriteLine("\nWARNING: YOU ARE RUNNING A DEBUG BUILD, USE A RELEASE BUILD FOR AN ACCURATE BENCHMARK");
Console.WriteLine("THE DEBUG BUILD IS ONLY GOOD FOR FIXING A CRASHING BENCHMARK\n"); Console.WriteLine("THE DEBUG BUILD IS ONLY GOOD FOR FIXING A CRASHING BENCHMARK\n");
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, new DebugInProcessConfig()); var baseConfig = new DebugInProcessConfig();
#else #else
var config = Environment.GetEnvironmentVariable("ROBUST_BENCHMARKS_ENABLE_SQL") != null ? DefaultSQLConfig.Instance : null; var baseConfig = Environment.GetEnvironmentVariable("ROBUST_BENCHMARKS_ENABLE_SQL") != null
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config); ? DefaultSQLConfig.Instance
: DefaultConfig.Instance;
#endif #endif
var config = ManualConfig.Create(baseConfig);
config.BuildTimeout = TimeSpan.FromMinutes(5);
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
} }
} }
} }

View file

@ -0,0 +1,126 @@
#nullable enable
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Content.IntegrationTests;
using Content.IntegrationTests.Pair;
using Robust.Shared;
using Robust.Shared.Analyzers;
using Robust.Shared.GameObjects;
namespace Content.Benchmarks;
[Virtual]
public class RaiseEventBenchmark
{
private TestPair _pair = default!;
private BenchSystem _sys = default!;
[GlobalSetup]
public void Setup()
{
ProgramShared.PathOffset = "../../../../";
PoolManager.Startup(typeof(BenchSystem).Assembly);
_pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
var entMan = _pair.Server.EntMan;
_sys = entMan.System<BenchSystem>();
_pair.Server.WaitPost(() =>
{
var uid = entMan.Spawn();
_sys.Ent = new(uid, entMan.GetComponent<TransformComponent>(uid));
_sys.Ent2 = new(_sys.Ent.Owner, _sys.Ent.Comp);
})
.GetAwaiter()
.GetResult();
}
[GlobalCleanup]
public async Task Cleanup()
{
await _pair.DisposeAsync();
PoolManager.Shutdown();
}
[Benchmark(Baseline = true)]
public int RaiseEvent()
{
return _sys.RaiseEvent();
}
[Benchmark]
public int RaiseCompEvent()
{
return _sys.RaiseCompEvent();
}
[Benchmark]
public int RaiseICompEvent()
{
return _sys.RaiseICompEvent();
}
[Benchmark]
public int RaiseCSharpEvent()
{
return _sys.CSharpEvent();
}
public sealed class BenchSystem : EntitySystem
{
public Entity<TransformComponent> Ent;
public Entity<IComponent> Ent2;
public delegate void EntityEventHandler(EntityUid uid, TransformComponent comp, ref BenchEv ev);
public event EntityEventHandler? OnCSharpEvent;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<TransformComponent, BenchEv>(OnEvent);
OnCSharpEvent += OnEvent;
}
public int RaiseEvent()
{
var ev = new BenchEv();
RaiseLocalEvent(Ent.Owner, ref ev);
return ev.N;
}
public int RaiseCompEvent()
{
var ev = new BenchEv();
EntityManager.EventBus.RaiseComponentEvent(Ent.Owner, Ent.Comp, ref ev);
return ev.N;
}
public int RaiseICompEvent()
{
// Raise with an IComponent instead of concrete type
var ev = new BenchEv();
EntityManager.EventBus.RaiseComponentEvent(Ent2.Owner, Ent2.Comp, ref ev);
return ev.N;
}
public int CSharpEvent()
{
var ev = new BenchEv();
OnCSharpEvent?.Invoke(Ent.Owner, Ent.Comp, ref ev);
return ev.N;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void OnEvent(EntityUid uid, TransformComponent component, ref BenchEv args)
{
args.N += uid.Id;
}
[ByRefEvent]
public struct BenchEv
{
public int N;
}
}
}

View file

@ -0,0 +1,26 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Orientation="Horizontal"
Margin="10 10 10 10"
VerticalExpand="True"
HorizontalExpand="True"
MinHeight="70">
<!-- Access groups -->
<BoxContainer Name="AccessGroupList" Access="Public" Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="0.5" Margin="0 0 10 0">
<!-- Populated with C# code -->
</BoxContainer>
<PanelContainer StyleClasses="LowDivider" VerticalExpand="True" Margin="0 0 0 0" SetWidth="2">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#FFFFFF" />
</PanelContainer.PanelOverride>
</PanelContainer>
<!-- Access levels -->
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" Margin="10 0 0 0">
<BoxContainer Name="AccessLevelChecklist" Access="Public" Orientation="Vertical" HorizontalAlignment="Left">
<!-- Populated with C# code -->
</BoxContainer>
</ScrollContainer>
</BoxContainer>

View file

@ -0,0 +1,449 @@
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.Access;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using System.Linq;
using System.Numerics;
namespace Content.Client.Access.UI;
[GenerateTypedNameReferences]
public sealed partial class GroupedAccessLevelChecklist : BoxContainer
{
[Dependency] private readonly IPrototypeManager _protoManager = default!;
private bool _isMonotone;
private string? _labelStyleClass;
// Access data
private HashSet<ProtoId<AccessGroupPrototype>> _accessGroups = new();
private HashSet<ProtoId<AccessLevelPrototype>> _accessLevels = new();
private HashSet<ProtoId<AccessLevelPrototype>> _activeAccessLevels = new();
// Button groups
private readonly ButtonGroup _accessGroupsButtons = new();
// Temp values
private int _accessGroupTabIndex = 0;
private bool _canInteract = false;
private List<AccessLevelPrototype> _accessLevelsForTab = new();
private readonly List<AccessLevelEntry> _accessLevelEntries = new();
private readonly Dictionary<AccessGroupPrototype, List<AccessLevelPrototype>> _groupedAccessLevels = new();
// Events
public event Action<HashSet<ProtoId<AccessLevelPrototype>>, bool>? OnAccessLevelsChangedEvent;
/// <summary>
/// Creates a UI control for changing access levels.
/// Access levels are organized under a list of tabs by their associated access group.
/// </summary>
public GroupedAccessLevelChecklist()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
private void ArrangeAccessControls()
{
// Create a list of known access groups with which to populate the UI
_groupedAccessLevels.Clear();
foreach (var accessGroup in _accessGroups)
{
if (!_protoManager.TryIndex(accessGroup, out var accessGroupProto))
continue;
_groupedAccessLevels.Add(accessGroupProto, new());
}
// Ensure that the 'general' access group is added to handle
// misc. access levels that aren't associated with any group
if (_protoManager.TryIndex<AccessGroupPrototype>("General", out var generalAccessProto))
_groupedAccessLevels.TryAdd(generalAccessProto, new());
// Assign known access levels with their associated groups
foreach (var accessLevel in _accessLevels)
{
if (!_protoManager.TryIndex(accessLevel, out var accessLevelProto))
continue;
var assigned = false;
foreach (var (accessGroup, accessLevels) in _groupedAccessLevels)
{
if (!accessGroup.Tags.Contains(accessLevelProto.ID))
continue;
assigned = true;
_groupedAccessLevels[accessGroup].Add(accessLevelProto);
}
if (!assigned && generalAccessProto != null)
_groupedAccessLevels[generalAccessProto].Add(accessLevelProto);
}
// Remove access groups that have no assigned access levels
foreach (var (group, accessLevels) in _groupedAccessLevels)
{
if (accessLevels.Count == 0)
_groupedAccessLevels.Remove(group);
}
}
private bool TryRebuildAccessGroupControls()
{
AccessGroupList.DisposeAllChildren();
AccessLevelChecklist.DisposeAllChildren();
// No access level prototypes were assigned to any of the access level groups.
// Either the turret controller has no assigned access levels or their names were invalid.
if (_groupedAccessLevels.Count == 0)
return false;
// Reorder the access groups alphabetically
var orderedAccessGroups = _groupedAccessLevels.Keys.OrderBy(x => x.GetAccessGroupName()).ToList();
// Add group access buttons to the UI
foreach (var accessGroup in orderedAccessGroups)
{
var accessGroupButton = CreateAccessGroupButton();
// Button styling
if (_groupedAccessLevels.Count > 1)
{
if (AccessGroupList.ChildCount == 0)
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenLeft);
else if (_groupedAccessLevels.Count > 1 && AccessGroupList.ChildCount == (_groupedAccessLevels.Count - 1))
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenRight);
else
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenBoth);
}
accessGroupButton.Pressed = _accessGroupTabIndex == orderedAccessGroups.IndexOf(accessGroup);
// Label text and styling
if (_labelStyleClass != null)
accessGroupButton.Label.SetOnlyStyleClass(_labelStyleClass);
var accessLevelPrototypes = _groupedAccessLevels[accessGroup];
var prefix = accessLevelPrototypes.All(x => _activeAccessLevels.Contains(x))
? "»"
: accessLevelPrototypes.Any(x => _activeAccessLevels.Contains(x))
? ""
: " ";
var text = Loc.GetString(
"turret-controls-window-access-group-label",
("prefix", prefix),
("label", accessGroup.GetAccessGroupName())
);
accessGroupButton.Text = text;
// Button events
accessGroupButton.OnPressed += _ => OnAccessGroupChanged(accessGroupButton.GetPositionInParent());
AccessGroupList.AddChild(accessGroupButton);
}
// Adjust the current tab index so it remains in range
if (_accessGroupTabIndex >= _groupedAccessLevels.Count)
_accessGroupTabIndex = _groupedAccessLevels.Count - 1;
return true;
}
/// <summary>
/// Rebuilds the checkbox list for the access level controls.
/// </summary>
public void RebuildAccessLevelsControls()
{
AccessLevelChecklist.DisposeAllChildren();
_accessLevelEntries.Clear();
// No access level prototypes were assigned to any of the access level groups
// Either turret controller has no assigned access levels, or their names were invalid
if (_groupedAccessLevels.Count == 0)
return;
// Reorder the access groups alphabetically
var orderedAccessGroups = _groupedAccessLevels.Keys.OrderBy(x => x.GetAccessGroupName()).ToList();
// Get the access levels associated with the current tab
var selectedAccessGroupTabProto = orderedAccessGroups[_accessGroupTabIndex];
_accessLevelsForTab = _groupedAccessLevels[selectedAccessGroupTabProto];
_accessLevelsForTab = _accessLevelsForTab.OrderBy(x => x.GetAccessLevelName()).ToList();
// Add an 'all' checkbox as the first child of the list if it has more than one access level
// Toggling this checkbox on will mark all other boxes below it on/off
var allCheckBox = CreateAccessLevelCheckbox();
allCheckBox.Text = Loc.GetString("turret-controls-window-all-checkbox");
if (_labelStyleClass != null)
allCheckBox.Label.SetOnlyStyleClass(_labelStyleClass);
// Add the 'all' checkbox events
allCheckBox.OnPressed += args =>
{
SetCheckBoxPressedState(_accessLevelEntries, allCheckBox.Pressed);
var accessLevels = new HashSet<ProtoId<AccessLevelPrototype>>();
foreach (var accessLevel in _accessLevelsForTab)
{
accessLevels.Add(accessLevel);
}
OnAccessLevelsChangedEvent?.Invoke(accessLevels, allCheckBox.Pressed);
};
AccessLevelChecklist.AddChild(allCheckBox);
// Hide the 'all' checkbox if the tab has only one access level
var allCheckBoxVisible = _accessLevelsForTab.Count > 1;
allCheckBox.Visible = allCheckBoxVisible;
allCheckBox.Disabled = !_canInteract;
// Add any remaining missing access level buttons to the UI
foreach (var accessLevel in _accessLevelsForTab)
{
// Create the entry
var accessLevelEntry = new AccessLevelEntry(_isMonotone);
accessLevelEntry.AccessLevel = accessLevel;
accessLevelEntry.CheckBox.Text = accessLevel.GetAccessLevelName();
accessLevelEntry.CheckBox.Pressed = _activeAccessLevels.Contains(accessLevel);
accessLevelEntry.CheckBox.Disabled = !_canInteract;
if (_labelStyleClass != null)
accessLevelEntry.CheckBox.Label.SetOnlyStyleClass(_labelStyleClass);
// Set the checkbox linkage lines
var isEndOfList = _accessLevelsForTab.IndexOf(accessLevel) == (_accessLevelsForTab.Count - 1);
var lines = new List<(Vector2, Vector2)>
{
(new Vector2(0.5f, 0f), new Vector2(0.5f, isEndOfList ? 0.5f : 1f)),
(new Vector2(0.5f, 0.5f), new Vector2(1f, 0.5f)),
};
accessLevelEntry.UpdateCheckBoxLink(lines);
accessLevelEntry.CheckBoxLink.Visible = allCheckBoxVisible;
accessLevelEntry.CheckBoxLink.Modulate = !_canInteract ? Color.Gray : Color.White;
// Add checkbox events
accessLevelEntry.CheckBox.OnPressed += args =>
{
// If the checkbox and its siblings are checked, check the 'all' checkbox too
allCheckBox.Pressed = AreAllCheckBoxesPressed(_accessLevelEntries.Select(x => x.CheckBox));
OnAccessLevelsChangedEvent?.Invoke([accessLevelEntry.AccessLevel], accessLevelEntry.CheckBox.Pressed);
};
AccessLevelChecklist.AddChild(accessLevelEntry);
_accessLevelEntries.Add(accessLevelEntry);
}
// Press the 'all' checkbox if all others are pressed
allCheckBox.Pressed = AreAllCheckBoxesPressed(_accessLevelEntries.Select(x => x.CheckBox));
}
private bool AreAllCheckBoxesPressed(IEnumerable<CheckBox> checkBoxes)
{
foreach (var checkBox in checkBoxes)
{
if (!checkBox.Pressed)
return false;
}
return true;
}
private void SetCheckBoxPressedState(List<AccessLevelEntry> accessLevelEntries, bool pressed)
{
foreach (var accessLevelEntry in accessLevelEntries)
{
accessLevelEntry.CheckBox.Pressed = pressed;
}
}
/// <summary>
/// Provides the UI with a list of access groups using which list of tabs should be populated.
/// </summary>
public void SetAccessGroups(HashSet<ProtoId<AccessGroupPrototype>> accessGroups)
{
_accessGroups = accessGroups;
ArrangeAccessControls();
if (TryRebuildAccessGroupControls())
RebuildAccessLevelsControls();
}
/// <summary>
/// Provides the UI with a list of access levels with which it can populate the currently selected tab.
/// </summary>
public void SetAccessLevels(HashSet<ProtoId<AccessLevelPrototype>> accessLevels)
{
_accessLevels = accessLevels;
ArrangeAccessControls();
if (TryRebuildAccessGroupControls())
RebuildAccessLevelsControls();
}
/// <summary>
/// Sets which access level checkboxes should be marked on the UI.
/// </summary>
public void SetActiveAccessLevels(HashSet<ProtoId<AccessLevelPrototype>> activeAccessLevels)
{
_activeAccessLevels = activeAccessLevels;
if (TryRebuildAccessGroupControls())
RebuildAccessLevelsControls();
}
/// <summary>
/// Sets whether the local player can interact with the checkboxes.
/// </summary>
public void SetLocalPlayerAccessibility(bool canInteract)
{
_canInteract = canInteract;
if (TryRebuildAccessGroupControls())
RebuildAccessLevelsControls();
}
/// <summary>
/// Sets whether the UI should use monotone buttons and checkboxes.
/// </summary>
public void SetMonotone(bool monotone)
{
_isMonotone = monotone;
if (TryRebuildAccessGroupControls())
RebuildAccessLevelsControls();
}
/// <summary>
/// Applies the specified style to the labels on the UI buttons and checkboxes.
/// </summary>
public void SetLabelStyleClass(string? styleClass)
{
_labelStyleClass = styleClass;
if (TryRebuildAccessGroupControls())
RebuildAccessLevelsControls();
}
private void OnAccessGroupChanged(int newTabIndex)
{
if (newTabIndex == _accessGroupTabIndex)
return;
_accessGroupTabIndex = newTabIndex;
if (TryRebuildAccessGroupControls())
RebuildAccessLevelsControls();
}
private Button CreateAccessGroupButton()
{
var button = _isMonotone ? new MonotoneButton() : new Button();
button.ToggleMode = true;
button.Group = _accessGroupsButtons;
button.Label.HorizontalAlignment = HAlignment.Left;
return button;
}
private CheckBox CreateAccessLevelCheckbox()
{
var checkbox = _isMonotone ? new MonotoneCheckBox() : new CheckBox();
checkbox.Margin = new Thickness(0, 0, 0, 3);
checkbox.ToggleMode = true;
checkbox.ReservesSpace = false;
return checkbox;
}
private sealed class AccessLevelEntry : BoxContainer
{
public ProtoId<AccessLevelPrototype> AccessLevel;
public readonly CheckBox CheckBox;
public readonly LineRenderer CheckBoxLink;
public AccessLevelEntry(bool monotone)
{
HorizontalExpand = true;
CheckBoxLink = new LineRenderer
{
SetWidth = 22,
VerticalExpand = true,
Margin = new Thickness(0, -1),
ReservesSpace = false,
};
AddChild(CheckBoxLink);
CheckBox = monotone ? new MonotoneCheckBox() : new CheckBox();
CheckBox.ToggleMode = true;
CheckBox.Margin = new Thickness(0f, 0f, 0f, 3f);
AddChild(CheckBox);
}
public void UpdateCheckBoxLink(List<(Vector2, Vector2)> lines)
{
CheckBoxLink.Lines = lines;
}
}
private sealed class LineRenderer : Control
{
/// <summary>
/// List of lines to render (their start and end x-y coordinates).
/// Position (0,0) is the top left corner of the control and
/// position (1,1) is the bottom right corner.
/// </summary>
/// <remarks>
/// The color of the lines is inherited from the control.
/// </remarks>
public List<(Vector2, Vector2)> Lines;
public LineRenderer()
{
Lines = new List<(Vector2, Vector2)>();
}
public LineRenderer(List<(Vector2, Vector2)> lines)
{
Lines = lines;
}
protected override void Draw(DrawingHandleScreen handle)
{
foreach (var line in Lines)
{
var start = PixelPosition +
new Vector2(PixelWidth * line.Item1.X, PixelHeight * line.Item1.Y);
var end = PixelPosition +
new Vector2(PixelWidth * line.Item2.X, PixelHeight * line.Item2.Y);
handle.DrawLine(start, end, ActualModulateSelf);
}
}
}
}

View file

@ -1,8 +1,10 @@
using Content.Shared.Access; using Content.Shared.Access;
using Content.Shared.Access.Components; using Content.Shared.Access.Components;
using Content.Shared.Access.Systems; using Content.Shared.Access.Systems;
using Content.Shared.CCVar;
using Content.Shared.Containers.ItemSlots; using Content.Shared.Containers.ItemSlots;
using Content.Shared.CrewManifest; using Content.Shared.CrewManifest;
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;
@ -11,13 +13,21 @@ namespace Content.Client.Access.UI
public sealed class IdCardConsoleBoundUserInterface : BoundUserInterface public sealed class IdCardConsoleBoundUserInterface : BoundUserInterface
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
private readonly SharedIdCardConsoleSystem _idCardConsoleSystem = default!; private readonly SharedIdCardConsoleSystem _idCardConsoleSystem = default!;
private IdCardConsoleWindow? _window; private IdCardConsoleWindow? _window;
// CCVar.
private int _maxNameLength;
private int _maxIdJobLength;
public IdCardConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) public IdCardConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{ {
_idCardConsoleSystem = EntMan.System<SharedIdCardConsoleSystem>(); _idCardConsoleSystem = EntMan.System<SharedIdCardConsoleSystem>();
_maxNameLength =_cfgManager.GetCVar(CCVars.MaxNameLength);
_maxIdJobLength = _cfgManager.GetCVar(CCVars.MaxIdJobLength);
} }
protected override void Open() protected override void Open()
@ -66,11 +76,11 @@ namespace Content.Client.Access.UI
public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, string newJobPrototype) public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, string newJobPrototype)
{ {
if (newFullName.Length > MaxFullNameLength) if (newFullName.Length > _maxNameLength)
newFullName = newFullName[..MaxFullNameLength]; newFullName = newFullName[.._maxNameLength];
if (newJobTitle.Length > MaxJobTitleLength) if (newJobTitle.Length > _maxIdJobLength)
newJobTitle = newJobTitle[..MaxJobTitleLength]; newJobTitle = newJobTitle[.._maxIdJobLength];
SendMessage(new WriteToTargetIdMessage( SendMessage(new WriteToTargetIdMessage(
newFullName, newFullName,

View file

@ -1,11 +1,13 @@
using System.Linq; using System.Linq;
using Content.Shared.Access; using Content.Shared.Access;
using Content.Shared.Access.Systems; using Content.Shared.Access.Systems;
using Content.Shared.CCVar;
using Content.Shared.Roles; using Content.Shared.Roles;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls; 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.Configuration;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using static Content.Shared.Access.Components.IdCardConsoleComponent; using static Content.Shared.Access.Components.IdCardConsoleComponent;
@ -14,12 +16,17 @@ namespace Content.Client.Access.UI
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class IdCardConsoleWindow : DefaultWindow public sealed partial class IdCardConsoleWindow : DefaultWindow
{ {
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly ILogManager _logManager = default!;
private readonly ISawmill _logMill = default!; private readonly ISawmill _logMill = default!;
private readonly IdCardConsoleBoundUserInterface _owner; private readonly IdCardConsoleBoundUserInterface _owner;
// CCVar.
private int _maxNameLength;
private int _maxIdJobLength;
private AccessLevelControl _accessButtons = new(); private AccessLevelControl _accessButtons = new();
private readonly List<string> _jobPrototypeIds = new(); private readonly List<string> _jobPrototypeIds = new();
@ -39,7 +46,11 @@ namespace Content.Client.Access.UI
_owner = owner; _owner = owner;
_maxNameLength = _cfgManager.GetCVar(CCVars.MaxNameLength);
_maxIdJobLength = _cfgManager.GetCVar(CCVars.MaxIdJobLength);
FullNameLineEdit.OnTextEntered += _ => SubmitData(); FullNameLineEdit.OnTextEntered += _ => SubmitData();
FullNameLineEdit.IsValid = s => s.Length <= _maxNameLength;
FullNameLineEdit.OnTextChanged += _ => FullNameLineEdit.OnTextChanged += _ =>
{ {
FullNameSaveButton.Disabled = FullNameSaveButton.Text == _lastFullName; FullNameSaveButton.Disabled = FullNameSaveButton.Text == _lastFullName;
@ -47,6 +58,7 @@ namespace Content.Client.Access.UI
FullNameSaveButton.OnPressed += _ => SubmitData(); FullNameSaveButton.OnPressed += _ => SubmitData();
JobTitleLineEdit.OnTextEntered += _ => SubmitData(); JobTitleLineEdit.OnTextEntered += _ => SubmitData();
JobTitleLineEdit.IsValid = s => s.Length <= _maxIdJobLength;
JobTitleLineEdit.OnTextChanged += _ => JobTitleLineEdit.OnTextChanged += _ =>
{ {
JobTitleSaveButton.Disabled = JobTitleLineEdit.Text == _lastJobTitle; JobTitleSaveButton.Disabled = JobTitleLineEdit.Text == _lastJobTitle;

View file

@ -7,6 +7,8 @@ namespace Content.Client.Administration.Systems;
public sealed class KillSignSystem : EntitySystem public sealed class KillSignSystem : EntitySystem
{ {
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<KillSignComponent, ComponentStartup>(KillSignAdded); SubscribeLocalEvent<KillSignComponent, ComponentStartup>(KillSignAdded);
@ -18,10 +20,10 @@ public sealed class KillSignSystem : EntitySystem
if (!TryComp<SpriteComponent>(uid, out var sprite)) if (!TryComp<SpriteComponent>(uid, out var sprite))
return; return;
if (!sprite.LayerMapTryGet(KillSignKey.Key, out var layer)) if (!_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var layer, false))
return; return;
sprite.RemoveLayer(layer); _sprite.RemoveLayer((uid, sprite), layer);
} }
private void KillSignAdded(EntityUid uid, KillSignComponent component, ComponentStartup args) private void KillSignAdded(EntityUid uid, KillSignComponent component, ComponentStartup args)
@ -29,15 +31,15 @@ public sealed class KillSignSystem : EntitySystem
if (!TryComp<SpriteComponent>(uid, out var sprite)) if (!TryComp<SpriteComponent>(uid, out var sprite))
return; return;
if (sprite.LayerMapTryGet(KillSignKey.Key, out var _)) if (_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var _, false))
return; return;
var adj = sprite.Bounds.Height / 2 + ((1.0f/32) * 6.0f); var adj = _sprite.GetLocalBounds((uid, sprite)).Height / 2 + ((1.0f / 32) * 6.0f);
var layer = sprite.AddLayer(new SpriteSpecifier.Rsi(new ResPath("Objects/Misc/killsign.rsi"), "sign")); var layer = _sprite.AddLayer((uid, sprite), new SpriteSpecifier.Rsi(new ResPath("Objects/Misc/killsign.rsi"), "sign"));
sprite.LayerMapSet(KillSignKey.Key, layer); _sprite.LayerMapSet((uid, sprite), KillSignKey.Key, layer);
sprite.LayerSetOffset(layer, new Vector2(0.0f, adj)); _sprite.LayerSetOffset((uid, sprite), layer, new Vector2(0.0f, adj));
sprite.LayerSetShader(layer, "unshaded"); sprite.LayerSetShader(layer, "unshaded");
} }

View file

@ -19,10 +19,10 @@ namespace Content.Client.Administration.UI.SpawnExplosion;
public sealed partial class SpawnExplosionWindow : DefaultWindow public sealed partial class SpawnExplosionWindow : DefaultWindow
{ {
[Dependency] private readonly IClientConsoleHost _conHost = default!; [Dependency] private readonly IClientConsoleHost _conHost = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entMan = default!; [Dependency] private readonly IEntityManager _entMan = default!;
private readonly SharedMapSystem _mapSystem;
private readonly SharedTransformSystem _transform = default!; private readonly SharedTransformSystem _transform = default!;
private readonly SpawnExplosionEui _eui; private readonly SpawnExplosionEui _eui;
@ -38,6 +38,7 @@ public sealed partial class SpawnExplosionWindow : DefaultWindow
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
_mapSystem = _entMan.System<SharedMapSystem>();
_transform = _entMan.System<TransformSystem>(); _transform = _entMan.System<TransformSystem>();
_eui = eui; _eui = eui;
@ -87,7 +88,7 @@ public sealed partial class SpawnExplosionWindow : DefaultWindow
{ {
_mapData.Clear(); _mapData.Clear();
MapOptions.Clear(); MapOptions.Clear();
foreach (var map in _mapManager.GetAllMapIds()) foreach (var map in _mapSystem.GetAllMapIds())
{ {
_mapData.Add(map); _mapData.Add(map);
MapOptions.AddItem(map.ToString()); MapOptions.AddItem(map.ToString());

View file

@ -14,6 +14,9 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
[UsedImplicitly] [UsedImplicitly]
public sealed partial class LoadBlueprintsWindow : DefaultWindow public sealed partial class LoadBlueprintsWindow : DefaultWindow
{ {
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
public LoadBlueprintsWindow() public LoadBlueprintsWindow()
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
@ -21,9 +24,9 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
protected override void EnteredTree() protected override void EnteredTree()
{ {
var mapManager = IoCManager.Resolve<IMapManager>(); var mapSystem = _entityManager.System<SharedMapSystem>();
foreach (var mapId in mapManager.GetAllMapIds()) foreach (var mapId in mapSystem.GetAllMapIds())
{ {
MapOptions.AddItem(mapId.ToString(), (int) mapId); MapOptions.AddItem(mapId.ToString(), (int) mapId);
} }
@ -39,21 +42,19 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
private void Reset() private void Reset()
{ {
var entManager = IoCManager.Resolve<IEntityManager>(); var xformSystem = _entityManager.System<SharedTransformSystem>();
var xformSystem = entManager.System<SharedTransformSystem>(); var player = _playerManager.LocalEntity;
var playerManager = IoCManager.Resolve<IPlayerManager>();
var player = playerManager.LocalEntity;
var currentMap = MapId.Nullspace; var currentMap = MapId.Nullspace;
var position = Vector2.Zero; var position = Vector2.Zero;
var rotation = Angle.Zero; var rotation = Angle.Zero;
if (entManager.TryGetComponent<TransformComponent>(player, out var xform)) if (_entityManager.TryGetComponent<TransformComponent>(player, out var xform))
{ {
currentMap = xform.MapID; currentMap = xform.MapID;
position = xformSystem.GetWorldPosition(xform); position = xformSystem.GetWorldPosition(xform);
if (entManager.TryGetComponent<TransformComponent>(xform.GridUid, out var gridXform)) if (_entityManager.TryGetComponent<TransformComponent>(xform.GridUid, out var gridXform))
{ {
rotation = xformSystem.GetWorldRotation(gridXform); rotation = xformSystem.GetWorldRotation(gridXform);
} }

View file

@ -1,13 +1,13 @@
<Control <Control
xmlns="https://spacestation14.io" xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls" xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Margin="4" Margin="4"
MinSize="50 50"> MinSize="50 50">
<GridContainer <GridContainer
Columns="3"> Columns="3">
<cc:CommandButton Command="startround" Text="{Loc administration-ui-round-tab-start-round}" /> <controls:ConfirmButton Name="StartRound" Text="{Loc administration-ui-round-tab-start-round}" />
<cc:CommandButton Command="endround" Text="{Loc administration-ui-round-tab-end-round}" /> <controls:ConfirmButton Name="EndRound" Text="{Loc administration-ui-round-tab-end-round}" />
<cc:CommandButton Command="restartround" Text="{Loc administration-ui-round-tab-restart-round}" /> <controls:ConfirmButton Name="RestartRound" Text="{Loc administration-ui-round-tab-restart-round}" />
<cc:CommandButton Command="restartroundnow" Text="{Loc administration-ui-round-tab-restart-round-now}" /> <controls:ConfirmButton Name="RestartRoundNow" Text="{Loc administration-ui-round-tab-restart-round-now}" />
</GridContainer> </GridContainer>
</Control> </Control>

View file

@ -1,10 +1,24 @@
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Administration.UI.Tabs namespace Content.Client.Administration.UI.Tabs
{ {
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class RoundTab : Control public sealed partial class RoundTab : Control
{ {
[Dependency] private readonly IClientConsoleHost _console = default!;
public RoundTab()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
StartRound.OnPressed += _ => _console.ExecuteCommand("startround");
EndRound.OnPressed += _ => _console.ExecuteCommand("endround");
RestartRound.OnPressed += _ => _console.ExecuteCommand("restartround");
RestartRoundNow.OnPressed += _ => _console.ExecuteCommand("restartroundnow");
}
} }
} }

View file

@ -8,6 +8,8 @@ namespace Content.Client.AlertLevel;
public sealed class AlertLevelDisplaySystem : EntitySystem public sealed class AlertLevelDisplaySystem : EntitySystem
{ {
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@ -21,26 +23,26 @@ public sealed class AlertLevelDisplaySystem : EntitySystem
{ {
return; return;
} }
var layer = args.Sprite.LayerMapReserveBlank(AlertLevelDisplay.Layer); var layer = _sprite.LayerMapReserve((uid, args.Sprite), AlertLevelDisplay.Layer);
if (args.AppearanceData.TryGetValue(AlertLevelDisplay.Powered, out var poweredObject)) if (args.AppearanceData.TryGetValue(AlertLevelDisplay.Powered, out var poweredObject))
{ {
args.Sprite.LayerSetVisible(layer, poweredObject is true); _sprite.LayerSetVisible((uid, args.Sprite), layer, poweredObject is true);
} }
if (!args.AppearanceData.TryGetValue(AlertLevelDisplay.CurrentLevel, out var level)) if (!args.AppearanceData.TryGetValue(AlertLevelDisplay.CurrentLevel, out var level))
{ {
args.Sprite.LayerSetState(layer, alertLevelDisplay.AlertVisuals.Values.First()); _sprite.LayerSetRsiState((uid, args.Sprite), layer, alertLevelDisplay.AlertVisuals.Values.First());
return; return;
} }
if (alertLevelDisplay.AlertVisuals.TryGetValue((string) level, out var visual)) if (alertLevelDisplay.AlertVisuals.TryGetValue((string)level, out var visual))
{ {
args.Sprite.LayerSetState(layer, visual); _sprite.LayerSetRsiState((uid, args.Sprite), layer, visual);
} }
else else
{ {
args.Sprite.LayerSetState(layer, alertLevelDisplay.AlertVisuals.Values.First()); _sprite.LayerSetRsiState((uid, args.Sprite), layer, alertLevelDisplay.AlertVisuals.Values.First());
} }
} }
} }

View file

@ -15,6 +15,7 @@ public sealed class EntityPickupAnimationSystem : EntitySystem
{ {
[Dependency] private readonly AnimationPlayerSystem _animations = default!; [Dependency] private readonly AnimationPlayerSystem _animations = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly TransformSystem _transform = default!;
public override void Initialize() public override void Initialize()
@ -56,8 +57,8 @@ public sealed class EntityPickupAnimationSystem : EntitySystem
} }
var sprite = Comp<SpriteComponent>(animatableClone); var sprite = Comp<SpriteComponent>(animatableClone);
sprite.CopyFrom(sprite0); _sprite.CopySprite((uid, sprite0), (animatableClone, sprite));
sprite.Visible = true; _sprite.SetVisible((animatableClone, sprite), true);
var animations = Comp<AnimationPlayerComponent>(animatableClone); var animations = Comp<AnimationPlayerComponent>(animatableClone);

View file

@ -11,6 +11,7 @@ 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!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
@ -49,12 +50,12 @@ public sealed class AnomalySystem : SharedAnomalySystem
if (HasComp<AnomalySupercriticalComponent>(uid)) if (HasComp<AnomalySupercriticalComponent>(uid))
pulsing = true; pulsing = true;
if (!sprite.LayerMapTryGet(AnomalyVisualLayers.Base, out var layer) || if (!_sprite.LayerMapTryGet((uid, sprite), AnomalyVisualLayers.Base, out var layer, false) ||
!sprite.LayerMapTryGet(AnomalyVisualLayers.Animated, out var animatedLayer)) !_sprite.LayerMapTryGet((uid, sprite), AnomalyVisualLayers.Animated, out var animatedLayer, false))
return; return;
sprite.LayerSetVisible(layer, !pulsing); _sprite.LayerSetVisible((uid, sprite), layer, !pulsing);
sprite.LayerSetVisible(animatedLayer, pulsing); _sprite.LayerSetVisible((uid, sprite), animatedLayer, pulsing);
} }
public override void Update(float frameTime) public override void Update(float frameTime)
@ -63,16 +64,16 @@ public sealed class AnomalySystem : SharedAnomalySystem
var query = EntityQueryEnumerator<AnomalySupercriticalComponent, SpriteComponent>(); var query = EntityQueryEnumerator<AnomalySupercriticalComponent, SpriteComponent>();
while (query.MoveNext(out var super, out var sprite)) while (query.MoveNext(out var uid, out var super, out var sprite))
{ {
var completion = 1f - (float) ((super.EndTime - _timing.CurTime) / super.SupercriticalDuration); var completion = 1f - (float)((super.EndTime - _timing.CurTime) / super.SupercriticalDuration);
var scale = completion * (super.MaxScaleAmount - 1f) + 1f; var scale = completion * (super.MaxScaleAmount - 1f) + 1f;
sprite.Scale = new Vector2(scale, scale); _sprite.SetScale((uid, sprite), new Vector2(scale, scale));
var transparency = (byte) (65 * (1f - completion) + 190); var transparency = (byte)(65 * (1f - completion) + 190);
if (transparency < sprite.Color.AByte) if (transparency < sprite.Color.AByte)
{ {
sprite.Color = sprite.Color.WithAlpha(transparency); _sprite.SetColor((uid, sprite), sprite.Color.WithAlpha(transparency));
} }
} }
} }
@ -82,7 +83,7 @@ public sealed class AnomalySystem : SharedAnomalySystem
if (!TryComp<SpriteComponent>(ent, out var sprite)) if (!TryComp<SpriteComponent>(ent, out var sprite))
return; return;
sprite.Scale = Vector2.One; _sprite.SetScale((ent.Owner, sprite), Vector2.One);
sprite.Color = sprite.Color.WithAlpha(1f); _sprite.SetColor((ent.Owner, sprite), sprite.Color.WithAlpha(1f));
} }
} }

View file

@ -7,6 +7,8 @@ namespace Content.Client.Anomaly.Effects;
public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
{ {
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
SubscribeLocalEvent<InnerBodyAnomalyComponent, AfterAutoHandleStateEvent>(OnAfterHandleState); SubscribeLocalEvent<InnerBodyAnomalyComponent, AfterAutoHandleStateEvent>(OnAfterHandleState);
@ -21,21 +23,20 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
if (ent.Comp.FallbackSprite is null) if (ent.Comp.FallbackSprite is null)
return; return;
if (!sprite.LayerMapTryGet(ent.Comp.LayerMap, out var index)) var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap);
index = sprite.LayerMapReserveBlank(ent.Comp.LayerMap);
if (TryComp<BodyComponent>(ent, out var body) && if (TryComp<BodyComponent>(ent, out var body) &&
body.Prototype is not null && body.Prototype is not null &&
ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite)) ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite))
{ {
sprite.LayerSetSprite(index, speciesSprite); _sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite);
} }
else else
{ {
sprite.LayerSetSprite(index, ent.Comp.FallbackSprite); _sprite.LayerSetSprite((ent.Owner, sprite), index, ent.Comp.FallbackSprite);
} }
sprite.LayerSetVisible(index, true); _sprite.LayerSetVisible((ent.Owner, sprite), index, true);
sprite.LayerSetShader(index, "unshaded"); sprite.LayerSetShader(index, "unshaded");
} }
@ -44,7 +45,7 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
if (!TryComp<SpriteComponent>(ent, out var sprite)) if (!TryComp<SpriteComponent>(ent, out var sprite))
return; return;
var index = sprite.LayerMapGet(ent.Comp.LayerMap); var index = _sprite.LayerMapGet((ent.Owner, sprite), ent.Comp.LayerMap);
sprite.LayerSetVisible(index, false); _sprite.LayerSetVisible((ent.Owner, sprite), index, false);
} }
} }

View file

@ -11,6 +11,7 @@ namespace Content.Client.Atmos.EntitySystems;
public sealed class AtmosPipeAppearanceSystem : EntitySystem public sealed class AtmosPipeAppearanceSystem : EntitySystem
{ {
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -25,21 +26,22 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
if (!TryComp(uid, out SpriteComponent? sprite)) if (!TryComp(uid, out SpriteComponent? sprite))
return; return;
foreach (PipeConnectionLayer layerKey in Enum.GetValues(typeof(PipeConnectionLayer))) foreach (var layerKey in Enum.GetValues<PipeConnectionLayer>())
{ {
sprite.LayerMapReserveBlank(layerKey); var layer = _sprite.LayerMapReserve((uid, sprite), layerKey);
var layer = sprite.LayerMapGet(layerKey); _sprite.LayerSetRsi((uid, sprite), layer, component.Sprite.RsiPath);
sprite.LayerSetRSI(layer, component.Sprite.RsiPath); _sprite.LayerSetRsiState((uid, sprite), layer, component.Sprite.RsiState);
sprite.LayerSetState(layer, component.Sprite.RsiState); _sprite.LayerSetDirOffset((uid, sprite), layer, ToOffset(layerKey));
sprite.LayerSetDirOffset(layer, ToOffset(layerKey));
} }
} }
private void HideAllPipeConnection(SpriteComponent sprite) private void HideAllPipeConnection(Entity<SpriteComponent> entity)
{ {
foreach (PipeConnectionLayer layerKey in Enum.GetValues(typeof(PipeConnectionLayer))) var sprite = entity.Comp;
foreach (var layerKey in Enum.GetValues<PipeConnectionLayer>())
{ {
if (!sprite.LayerMapTryGet(layerKey, out var key)) if (!_sprite.LayerMapTryGet(entity.AsNullable(), layerKey, out var key, false))
continue; continue;
var layer = sprite[key]; var layer = sprite[key];
@ -61,7 +63,7 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
if (!_appearance.TryGetData<PipeDirection>(uid, PipeVisuals.VisualState, out var worldConnectedDirections, args.Component)) if (!_appearance.TryGetData<PipeDirection>(uid, PipeVisuals.VisualState, out var worldConnectedDirections, args.Component))
{ {
HideAllPipeConnection(args.Sprite); HideAllPipeConnection((uid, args.Sprite));
return; return;
} }
@ -71,13 +73,13 @@ public sealed class AtmosPipeAppearanceSystem : EntitySystem
// transform connected directions to local-coordinates // transform connected directions to local-coordinates
var connectedDirections = worldConnectedDirections.RotatePipeDirection(-Transform(uid).LocalRotation); var connectedDirections = worldConnectedDirections.RotatePipeDirection(-Transform(uid).LocalRotation);
foreach (PipeConnectionLayer layerKey in Enum.GetValues(typeof(PipeConnectionLayer))) foreach (var layerKey in Enum.GetValues<PipeConnectionLayer>())
{ {
if (!args.Sprite.LayerMapTryGet(layerKey, out var key)) if (!_sprite.LayerMapTryGet((uid, args.Sprite), layerKey, out var key, false))
continue; continue;
var layer = args.Sprite[key]; var layer = args.Sprite[key];
var dir = (PipeDirection) layerKey; var dir = (PipeDirection)layerKey;
var visible = connectedDirections.HasDirection(dir); var visible = connectedDirections.HasDirection(dir);
layer.Visible &= visible; layer.Visible &= visible;

View file

@ -2,6 +2,7 @@ using Content.Client.Atmos.Components;
using Content.Shared.Atmos; using Content.Shared.Atmos;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Utility;
namespace Content.Client.Atmos.EntitySystems; namespace Content.Client.Atmos.EntitySystems;
@ -31,9 +32,9 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
// Need LayerMapTryGet because Init fails if there's no existing sprite / appearancecomp // Need LayerMapTryGet because Init fails if there's no existing sprite / appearancecomp
// which means in some setups (most frequently no AppearanceComp) the layer never exists. // which means in some setups (most frequently no AppearanceComp) the layer never exists.
if (TryComp<SpriteComponent>(uid, out var sprite) && if (TryComp<SpriteComponent>(uid, out var sprite) &&
sprite.LayerMapTryGet(FireVisualLayers.Fire, out var layer)) SpriteSystem.LayerMapTryGet((uid, sprite), FireVisualLayers.Fire, out var layer, false))
{ {
sprite.RemoveLayer(layer); SpriteSystem.RemoveLayer((uid, sprite), layer);
} }
} }
@ -42,11 +43,11 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
if (!TryComp<SpriteComponent>(uid, out var sprite) || !TryComp(uid, out AppearanceComponent? appearance)) if (!TryComp<SpriteComponent>(uid, out var sprite) || !TryComp(uid, out AppearanceComponent? appearance))
return; return;
sprite.LayerMapReserveBlank(FireVisualLayers.Fire); SpriteSystem.LayerMapReserve((uid, sprite), FireVisualLayers.Fire);
sprite.LayerSetVisible(FireVisualLayers.Fire, false); SpriteSystem.LayerSetVisible((uid, sprite), FireVisualLayers.Fire, false);
sprite.LayerSetShader(FireVisualLayers.Fire, "unshaded"); sprite.LayerSetShader(FireVisualLayers.Fire, "unshaded");
if (component.Sprite != null) if (component.Sprite != null)
sprite.LayerSetRSI(FireVisualLayers.Fire, component.Sprite); SpriteSystem.LayerSetRsi((uid, sprite), FireVisualLayers.Fire, new ResPath(component.Sprite));
UpdateAppearance(uid, component, sprite, appearance); UpdateAppearance(uid, component, sprite, appearance);
} }
@ -59,12 +60,12 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
private void UpdateAppearance(EntityUid uid, FireVisualsComponent component, SpriteComponent sprite, AppearanceComponent appearance) private void UpdateAppearance(EntityUid uid, FireVisualsComponent component, SpriteComponent sprite, AppearanceComponent appearance)
{ {
if (!sprite.LayerMapTryGet(FireVisualLayers.Fire, out var index)) if (!SpriteSystem.LayerMapTryGet((uid, sprite), FireVisualLayers.Fire, out var index, false))
return; return;
AppearanceSystem.TryGetData<bool>(uid, FireVisuals.OnFire, out var onFire, appearance); AppearanceSystem.TryGetData<bool>(uid, FireVisuals.OnFire, out var onFire, appearance);
AppearanceSystem.TryGetData<float>(uid, FireVisuals.FireStacks, out var fireStacks, appearance); AppearanceSystem.TryGetData<float>(uid, FireVisuals.FireStacks, out var fireStacks, appearance);
sprite.LayerSetVisible(index, onFire); SpriteSystem.LayerSetVisible((uid, sprite), index, onFire);
if (!onFire) if (!onFire)
{ {
@ -78,9 +79,9 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
} }
if (fireStacks > component.FireStackAlternateState && !string.IsNullOrEmpty(component.AlternateState)) if (fireStacks > component.FireStackAlternateState && !string.IsNullOrEmpty(component.AlternateState))
sprite.LayerSetState(index, component.AlternateState); SpriteSystem.LayerSetRsiState((uid, sprite), index, component.AlternateState);
else else
sprite.LayerSetState(index, component.NormalState); SpriteSystem.LayerSetRsiState((uid, sprite), index, component.NormalState);
component.LightEntity ??= Spawn(null, new EntityCoordinates(uid, default)); component.LightEntity ??= Spawn(null, new EntityCoordinates(uid, default));
var light = EnsureComp<PointLightComponent>(component.LightEntity.Value); var light = EnsureComp<PointLightComponent>(component.LightEntity.Value);

View file

@ -9,7 +9,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
{ {
protected override void OnAppearanceChange(EntityUid uid, AtmosAlarmableVisualsComponent component, ref AppearanceChangeEvent args) protected override void OnAppearanceChange(EntityUid uid, AtmosAlarmableVisualsComponent component, ref AppearanceChangeEvent args)
{ {
if (args.Sprite == null || !args.Sprite.LayerMapTryGet(component.LayerMap, out var layer)) if (args.Sprite == null || !SpriteSystem.LayerMapTryGet((uid, args.Sprite), component.LayerMap, out var layer, false))
return; return;
if (!args.AppearanceData.TryGetValue(PowerDeviceVisuals.Powered, out var poweredObject) || if (!args.AppearanceData.TryGetValue(PowerDeviceVisuals.Powered, out var poweredObject) ||
@ -22,8 +22,8 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
{ {
foreach (var visLayer in component.HideOnDepowered) foreach (var visLayer in component.HideOnDepowered)
{ {
if (args.Sprite.LayerMapTryGet(visLayer, out var powerVisibilityLayer)) if (SpriteSystem.LayerMapTryGet((uid, args.Sprite), visLayer, out var powerVisibilityLayer, false))
args.Sprite.LayerSetVisible(powerVisibilityLayer, powered); SpriteSystem.LayerSetVisible((uid, args.Sprite), powerVisibilityLayer, powered);
} }
} }
@ -31,8 +31,8 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
{ {
foreach (var (setLayer, powerState) in component.SetOnDepowered) foreach (var (setLayer, powerState) in component.SetOnDepowered)
{ {
if (args.Sprite.LayerMapTryGet(setLayer, out var setStateLayer)) if (SpriteSystem.LayerMapTryGet((uid, args.Sprite), setLayer, out var setStateLayer, false))
args.Sprite.LayerSetState(setStateLayer, new RSI.StateId(powerState)); SpriteSystem.LayerSetRsiState((uid, args.Sprite), setStateLayer, new RSI.StateId(powerState));
} }
} }
@ -41,7 +41,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
&& powered && powered
&& component.AlarmStates.TryGetValue(alarmType, out var state)) && component.AlarmStates.TryGetValue(alarmType, out var state))
{ {
args.Sprite.LayerSetState(layer, new RSI.StateId(state)); SpriteSystem.LayerSetRsiState((uid, args.Sprite), layer, new RSI.StateId(state));
} }
} }
} }

View file

@ -74,7 +74,13 @@
<!-- Mode buttons --> <!-- Mode buttons -->
<BoxContainer Orientation="Horizontal"> <BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'air-alarm-ui-window-mode-label'}" Margin="0 0 2 0" /> <Label Text="{Loc 'air-alarm-ui-window-mode-label'}" Margin="0 0 2 0" />
<OptionButton Name="CModeButton" HorizontalExpand="True" /> <Control HorizontalExpand="True">
<OptionButton Name="CModeButton" />
<ui:StripeBack Name="CModeSelectLocked">
<RichTextLabel Text="{Loc 'air-alarm-ui-window-mode-select-locked-label'}"
HorizontalAlignment="Center" />
</ui:StripeBack>
</Control>
<CheckBox Name="AutoModeCheckBox" Text="{Loc 'air-alarm-ui-window-auto-mode-label'}" /> <CheckBox Name="AutoModeCheckBox" Text="{Loc 'air-alarm-ui-window-auto-mode-label'}" />
</BoxContainer> </BoxContainer>
</BoxContainer> </BoxContainer>

View file

@ -110,6 +110,8 @@ public sealed partial class AirAlarmWindow : FancyWindow
{ {
UpdateDeviceData(addr, dev); UpdateDeviceData(addr, dev);
} }
_modes.Visible = !state.PanicWireCut;
CModeSelectLocked.Visible = state.PanicWireCut;
} }
public void UpdateModeSelector(AirAlarmMode mode) public void UpdateModeSelector(AirAlarmMode mode)

View file

@ -71,6 +71,7 @@ public sealed partial class ScrubberControl : BoxContainer
_data.PumpDirection = (ScrubberPumpDirection) args.Id; _data.PumpDirection = (ScrubberPumpDirection) args.Id;
ScrubberDataChanged?.Invoke(_address, _data); ScrubberDataChanged?.Invoke(_address, _data);
}; };
_pumpDirection.Disabled = data.AirAlarmPanicWireCut;
_copySettings.OnPressed += _ => _copySettings.OnPressed += _ =>
{ {
@ -109,6 +110,7 @@ public sealed partial class ScrubberControl : BoxContainer
_data.PumpDirection = data.PumpDirection; _data.PumpDirection = data.PumpDirection;
_pumpDirection.Select((int) _data.PumpDirection); _pumpDirection.Select((int) _data.PumpDirection);
_pumpDirection.Disabled = data.AirAlarmPanicWireCut;
_data.VolumeRate = data.VolumeRate; _data.VolumeRate = data.VolumeRate;
_volumeRate.Value = _data.VolumeRate; _volumeRate.Value = _data.VolumeRate;

View file

@ -21,6 +21,7 @@ namespace Content.Client.Atmos.Overlays
{ {
private readonly IEntityManager _entManager; private readonly IEntityManager _entManager;
private readonly IMapManager _mapManager; private readonly IMapManager _mapManager;
private readonly SharedMapSystem _mapSystem;
private readonly SharedTransformSystem _xformSys; private readonly SharedTransformSystem _xformSys;
public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld; public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld;
@ -51,6 +52,7 @@ namespace Content.Client.Atmos.Overlays
{ {
_entManager = entManager; _entManager = entManager;
_mapManager = IoCManager.Resolve<IMapManager>(); _mapManager = IoCManager.Resolve<IMapManager>();
_mapSystem = entManager.System<SharedMapSystem>();
_xformSys = xformSys; _xformSys = xformSys;
_shader = protoMan.Index<ShaderPrototype>("unshaded").Instance(); _shader = protoMan.Index<ShaderPrototype>("unshaded").Instance();
ZIndex = GasOverlayZIndex; ZIndex = GasOverlayZIndex;
@ -163,7 +165,7 @@ namespace Content.Client.Atmos.Overlays
xformQuery, xformQuery,
_xformSys); _xformSys);
var mapUid = _mapManager.GetMapEntityId(args.MapId); var mapUid = _mapSystem.GetMapOrInvalid(args.MapId);
if (_entManager.TryGetComponent<MapAtmosphereComponent>(mapUid, out var atmos)) if (_entManager.TryGetComponent<MapAtmosphereComponent>(mapUid, out var atmos))
DrawMapOverlay(drawHandle, args, mapUid, atmos); DrawMapOverlay(drawHandle, args, mapUid, atmos);

View file

@ -0,0 +1,8 @@
using Content.Shared.Atmos.Piping.Binary.Systems;
namespace Content.Client.Atmos.Piping.Binary.Systems;
public sealed class GasValveSystem : SharedGasValveSystem
{
}

View file

@ -0,0 +1,29 @@
using Content.Client.Atmos.UI;
using Content.Shared.Atmos.Piping.Unary.Components;
using Content.Shared.Atmos.Piping.Unary.Systems;
namespace Content.Client.Atmos.Piping.Unary.Systems;
public sealed class GasThermoMachineSystem : SharedGasThermoMachineSystem
{
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasThermoMachineComponent, AfterAutoHandleStateEvent>(OnGasAfterState);
}
private void OnGasAfterState(Entity<GasThermoMachineComponent> ent, ref AfterAutoHandleStateEvent args)
{
DirtyUI(ent.Owner, ent.Comp);
}
protected override void DirtyUI(EntityUid uid, GasThermoMachineComponent? thermoMachine, UserInterfaceComponent? ui = null)
{
if (_ui.TryGetOpenUi<GasThermomachineBoundUserInterface>(uid, ThermomachineUiKey.Key, out var bui))
{
bui.Update();
}
}
}

View file

@ -1,5 +1,8 @@
using Content.Shared.Atmos; using Content.Client.Power.EntitySystems;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.Atmos.Piping.Unary.Components;
using Content.Shared.Atmos.Piping.Unary.Systems;
using Content.Shared.Power.Components;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
@ -36,6 +39,8 @@ namespace Content.Client.Atmos.UI
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
_window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value); _window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value);
_window.Entity = Owner;
Update();
} }
private void OnToggleStatusButtonPressed() private void OnToggleStatusButtonPressed()
@ -43,7 +48,7 @@ namespace Content.Client.Atmos.UI
if (_window is null) return; if (_window is null) return;
_window.SetActive(!_window.Active); _window.SetActive(!_window.Active);
SendMessage(new GasThermomachineToggleMessage()); SendPredictedMessage(new GasThermomachineToggleMessage());
} }
private void OnTemperatureChanged(float value) private void OnTemperatureChanged(float value)
@ -60,25 +65,32 @@ namespace Content.Client.Atmos.UI
return; return;
} }
SendMessage(new GasThermomachineChangeTemperatureMessage(actual)); SendPredictedMessage(new GasThermomachineChangeTemperatureMessage(actual));
} }
/// <summary> public override void Update()
/// Update the UI state based on server-sent info
/// </summary>
/// <param name="state"></param>
protected override void UpdateState(BoundUserInterfaceState state)
{ {
base.UpdateState(state); if (_window == null || !EntMan.TryGetComponent(Owner, out GasThermoMachineComponent? thermo))
if (_window == null || state is not GasThermomachineBoundUserInterfaceState cast)
return; return;
_minTemp = cast.MinTemperature; var system = EntMan.System<SharedGasThermoMachineSystem>();
_maxTemp = cast.MaxTemperature; _minTemp = thermo.MinTemperature;
_isHeater = cast.IsHeater; _maxTemp = thermo.MaxTemperature;
_isHeater = system.IsHeater(thermo);
_window.SetTemperature(thermo.TargetTemperature);
var receiverSys = EntMan.System<PowerReceiverSystem>();
SharedApcPowerReceiverComponent? receiver = null;
receiverSys.ResolveApc(Owner, ref receiver);
// Also set in frameupdates.
if (receiver != null)
{
_window.SetActive(!receiver.PowerDisabled);
}
_window.SetTemperature(cast.Temperature);
_window.SetActive(cast.Enabled);
_window.Title = _isHeater switch _window.Title = _isHeater switch
{ {
false => Loc.GetString("comp-gas-thermomachine-ui-title-freezer"), false => Loc.GetString("comp-gas-thermomachine-ui-title-freezer"),

View file

@ -1,5 +1,6 @@
<DefaultWindow xmlns="https://spacestation14.io" <controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="300 120" Title="{Loc comp-gas-thermomachine-ui-title-freezer}"> MinSize="300 120" Title="{Loc comp-gas-thermomachine-ui-title-freezer}">
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10"> <BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"> <BoxContainer Orientation="Horizontal" HorizontalExpand="True">
@ -11,4 +12,4 @@
<Label Text="{Loc comp-gas-thermomachine-ui-temperature}"/> <Label Text="{Loc comp-gas-thermomachine-ui-temperature}"/>
</BoxContainer> </BoxContainer>
</BoxContainer> </BoxContainer>
</DefaultWindow> </controls:FancyWindow>

View file

@ -1,19 +1,26 @@
using Content.Client.Power.Components;
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML; using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.Atmos.UI; namespace Content.Client.Atmos.UI;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class GasThermomachineWindow : DefaultWindow public sealed partial class GasThermomachineWindow : FancyWindow
{ {
[Dependency] private readonly IEntityManager _entManager = default!;
public bool Active = true; public bool Active = true;
public FloatSpinBox TemperatureSpinbox; public FloatSpinBox TemperatureSpinbox;
public EntityUid Entity;
public GasThermomachineWindow() public GasThermomachineWindow()
{ {
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
SpinboxHBox.AddChild( SpinboxHBox.AddChild(
@ -27,12 +34,10 @@ public sealed partial class GasThermomachineWindow : DefaultWindow
if (active) if (active)
{ {
ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-enabled"); ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-enabled");
ToggleStatusButton.Pressed = true;
} }
else else
{ {
ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-disabled"); ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-disabled");
ToggleStatusButton.Pressed = false;
} }
} }
@ -40,4 +45,14 @@ public sealed partial class GasThermomachineWindow : DefaultWindow
{ {
TemperatureSpinbox.Value = temperature; TemperatureSpinbox.Value = temperature;
} }
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (_entManager.TryGetComponent(Entity, out ApcPowerReceiverComponent? receiver))
{
SetActive(!receiver.PowerDisabled);
}
}
} }

View file

@ -2,35 +2,35 @@ using Robust.Client.GameObjects;
using Content.Shared.Atmos.Visuals; using Content.Shared.Atmos.Visuals;
using Content.Client.Power; using Content.Client.Power;
namespace Content.Client.Atmos.Visualizers namespace Content.Client.Atmos.Visualizers;
/// <summary>
/// Controls client-side visuals for portable scrubbers.
/// </summary>
public sealed class PortableScrubberSystem : VisualizerSystem<PortableScrubberVisualsComponent>
{ {
/// <summary> protected override void OnAppearanceChange(EntityUid uid, PortableScrubberVisualsComponent component, ref AppearanceChangeEvent args)
/// Controls client-side visuals for portable scrubbers.
/// </summary>
public sealed class PortableScrubberSystem : VisualizerSystem<PortableScrubberVisualsComponent>
{ {
protected override void OnAppearanceChange(EntityUid uid, PortableScrubberVisualsComponent component, ref AppearanceChangeEvent args) if (args.Sprite == null)
return;
if (AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsFull, out var isFull, args.Component)
&& AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsRunning, out var isRunning, args.Component))
{ {
if (args.Sprite == null) var runningState = isRunning ? component.RunningState : component.IdleState;
return; SpriteSystem.LayerSetRsiState((uid, args.Sprite), PortableScrubberVisualLayers.IsRunning, runningState);
if (AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsFull, out var isFull, args.Component) var fullState = isFull ? component.FullState : component.ReadyState;
&& AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsRunning, out var isRunning, args.Component)) SpriteSystem.LayerSetRsiState((uid, args.Sprite), PowerDeviceVisualLayers.Powered, fullState);
{ }
var runningState = isRunning ? component.RunningState : component.IdleState;
args.Sprite.LayerSetState(PortableScrubberVisualLayers.IsRunning, runningState);
var fullState = isFull ? component.FullState : component.ReadyState; if (AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsDraining, out var isDraining, args.Component))
args.Sprite.LayerSetState(PowerDeviceVisualLayers.Powered, fullState); {
} SpriteSystem.LayerSetVisible((uid, args.Sprite), PortableScrubberVisualLayers.IsDraining, isDraining);
if (AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsDraining, out var isDraining, args.Component))
{
args.Sprite.LayerSetVisible(PortableScrubberVisualLayers.IsDraining, isDraining);
}
} }
} }
} }
public enum PortableScrubberVisualLayers : byte public enum PortableScrubberVisualLayers : byte
{ {
IsRunning, IsRunning,

View file

@ -12,6 +12,7 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
[Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -64,7 +65,7 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
visualState = JukeboxVisualState.On; visualState = JukeboxVisualState.On;
} }
UpdateAppearance(uid, visualState, component, sprite); UpdateAppearance((uid, sprite), visualState, component);
} }
private void OnAppearanceChange(EntityUid uid, JukeboxComponent component, ref AppearanceChangeEvent args) private void OnAppearanceChange(EntityUid uid, JukeboxComponent component, ref AppearanceChangeEvent args)
@ -78,25 +79,25 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
visualState = JukeboxVisualState.On; visualState = JukeboxVisualState.On;
} }
UpdateAppearance(uid, visualState, component, args.Sprite); UpdateAppearance((uid, args.Sprite), visualState, component);
} }
private void UpdateAppearance(EntityUid uid, JukeboxVisualState visualState, JukeboxComponent component, SpriteComponent sprite) private void UpdateAppearance(Entity<SpriteComponent> entity, JukeboxVisualState visualState, JukeboxComponent component)
{ {
SetLayerState(JukeboxVisualLayers.Base, component.OffState, sprite); SetLayerState(JukeboxVisualLayers.Base, component.OffState, entity);
switch (visualState) switch (visualState)
{ {
case JukeboxVisualState.On: case JukeboxVisualState.On:
SetLayerState(JukeboxVisualLayers.Base, component.OnState, sprite); SetLayerState(JukeboxVisualLayers.Base, component.OnState, entity);
break; break;
case JukeboxVisualState.Off: case JukeboxVisualState.Off:
SetLayerState(JukeboxVisualLayers.Base, component.OffState, sprite); SetLayerState(JukeboxVisualLayers.Base, component.OffState, entity);
break; break;
case JukeboxVisualState.Select: case JukeboxVisualState.Select:
PlayAnimation(uid, JukeboxVisualLayers.Base, component.SelectState, 1.0f, sprite); PlayAnimation(entity.Owner, JukeboxVisualLayers.Base, component.SelectState, 1.0f, entity);
break; break;
} }
} }
@ -109,7 +110,7 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
if (!_animationPlayer.HasRunningAnimation(uid, state)) if (!_animationPlayer.HasRunningAnimation(uid, state))
{ {
var animation = GetAnimation(layer, state, animationTime); var animation = GetAnimation(layer, state, animationTime);
sprite.LayerSetVisible(layer, true); _sprite.LayerSetVisible((uid, sprite), layer, true);
_animationPlayer.Play(uid, animation, state); _animationPlayer.Play(uid, animation, state);
} }
} }
@ -133,13 +134,13 @@ public sealed class JukeboxSystem : SharedJukeboxSystem
}; };
} }
private void SetLayerState(JukeboxVisualLayers layer, string? state, SpriteComponent sprite) private void SetLayerState(JukeboxVisualLayers layer, string? state, Entity<SpriteComponent> sprite)
{ {
if (string.IsNullOrEmpty(state)) if (string.IsNullOrEmpty(state))
return; return;
sprite.LayerSetVisible(layer, true); _sprite.LayerSetVisible(sprite.AsNullable(), layer, true);
sprite.LayerSetAutoAnimated(layer, true); _sprite.LayerSetAutoAnimated(sprite.AsNullable(), layer, true);
sprite.LayerSetState(layer, state); _sprite.LayerSetRsiState(sprite.AsNullable(), layer, state);
} }
} }

View file

@ -41,12 +41,12 @@ public sealed class BarSignSystem : VisualizerSystem<BarSignComponent>
&& sign.Current != null && sign.Current != null
&& _prototypeManager.TryIndex(sign.Current, out var proto)) && _prototypeManager.TryIndex(sign.Current, out var proto))
{ {
sprite.LayerSetSprite(0, proto.Icon); SpriteSystem.LayerSetSprite((id, sprite), 0, proto.Icon);
sprite.LayerSetShader(0, "unshaded"); sprite.LayerSetShader(0, "unshaded");
} }
else else
{ {
sprite.LayerSetState(0, "empty"); SpriteSystem.LayerSetRsiState((id, sprite), 0, "empty");
sprite.LayerSetShader(0, null, null); sprite.LayerSetShader(0, null, null);
} }
} }

View file

@ -7,6 +7,8 @@ namespace Content.Client.Beam;
public sealed class BeamSystem : SharedBeamSystem public sealed class BeamSystem : SharedBeamSystem
{ {
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@ -21,11 +23,11 @@ public sealed class BeamSystem : SharedBeamSystem
if (TryComp<SpriteComponent>(beam, out var sprites)) if (TryComp<SpriteComponent>(beam, out var sprites))
{ {
sprites.Rotation = args.UserAngle; _sprite.SetRotation((beam, sprites), args.UserAngle);
if (args.BodyState != null) if (args.BodyState != null)
{ {
sprites.LayerSetState(0, args.BodyState); _sprite.LayerSetRsiState((beam, sprites), 0, args.BodyState);
sprites.LayerSetShader(0, args.Shader); sprites.LayerSetShader(0, args.Shader);
} }
} }

View file

@ -0,0 +1,8 @@
using Content.Shared.Bed;
namespace Content.Client.Bed;
public sealed class BedSystem : SharedBedSystem
{
}

View file

@ -10,7 +10,7 @@ public sealed class StasisBedSystem : VisualizerSystem<StasisBedVisualsComponent
if (args.Sprite != null if (args.Sprite != null
&& AppearanceSystem.TryGetData<bool>(uid, StasisBedVisuals.IsOn, out var isOn, args.Component)) && AppearanceSystem.TryGetData<bool>(uid, StasisBedVisuals.IsOn, out var isOn, args.Component))
{ {
args.Sprite.LayerSetVisible(StasisBedVisualLayers.IsOn, isOn); SpriteSystem.LayerSetVisible((uid, args.Sprite), StasisBedVisualLayers.IsOn, isOn);
} }
} }
} }

View file

@ -1,6 +1,7 @@
using Content.Client.Botany.Components; using Content.Client.Botany.Components;
using Content.Shared.Botany; using Content.Shared.Botany;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.Utility;
namespace Content.Client.Botany; namespace Content.Client.Botany;
@ -17,8 +18,8 @@ public sealed class PlantHolderVisualizerSystem : VisualizerSystem<PlantHolderVi
if (!TryComp<SpriteComponent>(uid, out var sprite)) if (!TryComp<SpriteComponent>(uid, out var sprite))
return; return;
sprite.LayerMapReserveBlank(PlantHolderLayers.Plant); SpriteSystem.LayerMapReserve((uid, sprite), PlantHolderLayers.Plant);
sprite.LayerSetVisible(PlantHolderLayers.Plant, false); SpriteSystem.LayerSetVisible((uid, sprite), PlantHolderLayers.Plant, false);
} }
protected override void OnAppearanceChange(EntityUid uid, PlantHolderVisualsComponent component, ref AppearanceChangeEvent args) protected override void OnAppearanceChange(EntityUid uid, PlantHolderVisualsComponent component, ref AppearanceChangeEvent args)
@ -31,12 +32,12 @@ public sealed class PlantHolderVisualizerSystem : VisualizerSystem<PlantHolderVi
{ {
var valid = !string.IsNullOrWhiteSpace(state); var valid = !string.IsNullOrWhiteSpace(state);
args.Sprite.LayerSetVisible(PlantHolderLayers.Plant, valid); SpriteSystem.LayerSetVisible((uid, args.Sprite), PlantHolderLayers.Plant, valid);
if (valid) if (valid)
{ {
args.Sprite.LayerSetRSI(PlantHolderLayers.Plant, rsi); SpriteSystem.LayerSetRsi((uid, args.Sprite), PlantHolderLayers.Plant, new ResPath(rsi));
args.Sprite.LayerSetState(PlantHolderLayers.Plant, state); SpriteSystem.LayerSetRsiState((uid, args.Sprite), PlantHolderLayers.Plant, state);
} }
} }
} }

View file

@ -15,7 +15,7 @@ public sealed class PotencyVisualsSystem : VisualizerSystem<PotencyVisualsCompon
if (AppearanceSystem.TryGetData<float>(uid, ProduceVisuals.Potency, out var potency, args.Component)) if (AppearanceSystem.TryGetData<float>(uid, ProduceVisuals.Potency, out var potency, args.Component))
{ {
var scale = MathHelper.Lerp(component.MinimumScale, component.MaximumScale, potency / 100); var scale = MathHelper.Lerp(component.MinimumScale, component.MaximumScale, potency / 100);
args.Sprite.Scale = new Vector2(scale, scale); SpriteSystem.SetScale((uid, args.Sprite), new Vector2(scale, scale));
} }
} }
} }

View file

@ -13,6 +13,7 @@ internal sealed class BuckleSystem : SharedBuckleSystem
[Dependency] private readonly RotationVisualizerSystem _rotationVisualizerSystem = default!; [Dependency] private readonly RotationVisualizerSystem _rotationVisualizerSystem = default!;
[Dependency] private readonly IEyeManager _eye = default!; [Dependency] private readonly IEyeManager _eye = default!;
[Dependency] private readonly SharedTransformSystem _xformSystem = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -69,11 +70,11 @@ internal sealed class BuckleSystem : SharedBuckleSystem
{ {
// This will only assign if empty, it won't get overwritten by new depth on multiple calls, which do happen easily // This will only assign if empty, it won't get overwritten by new depth on multiple calls, which do happen easily
buckle.OriginalDrawDepth ??= buckledSprite.DrawDepth; buckle.OriginalDrawDepth ??= buckledSprite.DrawDepth;
buckledSprite.DrawDepth = strapSprite.DrawDepth - 1; _sprite.SetDrawDepth((buckledEntity, buckledSprite), strapSprite.DrawDepth - 1);
} }
else if (buckle.OriginalDrawDepth.HasValue) else if (buckle.OriginalDrawDepth.HasValue)
{ {
buckledSprite.DrawDepth = buckle.OriginalDrawDepth.Value; _sprite.SetDrawDepth((buckledEntity, buckledSprite), buckle.OriginalDrawDepth.Value);
buckle.OriginalDrawDepth = null; buckle.OriginalDrawDepth = null;
} }
} }
@ -97,7 +98,7 @@ internal sealed class BuckleSystem : SharedBuckleSystem
return; return;
ent.Comp.OriginalDrawDepth ??= buckledSprite.DrawDepth; ent.Comp.OriginalDrawDepth ??= buckledSprite.DrawDepth;
buckledSprite.DrawDepth = strapSprite.DrawDepth - 1; _sprite.SetDrawDepth((ent.Owner, buckledSprite), strapSprite.DrawDepth - 1);
} }
/// <summary> /// <summary>
@ -111,7 +112,7 @@ internal sealed class BuckleSystem : SharedBuckleSystem
if (!ent.Comp.OriginalDrawDepth.HasValue) if (!ent.Comp.OriginalDrawDepth.HasValue)
return; return;
buckledSprite.DrawDepth = ent.Comp.OriginalDrawDepth.Value; _sprite.SetDrawDepth((ent.Owner, buckledSprite), ent.Comp.OriginalDrawDepth.Value);
ent.Comp.OriginalDrawDepth = null; ent.Comp.OriginalDrawDepth = null;
} }

View file

@ -13,6 +13,7 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
[Dependency] private readonly EntityLookupSystem _entityLookup = default!; [Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
private EntityQuery<BodyComponent> _bodyQuery; private EntityQuery<BodyComponent> _bodyQuery;
@ -74,7 +75,7 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
if (!xformQuery.TryGetComponent(ent, out var entTransform) || !TryComp<SpriteComponent>(ent, out var sprite)) if (!xformQuery.TryGetComponent(ent, out var entTransform) || !TryComp<SpriteComponent>(ent, out var sprite))
continue; continue;
sprite.Offset = new Vector2(0, 1); _sprite.SetOffset((ent, sprite), new Vector2(0, 1));
_transform.SetParent(ent, entTransform, mob); _transform.SetParent(ent, entTransform, mob);
} }

View file

@ -138,6 +138,11 @@ namespace Content.Client.Cargo.BUI
AccountName = cState.Name; AccountName = cState.Name;
if (_menu == null)
return;
_menu.ProductCatalogue = cState.Products;
_menu?.UpdateStation(station); _menu?.UpdateStation(station);
Populate(cState.Orders); Populate(cState.Orders);
} }

View file

@ -10,6 +10,7 @@ namespace Content.Client.Cargo.Systems;
public sealed partial class CargoSystem public sealed partial class CargoSystem
{ {
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
private static readonly Animation CargoTelepadBeamAnimation = new() private static readonly Animation CargoTelepadBeamAnimation = new()
{ {
@ -80,12 +81,12 @@ public sealed partial class CargoSystem
_player.Play((uid, player), CargoTelepadBeamAnimation, TelepadBeamKey); _player.Play((uid, player), CargoTelepadBeamAnimation, TelepadBeamKey);
break; break;
case CargoTelepadState.Unpowered: case CargoTelepadState.Unpowered:
sprite.LayerSetVisible(CargoTelepadLayers.Beam, false); _sprite.LayerSetVisible((uid, sprite), CargoTelepadLayers.Beam, false);
_player.Stop(uid, player, TelepadBeamKey); _player.Stop(uid, player, TelepadBeamKey);
_player.Stop(uid, player, TelepadIdleKey); _player.Stop(uid, player, TelepadIdleKey);
break; break;
default: default:
sprite.LayerSetVisible(CargoTelepadLayers.Beam, true); _sprite.LayerSetVisible((uid, sprite), CargoTelepadLayers.Beam, true);
if (_player.HasRunningAnimation(uid, player, TelepadIdleKey) || if (_player.HasRunningAnimation(uid, player, TelepadIdleKey) ||
_player.HasRunningAnimation(uid, player, TelepadBeamKey)) _player.HasRunningAnimation(uid, player, TelepadBeamKey))

View file

@ -38,9 +38,10 @@
<!-- Products get added here by code --> <!-- Products get added here by code -->
</BoxContainer> </BoxContainer>
</ScrollContainer> </ScrollContainer>
<Control MinHeight="5"/> <Control MinHeight="5" Name="OrdersSpacer"/>
<PanelContainer VerticalExpand="True" <PanelContainer VerticalExpand="True"
SizeFlagsStretchRatio="1"> SizeFlagsStretchRatio="1"
Name="Orders">
<PanelContainer.PanelOverride> <PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#000000" /> <gfx:StyleBoxFlat BackgroundColor="#000000" />
</PanelContainer.PanelOverride> </PanelContainer.PanelOverride>

View file

@ -40,6 +40,8 @@ namespace Content.Client.Cargo.UI
private readonly List<string> _categoryStrings = new(); private readonly List<string> _categoryStrings = new();
private string? _category; private string? _category;
public List<ProtoId<CargoProductPrototype>> ProductCatalogue = new();
public CargoConsoleMenu(EntityUid owner, IEntityManager entMan, IPrototypeManager protoManager, SpriteSystem spriteSystem) public CargoConsoleMenu(EntityUid owner, IEntityManager entMan, IPrototypeManager protoManager, SpriteSystem spriteSystem)
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
@ -113,14 +115,16 @@ namespace Content.Client.Cargo.UI
Categories.SelectId(id); Categories.SelectId(id);
} }
public IEnumerable<CargoProductPrototype> ProductPrototypes private IEnumerable<CargoProductPrototype> ProductPrototypes
{ {
get get
{ {
var allowedGroups = _entityManager.GetComponentOrNull<CargoOrderConsoleComponent>(_owner)?.AllowedGroups; var allowedGroups = _entityManager.GetComponentOrNull<CargoOrderConsoleComponent>(_owner)?.AllowedGroups;
foreach (var cargoPrototype in _protoManager.EnumeratePrototypes<CargoProductPrototype>()) foreach (var cargoPrototypeId in ProductCatalogue)
{ {
var cargoPrototype = _protoManager.Index(cargoPrototypeId);
if (!allowedGroups?.Contains(cargoPrototype.Group) ?? false) if (!allowedGroups?.Contains(cargoPrototype.Group) ?? false)
continue; continue;
@ -208,6 +212,7 @@ namespace Content.Client.Cargo.UI
var product = _protoManager.Index<EntityPrototype>(order.ProductId); var product = _protoManager.Index<EntityPrototype>(order.ProductId);
var productName = product.Name; var productName = product.Name;
var account = _protoManager.Index(order.Account);
var row = new CargoOrderRow var row = new CargoOrderRow
{ {
@ -219,7 +224,9 @@ namespace Content.Client.Cargo.UI
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text", "cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
("productName", productName), ("productName", productName),
("orderAmount", order.OrderQuantity), ("orderAmount", order.OrderQuantity),
("orderRequester", order.Requester)) ("orderRequester", order.Requester),
("accountColor", account.Color),
("account", Loc.GetString(account.Code)))
}, },
Description = Description =
{ {
@ -282,6 +289,9 @@ namespace Content.Client.Cargo.UI
AccountActionButton.Disabled = TransferSpinBox.Value <= 0 || AccountActionButton.Disabled = TransferSpinBox.Value <= 0 ||
TransferSpinBox.Value > bankAccount.Accounts[orderConsole.Account] * orderConsole.TransferLimit || TransferSpinBox.Value > bankAccount.Accounts[orderConsole.Account] * orderConsole.TransferLimit ||
_timing.CurTime < orderConsole.NextAccountActionTime; _timing.CurTime < orderConsole.NextAccountActionTime;
OrdersSpacer.Visible = !orderConsole.SlipPrinter;
Orders.Visible = !orderConsole.SlipPrinter;
} }
} }
} }

View file

@ -11,11 +11,10 @@
<BoxContainer Orientation="Vertical" <BoxContainer Orientation="Vertical"
HorizontalExpand="True" HorizontalExpand="True"
VerticalExpand="True"> VerticalExpand="True">
<Label Name="ProductName" <RichTextLabel Name="ProductName"
Access="Public" Access="Public"
HorizontalExpand="True" HorizontalExpand="True"
StyleClasses="LabelSubText" StyleClasses="LabelSubText" />
ClipText="True" />
<Label Name="Description" <Label Name="Description"
Access="Public" Access="Public"
HorizontalExpand="True" HorizontalExpand="True"

View file

@ -36,6 +36,7 @@ namespace Content.Client.Cargo.UI
{ {
var product = protoManager.Index<EntityPrototype>(order.ProductId); var product = protoManager.Index<EntityPrototype>(order.ProductId);
var productName = product.Name; var productName = product.Name;
var account = protoManager.Index(order.Account);
var row = new CargoOrderRow var row = new CargoOrderRow
{ {
@ -47,7 +48,9 @@ namespace Content.Client.Cargo.UI
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text", "cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
("productName", productName), ("productName", productName),
("orderAmount", order.OrderQuantity - order.NumDispatched), ("orderAmount", order.OrderQuantity - order.NumDispatched),
("orderRequester", order.Requester)) ("orderRequester", order.Requester),
("accountColor", account.Color),
("account", Loc.GetString(account.Code)))
}, },
Description = {Text = Loc.GetString("cargo-console-menu-order-reason-description", Description = {Text = Loc.GetString("cargo-console-menu-order-reason-description",
("reason", order.Reason))} ("reason", order.Reason))}

View file

@ -11,6 +11,7 @@ namespace Content.Client.Chasm;
public sealed class ChasmFallingVisualsSystem : EntitySystem public sealed class ChasmFallingVisualsSystem : EntitySystem
{ {
[Dependency] private readonly AnimationPlayerSystem _anim = default!; [Dependency] private readonly AnimationPlayerSystem _anim = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
private readonly string _chasmFallAnimationKey = "chasm_fall"; private readonly string _chasmFallAnimationKey = "chasm_fall";
@ -46,7 +47,7 @@ public sealed class ChasmFallingVisualsSystem : EntitySystem
if (!TryComp<SpriteComponent>(uid, out var sprite)) if (!TryComp<SpriteComponent>(uid, out var sprite))
return; return;
sprite.Scale = component.OriginalScale; _sprite.SetScale((uid, sprite), component.OriginalScale);
if (!TryComp<AnimationPlayerComponent>(uid, out var player)) if (!TryComp<AnimationPlayerComponent>(uid, out var player))
return; return;

View file

@ -16,6 +16,7 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem
private readonly TimeSpan _typingTimeout = TimeSpan.FromSeconds(2); private readonly TimeSpan _typingTimeout = TimeSpan.FromSeconds(2);
private TimeSpan _lastTextChange; private TimeSpan _lastTextChange;
private bool _isClientTyping; private bool _isClientTyping;
private bool _isClientChatFocused;
public override void Initialize() public override void Initialize()
{ {
@ -31,7 +32,8 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem
return; return;
// client typed something - show typing indicator // client typed something - show typing indicator
ClientUpdateTyping(true); _isClientTyping = true;
ClientUpdateTyping();
_lastTextChange = _time.CurTime; _lastTextChange = _time.CurTime;
} }
@ -42,36 +44,53 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem
return; return;
// client submitted text - hide typing indicator // client submitted text - hide typing indicator
ClientUpdateTyping(false); _isClientTyping = false;
ClientUpdateTyping();
}
public void ClientChangedChatFocus(bool isFocused)
{
// don't update it if player don't want to show typing
if (!_cfg.GetCVar(CCVars.ChatShowTypingIndicator))
return;
// client submitted text - hide typing indicator
_isClientChatFocused = isFocused;
ClientUpdateTyping();
} }
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);
if (!_time.IsFirstTimePredicted)
return;
// check if client didn't changed chat text box for a long time // check if client didn't changed chat text box for a long time
if (_isClientTyping) if (_isClientTyping)
{ {
var dif = _time.CurTime - _lastTextChange; var dif = _time.CurTime - _lastTextChange;
if (dif > _typingTimeout) if (dif > _typingTimeout)
{ {
// client didn't typed anything for a long time - hide indicator // client didn't typed anything for a long time - change indicator
ClientUpdateTyping(false); _isClientTyping = false;
ClientUpdateTyping();
} }
} }
} }
private void ClientUpdateTyping(bool isClientTyping) private void ClientUpdateTyping()
{ {
if (_isClientTyping == isClientTyping) // check if player controls any pawn
return;
// check if player controls any entity.
if (_playerManager.LocalEntity == null) if (_playerManager.LocalEntity == null)
return; return;
_isClientTyping = isClientTyping; var state = TypingIndicatorState.None;
RaisePredictiveEvent(new TypingChangedEvent(isClientTyping)); if (_isClientChatFocused)
state = _isClientTyping ? TypingIndicatorState.Typing : TypingIndicatorState.Idle;
// send a networked event to server
RaisePredictiveEvent(new TypingChangedEvent(state));
} }
private void OnShowTypingChanged(bool showTyping) private void OnShowTypingChanged(bool showTyping)
@ -79,7 +98,8 @@ public sealed class TypingIndicatorSystem : SharedTypingIndicatorSystem
// hide typing indicator immediately if player don't want to show it anymore // hide typing indicator immediately if player don't want to show it anymore
if (!showTyping) if (!showTyping)
{ {
ClientUpdateTyping(false); _isClientTyping = false;
ClientUpdateTyping();
} }
} }
} }

View file

@ -1,6 +1,5 @@
using Content.Shared.Chat.TypingIndicator; using Content.Shared.Chat.TypingIndicator;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Content.Shared.Inventory; using Content.Shared.Inventory;
@ -11,7 +10,6 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly InventorySystem _inventory = default!;
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args) protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
{ {
if (args.Sprite == null) if (args.Sprite == null)
@ -35,15 +33,25 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
return; return;
} }
AppearanceSystem.TryGetData<bool>(uid, TypingIndicatorVisuals.IsTyping, out var isTyping, args.Component); var layerExists = SpriteSystem.LayerMapTryGet((uid, args.Sprite), TypingIndicatorLayers.Base, out var layer, false);
var layerExists = args.Sprite.LayerMapTryGet(TypingIndicatorLayers.Base, out var layer);
if (!layerExists) if (!layerExists)
layer = args.Sprite.LayerMapReserveBlank(TypingIndicatorLayers.Base); layer = SpriteSystem.LayerMapReserve((uid, args.Sprite), TypingIndicatorLayers.Base);
args.Sprite.LayerSetRSI(layer, proto.SpritePath); SpriteSystem.LayerSetRsi((uid, args.Sprite), layer, proto.SpritePath);
args.Sprite.LayerSetState(layer, proto.TypingState); SpriteSystem.LayerSetRsiState((uid, args.Sprite), layer, proto.TypingState);
args.Sprite.LayerSetShader(layer, proto.Shader); args.Sprite.LayerSetShader(layer, proto.Shader);
args.Sprite.LayerSetOffset(layer, proto.Offset); SpriteSystem.LayerSetOffset((uid, args.Sprite), layer, proto.Offset);
args.Sprite.LayerSetVisible(layer, isTyping);
AppearanceSystem.TryGetData<TypingIndicatorState>(uid, TypingIndicatorVisuals.State, out var state);
SpriteSystem.LayerSetVisible((uid, args.Sprite), layer, state != TypingIndicatorState.None);
switch (state)
{
case TypingIndicatorState.Idle:
SpriteSystem.LayerSetRsiState((uid, args.Sprite), layer, proto.IdleState);
break;
case TypingIndicatorState.Typing:
SpriteSystem.LayerSetRsiState((uid, args.Sprite), layer, proto.TypingState);
break;
}
} }
} }

View file

@ -5,6 +5,8 @@ namespace Content.Client.Chemistry.EntitySystems;
public sealed class PillSystem : EntitySystem public sealed class PillSystem : EntitySystem
{ {
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@ -16,9 +18,9 @@ public sealed class PillSystem : EntitySystem
if (!TryComp(uid, out SpriteComponent? sprite)) if (!TryComp(uid, out SpriteComponent? sprite))
return; return;
if (!sprite.TryGetLayer(0, out var layer)) if (!_sprite.TryGetLayer((uid, sprite), 0, out var layer, false))
return; return;
layer.SetState($"pill{component.PillType + 1}"); _sprite.LayerSetRsiState(layer, $"pill{component.PillType + 1}");
} }
} }

View file

@ -44,7 +44,7 @@ public sealed class HyposprayStatusControl : Control
PrevMaxVolume = solution.MaxVolume; PrevMaxVolume = solution.MaxVolume;
PrevOnlyAffectsMobs = _parent.Comp.OnlyAffectsMobs; PrevOnlyAffectsMobs = _parent.Comp.OnlyAffectsMobs;
var modeStringLocalized = Loc.GetString(_parent.Comp.OnlyAffectsMobs switch var modeStringLocalized = Loc.GetString((_parent.Comp.OnlyAffectsMobs && _parent.Comp.CanContainerDraw) switch
{ {
false => "hypospray-all-mode-text", false => "hypospray-all-mode-text",
true => "hypospray-mobs-only-mode-text", true => "hypospray-mobs-only-mode-text",

View file

@ -1,4 +1,5 @@
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
using Content.Shared.Storage;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
@ -9,15 +10,15 @@ namespace Content.Client.Chemistry.UI;
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class ReagentCardControl : Control public sealed partial class ReagentCardControl : Control
{ {
public string StorageSlotId { get; } public ItemStorageLocation StorageLocation { get; }
public Action<string>? OnPressed; public Action<ItemStorageLocation>? OnPressed;
public Action<string>? OnEjectButtonPressed; public Action<ItemStorageLocation>? OnEjectButtonPressed;
public ReagentCardControl(ReagentInventoryItem item) public ReagentCardControl(ReagentInventoryItem item)
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
StorageSlotId = item.StorageSlotId; StorageLocation = item.StorageLocation;
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor }; ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor };
ReagentNameLabel.Text = item.ReagentLabel; ReagentNameLabel.Text = item.ReagentLabel;
FillLabel.Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", item.Quantity));; FillLabel.Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", item.Quantity));;
@ -26,7 +27,7 @@ public sealed partial class ReagentCardControl : Control
if (item.Quantity == 0.0) if (item.Quantity == 0.0)
MainButton.Disabled = true; MainButton.Disabled = true;
MainButton.OnPressed += args => OnPressed?.Invoke(StorageSlotId); MainButton.OnPressed += args => OnPressed?.Invoke(StorageLocation);
EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageSlotId); EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageLocation);
} }
} }

View file

@ -40,8 +40,8 @@ namespace Content.Client.Chemistry.UI
_window.AmountGrid.OnButtonPressed += s => SendMessage(new ReagentDispenserSetDispenseAmountMessage(s)); _window.AmountGrid.OnButtonPressed += s => SendMessage(new ReagentDispenserSetDispenseAmountMessage(s));
_window.OnDispenseReagentButtonPressed += (id) => SendMessage(new ReagentDispenserDispenseReagentMessage(id)); _window.OnDispenseReagentButtonPressed += (location) => SendMessage(new ReagentDispenserDispenseReagentMessage(location));
_window.OnEjectJugButtonPressed += (id) => SendMessage(new ItemSlotButtonPressedEvent(id)); _window.OnEjectJugButtonPressed += (location) => SendMessage(new ReagentDispenserEjectContainerMessage(location));
} }
/// <summary> /// <summary>

View file

@ -2,6 +2,7 @@ using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Controls;
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent; using Content.Shared.Chemistry.Reagent;
using Content.Shared.Storage;
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;
@ -18,8 +19,8 @@ namespace Content.Client.Chemistry.UI
{ {
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
public event Action<string>? OnDispenseReagentButtonPressed; public event Action<ItemStorageLocation>? OnDispenseReagentButtonPressed;
public event Action<string>? OnEjectJugButtonPressed; public event Action<ItemStorageLocation>? OnEjectJugButtonPressed;
/// <summary> /// <summary>
/// Create and initialize the dispenser UI client-side. Creates the basic layout, /// Create and initialize the dispenser UI client-side. Creates the basic layout,

View file

@ -71,7 +71,7 @@ public sealed class FoamVisualizerSystem : VisualizerSystem<FoamVisualsComponent
return; return;
if (TryComp<SpriteComponent>(uid, out var sprite)) if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.Visible = false; SpriteSystem.SetVisible((uid, sprite), false);
} }
} }

View file

@ -15,8 +15,8 @@ public sealed class SmokeVisualizerSystem : VisualizerSystem<SmokeVisualsCompone
{ {
if (args.Sprite == null) if (args.Sprite == null)
return; return;
if(!AppearanceSystem.TryGetData<Color>(uid, SmokeVisuals.Color, out var color)) if (!AppearanceSystem.TryGetData<Color>(uid, SmokeVisuals.Color, out var color))
return; return;
args.Sprite.Color = color; SpriteSystem.SetColor((uid, args.Sprite), color);
} }
} }

View file

@ -49,7 +49,7 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
if (args.Sprite == null) if (args.Sprite == null)
return; return;
if (!args.Sprite.LayerMapTryGet(component.Layer, out var fillLayer)) if (!SpriteSystem.LayerMapTryGet((uid, args.Sprite), component.Layer, out var fillLayer, false))
return; return;
var maxFillLevels = component.MaxFillLevels; var maxFillLevels = component.MaxFillLevels;
@ -67,9 +67,9 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
} }
if (component.Metamorphic) if (component.Metamorphic)
{ {
if (args.Sprite.LayerMapTryGet(component.BaseLayer, out var baseLayer)) if (SpriteSystem.LayerMapTryGet((uid, args.Sprite), component.BaseLayer, out var baseLayer, false))
{ {
var hasOverlay = args.Sprite.LayerMapTryGet(component.OverlayLayer, out var overlayLayer); var hasOverlay = SpriteSystem.LayerMapTryGet((uid, args.Sprite), component.OverlayLayer, out var overlayLayer, false);
if (AppearanceSystem.TryGetData<string>(uid, SolutionContainerVisuals.BaseOverride, if (AppearanceSystem.TryGetData<string>(uid, SolutionContainerVisuals.BaseOverride,
out var baseOverride, out var baseOverride,
@ -79,35 +79,35 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
if (reagentProto?.MetamorphicSprite is { } sprite) if (reagentProto?.MetamorphicSprite is { } sprite)
{ {
args.Sprite.LayerSetSprite(baseLayer, sprite); SpriteSystem.LayerSetSprite((uid, args.Sprite), baseLayer, sprite);
if (reagentProto.MetamorphicMaxFillLevels > 0) if (reagentProto.MetamorphicMaxFillLevels > 0)
{ {
args.Sprite.LayerSetVisible(fillLayer, true); SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, true);
maxFillLevels = reagentProto.MetamorphicMaxFillLevels; maxFillLevels = reagentProto.MetamorphicMaxFillLevels;
fillBaseName = reagentProto.MetamorphicFillBaseName; fillBaseName = reagentProto.MetamorphicFillBaseName;
changeColor = reagentProto.MetamorphicChangeColor; changeColor = reagentProto.MetamorphicChangeColor;
fillSprite = sprite; fillSprite = sprite;
} }
else else
args.Sprite.LayerSetVisible(fillLayer, false); SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, false);
if (hasOverlay) if (hasOverlay)
args.Sprite.LayerSetVisible(overlayLayer, false); SpriteSystem.LayerSetVisible((uid, args.Sprite), overlayLayer, false);
} }
else else
{ {
args.Sprite.LayerSetVisible(fillLayer, true); SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, true);
if (hasOverlay) if (hasOverlay)
args.Sprite.LayerSetVisible(overlayLayer, true); SpriteSystem.LayerSetVisible((uid, args.Sprite), overlayLayer, true);
if (component.MetamorphicDefaultSprite != null) if (component.MetamorphicDefaultSprite != null)
args.Sprite.LayerSetSprite(baseLayer, component.MetamorphicDefaultSprite); SpriteSystem.LayerSetSprite((uid, args.Sprite), baseLayer, component.MetamorphicDefaultSprite);
} }
} }
} }
} }
else else
{ {
args.Sprite.LayerSetVisible(fillLayer, true); SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, true);
} }
var closestFillSprite = ContentHelpers.RoundToLevels(fraction, 1, maxFillLevels + 1); var closestFillSprite = ContentHelpers.RoundToLevels(fraction, 1, maxFillLevels + 1);
@ -119,25 +119,25 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
var stateName = fillBaseName + closestFillSprite; var stateName = fillBaseName + closestFillSprite;
if (fillSprite != null) if (fillSprite != null)
args.Sprite.LayerSetSprite(fillLayer, fillSprite); SpriteSystem.LayerSetSprite((uid, args.Sprite), fillLayer, fillSprite);
args.Sprite.LayerSetState(fillLayer, stateName); SpriteSystem.LayerSetRsiState((uid, args.Sprite), fillLayer, stateName);
if (changeColor && AppearanceSystem.TryGetData<Color>(uid, SolutionContainerVisuals.Color, out var color, args.Component)) if (changeColor && AppearanceSystem.TryGetData<Color>(uid, SolutionContainerVisuals.Color, out var color, args.Component))
args.Sprite.LayerSetColor(fillLayer, color); SpriteSystem.LayerSetColor((uid, args.Sprite), fillLayer, color);
else else
args.Sprite.LayerSetColor(fillLayer, Color.White); SpriteSystem.LayerSetColor((uid, args.Sprite), fillLayer, Color.White);
} }
else else
{ {
if (component.EmptySpriteName == null) if (component.EmptySpriteName == null)
args.Sprite.LayerSetVisible(fillLayer, false); SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, false);
else else
{ {
args.Sprite.LayerSetState(fillLayer, component.EmptySpriteName); SpriteSystem.LayerSetRsiState((uid, args.Sprite), fillLayer, component.EmptySpriteName);
if (changeColor) if (changeColor)
args.Sprite.LayerSetColor(fillLayer, component.EmptySpriteColor); SpriteSystem.LayerSetColor((uid, args.Sprite), fillLayer, component.EmptySpriteColor);
else else
args.Sprite.LayerSetColor(fillLayer, Color.White); SpriteSystem.LayerSetColor((uid, args.Sprite), fillLayer, Color.White);
} }
} }

View file

@ -52,7 +52,7 @@ public sealed class VaporVisualizerSystem : VisualizerSystem<VaporVisualsCompone
{ {
if (AppearanceSystem.TryGetData<Color>(uid, VaporVisuals.Color, out var color, args.Component) && args.Sprite != null) if (AppearanceSystem.TryGetData<Color>(uid, VaporVisuals.Color, out var color, args.Component) && args.Sprite != null)
{ {
args.Sprite.Color = color; SpriteSystem.SetColor((uid, args.Sprite), color);
} }
} }
} }

View file

@ -77,10 +77,10 @@ public sealed class ClickableSystem : EntitySystem
drawDepth = sprite.DrawDepth; drawDepth = sprite.DrawDepth;
renderOrder = sprite.RenderOrder; renderOrder = sprite.RenderOrder;
var (spritePos, spriteRot) = _transforms.GetWorldPositionRotation(transform); var (spritePos, spriteRot) = _transforms.GetWorldPositionRotation(transform);
var spriteBB = sprite.CalculateRotatedBoundingBox(spritePos, spriteRot, eye.Rotation); var spriteBB = _sprites.CalculateBounds((entity.Owner, sprite), spritePos, spriteRot, eye.Rotation);
bottom = Matrix3Helpers.CreateRotation(eye.Rotation).TransformBox(spriteBB).Bottom; bottom = Matrix3Helpers.CreateRotation(eye.Rotation).TransformBox(spriteBB).Bottom;
Matrix3x2.Invert(sprite.GetLocalMatrix(), out var invSpriteMatrix); Matrix3x2.Invert(sprite.LocalMatrix, out var invSpriteMatrix);
// This should have been the rotation of the sprite relative to the screen, but this is not the case with no-rot or directional sprites. // This should have been the rotation of the sprite relative to the screen, but this is not the case with no-rot or directional sprites.
var relativeRotation = (spriteRot + eye.Rotation).Reduced().FlipPositive(); var relativeRotation = (spriteRot + eye.Rotation).Reduced().FlipPositive();
@ -107,7 +107,7 @@ public sealed class ClickableSystem : EntitySystem
if (layer.Texture != null) if (layer.Texture != null)
{ {
// Convert to image coordinates // Convert to image coordinates
var imagePos = (Vector2i) (localPos * EyeManager.PixelsPerMeter * new Vector2(1, -1) + layer.Texture.Size / 2f); var imagePos = (Vector2i)(localPos * EyeManager.PixelsPerMeter * new Vector2(1, -1) + layer.Texture.Size / 2f);
if (_clickMapManager.IsOccluding(layer.Texture, imagePos)) if (_clickMapManager.IsOccluding(layer.Texture, imagePos))
return true; return true;
@ -125,7 +125,7 @@ public sealed class ClickableSystem : EntitySystem
var layerLocal = Vector2.Transform(localPos, inverseMatrix); var layerLocal = Vector2.Transform(localPos, inverseMatrix);
// Convert to image coordinates // Convert to image coordinates
var layerImagePos = (Vector2i) (layerLocal * EyeManager.PixelsPerMeter * new Vector2(1, -1) + rsiState.Size / 2f); var layerImagePos = (Vector2i)(layerLocal * EyeManager.PixelsPerMeter * new Vector2(1, -1) + rsiState.Size / 2f);
// Next, to get the right click map we need the "direction" of this layer that is actually being used to draw the sprite on the screen. // Next, to get the right click map we need the "direction" of this layer that is actually being used to draw the sprite on the screen.
// This **can** differ from the dir defined before, but can also just be the same. // This **can** differ from the dir defined before, but can also just be the same.

View file

@ -5,6 +5,8 @@ namespace Content.Client.Clock;
public sealed class ClockSystem : SharedClockSystem public sealed class ClockSystem : SharedClockSystem
{ {
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);
@ -12,15 +14,15 @@ public sealed class ClockSystem : SharedClockSystem
var query = EntityQueryEnumerator<ClockComponent, SpriteComponent>(); var query = EntityQueryEnumerator<ClockComponent, SpriteComponent>();
while (query.MoveNext(out var uid, out var comp, out var sprite)) while (query.MoveNext(out var uid, out var comp, out var sprite))
{ {
if (!sprite.LayerMapTryGet(ClockVisualLayers.HourHand, out var hourLayer) || if (!_sprite.LayerMapTryGet((uid, sprite), ClockVisualLayers.HourHand, out var hourLayer, false) ||
!sprite.LayerMapTryGet(ClockVisualLayers.MinuteHand, out var minuteLayer)) !_sprite.LayerMapTryGet((uid, sprite), ClockVisualLayers.MinuteHand, out var minuteLayer, false))
continue; continue;
var time = GetClockTime((uid, comp)); var time = GetClockTime((uid, comp));
var hourState = $"{comp.HoursBase}{time.Hours % 12}"; var hourState = $"{comp.HoursBase}{time.Hours % 12}";
var minuteState = $"{comp.MinutesBase}{time.Minutes / 5}"; var minuteState = $"{comp.MinutesBase}{time.Minutes / 5}";
sprite.LayerSetState(hourLayer, hourState); _sprite.LayerSetRsiState((uid, sprite), hourLayer, hourState);
sprite.LayerSetState(minuteLayer, minuteState); _sprite.LayerSetRsiState((uid, sprite), minuteLayer, minuteState);
} }
} }
} }

View file

@ -58,6 +58,7 @@ public sealed class ClientClothingSystem : ClothingSystem
[Dependency] private readonly IResourceCache _cache = default!; [Dependency] private readonly IResourceCache _cache = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!; [Dependency] private readonly DisplacementMapSystem _displacement = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!;
@ -82,10 +83,10 @@ public sealed class ClientClothingSystem : ClothingSystem
UpdateAllSlots(uid, component); UpdateAllSlots(uid, component);
// No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip. // No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip.
if (args.Sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer)) if (_sprite.LayerMapTryGet((uid, args.Sprite), HumanoidVisualLayers.StencilMask, out var layer, false))
{ {
DebugTools.Assert(!args.Sprite[layer].Visible); DebugTools.Assert(!args.Sprite[layer].Visible);
args.Sprite.LayerSetVisible(layer, false); _sprite.LayerSetVisible((uid, args.Sprite), layer, false);
} }
} }
@ -214,9 +215,9 @@ public sealed class ClientClothingSystem : ClothingSystem
RenderEquipment(uid, item, clothing.InSlot, component, null, clothing); RenderEquipment(uid, item, clothing.InSlot, component, null, clothing);
} }
private void OnDidUnequip(EntityUid uid, SpriteComponent component, DidUnequipEvent args) private void OnDidUnequip(Entity<SpriteComponent> entity, ref DidUnequipEvent args)
{ {
if (!TryComp(uid, out InventorySlotsComponent? inventorySlots)) if (!TryComp(entity, out InventorySlotsComponent? inventorySlots))
return; return;
if (!inventorySlots.VisualLayerKeys.TryGetValue(args.Slot, out var revealedLayers)) if (!inventorySlots.VisualLayerKeys.TryGetValue(args.Slot, out var revealedLayers))
@ -226,7 +227,7 @@ public sealed class ClientClothingSystem : ClothingSystem
// may eventually bloat the player with lots of invisible layers. // may eventually bloat the player with lots of invisible layers.
foreach (var layer in revealedLayers) foreach (var layer in revealedLayers)
{ {
component.RemoveLayer(layer); _sprite.RemoveLayer(entity.AsNullable(), layer);
} }
revealedLayers.Clear(); revealedLayers.Clear();
} }
@ -269,7 +270,7 @@ public sealed class ClientClothingSystem : ClothingSystem
{ {
foreach (var key in revealedLayers) foreach (var key in revealedLayers)
{ {
sprite.RemoveLayer(key); _sprite.RemoveLayer((equipee, sprite), key);
} }
revealedLayers.Clear(); revealedLayers.Clear();
} }
@ -290,7 +291,7 @@ public sealed class ClientClothingSystem : ClothingSystem
// temporary, until layer draw depths get added. Basically: a layer with the key "slot" is being used as a // temporary, until layer draw depths get added. Basically: a layer with the key "slot" is being used as a
// bookmark to determine where in the list of layers we should insert the clothing layers. // bookmark to determine where in the list of layers we should insert the clothing layers.
bool slotLayerExists = sprite.LayerMapTryGet(slot, out var index); var slotLayerExists = _sprite.LayerMapTryGet((equipee, sprite), slot, out var index, false);
// Select displacement maps // Select displacement maps
var displacementData = inventory.Displacements.GetValueOrDefault(slot); //Default unsexed map var displacementData = inventory.Displacements.GetValueOrDefault(slot); //Default unsexed map
@ -348,16 +349,16 @@ public sealed class ClientClothingSystem : ClothingSystem
{ {
index++; index++;
// note that every insertion requires reshuffling & remapping all the existing layers. // note that every insertion requires reshuffling & remapping all the existing layers.
sprite.AddBlankLayer(index); _sprite.AddBlankLayer((equipee, sprite), index);
sprite.LayerMapSet(key, index); _sprite.LayerMapSet((equipee, sprite), key, index);
if (layerData.Color != null) if (layerData.Color != null)
sprite.LayerSetColor(key, layerData.Color.Value); _sprite.LayerSetColor((equipee, sprite), key, layerData.Color.Value);
if (layerData.Scale != null) if (layerData.Scale != null)
sprite.LayerSetScale(key, layerData.Scale.Value); _sprite.LayerSetScale((equipee, sprite), key, layerData.Scale.Value);
} }
else else
index = sprite.LayerMapReserveBlank(key); index = _sprite.LayerMapReserve((equipee, sprite), key);
if (sprite[index] is not Layer layer) if (sprite[index] is not Layer layer)
continue; continue;
@ -368,11 +369,11 @@ public sealed class ClientClothingSystem : ClothingSystem
&& layer.RSI == null && layer.RSI == null
&& TryComp(equipment, out SpriteComponent? clothingSprite)) && TryComp(equipment, out SpriteComponent? clothingSprite))
{ {
layer.SetRsi(clothingSprite.BaseRSI); _sprite.LayerSetRsi(layer, clothingSprite.BaseRSI);
} }
sprite.LayerSetData(index, layerData); _sprite.LayerSetData((equipee, sprite), index, layerData);
layer.Offset += slotDef.Offset; _sprite.LayerSetOffset(layer, layer.Offset + slotDef.Offset);
if (displacementData is not null) if (displacementData is not null)
{ {
@ -381,7 +382,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|| bodyTypeName is not null && layerData.State.EndsWith(bodyTypeName))) || bodyTypeName is not null && layerData.State.EndsWith(bodyTypeName)))
continue; continue;
if (_displacement.TryAddDisplacement(displacementData, sprite, index, key, out var displacementKey)) if (_displacement.TryAddDisplacement(displacementData, (equipee, sprite), index, key, out var displacementKey))
{ {
revealedLayers.Add(displacementKey); revealedLayers.Add(displacementKey);
index++; index++;

View file

@ -32,7 +32,7 @@ public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<Flippab
if (clothing.MappedLayer == null || if (clothing.MappedLayer == null ||
!AppearanceSystem.TryGetData<bool>(ent, FoldableSystem.FoldedVisuals.State, out var folding) || !AppearanceSystem.TryGetData<bool>(ent, FoldableSystem.FoldedVisuals.State, out var folding) ||
!sprite.LayerMapTryGet(folding ? ent.Comp.FoldingLayer : ent.Comp.UnfoldingLayer, out var idx)) !SpriteSystem.LayerMapTryGet((ent.Owner, sprite), folding ? ent.Comp.FoldingLayer : ent.Comp.UnfoldingLayer, out var idx, false))
return; return;
// add each layer to the visuals // add each layer to the visuals

View file

@ -12,8 +12,6 @@ namespace Content.Client.Clothing.Systems;
public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem
{ {
[Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly EntityManager _entManager = default!;
private static readonly SlotFlags[] IgnoredSlots = private static readonly SlotFlags[] IgnoredSlots =
{ {
@ -49,7 +47,7 @@ public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem
{ {
base.UpdateSprite(uid, proto); base.UpdateSprite(uid, proto);
if (TryComp(uid, out SpriteComponent? sprite) if (TryComp(uid, out SpriteComponent? sprite)
&& proto.TryGetComponent(out SpriteComponent? otherSprite, _factory)) && proto.TryGetComponent(out SpriteComponent? otherSprite, Factory))
{ {
sprite.CopyFrom(otherSprite); sprite.CopyFrom(otherSprite);
} }
@ -65,14 +63,14 @@ public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem
return; return;
if (TryComp(helmet.ClothingUid, out SpriteComponent? helmetSprite) if (TryComp(helmet.ClothingUid, out SpriteComponent? helmetSprite)
&& prototypeHelmetOther.TryGetComponent(out SpriteComponent? otherHelmetSprite, _factory)) && prototypeHelmetOther.TryGetComponent(out SpriteComponent? otherHelmetSprite, Factory))
{ {
helmetSprite.CopyFrom(otherHelmetSprite); helmetSprite.CopyFrom(otherHelmetSprite);
} }
// Sunrise-end // Sunrise-end
// Edgecase for PDAs to include visuals when UI is open // Edgecase for PDAs to include visuals when UI is open
if (TryComp(uid, out PdaBorderColorComponent? borderColor) if (TryComp(uid, out PdaBorderColorComponent? borderColor)
&& proto.TryGetComponent(out PdaBorderColorComponent? otherBorderColor, _factory)) && proto.TryGetComponent(out PdaBorderColorComponent? otherBorderColor, Factory))
{ {
borderColor.BorderColor = otherBorderColor.BorderColor; borderColor.BorderColor = otherBorderColor.BorderColor;
borderColor.AccentHColor = otherBorderColor.AccentHColor; borderColor.AccentHColor = otherBorderColor.AccentHColor;
@ -106,7 +104,7 @@ public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem
// check if this is valid clothing // check if this is valid clothing
if (!IsValidTarget(proto)) if (!IsValidTarget(proto))
continue; continue;
if (!proto.TryGetComponent(out ClothingComponent? item, _factory)) if (!proto.TryGetComponent(out ClothingComponent? item, Factory))
continue; continue;
// sort item by their slot flags // sort item by their slot flags

View file

@ -12,7 +12,6 @@ namespace Content.Client.Clothing.UI;
[UsedImplicitly] [UsedImplicitly]
public sealed class ChameleonBoundUserInterface : BoundUserInterface public sealed class ChameleonBoundUserInterface : BoundUserInterface
{ {
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly IPrototypeManager _proto = default!;
private readonly ChameleonClothingSystem _chameleon; private readonly ChameleonClothingSystem _chameleon;
private readonly TagSystem _tag; private readonly TagSystem _tag;
@ -49,7 +48,7 @@ public sealed class ChameleonBoundUserInterface : BoundUserInterface
if (string.IsNullOrEmpty(target) || !_proto.TryIndex(target, out EntityPrototype? proto)) if (string.IsNullOrEmpty(target) || !_proto.TryIndex(target, out EntityPrototype? proto))
continue; continue;
if (!proto.TryGetComponent(out TagComponent? tag, _factory) || !_tag.HasTag(tag, st.RequiredTag)) if (!proto.TryGetComponent(out TagComponent? tag, EntMan.ComponentFactory) || !_tag.HasTag(tag, st.RequiredTag))
continue; continue;
newTargets.Add(target); newTargets.Add(target);

View file

@ -18,23 +18,19 @@ public sealed class HideMechanismsCommand : LocalizedCommands
public override void Execute(IConsoleShell shell, string argStr, string[] args) public override void Execute(IConsoleShell shell, string argStr, string[] args)
{ {
var containerSys = _entityManager.System<SharedContainerSystem>(); var containerSys = _entityManager.System<SharedContainerSystem>();
var query = _entityManager.AllEntityQueryEnumerator<OrganComponent>(); var spriteSys = _entityManager.System<SpriteSystem>();
var query = _entityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
while (query.MoveNext(out var uid, out _)) while (query.MoveNext(out var uid, out _, out var sprite))
{ {
if (!_entityManager.TryGetComponent(uid, out SpriteComponent? sprite)) spriteSys.SetContainerOccluded((uid, sprite), false);
{
continue;
}
sprite.ContainerOccluded = false;
var tempParent = uid; var tempParent = uid;
while (containerSys.TryGetContainingContainer((tempParent, null, null), out var container)) while (containerSys.TryGetContainingContainer((tempParent, null, null), out var container))
{ {
if (!container.ShowContents) if (!container.ShowContents)
{ {
sprite.ContainerOccluded = true; spriteSys.SetContainerOccluded((uid, sprite), true);
break; break;
} }

View file

@ -16,11 +16,12 @@ public sealed class ShowMechanismsCommand : LocalizedCommands
public override void Execute(IConsoleShell shell, string argStr, string[] args) public override void Execute(IConsoleShell shell, string argStr, string[] args)
{ {
var spriteSys = _entManager.System<SpriteSystem>();
var query = _entManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>(); var query = _entManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
while (query.MoveNext(out _, out var sprite)) while (query.MoveNext(out var uid, out _, out var sprite))
{ {
sprite.ContainerOccluded = false; spriteSys.SetContainerOccluded((uid, sprite), false);
} }
} }
} }

View file

@ -27,6 +27,7 @@ namespace Content.Client.Construction
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly ExamineSystemShared _examineSystem = default!; [Dependency] private readonly ExamineSystemShared _examineSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!;
private readonly Dictionary<int, EntityUid> _ghosts = new(); private readonly Dictionary<int, EntityUid> _ghosts = new();
@ -293,14 +294,14 @@ namespace Content.Client.Construction
_ghosts.Add(comp.GhostId, ghost.Value); _ghosts.Add(comp.GhostId, ghost.Value);
var sprite = EntityManager.GetComponent<SpriteComponent>(ghost.Value); var sprite = EntityManager.GetComponent<SpriteComponent>(ghost.Value);
sprite.Color = new Color(48, 255, 48, 128); _sprite.SetColor((ghost.Value, sprite), new Color(48, 255, 48, 128));
if (targetProto.TryGetComponent(out IconComponent? icon, EntityManager.ComponentFactory)) if (targetProto.TryGetComponent(out IconComponent? icon, EntityManager.ComponentFactory))
{ {
sprite.AddBlankLayer(0); _sprite.AddBlankLayer((ghost.Value, sprite), 0);
sprite.LayerSetSprite(0, icon.Icon); _sprite.LayerSetSprite((ghost.Value, sprite), 0, icon.Icon);
sprite.LayerSetShader(0, "unshaded"); sprite.LayerSetShader(0, "unshaded");
sprite.LayerSetVisible(0, true); _sprite.LayerSetVisible((ghost.Value, sprite), 0, true);
} }
else if (targetProto.Components.TryGetValue("Sprite", out _)) else if (targetProto.Components.TryGetValue("Sprite", out _))
{ {
@ -318,10 +319,10 @@ namespace Content.Client.Construction
state.StateId.Name is null) state.StateId.Name is null)
continue; continue;
sprite.AddBlankLayer(i); _sprite.AddBlankLayer((ghost.Value, sprite), i);
sprite.LayerSetSprite(i, new SpriteSpecifier.Rsi(rsi.Path, state.StateId.Name)); _sprite.LayerSetSprite((ghost.Value, sprite), i, new SpriteSpecifier.Rsi(rsi.Path, state.StateId.Name));
sprite.LayerSetShader(i, "unshaded"); sprite.LayerSetShader(i, "unshaded");
sprite.LayerSetVisible(i, true); _sprite.LayerSetVisible((ghost.Value, sprite), i, true);
} }
EntityManager.DeleteEntity(dummy); EntityManager.DeleteEntity(dummy);

View file

@ -9,6 +9,7 @@ namespace Content.Client.Construction;
public sealed class FlatpackSystem : SharedFlatpackSystem public sealed class FlatpackSystem : SharedFlatpackSystem
{ {
[Dependency] private readonly AppearanceSystem _appearance = default!; [Dependency] private readonly AppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <inheritdoc/> /// <inheritdoc/>
public override void Initialize() public override void Initialize()
@ -43,6 +44,6 @@ public sealed class FlatpackSystem : SharedFlatpackSystem
} }
if (color != null) if (color != null)
args.Sprite.LayerSetColor(FlatpackVisualLayers.Overlay, color.Value); _sprite.LayerSetColor((ent.Owner, args.Sprite), FlatpackVisualLayers.Overlay, color.Value);
} }
} }

View file

@ -1,5 +1,6 @@
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Content.Client.Lobby;
using Content.Client.Stylesheets; using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.MenuBar.Widgets; using Content.Client.UserInterface.Systems.MenuBar.Widgets;
using Content.Shared.Construction.Prototypes; using Content.Shared.Construction.Prototypes;
@ -28,6 +29,7 @@ namespace Content.Client.Construction.UI
[Dependency] private readonly IPlacementManager _placementManager = default!; [Dependency] private readonly IPlacementManager _placementManager = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!; [Dependency] private readonly IUserInterfaceManager _uiManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
private readonly SpriteSystem _spriteSystem; private readonly SpriteSystem _spriteSystem;
private readonly IConstructionMenuView _constructionView; private readonly IConstructionMenuView _constructionView;
@ -116,7 +118,7 @@ namespace Content.Client.Construction.UI
_constructionView.RecipeFavorited += (_, _) => OnViewFavoriteRecipe(); _constructionView.RecipeFavorited += (_, _) => OnViewFavoriteRecipe();
PopulateCategories(); SetFavorites(_preferencesManager.Preferences?.ConstructionFavorites ?? []);
OnViewPopulateRecipes(_constructionView, (string.Empty, string.Empty)); OnViewPopulateRecipes(_constructionView, (string.Empty, string.Empty));
} }
@ -493,10 +495,34 @@ namespace Content.Client.Construction.UI
_favoritedRecipes.Count > 0 ? (string.Empty, FavoriteCatName) : (string.Empty, string.Empty)); _favoritedRecipes.Count > 0 ? (string.Empty, FavoriteCatName) : (string.Empty, string.Empty));
} }
var newFavorites = new List<ProtoId<ConstructionPrototype>>(_favoritedRecipes.Count);
foreach (var recipe in _favoritedRecipes)
newFavorites.Add(recipe.ID);
_preferencesManager.UpdateConstructionFavorites(newFavorites);
PopulateInfo(_selected); PopulateInfo(_selected);
PopulateCategories(_selectedCategory); PopulateCategories(_selectedCategory);
} }
public void SetFavorites(IReadOnlyList<ProtoId<ConstructionPrototype>> favorites)
{
_favoritedRecipes.Clear();
foreach (var id in favorites)
{
if (_prototypeManager.TryIndex(id, out ConstructionPrototype? recipe, logError: false))
_favoritedRecipes.Add(recipe);
}
if (_selectedCategory == FavoriteCatName)
{
OnViewPopulateRecipes(_constructionView,
_favoritedRecipes.Count > 0 ? (string.Empty, FavoriteCatName) : (string.Empty, string.Empty));
}
PopulateCategories(_selectedCategory);
}
private void SystemBindingChanged(ConstructionSystem? newSystem) private void SystemBindingChanged(ConstructionSystem? newSystem)
{ {
if (newSystem is null) if (newSystem is null)

View file

@ -4,12 +4,14 @@ using Content.Shared.Cuffs.Components;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Utility;
namespace Content.Client.Cuffs; namespace Content.Client.Cuffs;
public sealed class CuffableSystem : SharedCuffableSystem public sealed class CuffableSystem : SharedCuffableSystem
{ {
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -22,7 +24,7 @@ public sealed class CuffableSystem : SharedCuffableSystem
private void OnCuffableShutdown(EntityUid uid, CuffableComponent component, ComponentShutdown args) private void OnCuffableShutdown(EntityUid uid, CuffableComponent component, ComponentShutdown args)
{ {
if (TryComp<SpriteComponent>(uid, out var sprite)) if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, false); _sprite.LayerSetVisible((uid, sprite), HumanoidVisualLayers.Handcuffs, false);
} }
private void OnCuffableHandleState(EntityUid uid, CuffableComponent component, ref ComponentHandleState args) private void OnCuffableHandleState(EntityUid uid, CuffableComponent component, ref ComponentHandleState args)
@ -39,22 +41,22 @@ public sealed class CuffableSystem : SharedCuffableSystem
if (!TryComp<SpriteComponent>(uid, out var sprite)) if (!TryComp<SpriteComponent>(uid, out var sprite))
return; return;
var cuffed = cuffState.NumHandsCuffed > 0; var cuffed = cuffState.NumHandsCuffed > 0;
sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, cuffed); _sprite.LayerSetVisible((uid, sprite), HumanoidVisualLayers.Handcuffs, cuffed);
// if they are not cuffed, that means that we didn't get a valid color, // if they are not cuffed, that means that we didn't get a valid color,
// iconstate, or RSI. that also means we don't need to update the sprites. // iconstate, or RSI. that also means we don't need to update the sprites.
if (!cuffed) if (!cuffed)
return; return;
sprite.LayerSetColor(HumanoidVisualLayers.Handcuffs, cuffState.Color!.Value); _sprite.LayerSetColor((uid, sprite), HumanoidVisualLayers.Handcuffs, cuffState.Color!.Value);
if (!Equals(component.CurrentRSI, cuffState.RSI) && cuffState.RSI != null) // we don't want to keep loading the same RSI if (!Equals(component.CurrentRSI, cuffState.RSI) && cuffState.RSI != null) // we don't want to keep loading the same RSI
{ {
component.CurrentRSI = cuffState.RSI; component.CurrentRSI = cuffState.RSI;
sprite.LayerSetState(HumanoidVisualLayers.Handcuffs, cuffState.IconState, component.CurrentRSI); _sprite.LayerSetRsi((uid, sprite), _sprite.LayerMapGet((uid, sprite), HumanoidVisualLayers.Handcuffs), new ResPath(component.CurrentRSI), cuffState.IconState);
} }
else else
{ {
sprite.LayerSetState(HumanoidVisualLayers.Handcuffs, cuffState.IconState); _sprite.LayerSetRsiState((uid, sprite), HumanoidVisualLayers.Handcuffs, cuffState.IconState);
} }
} }
} }

View file

@ -228,7 +228,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
// the layer key just doesn't exist, we skip it. // the layer key just doesn't exist, we skip it.
foreach (var key in damageVisComp.TargetLayers) foreach (var key in damageVisComp.TargetLayers)
{ {
if (!spriteComponent.LayerMapTryGet(key, out var index)) if (!SpriteSystem.LayerMapTryGet((entity, spriteComponent), key, out var index, false))
{ {
Log.Warning($"Layer at key {key} was invalid for entity {entity}."); Log.Warning($"Layer at key {key} was invalid for entity {entity}.");
continue; continue;
@ -253,7 +253,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
foreach (var layer in damageVisComp.TargetLayerMapKeys) foreach (var layer in damageVisComp.TargetLayerMapKeys)
{ {
var layerCount = spriteComponent.AllLayers.Count(); var layerCount = spriteComponent.AllLayers.Count();
var index = spriteComponent.LayerMapGet(layer); var index = SpriteSystem.LayerMapGet((entity, spriteComponent), layer);
// var layerState = spriteComponent.LayerGetState(index).ToString()!; // var layerState = spriteComponent.LayerGetState(index).ToString()!;
if (index + 1 != layerCount) if (index + 1 != layerCount)
@ -269,7 +269,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{ {
foreach (var (group, sprite) in damageVisComp.DamageOverlayGroups) foreach (var (group, sprite) in damageVisComp.DamageOverlayGroups)
{ {
AddDamageLayerToSprite(spriteComponent, AddDamageLayerToSprite((entity, spriteComponent),
sprite, sprite,
$"{layer}_{group}_{damageVisComp.Thresholds[1]}", $"{layer}_{group}_{damageVisComp.Thresholds[1]}",
$"{layer}{group}", $"{layer}{group}",
@ -283,7 +283,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
// was taken. // was taken.
else if (damageVisComp.DamageOverlay != null) else if (damageVisComp.DamageOverlay != null)
{ {
AddDamageLayerToSprite(spriteComponent, AddDamageLayerToSprite((entity, spriteComponent),
damageVisComp.DamageOverlay, damageVisComp.DamageOverlay,
$"{layer}_{damageVisComp.Thresholds[1]}", $"{layer}_{damageVisComp.Thresholds[1]}",
$"{layer}trackDamage", $"{layer}trackDamage",
@ -301,7 +301,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{ {
foreach (var (group, sprite) in damageVisComp.DamageOverlayGroups) foreach (var (group, sprite) in damageVisComp.DamageOverlayGroups)
{ {
AddDamageLayerToSprite(spriteComponent, AddDamageLayerToSprite((entity, spriteComponent),
sprite, sprite,
$"DamageOverlay_{group}_{damageVisComp.Thresholds[1]}", $"DamageOverlay_{group}_{damageVisComp.Thresholds[1]}",
$"DamageOverlay{group}"); $"DamageOverlay{group}");
@ -310,7 +310,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
} }
else if (damageVisComp.DamageOverlay != null) else if (damageVisComp.DamageOverlay != null)
{ {
AddDamageLayerToSprite(spriteComponent, AddDamageLayerToSprite((entity, spriteComponent),
damageVisComp.DamageOverlay, damageVisComp.DamageOverlay,
$"DamageOverlay_{damageVisComp.Thresholds[1]}", $"DamageOverlay_{damageVisComp.Thresholds[1]}",
"DamageOverlay"); "DamageOverlay");
@ -322,16 +322,19 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary> /// <summary>
/// Adds a damage tracking layer to a given sprite component. /// Adds a damage tracking layer to a given sprite component.
/// </summary> /// </summary>
private void AddDamageLayerToSprite(SpriteComponent spriteComponent, DamageVisualizerSprite sprite, string state, string mapKey, int? index = null) private void AddDamageLayerToSprite(Entity<SpriteComponent?> spriteEnt, DamageVisualizerSprite sprite, string state, string mapKey, int? index = null)
{ {
var newLayer = spriteComponent.AddLayer( var newLayer = SpriteSystem.AddLayer(
spriteEnt,
new SpriteSpecifier.Rsi( new SpriteSpecifier.Rsi(
new (sprite.Sprite), state new(sprite.Sprite), state
), index); ),
spriteComponent.LayerMapSet(mapKey, newLayer); index
);
SpriteSystem.LayerMapSet(spriteEnt, mapKey, newLayer);
if (sprite.Color != null) if (sprite.Color != null)
spriteComponent.LayerSetColor(newLayer, Color.FromHex(sprite.Color)); SpriteSystem.LayerSetColor(spriteEnt, newLayer, Color.FromHex(sprite.Color));
spriteComponent.LayerSetVisible(newLayer, false); SpriteSystem.LayerSetVisible(spriteEnt, newLayer, false);
} }
protected override void OnAppearanceChange(EntityUid uid, DamageVisualsComponent damageVisComp, ref AppearanceChangeEvent args) protected override void OnAppearanceChange(EntityUid uid, DamageVisualsComponent damageVisComp, ref AppearanceChangeEvent args)
@ -362,18 +365,18 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
UpdateDisabledLayers(uid, spriteComponent, component, damageVisComp); UpdateDisabledLayers(uid, spriteComponent, component, damageVisComp);
if (damageVisComp.Overlay && damageVisComp.DamageOverlayGroups != null && damageVisComp.TargetLayers == null) if (damageVisComp.Overlay && damageVisComp.DamageOverlayGroups != null && damageVisComp.TargetLayers == null)
CheckOverlayOrdering(spriteComponent, damageVisComp); CheckOverlayOrdering((uid, spriteComponent), damageVisComp);
if (AppearanceSystem.TryGetData<bool>(uid, DamageVisualizerKeys.ForceUpdate, out var update, component) if (AppearanceSystem.TryGetData<bool>(uid, DamageVisualizerKeys.ForceUpdate, out var update, component)
&& update) && update)
{ {
ForceUpdateLayers(damageComponent, spriteComponent, damageVisComp); ForceUpdateLayers((uid, damageComponent, spriteComponent, damageVisComp));
return; return;
} }
if (damageVisComp.TrackAllDamage) if (damageVisComp.TrackAllDamage)
{ {
UpdateDamageVisuals(damageComponent, spriteComponent, damageVisComp); UpdateDamageVisuals((uid, damageComponent, spriteComponent, damageVisComp));
return; return;
} }
@ -383,7 +386,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
data = new DamageVisualizerGroupData(Comp<DamageableComponent>(uid).DamagePerGroup.Keys.ToList()); data = new DamageVisualizerGroupData(Comp<DamageableComponent>(uid).DamagePerGroup.Keys.ToList());
} }
UpdateDamageVisuals(data.GroupList, damageComponent, spriteComponent, damageVisComp); UpdateDamageVisuals(data.GroupList, (uid, damageComponent, spriteComponent, damageVisComp));
} }
/// <summary> /// <summary>
@ -406,7 +409,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
damageVisComp.DisabledLayers[layer] = disabled; damageVisComp.DisabledLayers[layer] = disabled;
if (damageVisComp.TrackAllDamage) if (damageVisComp.TrackAllDamage)
{ {
spriteComponent.LayerSetVisible($"{layer}trackDamage", !disabled); SpriteSystem.LayerSetVisible((uid, spriteComponent), $"{layer}trackDamage", !disabled);
continue; continue;
} }
@ -415,7 +418,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
foreach (var damageGroup in damageVisComp.DamageOverlayGroups.Keys) foreach (var damageGroup in damageVisComp.DamageOverlayGroups.Keys)
{ {
spriteComponent.LayerSetVisible($"{layer}{damageGroup}", !disabled); SpriteSystem.LayerSetVisible((uid, spriteComponent), $"{layer}{damageGroup}", !disabled);
} }
} }
} }
@ -427,16 +430,16 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// most layer doesn't match, the sprite /// most layer doesn't match, the sprite
/// layers are recreated and placed on top. /// layers are recreated and placed on top.
/// </summary> /// </summary>
private void CheckOverlayOrdering(SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp) private void CheckOverlayOrdering(Entity<SpriteComponent> spriteEnt, DamageVisualsComponent damageVisComp)
{ {
if (spriteComponent[damageVisComp.TopMostLayerKey] != spriteComponent[spriteComponent.AllLayers.Count() - 1]) if (spriteEnt.Comp[damageVisComp.TopMostLayerKey] != spriteEnt.Comp[spriteEnt.Comp.AllLayers.Count() - 1])
{ {
if (!damageVisComp.TrackAllDamage && damageVisComp.DamageOverlayGroups != null) if (!damageVisComp.TrackAllDamage && damageVisComp.DamageOverlayGroups != null)
{ {
foreach (var (damageGroup, sprite) in damageVisComp.DamageOverlayGroups) foreach (var (damageGroup, sprite) in damageVisComp.DamageOverlayGroups)
{ {
var threshold = damageVisComp.LastThresholdPerGroup[damageGroup]; var threshold = damageVisComp.LastThresholdPerGroup[damageGroup];
ReorderOverlaySprite(spriteComponent, ReorderOverlaySprite(spriteEnt,
damageVisComp, damageVisComp,
sprite, sprite,
$"DamageOverlay{damageGroup}", $"DamageOverlay{damageGroup}",
@ -446,7 +449,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
} }
else if (damageVisComp.TrackAllDamage && damageVisComp.DamageOverlay != null) else if (damageVisComp.TrackAllDamage && damageVisComp.DamageOverlay != null)
{ {
ReorderOverlaySprite(spriteComponent, ReorderOverlaySprite(spriteEnt,
damageVisComp, damageVisComp,
damageVisComp.DamageOverlay, damageVisComp.DamageOverlay,
$"DamageOverlay", $"DamageOverlay",
@ -456,21 +459,22 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
} }
} }
private void ReorderOverlaySprite(SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp, DamageVisualizerSprite sprite, string key, string statePrefix, FixedPoint2 threshold) private void ReorderOverlaySprite(Entity<SpriteComponent> spriteEnt, DamageVisualsComponent damageVisComp, DamageVisualizerSprite sprite, string key, string statePrefix, FixedPoint2 threshold)
{ {
spriteComponent.LayerMapTryGet(key, out var spriteLayer); SpriteSystem.LayerMapTryGet(spriteEnt.AsNullable(), key, out var spriteLayer, false);
var visibility = spriteComponent[spriteLayer].Visible; var visibility = spriteEnt.Comp[spriteLayer].Visible;
spriteComponent.RemoveLayer(spriteLayer); SpriteSystem.RemoveLayer(spriteEnt.AsNullable(), spriteLayer);
if (threshold == FixedPoint2.Zero) // these should automatically be invisible if (threshold == FixedPoint2.Zero) // these should automatically be invisible
threshold = damageVisComp.Thresholds[1]; threshold = damageVisComp.Thresholds[1];
spriteLayer = spriteComponent.AddLayer( spriteLayer = SpriteSystem.AddLayer(
spriteEnt.AsNullable(),
new SpriteSpecifier.Rsi( new SpriteSpecifier.Rsi(
new (sprite.Sprite), new(sprite.Sprite),
$"{statePrefix}_{threshold}" $"{statePrefix}_{threshold}"
), ),
spriteLayer); spriteLayer);
spriteComponent.LayerMapSet(key, spriteLayer); SpriteSystem.LayerMapSet(spriteEnt.AsNullable(), key, spriteLayer);
spriteComponent.LayerSetVisible(spriteLayer, visibility); SpriteSystem.LayerSetVisible(spriteEnt.AsNullable(), spriteLayer, visibility);
// this is somewhat iffy since it constantly reallocates // this is somewhat iffy since it constantly reallocates
damageVisComp.TopMostLayerKey = key; damageVisComp.TopMostLayerKey = key;
} }
@ -479,8 +483,12 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// Updates damage visuals without tracking /// Updates damage visuals without tracking
/// any damage groups. /// any damage groups.
/// </summary> /// </summary>
private void UpdateDamageVisuals(DamageableComponent damageComponent, SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp) private void UpdateDamageVisuals(Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
{ {
var damageComponent = entity.Comp1;
var spriteComponent = entity.Comp2;
var damageVisComp = entity.Comp3;
if (!CheckThresholdBoundary(damageComponent.TotalDamage, damageVisComp.LastDamageThreshold, damageVisComp, out var threshold)) if (!CheckThresholdBoundary(damageComponent.TotalDamage, damageVisComp.LastDamageThreshold, damageVisComp, out var threshold))
return; return;
@ -490,12 +498,12 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{ {
foreach (var layerMapKey in damageVisComp.TargetLayerMapKeys) foreach (var layerMapKey in damageVisComp.TargetLayerMapKeys)
{ {
UpdateTargetLayer(spriteComponent, damageVisComp, layerMapKey, threshold); UpdateTargetLayer((entity, spriteComponent), damageVisComp, layerMapKey, threshold);
} }
} }
else else
{ {
UpdateOverlay(spriteComponent, threshold); UpdateOverlay((entity, spriteComponent), threshold);
} }
} }
@ -504,8 +512,12 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// according to the list of damage groups /// according to the list of damage groups
/// passed into it. /// passed into it.
/// </summary> /// </summary>
private void UpdateDamageVisuals(List<string> delta, DamageableComponent damageComponent, SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp) private void UpdateDamageVisuals(List<string> delta, Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
{ {
var damageComponent = entity.Comp1;
var spriteComponent = entity.Comp2;
var damageVisComp = entity.Comp3;
foreach (var damageGroup in delta) foreach (var damageGroup in delta)
{ {
if (!damageVisComp.Overlay && damageGroup != damageVisComp.DamageGroup) if (!damageVisComp.Overlay && damageGroup != damageVisComp.DamageGroup)
@ -525,12 +537,12 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{ {
foreach (var layerMapKey in damageVisComp.TargetLayerMapKeys) foreach (var layerMapKey in damageVisComp.TargetLayerMapKeys)
{ {
UpdateTargetLayer(spriteComponent, damageVisComp, layerMapKey, damageGroup, threshold); UpdateTargetLayer((entity, spriteComponent, damageVisComp), layerMapKey, damageGroup, threshold);
} }
} }
else else
{ {
UpdateOverlay(spriteComponent, damageVisComp, damageGroup, threshold); UpdateOverlay((entity, spriteComponent, damageVisComp), damageGroup, threshold);
} }
} }
@ -567,19 +579,21 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// Does different things depending on /// Does different things depending on
/// the configuration of the visualizer. /// the configuration of the visualizer.
/// </summary> /// </summary>
private void ForceUpdateLayers(DamageableComponent damageComponent, SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp) private void ForceUpdateLayers(Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
{ {
var damageVisComp = entity.Comp3;
if (damageVisComp.DamageOverlayGroups != null) if (damageVisComp.DamageOverlayGroups != null)
{ {
UpdateDamageVisuals(damageVisComp.DamageOverlayGroups.Keys.ToList(), damageComponent, spriteComponent, damageVisComp); UpdateDamageVisuals(damageVisComp.DamageOverlayGroups.Keys.ToList(), entity);
} }
else if (damageVisComp.DamageGroup != null) else if (damageVisComp.DamageGroup != null)
{ {
UpdateDamageVisuals(new List<string>(){ damageVisComp.DamageGroup }, damageComponent, spriteComponent, damageVisComp); UpdateDamageVisuals(new List<string>() { damageVisComp.DamageGroup }, entity);
} }
else if (damageVisComp.DamageOverlay != null) else if (damageVisComp.DamageOverlay != null)
{ {
UpdateDamageVisuals(damageComponent, spriteComponent, damageVisComp); UpdateDamageVisuals(entity);
} }
} }
@ -588,16 +602,16 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// it assumes you're updating a layer that is tracking all /// it assumes you're updating a layer that is tracking all
/// damage. /// damage.
/// </summary> /// </summary>
private void UpdateTargetLayer(SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp, object layerMapKey, FixedPoint2 threshold) private void UpdateTargetLayer(Entity<SpriteComponent> spriteEnt, DamageVisualsComponent damageVisComp, object layerMapKey, FixedPoint2 threshold)
{ {
if (damageVisComp.Overlay && damageVisComp.DamageOverlayGroups != null) if (damageVisComp.Overlay && damageVisComp.DamageOverlayGroups != null)
{ {
if (!damageVisComp.DisabledLayers[layerMapKey]) if (!damageVisComp.DisabledLayers[layerMapKey])
{ {
var layerState = damageVisComp.LayerMapKeyStates[layerMapKey]; var layerState = damageVisComp.LayerMapKeyStates[layerMapKey];
spriteComponent.LayerMapTryGet($"{layerMapKey}trackDamage", out var spriteLayer); SpriteSystem.LayerMapTryGet(spriteEnt.AsNullable(), $"{layerMapKey}trackDamage", out var spriteLayer, false);
UpdateDamageLayerState(spriteComponent, UpdateDamageLayerState(spriteEnt,
spriteLayer, spriteLayer,
$"{layerState}", $"{layerState}",
threshold); threshold);
@ -606,9 +620,9 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
else if (!damageVisComp.Overlay) else if (!damageVisComp.Overlay)
{ {
var layerState = damageVisComp.LayerMapKeyStates[layerMapKey]; var layerState = damageVisComp.LayerMapKeyStates[layerMapKey];
spriteComponent.LayerMapTryGet(layerMapKey, out var spriteLayer); SpriteSystem.LayerMapTryGet(spriteEnt.AsNullable(), $"{layerMapKey}", out var spriteLayer, false);
UpdateDamageLayerState(spriteComponent, UpdateDamageLayerState(spriteEnt,
spriteLayer, spriteLayer,
$"{layerState}", $"{layerState}",
threshold); threshold);
@ -618,16 +632,20 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary> /// <summary>
/// Updates a target layer by damage group. /// Updates a target layer by damage group.
/// </summary> /// </summary>
private void UpdateTargetLayer(SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp, object layerMapKey, string damageGroup, FixedPoint2 threshold) private void UpdateTargetLayer(Entity<SpriteComponent, DamageVisualsComponent> entity, object layerMapKey, string damageGroup, FixedPoint2 threshold)
{ {
var spriteComponent = entity.Comp1;
var damageVisComp = entity.Comp2;
if (damageVisComp.Overlay && damageVisComp.DamageOverlayGroups != null) if (damageVisComp.Overlay && damageVisComp.DamageOverlayGroups != null)
{ {
if (damageVisComp.DamageOverlayGroups.ContainsKey(damageGroup) && !damageVisComp.DisabledLayers[layerMapKey]) if (damageVisComp.DamageOverlayGroups.ContainsKey(damageGroup) && !damageVisComp.DisabledLayers[layerMapKey])
{ {
var layerState = damageVisComp.LayerMapKeyStates[layerMapKey]; var layerState = damageVisComp.LayerMapKeyStates[layerMapKey];
spriteComponent.LayerMapTryGet($"{layerMapKey}{damageGroup}", out var spriteLayer); SpriteSystem.LayerMapTryGet((entity, spriteComponent), $"{layerMapKey}{damageGroup}", out var spriteLayer, false);
UpdateDamageLayerState(spriteComponent, UpdateDamageLayerState(
(entity, spriteComponent),
spriteLayer, spriteLayer,
$"{layerState}_{damageGroup}", $"{layerState}_{damageGroup}",
threshold); threshold);
@ -636,9 +654,10 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
else if (!damageVisComp.Overlay) else if (!damageVisComp.Overlay)
{ {
var layerState = damageVisComp.LayerMapKeyStates[layerMapKey]; var layerState = damageVisComp.LayerMapKeyStates[layerMapKey];
spriteComponent.LayerMapTryGet(layerMapKey, out var spriteLayer); SpriteSystem.LayerMapTryGet((entity, spriteComponent), $"{layerMapKey}", out var spriteLayer, false);
UpdateDamageLayerState(spriteComponent, UpdateDamageLayerState(
(entity, spriteComponent),
spriteLayer, spriteLayer,
$"{layerState}_{damageGroup}", $"{layerState}_{damageGroup}",
threshold); threshold);
@ -648,11 +667,11 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary> /// <summary>
/// Updates an overlay that is tracking all damage. /// Updates an overlay that is tracking all damage.
/// </summary> /// </summary>
private void UpdateOverlay(SpriteComponent spriteComponent, FixedPoint2 threshold) private void UpdateOverlay(Entity<SpriteComponent> spriteEnt, FixedPoint2 threshold)
{ {
spriteComponent.LayerMapTryGet($"DamageOverlay", out var spriteLayer); SpriteSystem.LayerMapTryGet(spriteEnt.AsNullable(), $"DamageOverlay", out var spriteLayer, false);
UpdateDamageLayerState(spriteComponent, UpdateDamageLayerState(spriteEnt,
spriteLayer, spriteLayer,
$"DamageOverlay", $"DamageOverlay",
threshold); threshold);
@ -661,15 +680,19 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary> /// <summary>
/// Updates an overlay based on damage group. /// Updates an overlay based on damage group.
/// </summary> /// </summary>
private void UpdateOverlay(SpriteComponent spriteComponent, DamageVisualsComponent damageVisComp, string damageGroup, FixedPoint2 threshold) private void UpdateOverlay(Entity<SpriteComponent, DamageVisualsComponent> entity, string damageGroup, FixedPoint2 threshold)
{ {
var spriteComponent = entity.Comp1;
var damageVisComp = entity.Comp2;
if (damageVisComp.DamageOverlayGroups != null) if (damageVisComp.DamageOverlayGroups != null)
{ {
if (damageVisComp.DamageOverlayGroups.ContainsKey(damageGroup)) if (damageVisComp.DamageOverlayGroups.ContainsKey(damageGroup))
{ {
spriteComponent.LayerMapTryGet($"DamageOverlay{damageGroup}", out var spriteLayer); SpriteSystem.LayerMapTryGet((entity, spriteComponent), $"DamageOverlay{damageGroup}", out var spriteLayer, false);
UpdateDamageLayerState(spriteComponent, UpdateDamageLayerState(
(entity, spriteComponent),
spriteLayer, spriteLayer,
$"DamageOverlay_{damageGroup}", $"DamageOverlay_{damageGroup}",
threshold); threshold);
@ -683,19 +706,19 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// function calls it), and what threshold /// function calls it), and what threshold
/// was passed into it. /// was passed into it.
/// </summary> /// </summary>
private void UpdateDamageLayerState(SpriteComponent spriteComponent, int spriteLayer, string statePrefix, FixedPoint2 threshold) private void UpdateDamageLayerState(Entity<SpriteComponent> spriteEnt, int spriteLayer, string statePrefix, FixedPoint2 threshold)
{ {
if (threshold == 0) if (threshold == 0)
{ {
spriteComponent.LayerSetVisible(spriteLayer, false); SpriteSystem.LayerSetVisible(spriteEnt.AsNullable(), spriteLayer, false);
} }
else else
{ {
if (!spriteComponent[spriteLayer].Visible) if (!spriteEnt.Comp[spriteLayer].Visible)
{ {
spriteComponent.LayerSetVisible(spriteLayer, true); SpriteSystem.LayerSetVisible(spriteEnt.AsNullable(), spriteLayer, true);
} }
spriteComponent.LayerSetState(spriteLayer, $"{statePrefix}_{threshold}"); SpriteSystem.LayerSetRsiState(spriteEnt.AsNullable(), spriteLayer, $"{statePrefix}_{threshold}");
} }
} }
} }

View file

@ -0,0 +1,7 @@
using Content.Shared.Damage.Systems;
namespace Content.Client.Damage.Systems;
public sealed partial class StaminaSystem : SharedStaminaSystem
{
}

View file

@ -21,34 +21,34 @@ public sealed class DamageStateVisualizerSystem : VisualizerSystem<DamageStateVi
} }
// Brain no worky rn so this was just easier. // Brain no worky rn so this was just easier.
foreach (var key in new []{ DamageStateVisualLayers.Base, DamageStateVisualLayers.BaseUnshaded }) foreach (var key in new[] { DamageStateVisualLayers.Base, DamageStateVisualLayers.BaseUnshaded })
{ {
if (!sprite.LayerMapTryGet(key, out _)) continue; if (!SpriteSystem.LayerMapTryGet((uid, sprite), key, out _, false)) continue;
sprite.LayerSetVisible(key, false); SpriteSystem.LayerSetVisible((uid, sprite), key, false);
} }
foreach (var (key, state) in layers) foreach (var (key, state) in layers)
{ {
// Inheritance moment. // Inheritance moment.
if (!sprite.LayerMapTryGet(key, out _)) continue; if (!SpriteSystem.LayerMapTryGet((uid, sprite), key, out _, false)) continue;
sprite.LayerSetVisible(key, true); SpriteSystem.LayerSetVisible((uid, sprite), key, true);
sprite.LayerSetState(key, state); SpriteSystem.LayerSetRsiState((uid, sprite), key, state);
} }
// So they don't draw over mobs anymore // So they don't draw over mobs anymore
if (data == MobState.Dead) if (data == MobState.Dead)
{ {
if (sprite.DrawDepth > (int) DrawDepth.DeadMobs) if (sprite.DrawDepth > (int)DrawDepth.DeadMobs)
{ {
component.OriginalDrawDepth = sprite.DrawDepth; component.OriginalDrawDepth = sprite.DrawDepth;
sprite.DrawDepth = (int) DrawDepth.DeadMobs; SpriteSystem.SetDrawDepth((uid, sprite), (int)DrawDepth.DeadMobs);
} }
} }
else if (component.OriginalDrawDepth != null) else if (component.OriginalDrawDepth != null)
{ {
sprite.DrawDepth = component.OriginalDrawDepth.Value; SpriteSystem.SetDrawDepth((uid, sprite), component.OriginalDrawDepth.Value);
component.OriginalDrawDepth = null; component.OriginalDrawDepth = null;
} }
} }

View file

@ -9,7 +9,6 @@ public sealed class DeliveryVisualizerSystem : VisualizerSystem<DeliveryComponen
{ {
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
private static readonly ProtoId<JobIconPrototype> UnknownIcon = "JobIconUnknown"; private static readonly ProtoId<JobIconPrototype> UnknownIcon = "JobIconUnknown";
@ -25,11 +24,11 @@ public sealed class DeliveryVisualizerSystem : VisualizerSystem<DeliveryComponen
if (!_prototype.TryIndex<JobIconPrototype>(job, out var icon)) if (!_prototype.TryIndex<JobIconPrototype>(job, out var icon))
{ {
args.Sprite.LayerSetTexture(DeliveryVisualLayers.JobStamp, _sprite.Frame0(_prototype.Index("JobIconUnknown"))); SpriteSystem.LayerSetTexture((uid, args.Sprite), DeliveryVisualLayers.JobStamp, SpriteSystem.Frame0(_prototype.Index("JobIconUnknown")));
return; return;
} }
args.Sprite.LayerSetTexture(DeliveryVisualLayers.JobStamp, _sprite.Frame0(icon.Icon)); SpriteSystem.LayerSetTexture((uid, args.Sprite), DeliveryVisualLayers.JobStamp, SpriteSystem.Frame0(icon.Icon));
} }
} }
@ -42,6 +41,8 @@ public enum DeliveryVisualLayers : byte
PriorityTape, PriorityTape,
Breakage, Breakage,
Trash, Trash,
Bomb,
BombPrimed,
} }
public enum DeliverySpawnerVisualLayers : byte public enum DeliverySpawnerVisualLayers : byte

View file

@ -5,6 +5,8 @@ namespace Content.Client.Dice;
public sealed class DiceSystem : SharedDiceSystem public sealed class DiceSystem : SharedDiceSystem
{ {
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@ -18,11 +20,11 @@ public sealed class DiceSystem : SharedDiceSystem
return; return;
// TODO maybe just move each die to its own RSI? // TODO maybe just move each die to its own RSI?
var state = sprite.LayerGetState(0).Name; var state = _sprite.LayerGetRsiState((entity.Owner, sprite), 0).Name;
if (state == null) if (state == null)
return; return;
var prefix = state.Substring(0, state.IndexOf('_')); var prefix = state.Substring(0, state.IndexOf('_'));
sprite.LayerSetState(0, $"{prefix}_{entity.Comp.CurrentValue}"); _sprite.LayerSetRsiState((entity.Owner, sprite), 0, $"{prefix}_{entity.Comp.CurrentValue}");
} }
} }

View file

@ -8,18 +8,19 @@ namespace Content.Client.DisplacementMap;
public sealed class DisplacementMapSystem : EntitySystem public sealed class DisplacementMapSystem : EntitySystem
{ {
[Dependency] private readonly ISerializationManager _serialization = default!; [Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <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>
/// <param name="data">Information package for applying the displacement map</param> /// <param name="data">Information package for applying the displacement map</param>
/// <param name="sprite">SpriteComponent</param> /// <param name="sprite">Entity with SpriteComponent</param>
/// <param name="index">Index of the layer where the new map layer will be added</param> /// <param name="index">Index of the layer where the new map layer will be added</param>
/// <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(DisplacementData data, public bool TryAddDisplacement(DisplacementData data,
SpriteComponent sprite, Entity<SpriteComponent> sprite,
int index, int index,
object key, object key,
out string displacementKey) out string displacementKey)
@ -30,10 +31,9 @@ public sealed class DisplacementMapSystem : EntitySystem
return false; return false;
if (data.ShaderOverride != null) if (data.ShaderOverride != null)
sprite.LayerSetShader(index, data.ShaderOverride); sprite.Comp.LayerSetShader(index, data.ShaderOverride);
if (sprite.LayerMapTryGet(displacementKey, out var oldIndex)) _sprite.RemoveLayer(sprite.AsNullable(), displacementKey, false);
sprite.RemoveLayer(oldIndex);
//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)
@ -55,7 +55,7 @@ public sealed class DisplacementMapSystem : EntitySystem
// We choose a displacement map from the possible ones, matching the size with the original layer size. // We choose a displacement map from the possible ones, matching the size with the original layer size.
// If there is no such a map, we use a standard 32 by 32 one // If there is no such a map, we use a standard 32 by 32 one
var displacementDataLayer = data.SizeMaps[EyeManager.PixelsPerMeter]; var displacementDataLayer = data.SizeMaps[EyeManager.PixelsPerMeter];
var actualRSI = sprite.LayerGetActualRSI(index); var actualRSI = _sprite.LayerGetEffectiveRsi(sprite.AsNullable(), index);
if (actualRSI is not null) if (actualRSI is not null)
{ {
if (actualRSI.Size.X != actualRSI.Size.Y) if (actualRSI.Size.X != actualRSI.Size.Y)
@ -72,9 +72,20 @@ 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"; displacementLayer.CopyToShaderParameters!.LayerKey = key.ToString() ?? "this is impossible";
sprite.AddLayer(displacementLayer, index); _sprite.AddLayer(sprite.AsNullable(), displacementLayer, index);
sprite.LayerMapSet(displacementKey, index); _sprite.LayerMapSet(sprite.AsNullable(), displacementKey, index);
return true; return true;
} }
/// <inheritdoc cref="TryAddDisplacement"/>
[Obsolete("Use the Entity<SpriteComponent> overload")]
public bool TryAddDisplacement(DisplacementData data,
SpriteComponent sprite,
int index,
object key,
out string displacementKey)
{
return TryAddDisplacement(data, (sprite.Owner, sprite), index, key, out displacementKey);
}
} }

View file

@ -13,6 +13,7 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
[Dependency] private readonly AnimationPlayerSystem _animationSystem = default!; [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
private const string AnimationKey = "disposal_unit_animation"; private const string AnimationKey = "disposal_unit_animation";
@ -67,13 +68,13 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
if (!_appearanceSystem.TryGetData<DisposalUnitComponent.VisualState>(ent, DisposalUnitComponent.Visuals.VisualState, out var state, appearance)) if (!_appearanceSystem.TryGetData<DisposalUnitComponent.VisualState>(ent, DisposalUnitComponent.Visuals.VisualState, out var state, appearance))
return; return;
sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == DisposalUnitComponent.VisualState.UnAnchored); _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.Unanchored, state == DisposalUnitComponent.VisualState.UnAnchored);
sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == DisposalUnitComponent.VisualState.Anchored); _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.Base, state == DisposalUnitComponent.VisualState.Anchored);
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFlush, state == DisposalUnitComponent.VisualState.OverlayFlushing); _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayFlush, state == DisposalUnitComponent.VisualState.OverlayFlushing);
sprite.LayerSetVisible(DisposalUnitVisualLayers.BaseCharging, state == DisposalUnitComponent.VisualState.OverlayCharging); _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.BaseCharging, state == DisposalUnitComponent.VisualState.OverlayCharging);
var chargingState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseCharging, out var chargingLayer) var chargingState = _sprite.LayerMapTryGet((ent, sprite), DisposalUnitVisualLayers.BaseCharging, out var chargingLayer, false)
? sprite.LayerGetState(chargingLayer) ? _sprite.LayerGetRsiState((ent, sprite), chargingLayer)
: new RSI.StateId(DefaultChargeState); : new RSI.StateId(DefaultChargeState);
// This is a transient state so not too worried about replaying in range. // This is a transient state so not too worried about replaying in range.
@ -81,8 +82,8 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
{ {
if (!_animationSystem.HasRunningAnimation(ent, AnimationKey)) if (!_animationSystem.HasRunningAnimation(ent, AnimationKey))
{ {
var flushState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.OverlayFlush, out var flushLayer) var flushState = _sprite.LayerMapTryGet((ent, sprite), DisposalUnitVisualLayers.OverlayFlush, out var flushLayer, false)
? sprite.LayerGetState(flushLayer) ? _sprite.LayerGetRsiState((ent, sprite), flushLayer)
: new RSI.StateId(DefaultFlushState); : new RSI.StateId(DefaultFlushState);
// Setup the flush animation to play // Setup the flush animation to play
@ -124,16 +125,16 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem
if (!_appearanceSystem.TryGetData<DisposalUnitComponent.HandleState>(ent, DisposalUnitComponent.Visuals.Handle, out var handleState, appearance)) if (!_appearanceSystem.TryGetData<DisposalUnitComponent.HandleState>(ent, DisposalUnitComponent.Visuals.Handle, out var handleState, appearance))
handleState = DisposalUnitComponent.HandleState.Normal; handleState = DisposalUnitComponent.HandleState.Normal;
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayEngaged, handleState != DisposalUnitComponent.HandleState.Normal); _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayEngaged, handleState != DisposalUnitComponent.HandleState.Normal);
if (!_appearanceSystem.TryGetData<DisposalUnitComponent.LightStates>(ent, DisposalUnitComponent.Visuals.Light, out var lightState, appearance)) if (!_appearanceSystem.TryGetData<DisposalUnitComponent.LightStates>(ent, DisposalUnitComponent.Visuals.Light, out var lightState, appearance))
lightState = DisposalUnitComponent.LightStates.Off; lightState = DisposalUnitComponent.LightStates.Off;
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayCharging, _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayCharging,
(lightState & DisposalUnitComponent.LightStates.Charging) != 0); (lightState & DisposalUnitComponent.LightStates.Charging) != 0);
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayReady, _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayReady,
(lightState & DisposalUnitComponent.LightStates.Ready) != 0); (lightState & DisposalUnitComponent.LightStates.Ready) != 0);
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFull, _sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayFull,
(lightState & DisposalUnitComponent.LightStates.Full) != 0); (lightState & DisposalUnitComponent.LightStates.Full) != 0);
} }
} }

View file

@ -21,6 +21,7 @@ public sealed class DoAfterOverlay : Overlay
private readonly MetaDataSystem _meta; private readonly MetaDataSystem _meta;
private readonly ProgressColorSystem _progressColor; private readonly ProgressColorSystem _progressColor;
private readonly SharedContainerSystem _container; private readonly SharedContainerSystem _container;
private readonly SpriteSystem _sprite;
private readonly Texture _barTexture; private readonly Texture _barTexture;
private readonly ShaderInstance _unshadedShader; private readonly ShaderInstance _unshadedShader;
@ -45,6 +46,7 @@ public sealed class DoAfterOverlay : Overlay
_meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>(); _meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>();
_container = _entManager.EntitySysManager.GetEntitySystem<SharedContainerSystem>(); _container = _entManager.EntitySysManager.GetEntitySystem<SharedContainerSystem>();
_progressColor = _entManager.System<ProgressColorSystem>(); _progressColor = _entManager.System<ProgressColorSystem>();
_sprite = _entManager.System<SpriteSystem>();
var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon"); var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
_barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite); _barTexture = _entManager.EntitySysManager.GetEntitySystem<SpriteSystem>().Frame0(sprite);
@ -118,7 +120,7 @@ public sealed class DoAfterOverlay : Overlay
// Use the sprite itself if we know its bounds. This means short or tall sprites don't get overlapped // Use the sprite itself if we know its bounds. This means short or tall sprites don't get overlapped
// by the bar. // by the bar.
float yOffset = sprite.Bounds.Height / 2f + 0.05f; var yOffset = _sprite.GetLocalBounds((uid, sprite)).Height / 2f + 0.05f;
// Position above the entity (we've already applied the matrix transform to the entity itself) // Position above the entity (we've already applied the matrix transform to the entity itself)
// Offset by the texture size for every do_after we have. // Offset by the texture size for every do_after we have.
@ -135,7 +137,7 @@ public sealed class DoAfterOverlay : Overlay
if (doAfter.CancelledTime != null) if (doAfter.CancelledTime != null)
{ {
var elapsed = doAfter.CancelledTime.Value - doAfter.StartTime; var elapsed = doAfter.CancelledTime.Value - doAfter.StartTime;
elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds); elapsedRatio = (float)Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds);
var cancelElapsed = (time - doAfter.CancelledTime.Value).TotalSeconds; var cancelElapsed = (time - doAfter.CancelledTime.Value).TotalSeconds;
var flash = Math.Floor(cancelElapsed / FlashTime) % 2 == 0; var flash = Math.Floor(cancelElapsed / FlashTime) % 2 == 0;
color = GetProgressColor(0, flash ? alpha : 0); color = GetProgressColor(0, flash ? alpha : 0);
@ -143,7 +145,7 @@ public sealed class DoAfterOverlay : Overlay
else else
{ {
var elapsed = time - doAfter.StartTime; var elapsed = time - doAfter.StartTime;
elapsedRatio = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds); elapsedRatio = (float)Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds);
color = GetProgressColor(elapsedRatio, alpha); color = GetProgressColor(elapsedRatio, alpha);
} }

View file

@ -10,6 +10,7 @@ namespace Content.Client.Doors;
public sealed class AirlockSystem : SharedAirlockSystem public sealed class AirlockSystem : SharedAirlockSystem
{ {
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!; [Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -21,7 +22,7 @@ public sealed class AirlockSystem : SharedAirlockSystem
private void OnComponentStartup(EntityUid uid, AirlockComponent comp, ComponentStartup args) private void OnComponentStartup(EntityUid uid, AirlockComponent comp, ComponentStartup args)
{ {
// Has to be on component startup because we don't know what order components initialize in and running this before DoorComponent inits _will_ crash. // Has to be on component startup because we don't know what order components initialize in and running this before DoorComponent inits _will_ crash.
if(!TryComp<DoorComponent>(uid, out var door)) if (!TryComp<DoorComponent>(uid, out var door))
return; return;
if (comp.OpenUnlitVisible) // Otherwise there are flashes of the fallback sprite between clicking on the door and the door closing animation starting. if (comp.OpenUnlitVisible) // Otherwise there are flashes of the fallback sprite between clicking on the door and the door closing animation starting.
@ -31,17 +32,17 @@ public sealed class AirlockSystem : SharedAirlockSystem
} }
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick() ((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
{ {
LayerKey = DoorVisualLayers.BaseUnlit, LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningSpriteState, 0f) }, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningSpriteState, 0f) },
} }
); );
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick() ((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
{ {
LayerKey = DoorVisualLayers.BaseUnlit, LayerKey = DoorVisualLayers.BaseUnlit,
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.ClosingSpriteState, 0f) }, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.ClosingSpriteState, 0f) },
} }
); );
door.DenyingAnimation = new Animation() door.DenyingAnimation = new Animation()
@ -57,19 +58,19 @@ public sealed class AirlockSystem : SharedAirlockSystem
} }
}; };
if(!comp.AnimatePanel) if (!comp.AnimatePanel)
return; return;
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick() ((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
{ {
LayerKey = WiresVisualLayers.MaintenancePanel, LayerKey = WiresVisualLayers.MaintenancePanel,
KeyFrames = {new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningPanelSpriteState, 0f)}, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningPanelSpriteState, 0f) },
}); });
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick ((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{ {
LayerKey = WiresVisualLayers.MaintenancePanel, LayerKey = WiresVisualLayers.MaintenancePanel,
KeyFrames = {new AnimationTrackSpriteFlick.KeyFrame(comp.ClosingPanelSpriteState, 0f)}, KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.ClosingPanelSpriteState, 0f) },
}); });
} }
@ -101,11 +102,12 @@ public sealed class AirlockSystem : SharedAirlockSystem
&& !boltedVisible && !emergencyLightsVisible; && !boltedVisible && !emergencyLightsVisible;
} }
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible); _sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseUnlit, unlitVisible);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseBolted, boltedVisible); _sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseBolted, boltedVisible);
if (comp.EmergencyAccessLayer) if (comp.EmergencyAccessLayer)
{ {
args.Sprite.LayerSetVisible( _sprite.LayerSetVisible(
(uid, args.Sprite),
DoorVisualLayers.BaseEmergencyAccess, DoorVisualLayers.BaseEmergencyAccess,
emergencyLightsVisible emergencyLightsVisible
&& state != DoorState.Open && state != DoorState.Open
@ -118,12 +120,12 @@ public sealed class AirlockSystem : SharedAirlockSystem
switch (state) switch (state)
{ {
case DoorState.Open: case DoorState.Open:
args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.ClosingSpriteState); _sprite.LayerSetRsiState((uid, args.Sprite), DoorVisualLayers.BaseUnlit, comp.ClosingSpriteState);
args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0); _sprite.LayerSetAnimationTime((uid, args.Sprite), DoorVisualLayers.BaseUnlit, 0);
break; break;
case DoorState.Closed: case DoorState.Closed:
args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.OpeningSpriteState); _sprite.LayerSetRsiState((uid, args.Sprite), DoorVisualLayers.BaseUnlit, comp.OpeningSpriteState);
args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0); _sprite.LayerSetAnimationTime((uid, args.Sprite), DoorVisualLayers.BaseUnlit, 0);
break; break;
} }
} }

View file

@ -11,6 +11,7 @@ public sealed class DoorSystem : SharedDoorSystem
{ {
[Dependency] private readonly AnimationPlayerSystem _animationSystem = default!; [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -85,7 +86,7 @@ public sealed class DoorSystem : SharedDoorSystem
state = DoorState.Closed; state = DoorState.Closed;
if (AppearanceSystem.TryGetData<string>(entity, DoorVisuals.BaseRSI, out var baseRsi, args.Component)) if (AppearanceSystem.TryGetData<string>(entity, DoorVisuals.BaseRSI, out var baseRsi, args.Component))
UpdateSpriteLayers(args.Sprite, baseRsi); UpdateSpriteLayers((entity.Owner, args.Sprite), baseRsi);
if (_animationSystem.HasRunningAnimation(entity, DoorComponent.AnimationKey)) if (_animationSystem.HasRunningAnimation(entity, DoorComponent.AnimationKey))
_animationSystem.Stop(entity.Owner, DoorComponent.AnimationKey); _animationSystem.Stop(entity.Owner, DoorComponent.AnimationKey);
@ -95,21 +96,21 @@ public sealed class DoorSystem : SharedDoorSystem
private void UpdateAppearanceForDoorState(Entity<DoorComponent> entity, SpriteComponent sprite, DoorState state) private void UpdateAppearanceForDoorState(Entity<DoorComponent> entity, SpriteComponent sprite, DoorState state)
{ {
sprite.DrawDepth = state is DoorState.Open ? entity.Comp.OpenDrawDepth : entity.Comp.ClosedDrawDepth; _sprite.SetDrawDepth((entity.Owner, sprite), state is DoorState.Open ? entity.Comp.OpenDrawDepth : entity.Comp.ClosedDrawDepth);
switch (state) switch (state)
{ {
case DoorState.Open: case DoorState.Open:
foreach (var (layer, layerState) in entity.Comp.OpenSpriteStates) foreach (var (layer, layerState) in entity.Comp.OpenSpriteStates)
{ {
sprite.LayerSetState(layer, layerState); _sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState);
} }
return; return;
case DoorState.Closed: case DoorState.Closed:
foreach (var (layer, layerState) in entity.Comp.ClosedSpriteStates) foreach (var (layer, layerState) in entity.Comp.ClosedSpriteStates)
{ {
sprite.LayerSetState(layer, layerState); _sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState);
} }
return; return;
@ -138,7 +139,7 @@ public sealed class DoorSystem : SharedDoorSystem
} }
} }
private void UpdateSpriteLayers(SpriteComponent sprite, string baseRsi) private void UpdateSpriteLayers(Entity<SpriteComponent> sprite, string baseRsi)
{ {
if (!_resourceCache.TryGetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / baseRsi, out var res)) if (!_resourceCache.TryGetResource<RSIResource>(SpriteSpecifierSerializer.TextureRoot / baseRsi, out var res))
{ {
@ -146,6 +147,6 @@ public sealed class DoorSystem : SharedDoorSystem
return; return;
} }
sprite.BaseRSI = res.RSI; _sprite.SetBaseRsi(sprite.AsNullable(), res.RSI);
} }
} }

View file

@ -8,6 +8,7 @@ namespace Content.Client.Doors;
public sealed class FirelockSystem : SharedFirelockSystem public sealed class FirelockSystem : SharedFirelockSystem
{ {
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -18,7 +19,7 @@ public sealed class FirelockSystem : SharedFirelockSystem
protected override void OnComponentStartup(Entity<FirelockComponent> ent, ref ComponentStartup args) protected override void OnComponentStartup(Entity<FirelockComponent> ent, ref ComponentStartup args)
{ {
base.OnComponentStartup(ent, ref args); base.OnComponentStartup(ent, ref args);
if(!TryComp<DoorComponent>(ent.Owner, out var door)) if (!TryComp<DoorComponent>(ent.Owner, out var door))
return; return;
door.ClosedSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.WarningLightSpriteState)); door.ClosedSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.WarningLightSpriteState));
@ -57,7 +58,7 @@ public sealed class FirelockSystem : SharedFirelockSystem
|| state == DoorState.Denying || state == DoorState.Denying
|| (_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) && closedLights); || (_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) && closedLights);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible && !boltedVisible); _sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseUnlit, unlitVisible && !boltedVisible);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseBolted, boltedVisible); _sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseBolted, boltedVisible);
} }
} }

View file

@ -13,8 +13,9 @@ namespace Content.Client.Doors;
public sealed class TurnstileSystem : SharedTurnstileSystem public sealed class TurnstileSystem : SharedTurnstileSystem
{ {
[Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
private static EntProtoId _examineArrow = "TurnstileArrow"; private static readonly EntProtoId ExamineArrow = "TurnstileArrow";
private const string AnimationKey = "Turnstile"; private const string AnimationKey = "Turnstile";
@ -33,12 +34,12 @@ public sealed class TurnstileSystem : SharedTurnstileSystem
if (!TryComp<SpriteComponent>(ent, out var sprite)) if (!TryComp<SpriteComponent>(ent, out var sprite))
return; return;
sprite.LayerSetState(TurnstileVisualLayers.Base, new RSI.StateId(ent.Comp.DefaultState)); _sprite.LayerSetRsiState((ent.Owner, sprite), TurnstileVisualLayers.Base, new RSI.StateId(ent.Comp.DefaultState));
} }
private void OnExamined(Entity<TurnstileComponent> ent, ref ExaminedEvent args) private void OnExamined(Entity<TurnstileComponent> ent, ref ExaminedEvent args)
{ {
Spawn(_examineArrow, new EntityCoordinates(ent, 0, 0)); Spawn(ExamineArrow, new EntityCoordinates(ent, 0, 0));
} }
protected override void PlayAnimation(EntityUid uid, string stateId) protected override void PlayAnimation(EntityUid uid, string stateId)

View file

@ -7,6 +7,7 @@ namespace Content.Client.Dragon;
public sealed class DragonSystem : EntitySystem public sealed class DragonSystem : EntitySystem
{ {
[Dependency] private readonly SharedPointLightSystem _lights = default!; [Dependency] private readonly SharedPointLightSystem _lights = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -31,7 +32,7 @@ public sealed class DragonSystem : EntitySystem
switch (state.State) switch (state.State)
{ {
case DragonRiftState.Charging: case DragonRiftState.Charging:
sprite?.LayerSetColor(0, Color.FromHex("#569fff")); _sprite.LayerSetColor((uid, sprite), 0, Color.FromHex("#569fff"));
if (light != null) if (light != null)
{ {
@ -39,7 +40,7 @@ public sealed class DragonSystem : EntitySystem
} }
break; break;
case DragonRiftState.AlmostFinished: case DragonRiftState.AlmostFinished:
sprite?.LayerSetColor(0, Color.FromHex("#cf4cff")); _sprite.LayerSetColor((uid, sprite), 0, Color.FromHex("#cf4cff"));
if (light != null) if (light != null)
{ {
@ -47,7 +48,7 @@ public sealed class DragonSystem : EntitySystem
} }
break; break;
case DragonRiftState.Finished: case DragonRiftState.Finished:
sprite?.LayerSetColor(0, Color.FromHex("#edbc36")); _sprite.LayerSetColor((uid, sprite), 0, Color.FromHex("#edbc36"));
if (light != null) if (light != null)
{ {

View file

@ -2,6 +2,7 @@ using Content.Shared.Drugs;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Player; using Robust.Client.Player;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.Client.Drugs; namespace Content.Client.Drugs;
@ -12,6 +13,7 @@ public sealed class DrugOverlaySystem : EntitySystem
{ {
[Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!; [Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private RainbowOverlay _overlay = default!; private RainbowOverlay _overlay = default!;
@ -45,7 +47,10 @@ public sealed class DrugOverlaySystem : EntitySystem
private void OnInit(EntityUid uid, SeeingRainbowsComponent component, ComponentInit args) private void OnInit(EntityUid uid, SeeingRainbowsComponent component, ComponentInit args)
{ {
if (_player.LocalEntity == uid) if (_player.LocalEntity == uid)
{
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
_overlayMan.AddOverlay(_overlay); _overlayMan.AddOverlay(_overlay);
}
} }
private void OnShutdown(EntityUid uid, SeeingRainbowsComponent component, ComponentShutdown args) private void OnShutdown(EntityUid uid, SeeingRainbowsComponent component, ComponentShutdown args)

View file

@ -24,16 +24,27 @@ public sealed class RainbowOverlay : Overlay
public float Intoxication = 0.0f; public float Intoxication = 0.0f;
public float TimeTicker = 0.0f; public float TimeTicker = 0.0f;
public float Phase = 0.0f;
private const float VisualThreshold = 10.0f; private const float VisualThreshold = 10.0f;
private const float PowerDivisor = 250.0f; private const float PowerDivisor = 250.0f;
private float _timeScale = 0.0f;
private float _warpScale = 0.0f;
private float EffectScale => Math.Clamp((Intoxication - VisualThreshold) / PowerDivisor, 0.0f, 1.0f); private float EffectScale => Math.Clamp((Intoxication - VisualThreshold) / PowerDivisor, 0.0f, 1.0f);
public RainbowOverlay() public RainbowOverlay()
{ {
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
_rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique(); _rainbowShader = _prototypeManager.Index<ShaderPrototype>("Rainbow").InstanceUnique();
_config.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
}
private void OnReducedMotionChanged(bool reducedMotion)
{
_timeScale = reducedMotion ? 0.0f : 1.0f;
_warpScale = reducedMotion ? 0.0f : 1.0f;
} }
protected override void FrameUpdate(FrameEventArgs args) protected override void FrameUpdate(FrameEventArgs args)
@ -51,7 +62,7 @@ public sealed class RainbowOverlay : Overlay
if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status)) if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status))
return; return;
var timeLeft = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds; var timeLeft = (float)(time.Value.Item2 - time.Value.Item1).TotalSeconds;
TimeTicker += args.DeltaSeconds; TimeTicker += args.DeltaSeconds;
@ -61,7 +72,7 @@ public sealed class RainbowOverlay : Overlay
} }
else else
{ {
Intoxication -= Intoxication/(timeLeft - TimeTicker) * args.DeltaSeconds; Intoxication -= Intoxication / (timeLeft - TimeTicker) * args.DeltaSeconds;
} }
} }
@ -78,16 +89,15 @@ public sealed class RainbowOverlay : Overlay
protected override void Draw(in OverlayDrawArgs args) protected override void Draw(in OverlayDrawArgs args)
{ {
// TODO disable only the motion part or ike's idea (single static frame of the overlay)
if (_config.GetCVar(CCVars.ReducedMotion))
return;
if (ScreenTexture == null) if (ScreenTexture == null)
return; return;
var handle = args.WorldHandle; var handle = args.WorldHandle;
_rainbowShader.SetParameter("SCREEN_TEXTURE", ScreenTexture); _rainbowShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_rainbowShader.SetParameter("effectScale", EffectScale); _rainbowShader.SetParameter("colorScale", EffectScale);
_rainbowShader.SetParameter("timeScale", _timeScale);
_rainbowShader.SetParameter("warpScale", _warpScale * EffectScale);
_rainbowShader.SetParameter("phase", Phase);
handle.UseShader(_rainbowShader); handle.UseShader(_rainbowShader);
handle.DrawRect(args.WorldBounds, Color.White); handle.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null); handle.UseShader(null);

View file

@ -13,6 +13,7 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
{ {
[Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly AnimationPlayerSystem _animation = default!; [Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <summary> /// <summary>
/// It's a little on the long side but given we use multiple colours denoting what happened it makes it easier to register. /// It's a little on the long side but given we use multiple colours denoting what happened it makes it easier to register.
@ -44,7 +45,7 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
if (TryComp<SpriteComponent>(uid, out var sprite)) if (TryComp<SpriteComponent>(uid, out var sprite))
{ {
sprite.Color = component.Color; _sprite.SetColor((uid, sprite), component.Color);
} }
} }

View file

@ -53,15 +53,12 @@ public sealed class ElectrocutionHUDVisualizerSystem : VisualizerSystem<Electroc
private void ShowHUD() private void ShowHUD()
{ {
var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>(); var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>();
while (electrifiedQuery.MoveNext(out var uid, out var _, out var appearanceComp, out var spriteComp)) while (electrifiedQuery.MoveNext(out var uid, out _, out var appearanceComp, out var spriteComp))
{ {
if (!AppearanceSystem.TryGetData<bool>(uid, ElectrifiedVisuals.IsElectrified, out var electrified, appearanceComp)) if (!AppearanceSystem.TryGetData<bool>(uid, ElectrifiedVisuals.IsElectrified, out var electrified, appearanceComp))
continue; continue;
if (electrified) SpriteSystem.LayerSetVisible((uid, spriteComp), ElectrifiedLayers.HUD, electrified);
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, true);
else
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
} }
} }
@ -70,10 +67,9 @@ public sealed class ElectrocutionHUDVisualizerSystem : VisualizerSystem<Electroc
private void RemoveHUD() private void RemoveHUD()
{ {
var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>(); var electrifiedQuery = AllEntityQuery<ElectrocutionHUDVisualsComponent, AppearanceComponent, SpriteComponent>();
while (electrifiedQuery.MoveNext(out var uid, out var _, out var appearanceComp, out var spriteComp)) while (electrifiedQuery.MoveNext(out var uid, out _, out _, out var spriteComp))
{ {
SpriteSystem.LayerSetVisible((uid, spriteComp), ElectrifiedLayers.HUD, false);
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
} }
} }
@ -87,9 +83,6 @@ public sealed class ElectrocutionHUDVisualizerSystem : VisualizerSystem<Electroc
return; return;
var player = _playerMan.LocalEntity; var player = _playerMan.LocalEntity;
if (electrified && HasComp<ShowElectrocutionHUDComponent>(player)) SpriteSystem.LayerSetVisible((uid, args.Sprite), ElectrifiedLayers.HUD, electrified && HasComp<ShowElectrocutionHUDComponent>(player));
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, true);
else
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, false);
} }
} }

View file

@ -1,12 +1,14 @@
using Content.Shared.Ensnaring; using Content.Shared.Ensnaring;
using Content.Shared.Ensnaring.Components; using Content.Shared.Ensnaring.Components;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.Utility;
namespace Content.Client.Ensnaring; namespace Content.Client.Ensnaring;
public sealed class EnsnareableSystem : SharedEnsnareableSystem public sealed class EnsnareableSystem : SharedEnsnareableSystem
{ {
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -19,25 +21,25 @@ public sealed class EnsnareableSystem : SharedEnsnareableSystem
{ {
base.OnEnsnareInit(ent, ref args); base.OnEnsnareInit(ent, ref args);
if(!TryComp<SpriteComponent>(ent.Owner, out var sprite)) if (!TryComp<SpriteComponent>(ent.Owner, out var sprite))
return; return;
// TODO remove this, this should just be in yaml. // TODO remove this, this should just be in yaml.
sprite.LayerMapReserveBlank(EnsnaredVisualLayers.Ensnared); _sprite.LayerMapReserve((ent.Owner, sprite), EnsnaredVisualLayers.Ensnared);
} }
private void OnAppearanceChange(EntityUid uid, EnsnareableComponent component, ref AppearanceChangeEvent args) private void OnAppearanceChange(EntityUid uid, EnsnareableComponent component, ref AppearanceChangeEvent args)
{ {
if (args.Sprite == null || !args.Sprite.LayerMapTryGet(EnsnaredVisualLayers.Ensnared, out var layer)) if (args.Sprite == null || !_sprite.LayerMapTryGet((uid, args.Sprite), EnsnaredVisualLayers.Ensnared, out var layer, false))
return; return;
if (_appearance.TryGetData<bool>(uid, EnsnareableVisuals.IsEnsnared, out var isEnsnared, args.Component)) if (_appearance.TryGetData<bool>(uid, EnsnareableVisuals.IsEnsnared, out var isEnsnared, args.Component))
{ {
if (component.Sprite != null) if (component.Sprite != null)
{ {
args.Sprite.LayerSetRSI(layer, component.Sprite); _sprite.LayerSetRsi((uid, args.Sprite), layer, new ResPath(component.Sprite));
args.Sprite.LayerSetState(layer, component.State); _sprite.LayerSetRsiState((uid, args.Sprite), layer, component.State);
args.Sprite.LayerSetVisible(layer, isEnsnared); _sprite.LayerSetVisible((uid, args.Sprite), layer, isEnsnared);
} }
} }
} }

View file

@ -12,6 +12,6 @@ public sealed class ClusterGrenadeVisualizerSystem : VisualizerSystem<ClusterGre
return; return;
if (AppearanceSystem.TryGetData<int>(uid, ClusterGrenadeVisuals.GrenadesCounter, out var grenadesCounter, args.Component)) if (AppearanceSystem.TryGetData<int>(uid, ClusterGrenadeVisuals.GrenadesCounter, out var grenadesCounter, args.Component))
args.Sprite.LayerSetState(0, $"{comp.State}-{grenadesCounter}"); SpriteSystem.LayerSetRsiState((uid, args.Sprite), 0, $"{comp.State}-{grenadesCounter}");
} }
} }

View file

@ -4,7 +4,6 @@ using Robust.Client.Graphics;
using Robust.Client.ResourceManagement; using Robust.Client.ResourceManagement;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Graphics.RSI; using Robust.Shared.Graphics.RSI;
using Robust.Shared.Map;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Client.Explosion; namespace Content.Client.Explosion;
@ -19,7 +18,7 @@ public sealed class ExplosionOverlaySystem : EntitySystem
[Dependency] private readonly IResourceCache _resCache = default!; [Dependency] private readonly IResourceCache _resCache = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!; [Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly SharedPointLightSystem _lights = default!; [Dependency] private readonly SharedPointLightSystem _lights = default!;
[Dependency] private readonly IMapManager _mapMan = default!; [Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
public override void Initialize() public override void Initialize()
@ -69,7 +68,7 @@ public sealed class ExplosionOverlaySystem : EntitySystem
} }
// Map may have been deleted. // Map may have been deleted.
if (_mapMan.MapExists(component.Epicenter.MapId)) if (_mapSystem.MapExists(component.Epicenter.MapId))
{ {
// spawn in a client-side light source at the epicenter // spawn in a client-side light source at the epicenter
var lightEntity = Spawn("ExplosionLight", component.Epicenter); var lightEntity = Spawn("ExplosionLight", component.Epicenter);

View file

@ -9,6 +9,7 @@ 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!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/* /*
* Currently all of the appearance stuff is hardcoded for portable flashers * Currently all of the appearance stuff is hardcoded for portable flashers
@ -79,7 +80,7 @@ public sealed partial class TriggerSystem
if (!_appearance.TryGetData<ProximityTriggerVisuals>(uid, ProximityTriggerVisualState.State, out var state, appearance)) if (!_appearance.TryGetData<ProximityTriggerVisuals>(uid, ProximityTriggerVisualState.State, out var state, appearance))
return; return;
if (!spriteComponent.LayerMapTryGet(ProximityTriggerVisualLayers.Base, out var layer)) if (!_sprite.LayerMapTryGet((uid, spriteComponent), ProximityTriggerVisualLayers.Base, out var layer, false))
// Don't do anything if the sprite doesn't have the layer. // Don't do anything if the sprite doesn't have the layer.
return; return;
@ -89,7 +90,7 @@ public sealed partial class TriggerSystem
// Don't interrupt the flash animation // Don't interrupt the flash animation
if (_player.HasRunningAnimation(uid, player, AnimKey)) return; if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
_player.Stop(uid, player, AnimKey); _player.Stop(uid, player, AnimKey);
spriteComponent.LayerSetState(layer, "on"); _sprite.LayerSetRsiState((uid, spriteComponent), layer, "on");
break; break;
case ProximityTriggerVisuals.Active: case ProximityTriggerVisuals.Active:
if (_player.HasRunningAnimation(uid, player, AnimKey)) return; if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
@ -98,7 +99,7 @@ public sealed partial class TriggerSystem
case ProximityTriggerVisuals.Off: case ProximityTriggerVisuals.Off:
default: default:
_player.Stop(uid, player, AnimKey); _player.Stop(uid, player, AnimKey);
spriteComponent.LayerSetState(layer, "off"); _sprite.LayerSetRsiState((uid, spriteComponent), layer, "off");
break; break;
} }
} }

View file

@ -1,45 +1,119 @@
<DefaultWindow xmlns="https://spacestation14.io" <DefaultWindow
Title="{Loc 'fax-machine-ui-window'}" xmlns="https://spacestation14.io"
MinWidth="250"> Title="{Loc 'fax-machine-ui-window'}"
<BoxContainer Orientation="Vertical" VerticalExpand="True"> MinSize="380 220">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"> <BoxContainer Orientation="Vertical"
<Label Text="{Loc 'fax-machine-ui-paper'}" /> SeparationOverride="2"
<Control MinWidth="4" /> VerticalExpand="True">
<Label Name="PaperStatusLabel" />
</BoxContainer> <PanelContainer StyleClasses="PanelBackgroundBaseDark" HorizontalExpand="True">
<Control HorizontalExpand="True" MinHeight="20" /> <BoxContainer Orientation="Vertical"
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"> Margin="0 0 0 2">
<Label Text="{Loc 'fax-machine-ui-from'}" />
<Control MinWidth="4" /> <!-- From Line -->
<Label Name="FromLabel" /> <BoxContainer Orientation="Horizontal">
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"> <!-- From Value Name -->
<Label Text="{Loc 'fax-machine-ui-to'}" /> <Label Text="{Loc 'fax-machine-ui-from'}"
<Control MinWidth="4" /> HorizontalAlignment="Left"
<OptionButton Name="PeerSelector" HorizontalExpand="True" /> VerticalAlignment="Bottom"/>
</BoxContainer>
<Control HorizontalExpand="True" MinHeight="20" /> <Control HorizontalExpand="True"
<!--> Sunrise-Edit <--> MinWidth="8"
<!--> <BoxContainer Orientation="Horizontal" HorizontalExpand="True"> HorizontalAlignment="Center"/>
<Button Name="FileButton"
Text="{Loc 'fax-machine-ui-file-button'}" <!-- From Value -->
HorizontalExpand="False"/> <Label Name="FromLabel"
</BoxContainer> <--> HorizontalAlignment="Right"
<BoxContainer Orientation="Horizontal" HorizontalExpand="True"> VerticalAlignment="Center"
<!--> Sunrise-Edit <--> Align="Right"/>
<!--> <Button Name="CopyButton" </BoxContainer>
Text="{Loc 'fax-machine-ui-copy-button'}"
HorizontalExpand="False" <!-- To Line -->
Disabled="True" /> <--> <BoxContainer
<Button Name="SendButton" Orientation="Horizontal">
Text="{Loc 'fax-machine-ui-send-button'}"
HorizontalExpand="True" <!-- To Label -->
Disabled="True" /> <Label Text="{Loc 'fax-machine-ui-to'}"
<Button Name="RefreshButton" HorizontalAlignment="Left"
Text="{Loc 'fax-machine-ui-refresh-button'}" /> VerticalAlignment="Bottom"/>
<Button Name="PaperButton"
Text="{Loc 'fax-machine-ui-paper-button-normal'}" <Control HorizontalExpand="True"
HorizontalExpand="False"/> MinWidth="8"
</BoxContainer> HorizontalAlignment="Center"/>
<BoxContainer Orientation="Horizontal">
<!-- To Value -->
<OptionButton Name="PeerSelector"
StyleClasses="OpenRight" />
<!-- Refresh Fax Recipients -->
<Button StyleClasses="OpenLeft"
Name="RefreshButton"
ToolTip="{Loc 'fax-machine-ui-refresh-button'}">
<TextureButton
MouseFilter="Ignore"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Scale="0.9 0.9"
StyleClasses="Refresh" />
</Button>
</BoxContainer>
</BoxContainer>
<PanelContainer StyleClasses="LowDivider" Margin="0 4 0 4"/>
<!-- Send & Copy -->
<BoxContainer Orientation="Vertical">
<!-- Paper Status -->
<Label Name="PaperStatusLabel"
HorizontalAlignment="Center" />
<BoxContainer>
<!--> Sunrise-Edit <-->
<!--><Button Name="CopyButton"
Text="{Loc 'fax-machine-ui-copy-button'}"
StyleClasses="OpenRight"
HorizontalExpand="True"
Disabled="True" /><-->
<Button Name="SendButton"
Text="{Loc 'fax-machine-ui-send-button'}"
StyleClasses="OpenLeft"
HorizontalExpand="True"
Disabled="True" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
</PanelContainer>
<PanelContainer StyleClasses="PanelBackgroundBaseDark"
HorizontalExpand="True" Margin="0 10 0 0"
VerticalExpand="True" VerticalAlignment="Bottom">
<BoxContainer Orientation="Vertical"
VerticalExpand="True">
<!-- Other actions -->
<BoxContainer Margin="0 4 0 4">
<Button Name="PaperButton"
Text="{Loc 'fax-machine-ui-paper-button-normal'}"
StyleClasses="OpenRight"
HorizontalExpand="True"/>
<!--> Sunrise-Edit <-->
<!--><Button Name="FileButton"
Text="{Loc 'fax-machine-ui-file-button'}"
StyleClasses="OpenLeft"
HorizontalExpand="True"/>
<-->
</BoxContainer>
<!-- It would be cool to add a display of the inserted file here. -->
</BoxContainer>
</PanelContainer>
</BoxContainer> </BoxContainer>
</DefaultWindow> </DefaultWindow>

View file

@ -10,6 +10,7 @@ namespace Content.Client.Fluids;
public sealed class PuddleSystem : SharedPuddleSystem public sealed class PuddleSystem : SharedPuddleSystem
{ {
[Dependency] private readonly IconSmoothSystem _smooth = default!; [Dependency] private readonly IconSmoothSystem _smooth = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
@ -27,7 +28,7 @@ public sealed class PuddleSystem : SharedPuddleSystem
if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj)) if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
{ {
volume = (float) volumeObj; volume = (float)volumeObj;
} }
// Update smoothing and sprite based on volume. // Update smoothing and sprite based on volume.
@ -35,19 +36,19 @@ public sealed class PuddleSystem : SharedPuddleSystem
{ {
if (volume < LowThreshold) if (volume < LowThreshold)
{ {
args.Sprite.LayerSetState(0, $"{smooth.StateBase}a"); _sprite.LayerSetRsiState((uid, args.Sprite), 0, $"{smooth.StateBase}a");
_smooth.SetEnabled(uid, false, smooth); _smooth.SetEnabled(uid, false, smooth);
} }
else if (volume < MediumThreshold) else if (volume < MediumThreshold)
{ {
args.Sprite.LayerSetState(0, $"{smooth.StateBase}b"); _sprite.LayerSetRsiState((uid, args.Sprite), 0, $"{smooth.StateBase}b");
_smooth.SetEnabled(uid, false, smooth); _smooth.SetEnabled(uid, false, smooth);
} }
else else
{ {
if (!smooth.Enabled) if (!smooth.Enabled)
{ {
args.Sprite.LayerSetState(0, $"{smooth.StateBase}0"); _sprite.LayerSetRsiState((uid, args.Sprite), 0, $"{smooth.StateBase}0");
_smooth.SetEnabled(uid, true, smooth); _smooth.SetEnabled(uid, true, smooth);
_smooth.DirtyNeighbours(uid); _smooth.DirtyNeighbours(uid);
} }
@ -58,12 +59,12 @@ public sealed class PuddleSystem : SharedPuddleSystem
if (args.AppearanceData.TryGetValue(PuddleVisuals.SolutionColor, out var colorObj)) if (args.AppearanceData.TryGetValue(PuddleVisuals.SolutionColor, out var colorObj))
{ {
var color = (Color) colorObj; var color = (Color)colorObj;
args.Sprite.Color = color * baseColor; _sprite.SetColor((uid, args.Sprite), color * baseColor);
} }
else else
{ {
args.Sprite.Color *= baseColor; _sprite.SetColor((uid, args.Sprite), args.Sprite.Color * baseColor);
} }
} }

View file

@ -19,6 +19,7 @@ namespace Content.Client.Ghost
[Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly PointLightSystem _pointLightSystem = default!; [Dependency] private readonly PointLightSystem _pointLightSystem = default!;
[Dependency] private readonly ContentEyeSystem _contentEye = default!; [Dependency] private readonly ContentEyeSystem _contentEye = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly AudioSystem _audioSystem = default!; [Dependency] private readonly AudioSystem _audioSystem = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!; // Sunrise-Edit [Dependency] private readonly IConfigurationManager _cfg = default!; // Sunrise-Edit
@ -41,7 +42,7 @@ namespace Content.Client.Ghost
var query = AllEntityQuery<GhostComponent, SpriteComponent>(); var query = AllEntityQuery<GhostComponent, SpriteComponent>();
while (query.MoveNext(out var uid, out _, out var sprite)) while (query.MoveNext(out var uid, out _, out var sprite))
{ {
sprite.Visible = value || uid == _playerManager.LocalEntity; _sprite.SetVisible((uid, sprite), value || uid == _playerManager.LocalEntity);
} }
} }
} }
@ -78,7 +79,7 @@ namespace Content.Client.Ghost
private void OnStartup(EntityUid uid, GhostComponent component, ComponentStartup args) private void OnStartup(EntityUid uid, GhostComponent component, ComponentStartup args)
{ {
if (TryComp(uid, out SpriteComponent? sprite)) if (TryComp(uid, out SpriteComponent? sprite))
sprite.Visible = GhostVisibility || uid == _playerManager.LocalEntity; _sprite.SetVisible((uid, sprite), GhostVisibility || uid == _playerManager.LocalEntity);
} }
private void OnToggleLighting(EntityUid uid, EyeComponent component, ToggleLightingActionEvent args) private void OnToggleLighting(EntityUid uid, EyeComponent component, ToggleLightingActionEvent args)
@ -156,7 +157,7 @@ namespace Content.Client.Ghost
private void OnGhostState(EntityUid uid, GhostComponent component, ref AfterAutoHandleStateEvent args) private void OnGhostState(EntityUid uid, GhostComponent component, ref AfterAutoHandleStateEvent args)
{ {
if (TryComp<SpriteComponent>(uid, out var sprite)) if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.LayerSetColor(0, component.Color); _sprite.LayerSetColor((uid, sprite), 0, component.Color);
if (uid != _playerManager.LocalEntity) if (uid != _playerManager.LocalEntity)
return; return;

View file

@ -25,6 +25,7 @@ public sealed class GhostToggleSelfVisibility : IConsoleCommand
if (!entityManager.TryGetComponent(attachedEntity, out SpriteComponent? spriteComponent)) if (!entityManager.TryGetComponent(attachedEntity, out SpriteComponent? spriteComponent))
return; return;
spriteComponent.Visible = !spriteComponent.Visible; var spriteSys = entityManager.System<SpriteSystem>();
spriteSys.SetVisible((attachedEntity.Value, spriteComponent), !spriteComponent.Visible);
} }
} }

View file

@ -7,6 +7,8 @@ namespace Content.Client.Gravity;
public sealed partial class GravitySystem : SharedGravitySystem public sealed partial class GravitySystem : SharedGravitySystem
{ {
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!; [Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@ -26,34 +28,34 @@ public sealed partial class GravitySystem : SharedGravitySystem
{ {
if (comp.SpriteMap.TryGetValue(state, out var spriteState)) if (comp.SpriteMap.TryGetValue(state, out var spriteState))
{ {
var layer = args.Sprite.LayerMapGet(GravityGeneratorVisualLayers.Base); var layer = _sprite.LayerMapGet((uid, args.Sprite), GravityGeneratorVisualLayers.Base);
args.Sprite.LayerSetState(layer, spriteState); _sprite.LayerSetRsiState((uid, args.Sprite), layer, spriteState);
} }
} }
if (_appearanceSystem.TryGetData<float>(uid, PowerChargeVisuals.Charge, out var charge, args.Component)) if (_appearanceSystem.TryGetData<float>(uid, PowerChargeVisuals.Charge, out var charge, args.Component))
{ {
var layer = args.Sprite.LayerMapGet(GravityGeneratorVisualLayers.Core); var layer = _sprite.LayerMapGet((uid, args.Sprite), GravityGeneratorVisualLayers.Core);
switch (charge) switch (charge)
{ {
case < 0.2f: case < 0.2f:
args.Sprite.LayerSetVisible(layer, false); _sprite.LayerSetVisible((uid, args.Sprite), layer, false);
break; break;
case >= 0.2f and < 0.4f: case >= 0.2f and < 0.4f:
args.Sprite.LayerSetVisible(layer, true); _sprite.LayerSetVisible((uid, args.Sprite), layer, true);
args.Sprite.LayerSetState(layer, comp.CoreStartupState); _sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreStartupState);
break; break;
case >= 0.4f and < 0.6f: case >= 0.4f and < 0.6f:
args.Sprite.LayerSetVisible(layer, true); _sprite.LayerSetVisible((uid, args.Sprite), layer, true);
args.Sprite.LayerSetState(layer, comp.CoreIdleState); _sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreIdleState);
break; break;
case >= 0.6f and < 0.8f: case >= 0.6f and < 0.8f:
args.Sprite.LayerSetVisible(layer, true); _sprite.LayerSetVisible((uid, args.Sprite), layer, true);
args.Sprite.LayerSetState(layer, comp.CoreActivatingState); _sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreActivatingState);
break; break;
default: default:
args.Sprite.LayerSetVisible(layer, true); _sprite.LayerSetVisible((uid, args.Sprite), layer, true);
args.Sprite.LayerSetState(layer, comp.CoreActivatedState); _sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreActivatedState);
break; break;
} }
} }

View file

@ -28,12 +28,15 @@ public sealed partial class GuideEntityEmbed : BoxContainer, IDocumentTag
{ {
[Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IEntitySystemManager _systemManager = default!; [Dependency] private readonly IEntitySystemManager _systemManager = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!; [Dependency] private readonly IUserInterfaceManager _ui = default!;
private readonly TagSystem _tagSystem; private readonly TagSystem _tagSystem;
private readonly ExamineSystem _examineSystem; private readonly ExamineSystem _examineSystem;
private readonly GuidebookSystem _guidebookSystem; private readonly GuidebookSystem _guidebookSystem;
private readonly ISawmill _sawmill;
public bool Interactive; public bool Interactive;
public Entity<SpriteComponent>? Sprite => View.Entity == null || View.Sprite == null public Entity<SpriteComponent>? Sprite => View.Entity == null || View.Sprite == null
@ -53,6 +56,7 @@ public sealed partial class GuideEntityEmbed : BoxContainer, IDocumentTag
_tagSystem = _systemManager.GetEntitySystem<TagSystem>(); _tagSystem = _systemManager.GetEntitySystem<TagSystem>();
_examineSystem = _systemManager.GetEntitySystem<ExamineSystem>(); _examineSystem = _systemManager.GetEntitySystem<ExamineSystem>();
_guidebookSystem = _systemManager.GetEntitySystem<GuidebookSystem>(); _guidebookSystem = _systemManager.GetEntitySystem<GuidebookSystem>();
_sawmill = _logManager.GetSawmill("guidebook.entity");
MouseFilter = MouseFilterMode.Stop; MouseFilter = MouseFilterMode.Stop;
} }
@ -135,7 +139,7 @@ public sealed partial class GuideEntityEmbed : BoxContainer, IDocumentTag
{ {
if (!args.TryGetValue("Entity", out var proto)) if (!args.TryGetValue("Entity", out var proto))
{ {
Logger.Error("Entity embed tag is missing entity prototype argument"); _sawmill.Error("Entity embed tag is missing entity prototype argument");
control = null; control = null;
return false; return false;
} }

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