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/Guidebook/ServerRules/ @nikthechampiongr @crazybrain23
/Resources/Prototypes/Maps/** @Emisse
/Resources/Prototypes/Maps/** @Emisse @ArtisticRoomba
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
/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:
group: publish-testing
cancel-in-progress: true
on:
workflow_dispatch:

View file

@ -2,6 +2,7 @@ name: Publish
concurrency:
group: publish
cancel-in-progress: true
on:
workflow_dispatch:
@ -68,18 +69,21 @@ jobs:
DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_SUNRISE }}
- name: Publish discord changelog (LUST)
continue-on-error: true
run: Tools/_sunrise/actions_changelogs_since_last_run.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_LUST }}
- name: Publish discord changelog (FISH)
continue-on-error: true
run: Tools/_sunrise/actions_changelogs_since_last_run.py
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DISCORD_WEBHOOK_URL: ${{ secrets.CHANGELOG_DISCORD_WEBHOOK_FISH }}
# - name: Publish changelog (RSS)
# continue-on-error: true
# run: Tools/actions_changelog_rss.py
# env:
# 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]
public class ComponentQueryBenchmark
{
public const string Map = "Maps/atlas.yml";
public const string Map = "Maps/saltern.yml";
private TestPair _pair = default!;
private IEntityManager _entMan = default!;

View file

@ -1,15 +1,7 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using BenchmarkDotNet.Running;
using Content.IntegrationTests;
using Content.Server.Maps;
#if DEBUG
using BenchmarkDotNet.Configs;
#else
using Robust.Benchmarks.Configs;
#endif
using Robust.Shared.Prototypes;
namespace Content.Benchmarks
{
@ -22,11 +14,15 @@ namespace Content.Benchmarks
Console.ForegroundColor = ConsoleColor.Red;
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");
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, new DebugInProcessConfig());
var baseConfig = new DebugInProcessConfig();
#else
var config = Environment.GetEnvironmentVariable("ROBUST_BENCHMARKS_ENABLE_SQL") != null ? DefaultSQLConfig.Instance : null;
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config);
var baseConfig = Environment.GetEnvironmentVariable("ROBUST_BENCHMARKS_ENABLE_SQL") != null
? DefaultSQLConfig.Instance
: DefaultConfig.Instance;
#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.Components;
using Content.Shared.Access.Systems;
using Content.Shared.CCVar;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.CrewManifest;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using static Content.Shared.Access.Components.IdCardConsoleComponent;
@ -11,13 +13,21 @@ namespace Content.Client.Access.UI
public sealed class IdCardConsoleBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
private readonly SharedIdCardConsoleSystem _idCardConsoleSystem = default!;
private IdCardConsoleWindow? _window;
// CCVar.
private int _maxNameLength;
private int _maxIdJobLength;
public IdCardConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
_idCardConsoleSystem = EntMan.System<SharedIdCardConsoleSystem>();
_maxNameLength =_cfgManager.GetCVar(CCVars.MaxNameLength);
_maxIdJobLength = _cfgManager.GetCVar(CCVars.MaxIdJobLength);
}
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)
{
if (newFullName.Length > MaxFullNameLength)
newFullName = newFullName[..MaxFullNameLength];
if (newFullName.Length > _maxNameLength)
newFullName = newFullName[.._maxNameLength];
if (newJobTitle.Length > MaxJobTitleLength)
newJobTitle = newJobTitle[..MaxJobTitleLength];
if (newJobTitle.Length > _maxIdJobLength)
newJobTitle = newJobTitle[.._maxIdJobLength];
SendMessage(new WriteToTargetIdMessage(
newFullName,

View file

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

View file

@ -7,6 +7,8 @@ namespace Content.Client.Administration.Systems;
public sealed class KillSignSystem : EntitySystem
{
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
SubscribeLocalEvent<KillSignComponent, ComponentStartup>(KillSignAdded);
@ -18,10 +20,10 @@ public sealed class KillSignSystem : EntitySystem
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;
if (!sprite.LayerMapTryGet(KillSignKey.Key, out var layer))
if (!_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var layer, false))
return;
sprite.RemoveLayer(layer);
_sprite.RemoveLayer((uid, sprite), layer);
}
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))
return;
if (sprite.LayerMapTryGet(KillSignKey.Key, out var _))
if (_sprite.LayerMapTryGet((uid, sprite), KillSignKey.Key, out var _, false))
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"));
sprite.LayerMapSet(KillSignKey.Key, layer);
var layer = _sprite.AddLayer((uid, sprite), new SpriteSpecifier.Rsi(new ResPath("Objects/Misc/killsign.rsi"), "sign"));
_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");
}

View file

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

View file

@ -14,6 +14,9 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
[UsedImplicitly]
public sealed partial class LoadBlueprintsWindow : DefaultWindow
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
public LoadBlueprintsWindow()
{
RobustXamlLoader.Load(this);
@ -21,9 +24,9 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
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);
}
@ -39,21 +42,19 @@ namespace Content.Client.Administration.UI.Tabs.AdminbusTab
private void Reset()
{
var entManager = IoCManager.Resolve<IEntityManager>();
var xformSystem = entManager.System<SharedTransformSystem>();
var playerManager = IoCManager.Resolve<IPlayerManager>();
var player = playerManager.LocalEntity;
var xformSystem = _entityManager.System<SharedTransformSystem>();
var player = _playerManager.LocalEntity;
var currentMap = MapId.Nullspace;
var position = Vector2.Zero;
var rotation = Angle.Zero;
if (entManager.TryGetComponent<TransformComponent>(player, out var xform))
if (_entityManager.TryGetComponent<TransformComponent>(player, out var xform))
{
currentMap = xform.MapID;
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);
}

View file

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

View file

@ -1,10 +1,24 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Administration.UI.Tabs
{
[GenerateTypedNameReferences]
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
{
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
@ -21,26 +23,26 @@ public sealed class AlertLevelDisplaySystem : EntitySystem
{
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))
{
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))
{
args.Sprite.LayerSetState(layer, alertLevelDisplay.AlertVisuals.Values.First());
_sprite.LayerSetRsiState((uid, args.Sprite), layer, alertLevelDisplay.AlertVisuals.Values.First());
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
{
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 MetaDataSystem _metaData = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly TransformSystem _transform = default!;
public override void Initialize()
@ -56,8 +57,8 @@ public sealed class EntityPickupAnimationSystem : EntitySystem
}
var sprite = Comp<SpriteComponent>(animatableClone);
sprite.CopyFrom(sprite0);
sprite.Visible = true;
_sprite.CopySprite((uid, sprite0), (animatableClone, sprite));
_sprite.SetVisible((animatableClone, sprite), true);
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 FloatingVisualizerSystem _floating = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <inheritdoc/>
public override void Initialize()
@ -49,12 +50,12 @@ public sealed class AnomalySystem : SharedAnomalySystem
if (HasComp<AnomalySupercriticalComponent>(uid))
pulsing = true;
if (!sprite.LayerMapTryGet(AnomalyVisualLayers.Base, out var layer) ||
!sprite.LayerMapTryGet(AnomalyVisualLayers.Animated, out var animatedLayer))
if (!_sprite.LayerMapTryGet((uid, sprite), AnomalyVisualLayers.Base, out var layer, false) ||
!_sprite.LayerMapTryGet((uid, sprite), AnomalyVisualLayers.Animated, out var animatedLayer, false))
return;
sprite.LayerSetVisible(layer, !pulsing);
sprite.LayerSetVisible(animatedLayer, pulsing);
_sprite.LayerSetVisible((uid, sprite), layer, !pulsing);
_sprite.LayerSetVisible((uid, sprite), animatedLayer, pulsing);
}
public override void Update(float frameTime)
@ -63,16 +64,16 @@ public sealed class AnomalySystem : SharedAnomalySystem
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;
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)
{
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))
return;
sprite.Scale = Vector2.One;
sprite.Color = sprite.Color.WithAlpha(1f);
_sprite.SetScale((ent.Owner, sprite), Vector2.One);
_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
{
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
SubscribeLocalEvent<InnerBodyAnomalyComponent, AfterAutoHandleStateEvent>(OnAfterHandleState);
@ -21,21 +23,20 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
if (ent.Comp.FallbackSprite is null)
return;
if (!sprite.LayerMapTryGet(ent.Comp.LayerMap, out var index))
index = sprite.LayerMapReserveBlank(ent.Comp.LayerMap);
var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap);
if (TryComp<BodyComponent>(ent, out var body) &&
body.Prototype is not null &&
ent.Comp.SpeciesSprites.TryGetValue(body.Prototype.Value, out var speciesSprite))
{
sprite.LayerSetSprite(index, speciesSprite);
_sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite);
}
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");
}
@ -44,7 +45,7 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
if (!TryComp<SpriteComponent>(ent, out var sprite))
return;
var index = sprite.LayerMapGet(ent.Comp.LayerMap);
sprite.LayerSetVisible(index, false);
var index = _sprite.LayerMapGet((ent.Owner, sprite), ent.Comp.LayerMap);
_sprite.LayerSetVisible((ent.Owner, sprite), index, false);
}
}

View file

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

View file

@ -2,6 +2,7 @@ using Content.Client.Atmos.Components;
using Content.Shared.Atmos;
using Robust.Client.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Utility;
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
// which means in some setups (most frequently no AppearanceComp) the layer never exists.
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))
return;
sprite.LayerMapReserveBlank(FireVisualLayers.Fire);
sprite.LayerSetVisible(FireVisualLayers.Fire, false);
SpriteSystem.LayerMapReserve((uid, sprite), FireVisualLayers.Fire);
SpriteSystem.LayerSetVisible((uid, sprite), FireVisualLayers.Fire, false);
sprite.LayerSetShader(FireVisualLayers.Fire, "unshaded");
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);
}
@ -59,12 +60,12 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
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;
AppearanceSystem.TryGetData<bool>(uid, FireVisuals.OnFire, out var onFire, appearance);
AppearanceSystem.TryGetData<float>(uid, FireVisuals.FireStacks, out var fireStacks, appearance);
sprite.LayerSetVisible(index, onFire);
SpriteSystem.LayerSetVisible((uid, sprite), index, onFire);
if (!onFire)
{
@ -78,9 +79,9 @@ public sealed class FireVisualizerSystem : VisualizerSystem<FireVisualsComponent
}
if (fireStacks > component.FireStackAlternateState && !string.IsNullOrEmpty(component.AlternateState))
sprite.LayerSetState(index, component.AlternateState);
SpriteSystem.LayerSetRsiState((uid, sprite), index, component.AlternateState);
else
sprite.LayerSetState(index, component.NormalState);
SpriteSystem.LayerSetRsiState((uid, sprite), index, component.NormalState);
component.LightEntity ??= Spawn(null, new EntityCoordinates(uid, default));
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)
{
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;
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)
{
if (args.Sprite.LayerMapTryGet(visLayer, out var powerVisibilityLayer))
args.Sprite.LayerSetVisible(powerVisibilityLayer, powered);
if (SpriteSystem.LayerMapTryGet((uid, args.Sprite), visLayer, out var powerVisibilityLayer, false))
SpriteSystem.LayerSetVisible((uid, args.Sprite), powerVisibilityLayer, powered);
}
}
@ -31,8 +31,8 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
{
foreach (var (setLayer, powerState) in component.SetOnDepowered)
{
if (args.Sprite.LayerMapTryGet(setLayer, out var setStateLayer))
args.Sprite.LayerSetState(setStateLayer, new RSI.StateId(powerState));
if (SpriteSystem.LayerMapTryGet((uid, args.Sprite), setLayer, out var setStateLayer, false))
SpriteSystem.LayerSetRsiState((uid, args.Sprite), setStateLayer, new RSI.StateId(powerState));
}
}
@ -41,7 +41,7 @@ public sealed class AtmosAlarmableVisualsSystem : VisualizerSystem<AtmosAlarmabl
&& powered
&& 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 -->
<BoxContainer Orientation="Horizontal">
<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'}" />
</BoxContainer>
</BoxContainer>

View file

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

View file

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

View file

@ -21,6 +21,7 @@ namespace Content.Client.Atmos.Overlays
{
private readonly IEntityManager _entManager;
private readonly IMapManager _mapManager;
private readonly SharedMapSystem _mapSystem;
private readonly SharedTransformSystem _xformSys;
public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld;
@ -51,6 +52,7 @@ namespace Content.Client.Atmos.Overlays
{
_entManager = entManager;
_mapManager = IoCManager.Resolve<IMapManager>();
_mapSystem = entManager.System<SharedMapSystem>();
_xformSys = xformSys;
_shader = protoMan.Index<ShaderPrototype>("unshaded").Instance();
ZIndex = GasOverlayZIndex;
@ -163,7 +165,7 @@ namespace Content.Client.Atmos.Overlays
xformQuery,
_xformSys);
var mapUid = _mapManager.GetMapEntityId(args.MapId);
var mapUid = _mapSystem.GetMapOrInvalid(args.MapId);
if (_entManager.TryGetComponent<MapAtmosphereComponent>(mapUid, out var 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.Systems;
using Content.Shared.Power.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
@ -36,6 +39,8 @@ namespace Content.Client.Atmos.UI
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
_window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value);
_window.Entity = Owner;
Update();
}
private void OnToggleStatusButtonPressed()
@ -43,7 +48,7 @@ namespace Content.Client.Atmos.UI
if (_window is null) return;
_window.SetActive(!_window.Active);
SendMessage(new GasThermomachineToggleMessage());
SendPredictedMessage(new GasThermomachineToggleMessage());
}
private void OnTemperatureChanged(float value)
@ -60,25 +65,32 @@ namespace Content.Client.Atmos.UI
return;
}
SendMessage(new GasThermomachineChangeTemperatureMessage(actual));
SendPredictedMessage(new GasThermomachineChangeTemperatureMessage(actual));
}
/// <summary>
/// Update the UI state based on server-sent info
/// </summary>
/// <param name="state"></param>
protected override void UpdateState(BoundUserInterfaceState state)
public override void Update()
{
base.UpdateState(state);
if (_window == null || state is not GasThermomachineBoundUserInterfaceState cast)
if (_window == null || !EntMan.TryGetComponent(Owner, out GasThermoMachineComponent? thermo))
return;
_minTemp = cast.MinTemperature;
_maxTemp = cast.MaxTemperature;
_isHeater = cast.IsHeater;
var system = EntMan.System<SharedGasThermoMachineSystem>();
_minTemp = thermo.MinTemperature;
_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
{
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:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="300 120" Title="{Loc comp-gas-thermomachine-ui-title-freezer}">
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
@ -11,4 +12,4 @@
<Label Text="{Loc comp-gas-thermomachine-ui-temperature}"/>
</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.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.Atmos.UI;
[GenerateTypedNameReferences]
public sealed partial class GasThermomachineWindow : DefaultWindow
public sealed partial class GasThermomachineWindow : FancyWindow
{
[Dependency] private readonly IEntityManager _entManager = default!;
public bool Active = true;
public FloatSpinBox TemperatureSpinbox;
public EntityUid Entity;
public GasThermomachineWindow()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
SpinboxHBox.AddChild(
@ -27,12 +34,10 @@ public sealed partial class GasThermomachineWindow : DefaultWindow
if (active)
{
ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-enabled");
ToggleStatusButton.Pressed = true;
}
else
{
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;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (_entManager.TryGetComponent(Entity, out ApcPowerReceiverComponent? receiver))
{
SetActive(!receiver.PowerDisabled);
}
}
}

View file

@ -2,13 +2,13 @@ using Robust.Client.GameObjects;
using Content.Shared.Atmos.Visuals;
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>
/// 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)
@ -18,19 +18,19 @@ namespace Content.Client.Atmos.Visualizers
&& AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsRunning, out var isRunning, args.Component))
{
var runningState = isRunning ? component.RunningState : component.IdleState;
args.Sprite.LayerSetState(PortableScrubberVisualLayers.IsRunning, runningState);
SpriteSystem.LayerSetRsiState((uid, args.Sprite), PortableScrubberVisualLayers.IsRunning, runningState);
var fullState = isFull ? component.FullState : component.ReadyState;
args.Sprite.LayerSetState(PowerDeviceVisualLayers.Powered, fullState);
SpriteSystem.LayerSetRsiState((uid, args.Sprite), PowerDeviceVisualLayers.Powered, fullState);
}
if (AppearanceSystem.TryGetData<bool>(uid, PortableScrubberVisuals.IsDraining, out var isDraining, args.Component))
{
args.Sprite.LayerSetVisible(PortableScrubberVisualLayers.IsDraining, isDraining);
}
SpriteSystem.LayerSetVisible((uid, args.Sprite), PortableScrubberVisualLayers.IsDraining, isDraining);
}
}
}
public enum PortableScrubberVisualLayers : byte
{
IsRunning,

View file

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

View file

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

View file

@ -7,6 +7,8 @@ namespace Content.Client.Beam;
public sealed class BeamSystem : SharedBeamSystem
{
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
@ -21,11 +23,11 @@ public sealed class BeamSystem : SharedBeamSystem
if (TryComp<SpriteComponent>(beam, out var sprites))
{
sprites.Rotation = args.UserAngle;
_sprite.SetRotation((beam, sprites), args.UserAngle);
if (args.BodyState != null)
{
sprites.LayerSetState(0, args.BodyState);
_sprite.LayerSetRsiState((beam, sprites), 0, args.BodyState);
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
&& 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.Shared.Botany;
using Robust.Client.GameObjects;
using Robust.Shared.Utility;
namespace Content.Client.Botany;
@ -17,8 +18,8 @@ public sealed class PlantHolderVisualizerSystem : VisualizerSystem<PlantHolderVi
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;
sprite.LayerMapReserveBlank(PlantHolderLayers.Plant);
sprite.LayerSetVisible(PlantHolderLayers.Plant, false);
SpriteSystem.LayerMapReserve((uid, sprite), PlantHolderLayers.Plant);
SpriteSystem.LayerSetVisible((uid, sprite), PlantHolderLayers.Plant, false);
}
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);
args.Sprite.LayerSetVisible(PlantHolderLayers.Plant, valid);
SpriteSystem.LayerSetVisible((uid, args.Sprite), PlantHolderLayers.Plant, valid);
if (valid)
{
args.Sprite.LayerSetRSI(PlantHolderLayers.Plant, rsi);
args.Sprite.LayerSetState(PlantHolderLayers.Plant, state);
SpriteSystem.LayerSetRsi((uid, args.Sprite), PlantHolderLayers.Plant, new ResPath(rsi));
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))
{
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 IEyeManager _eye = default!;
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
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
buckle.OriginalDrawDepth ??= buckledSprite.DrawDepth;
buckledSprite.DrawDepth = strapSprite.DrawDepth - 1;
_sprite.SetDrawDepth((buckledEntity, buckledSprite), strapSprite.DrawDepth - 1);
}
else if (buckle.OriginalDrawDepth.HasValue)
{
buckledSprite.DrawDepth = buckle.OriginalDrawDepth.Value;
_sprite.SetDrawDepth((buckledEntity, buckledSprite), buckle.OriginalDrawDepth.Value);
buckle.OriginalDrawDepth = null;
}
}
@ -97,7 +98,7 @@ internal sealed class BuckleSystem : SharedBuckleSystem
return;
ent.Comp.OriginalDrawDepth ??= buckledSprite.DrawDepth;
buckledSprite.DrawDepth = strapSprite.DrawDepth - 1;
_sprite.SetDrawDepth((ent.Owner, buckledSprite), strapSprite.DrawDepth - 1);
}
/// <summary>
@ -111,7 +112,7 @@ internal sealed class BuckleSystem : SharedBuckleSystem
if (!ent.Comp.OriginalDrawDepth.HasValue)
return;
buckledSprite.DrawDepth = ent.Comp.OriginalDrawDepth.Value;
_sprite.SetDrawDepth((ent.Owner, buckledSprite), ent.Comp.OriginalDrawDepth.Value);
ent.Comp.OriginalDrawDepth = null;
}

View file

@ -13,6 +13,7 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly ExamineSystemShared _examine = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
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))
continue;
sprite.Offset = new Vector2(0, 1);
_sprite.SetOffset((ent, sprite), new Vector2(0, 1));
_transform.SetParent(ent, entTransform, mob);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -36,6 +36,7 @@ namespace Content.Client.Cargo.UI
{
var product = protoManager.Index<EntityPrototype>(order.ProductId);
var productName = product.Name;
var account = protoManager.Index(order.Account);
var row = new CargoOrderRow
{
@ -47,7 +48,9 @@ namespace Content.Client.Cargo.UI
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
("productName", productName),
("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",
("reason", order.Reason))}

View file

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

View file

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

View file

@ -1,6 +1,5 @@
using Content.Shared.Chat.TypingIndicator;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Prototypes;
using Content.Shared.Inventory;
@ -11,7 +10,6 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
@ -35,15 +33,25 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
return;
}
AppearanceSystem.TryGetData<bool>(uid, TypingIndicatorVisuals.IsTyping, out var isTyping, args.Component);
var layerExists = args.Sprite.LayerMapTryGet(TypingIndicatorLayers.Base, out var layer);
var layerExists = SpriteSystem.LayerMapTryGet((uid, args.Sprite), TypingIndicatorLayers.Base, out var layer, false);
if (!layerExists)
layer = args.Sprite.LayerMapReserveBlank(TypingIndicatorLayers.Base);
layer = SpriteSystem.LayerMapReserve((uid, args.Sprite), TypingIndicatorLayers.Base);
args.Sprite.LayerSetRSI(layer, proto.SpritePath);
args.Sprite.LayerSetState(layer, proto.TypingState);
SpriteSystem.LayerSetRsi((uid, args.Sprite), layer, proto.SpritePath);
SpriteSystem.LayerSetRsiState((uid, args.Sprite), layer, proto.TypingState);
args.Sprite.LayerSetShader(layer, proto.Shader);
args.Sprite.LayerSetOffset(layer, proto.Offset);
args.Sprite.LayerSetVisible(layer, isTyping);
SpriteSystem.LayerSetOffset((uid, args.Sprite), layer, proto.Offset);
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
{
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
@ -16,9 +18,9 @@ public sealed class PillSystem : EntitySystem
if (!TryComp(uid, out SpriteComponent? sprite))
return;
if (!sprite.TryGetLayer(0, out var layer))
if (!_sprite.TryGetLayer((uid, sprite), 0, out var layer, false))
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;
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",
true => "hypospray-mobs-only-mode-text",

View file

@ -1,4 +1,5 @@
using Content.Shared.Chemistry;
using Content.Shared.Storage;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
@ -9,15 +10,15 @@ namespace Content.Client.Chemistry.UI;
[GenerateTypedNameReferences]
public sealed partial class ReagentCardControl : Control
{
public string StorageSlotId { get; }
public Action<string>? OnPressed;
public Action<string>? OnEjectButtonPressed;
public ItemStorageLocation StorageLocation { get; }
public Action<ItemStorageLocation>? OnPressed;
public Action<ItemStorageLocation>? OnEjectButtonPressed;
public ReagentCardControl(ReagentInventoryItem item)
{
RobustXamlLoader.Load(this);
StorageSlotId = item.StorageSlotId;
StorageLocation = item.StorageLocation;
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor };
ReagentNameLabel.Text = item.ReagentLabel;
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)
MainButton.Disabled = true;
MainButton.OnPressed += args => OnPressed?.Invoke(StorageSlotId);
EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageSlotId);
MainButton.OnPressed += args => OnPressed?.Invoke(StorageLocation);
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.OnDispenseReagentButtonPressed += (id) => SendMessage(new ReagentDispenserDispenseReagentMessage(id));
_window.OnEjectJugButtonPressed += (id) => SendMessage(new ItemSlotButtonPressedEvent(id));
_window.OnDispenseReagentButtonPressed += (location) => SendMessage(new ReagentDispenserDispenseReagentMessage(location));
_window.OnEjectJugButtonPressed += (location) => SendMessage(new ReagentDispenserEjectContainerMessage(location));
}
/// <summary>

View file

@ -2,6 +2,7 @@ using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Storage;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
@ -18,8 +19,8 @@ namespace Content.Client.Chemistry.UI
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public event Action<string>? OnDispenseReagentButtonPressed;
public event Action<string>? OnEjectJugButtonPressed;
public event Action<ItemStorageLocation>? OnDispenseReagentButtonPressed;
public event Action<ItemStorageLocation>? OnEjectJugButtonPressed;
/// <summary>
/// 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;
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)
return;
if(!AppearanceSystem.TryGetData<Color>(uid, SmokeVisuals.Color, out var color))
if (!AppearanceSystem.TryGetData<Color>(uid, SmokeVisuals.Color, out var color))
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)
return;
if (!args.Sprite.LayerMapTryGet(component.Layer, out var fillLayer))
if (!SpriteSystem.LayerMapTryGet((uid, args.Sprite), component.Layer, out var fillLayer, false))
return;
var maxFillLevels = component.MaxFillLevels;
@ -67,9 +67,9 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
}
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,
out var baseOverride,
@ -79,35 +79,35 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
if (reagentProto?.MetamorphicSprite is { } sprite)
{
args.Sprite.LayerSetSprite(baseLayer, sprite);
SpriteSystem.LayerSetSprite((uid, args.Sprite), baseLayer, sprite);
if (reagentProto.MetamorphicMaxFillLevels > 0)
{
args.Sprite.LayerSetVisible(fillLayer, true);
SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, true);
maxFillLevels = reagentProto.MetamorphicMaxFillLevels;
fillBaseName = reagentProto.MetamorphicFillBaseName;
changeColor = reagentProto.MetamorphicChangeColor;
fillSprite = sprite;
}
else
args.Sprite.LayerSetVisible(fillLayer, false);
SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, false);
if (hasOverlay)
args.Sprite.LayerSetVisible(overlayLayer, false);
SpriteSystem.LayerSetVisible((uid, args.Sprite), overlayLayer, false);
}
else
{
args.Sprite.LayerSetVisible(fillLayer, true);
SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, true);
if (hasOverlay)
args.Sprite.LayerSetVisible(overlayLayer, true);
SpriteSystem.LayerSetVisible((uid, args.Sprite), overlayLayer, true);
if (component.MetamorphicDefaultSprite != null)
args.Sprite.LayerSetSprite(baseLayer, component.MetamorphicDefaultSprite);
SpriteSystem.LayerSetSprite((uid, args.Sprite), baseLayer, component.MetamorphicDefaultSprite);
}
}
}
}
else
{
args.Sprite.LayerSetVisible(fillLayer, true);
SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, true);
}
var closestFillSprite = ContentHelpers.RoundToLevels(fraction, 1, maxFillLevels + 1);
@ -119,25 +119,25 @@ public sealed class SolutionContainerVisualsSystem : VisualizerSystem<SolutionCo
var stateName = fillBaseName + closestFillSprite;
if (fillSprite != null)
args.Sprite.LayerSetSprite(fillLayer, fillSprite);
args.Sprite.LayerSetState(fillLayer, stateName);
SpriteSystem.LayerSetSprite((uid, args.Sprite), fillLayer, fillSprite);
SpriteSystem.LayerSetRsiState((uid, args.Sprite), fillLayer, stateName);
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
args.Sprite.LayerSetColor(fillLayer, Color.White);
SpriteSystem.LayerSetColor((uid, args.Sprite), fillLayer, Color.White);
}
else
{
if (component.EmptySpriteName == null)
args.Sprite.LayerSetVisible(fillLayer, false);
SpriteSystem.LayerSetVisible((uid, args.Sprite), fillLayer, false);
else
{
args.Sprite.LayerSetState(fillLayer, component.EmptySpriteName);
SpriteSystem.LayerSetRsiState((uid, args.Sprite), fillLayer, component.EmptySpriteName);
if (changeColor)
args.Sprite.LayerSetColor(fillLayer, component.EmptySpriteColor);
SpriteSystem.LayerSetColor((uid, args.Sprite), fillLayer, component.EmptySpriteColor);
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)
{
args.Sprite.Color = color;
SpriteSystem.SetColor((uid, args.Sprite), color);
}
}
}

View file

@ -77,10 +77,10 @@ public sealed class ClickableSystem : EntitySystem
drawDepth = sprite.DrawDepth;
renderOrder = sprite.RenderOrder;
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;
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.
var relativeRotation = (spriteRot + eye.Rotation).Reduced().FlipPositive();
@ -107,7 +107,7 @@ public sealed class ClickableSystem : EntitySystem
if (layer.Texture != null)
{
// 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))
return true;
@ -125,7 +125,7 @@ public sealed class ClickableSystem : EntitySystem
var layerLocal = Vector2.Transform(localPos, inverseMatrix);
// 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.
// 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
{
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Update(float frameTime)
{
base.Update(frameTime);
@ -12,15 +14,15 @@ public sealed class ClockSystem : SharedClockSystem
var query = EntityQueryEnumerator<ClockComponent, SpriteComponent>();
while (query.MoveNext(out var uid, out var comp, out var sprite))
{
if (!sprite.LayerMapTryGet(ClockVisualLayers.HourHand, out var hourLayer) ||
!sprite.LayerMapTryGet(ClockVisualLayers.MinuteHand, out var minuteLayer))
if (!_sprite.LayerMapTryGet((uid, sprite), ClockVisualLayers.HourHand, out var hourLayer, false) ||
!_sprite.LayerMapTryGet((uid, sprite), ClockVisualLayers.MinuteHand, out var minuteLayer, false))
continue;
var time = GetClockTime((uid, comp));
var hourState = $"{comp.HoursBase}{time.Hours % 12}";
var minuteState = $"{comp.MinutesBase}{time.Minutes / 5}";
sprite.LayerSetState(hourLayer, hourState);
sprite.LayerSetState(minuteLayer, minuteState);
_sprite.LayerSetRsiState((uid, sprite), hourLayer, hourState);
_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 InventorySystem _inventorySystem = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
@ -82,10 +83,10 @@ public sealed class ClientClothingSystem : ClothingSystem
UpdateAllSlots(uid, component);
// 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);
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);
}
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;
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.
foreach (var layer in revealedLayers)
{
component.RemoveLayer(layer);
_sprite.RemoveLayer(entity.AsNullable(), layer);
}
revealedLayers.Clear();
}
@ -269,7 +270,7 @@ public sealed class ClientClothingSystem : ClothingSystem
{
foreach (var key in revealedLayers)
{
sprite.RemoveLayer(key);
_sprite.RemoveLayer((equipee, sprite), key);
}
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
// 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
var displacementData = inventory.Displacements.GetValueOrDefault(slot); //Default unsexed map
@ -348,16 +349,16 @@ public sealed class ClientClothingSystem : ClothingSystem
{
index++;
// note that every insertion requires reshuffling & remapping all the existing layers.
sprite.AddBlankLayer(index);
sprite.LayerMapSet(key, index);
_sprite.AddBlankLayer((equipee, sprite), index);
_sprite.LayerMapSet((equipee, sprite), key, index);
if (layerData.Color != null)
sprite.LayerSetColor(key, layerData.Color.Value);
_sprite.LayerSetColor((equipee, sprite), key, layerData.Color.Value);
if (layerData.Scale != null)
sprite.LayerSetScale(key, layerData.Scale.Value);
_sprite.LayerSetScale((equipee, sprite), key, layerData.Scale.Value);
}
else
index = sprite.LayerMapReserveBlank(key);
index = _sprite.LayerMapReserve((equipee, sprite), key);
if (sprite[index] is not Layer layer)
continue;
@ -368,11 +369,11 @@ public sealed class ClientClothingSystem : ClothingSystem
&& layer.RSI == null
&& TryComp(equipment, out SpriteComponent? clothingSprite))
{
layer.SetRsi(clothingSprite.BaseRSI);
_sprite.LayerSetRsi(layer, clothingSprite.BaseRSI);
}
sprite.LayerSetData(index, layerData);
layer.Offset += slotDef.Offset;
_sprite.LayerSetData((equipee, sprite), index, layerData);
_sprite.LayerSetOffset(layer, layer.Offset + slotDef.Offset);
if (displacementData is not null)
{
@ -381,7 +382,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|| bodyTypeName is not null && layerData.State.EndsWith(bodyTypeName)))
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);
index++;

View file

@ -32,7 +32,7 @@ public sealed class FlippableClothingVisualizerSystem : VisualizerSystem<Flippab
if (clothing.MappedLayer == null ||
!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;
// add each layer to the visuals

View file

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

View file

@ -12,7 +12,6 @@ namespace Content.Client.Clothing.UI;
[UsedImplicitly]
public sealed class ChameleonBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
private readonly ChameleonClothingSystem _chameleon;
private readonly TagSystem _tag;
@ -49,7 +48,7 @@ public sealed class ChameleonBoundUserInterface : BoundUserInterface
if (string.IsNullOrEmpty(target) || !_proto.TryIndex(target, out EntityPrototype? proto))
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;
newTargets.Add(target);

View file

@ -18,23 +18,19 @@ public sealed class HideMechanismsCommand : LocalizedCommands
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
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))
{
continue;
}
sprite.ContainerOccluded = false;
spriteSys.SetContainerOccluded((uid, sprite), false);
var tempParent = uid;
while (containerSys.TryGetContainingContainer((tempParent, null, null), out var container))
{
if (!container.ShowContents)
{
sprite.ContainerOccluded = true;
spriteSys.SetContainerOccluded((uid, sprite), true);
break;
}

View file

@ -16,11 +16,12 @@ public sealed class ShowMechanismsCommand : LocalizedCommands
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var spriteSys = _entManager.System<SpriteSystem>();
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 ExamineSystemShared _examineSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
private readonly Dictionary<int, EntityUid> _ghosts = new();
@ -293,14 +294,14 @@ namespace Content.Client.Construction
_ghosts.Add(comp.GhostId, 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))
{
sprite.AddBlankLayer(0);
sprite.LayerSetSprite(0, icon.Icon);
_sprite.AddBlankLayer((ghost.Value, sprite), 0);
_sprite.LayerSetSprite((ghost.Value, sprite), 0, icon.Icon);
sprite.LayerSetShader(0, "unshaded");
sprite.LayerSetVisible(0, true);
_sprite.LayerSetVisible((ghost.Value, sprite), 0, true);
}
else if (targetProto.Components.TryGetValue("Sprite", out _))
{
@ -318,10 +319,10 @@ namespace Content.Client.Construction
state.StateId.Name is null)
continue;
sprite.AddBlankLayer(i);
sprite.LayerSetSprite(i, new SpriteSpecifier.Rsi(rsi.Path, state.StateId.Name));
_sprite.AddBlankLayer((ghost.Value, sprite), i);
_sprite.LayerSetSprite((ghost.Value, sprite), i, new SpriteSpecifier.Rsi(rsi.Path, state.StateId.Name));
sprite.LayerSetShader(i, "unshaded");
sprite.LayerSetVisible(i, true);
_sprite.LayerSetVisible((ghost.Value, sprite), i, true);
}
EntityManager.DeleteEntity(dummy);

View file

@ -9,6 +9,7 @@ namespace Content.Client.Construction;
public sealed class FlatpackSystem : SharedFlatpackSystem
{
[Dependency] private readonly AppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <inheritdoc/>
public override void Initialize()
@ -43,6 +44,6 @@ public sealed class FlatpackSystem : SharedFlatpackSystem
}
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.Numerics;
using Content.Client.Lobby;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Systems.MenuBar.Widgets;
using Content.Shared.Construction.Prototypes;
@ -28,6 +29,7 @@ namespace Content.Client.Construction.UI
[Dependency] private readonly IPlacementManager _placementManager = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;
private readonly SpriteSystem _spriteSystem;
private readonly IConstructionMenuView _constructionView;
@ -116,7 +118,7 @@ namespace Content.Client.Construction.UI
_constructionView.RecipeFavorited += (_, _) => OnViewFavoriteRecipe();
PopulateCategories();
SetFavorites(_preferencesManager.Preferences?.ConstructionFavorites ?? []);
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));
}
var newFavorites = new List<ProtoId<ConstructionPrototype>>(_favoritedRecipes.Count);
foreach (var recipe in _favoritedRecipes)
newFavorites.Add(recipe.ID);
_preferencesManager.UpdateConstructionFavorites(newFavorites);
PopulateInfo(_selected);
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)
{
if (newSystem is null)

View file

@ -4,12 +4,14 @@ using Content.Shared.Cuffs.Components;
using Content.Shared.Humanoid;
using Robust.Client.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Utility;
namespace Content.Client.Cuffs;
public sealed class CuffableSystem : SharedCuffableSystem
{
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
@ -22,7 +24,7 @@ public sealed class CuffableSystem : SharedCuffableSystem
private void OnCuffableShutdown(EntityUid uid, CuffableComponent component, ComponentShutdown args)
{
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)
@ -39,22 +41,22 @@ public sealed class CuffableSystem : SharedCuffableSystem
if (!TryComp<SpriteComponent>(uid, out var sprite))
return;
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,
// iconstate, or RSI. that also means we don't need to update the sprites.
if (!cuffed)
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
{
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
{
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.
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}.");
continue;
@ -253,7 +253,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
foreach (var layer in damageVisComp.TargetLayerMapKeys)
{
var layerCount = spriteComponent.AllLayers.Count();
var index = spriteComponent.LayerMapGet(layer);
var index = SpriteSystem.LayerMapGet((entity, spriteComponent), layer);
// var layerState = spriteComponent.LayerGetState(index).ToString()!;
if (index + 1 != layerCount)
@ -269,7 +269,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{
foreach (var (group, sprite) in damageVisComp.DamageOverlayGroups)
{
AddDamageLayerToSprite(spriteComponent,
AddDamageLayerToSprite((entity, spriteComponent),
sprite,
$"{layer}_{group}_{damageVisComp.Thresholds[1]}",
$"{layer}{group}",
@ -283,7 +283,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
// was taken.
else if (damageVisComp.DamageOverlay != null)
{
AddDamageLayerToSprite(spriteComponent,
AddDamageLayerToSprite((entity, spriteComponent),
damageVisComp.DamageOverlay,
$"{layer}_{damageVisComp.Thresholds[1]}",
$"{layer}trackDamage",
@ -301,7 +301,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{
foreach (var (group, sprite) in damageVisComp.DamageOverlayGroups)
{
AddDamageLayerToSprite(spriteComponent,
AddDamageLayerToSprite((entity, spriteComponent),
sprite,
$"DamageOverlay_{group}_{damageVisComp.Thresholds[1]}",
$"DamageOverlay{group}");
@ -310,7 +310,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
}
else if (damageVisComp.DamageOverlay != null)
{
AddDamageLayerToSprite(spriteComponent,
AddDamageLayerToSprite((entity, spriteComponent),
damageVisComp.DamageOverlay,
$"DamageOverlay_{damageVisComp.Thresholds[1]}",
"DamageOverlay");
@ -322,16 +322,19 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary>
/// Adds a damage tracking layer to a given sprite component.
/// </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 (sprite.Sprite), state
), index);
spriteComponent.LayerMapSet(mapKey, newLayer);
new(sprite.Sprite), state
),
index
);
SpriteSystem.LayerMapSet(spriteEnt, mapKey, newLayer);
if (sprite.Color != null)
spriteComponent.LayerSetColor(newLayer, Color.FromHex(sprite.Color));
spriteComponent.LayerSetVisible(newLayer, false);
SpriteSystem.LayerSetColor(spriteEnt, newLayer, Color.FromHex(sprite.Color));
SpriteSystem.LayerSetVisible(spriteEnt, newLayer, false);
}
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);
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)
&& update)
{
ForceUpdateLayers(damageComponent, spriteComponent, damageVisComp);
ForceUpdateLayers((uid, damageComponent, spriteComponent, damageVisComp));
return;
}
if (damageVisComp.TrackAllDamage)
{
UpdateDamageVisuals(damageComponent, spriteComponent, damageVisComp);
UpdateDamageVisuals((uid, damageComponent, spriteComponent, damageVisComp));
return;
}
@ -383,7 +386,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
data = new DamageVisualizerGroupData(Comp<DamageableComponent>(uid).DamagePerGroup.Keys.ToList());
}
UpdateDamageVisuals(data.GroupList, damageComponent, spriteComponent, damageVisComp);
UpdateDamageVisuals(data.GroupList, (uid, damageComponent, spriteComponent, damageVisComp));
}
/// <summary>
@ -406,7 +409,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
damageVisComp.DisabledLayers[layer] = disabled;
if (damageVisComp.TrackAllDamage)
{
spriteComponent.LayerSetVisible($"{layer}trackDamage", !disabled);
SpriteSystem.LayerSetVisible((uid, spriteComponent), $"{layer}trackDamage", !disabled);
continue;
}
@ -415,7 +418,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
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
/// layers are recreated and placed on top.
/// </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)
{
foreach (var (damageGroup, sprite) in damageVisComp.DamageOverlayGroups)
{
var threshold = damageVisComp.LastThresholdPerGroup[damageGroup];
ReorderOverlaySprite(spriteComponent,
ReorderOverlaySprite(spriteEnt,
damageVisComp,
sprite,
$"DamageOverlay{damageGroup}",
@ -446,7 +449,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
}
else if (damageVisComp.TrackAllDamage && damageVisComp.DamageOverlay != null)
{
ReorderOverlaySprite(spriteComponent,
ReorderOverlaySprite(spriteEnt,
damageVisComp,
damageVisComp.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);
var visibility = spriteComponent[spriteLayer].Visible;
spriteComponent.RemoveLayer(spriteLayer);
SpriteSystem.LayerMapTryGet(spriteEnt.AsNullable(), key, out var spriteLayer, false);
var visibility = spriteEnt.Comp[spriteLayer].Visible;
SpriteSystem.RemoveLayer(spriteEnt.AsNullable(), spriteLayer);
if (threshold == FixedPoint2.Zero) // these should automatically be invisible
threshold = damageVisComp.Thresholds[1];
spriteLayer = spriteComponent.AddLayer(
spriteLayer = SpriteSystem.AddLayer(
spriteEnt.AsNullable(),
new SpriteSpecifier.Rsi(
new (sprite.Sprite),
new(sprite.Sprite),
$"{statePrefix}_{threshold}"
),
spriteLayer);
spriteComponent.LayerMapSet(key, spriteLayer);
spriteComponent.LayerSetVisible(spriteLayer, visibility);
SpriteSystem.LayerMapSet(spriteEnt.AsNullable(), key, spriteLayer);
SpriteSystem.LayerSetVisible(spriteEnt.AsNullable(), spriteLayer, visibility);
// this is somewhat iffy since it constantly reallocates
damageVisComp.TopMostLayerKey = key;
}
@ -479,8 +483,12 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// Updates damage visuals without tracking
/// any damage groups.
/// </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))
return;
@ -490,12 +498,12 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{
foreach (var layerMapKey in damageVisComp.TargetLayerMapKeys)
{
UpdateTargetLayer(spriteComponent, damageVisComp, layerMapKey, threshold);
UpdateTargetLayer((entity, spriteComponent), damageVisComp, layerMapKey, threshold);
}
}
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
/// passed into it.
/// </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)
{
if (!damageVisComp.Overlay && damageGroup != damageVisComp.DamageGroup)
@ -525,12 +537,12 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
{
foreach (var layerMapKey in damageVisComp.TargetLayerMapKeys)
{
UpdateTargetLayer(spriteComponent, damageVisComp, layerMapKey, damageGroup, threshold);
UpdateTargetLayer((entity, spriteComponent, damageVisComp), layerMapKey, damageGroup, threshold);
}
}
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
/// the configuration of the visualizer.
/// </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)
{
UpdateDamageVisuals(damageVisComp.DamageOverlayGroups.Keys.ToList(), damageComponent, spriteComponent, damageVisComp);
UpdateDamageVisuals(damageVisComp.DamageOverlayGroups.Keys.ToList(), entity);
}
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)
{
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
/// damage.
/// </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.DisabledLayers[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,
$"{layerState}",
threshold);
@ -606,9 +620,9 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
else if (!damageVisComp.Overlay)
{
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,
$"{layerState}",
threshold);
@ -618,16 +632,20 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary>
/// Updates a target layer by damage group.
/// </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.DamageOverlayGroups.ContainsKey(damageGroup) && !damageVisComp.DisabledLayers[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,
$"{layerState}_{damageGroup}",
threshold);
@ -636,9 +654,10 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
else if (!damageVisComp.Overlay)
{
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,
$"{layerState}_{damageGroup}",
threshold);
@ -648,11 +667,11 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary>
/// Updates an overlay that is tracking all damage.
/// </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,
$"DamageOverlay",
threshold);
@ -661,15 +680,19 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// <summary>
/// Updates an overlay based on damage group.
/// </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.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,
$"DamageOverlay_{damageGroup}",
threshold);
@ -683,19 +706,19 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
/// function calls it), and what threshold
/// was passed into it.
/// </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)
{
spriteComponent.LayerSetVisible(spriteLayer, false);
SpriteSystem.LayerSetVisible(spriteEnt.AsNullable(), spriteLayer, false);
}
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.
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)
{
// Inheritance moment.
if (!sprite.LayerMapTryGet(key, out _)) continue;
if (!SpriteSystem.LayerMapTryGet((uid, sprite), key, out _, false)) continue;
sprite.LayerSetVisible(key, true);
sprite.LayerSetState(key, state);
SpriteSystem.LayerSetVisible((uid, sprite), key, true);
SpriteSystem.LayerSetRsiState((uid, sprite), key, state);
}
// So they don't draw over mobs anymore
if (data == MobState.Dead)
{
if (sprite.DrawDepth > (int) DrawDepth.DeadMobs)
if (sprite.DrawDepth > (int)DrawDepth.DeadMobs)
{
component.OriginalDrawDepth = sprite.DrawDepth;
sprite.DrawDepth = (int) DrawDepth.DeadMobs;
SpriteSystem.SetDrawDepth((uid, sprite), (int)DrawDepth.DeadMobs);
}
}
else if (component.OriginalDrawDepth != null)
{
sprite.DrawDepth = component.OriginalDrawDepth.Value;
SpriteSystem.SetDrawDepth((uid, sprite), component.OriginalDrawDepth.Value);
component.OriginalDrawDepth = null;
}
}

View file

@ -9,7 +9,6 @@ public sealed class DeliveryVisualizerSystem : VisualizerSystem<DeliveryComponen
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
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))
{
args.Sprite.LayerSetTexture(DeliveryVisualLayers.JobStamp, _sprite.Frame0(_prototype.Index("JobIconUnknown")));
SpriteSystem.LayerSetTexture((uid, args.Sprite), DeliveryVisualLayers.JobStamp, SpriteSystem.Frame0(_prototype.Index("JobIconUnknown")));
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,
Breakage,
Trash,
Bomb,
BombPrimed,
}
public enum DeliverySpawnerVisualLayers : byte

View file

@ -5,6 +5,8 @@ namespace Content.Client.Dice;
public sealed class DiceSystem : SharedDiceSystem
{
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
@ -18,11 +20,11 @@ public sealed class DiceSystem : SharedDiceSystem
return;
// 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)
return;
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
{
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <summary>
/// Attempting to apply a displacement map to a specific layer of SpriteComponent
/// </summary>
/// <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="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>
/// <returns></returns>
public bool TryAddDisplacement(DisplacementData data,
SpriteComponent sprite,
Entity<SpriteComponent> sprite,
int index,
object key,
out string displacementKey)
@ -30,10 +31,9 @@ public sealed class DisplacementMapSystem : EntitySystem
return false;
if (data.ShaderOverride != null)
sprite.LayerSetShader(index, data.ShaderOverride);
sprite.Comp.LayerSetShader(index, data.ShaderOverride);
if (sprite.LayerMapTryGet(displacementKey, out var oldIndex))
sprite.RemoveLayer(oldIndex);
_sprite.RemoveLayer(sprite.AsNullable(), displacementKey, false);
//allows you not to write it every time in the YML
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.
// If there is no such a map, we use a standard 32 by 32 one
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.Size.X != actualRSI.Size.Y)
@ -72,9 +72,20 @@ public sealed class DisplacementMapSystem : EntitySystem
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
displacementLayer.CopyToShaderParameters!.LayerKey = key.ToString() ?? "this is impossible";
sprite.AddLayer(displacementLayer, index);
sprite.LayerMapSet(displacementKey, index);
_sprite.AddLayer(sprite.AsNullable(), displacementLayer, index);
_sprite.LayerMapSet(sprite.AsNullable(), displacementKey, index);
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 SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
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))
return;
sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == DisposalUnitComponent.VisualState.UnAnchored);
sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == DisposalUnitComponent.VisualState.Anchored);
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFlush, state == DisposalUnitComponent.VisualState.OverlayFlushing);
sprite.LayerSetVisible(DisposalUnitVisualLayers.BaseCharging, state == DisposalUnitComponent.VisualState.OverlayCharging);
_sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.Unanchored, state == DisposalUnitComponent.VisualState.UnAnchored);
_sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.Base, state == DisposalUnitComponent.VisualState.Anchored);
_sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayFlush, state == DisposalUnitComponent.VisualState.OverlayFlushing);
_sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.BaseCharging, state == DisposalUnitComponent.VisualState.OverlayCharging);
var chargingState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseCharging, out var chargingLayer)
? sprite.LayerGetState(chargingLayer)
var chargingState = _sprite.LayerMapTryGet((ent, sprite), DisposalUnitVisualLayers.BaseCharging, out var chargingLayer, false)
? _sprite.LayerGetRsiState((ent, sprite), chargingLayer)
: new RSI.StateId(DefaultChargeState);
// 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))
{
var flushState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.OverlayFlush, out var flushLayer)
? sprite.LayerGetState(flushLayer)
var flushState = _sprite.LayerMapTryGet((ent, sprite), DisposalUnitVisualLayers.OverlayFlush, out var flushLayer, false)
? _sprite.LayerGetRsiState((ent, sprite), flushLayer)
: new RSI.StateId(DefaultFlushState);
// 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))
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))
lightState = DisposalUnitComponent.LightStates.Off;
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayCharging,
_sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayCharging,
(lightState & DisposalUnitComponent.LightStates.Charging) != 0);
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayReady,
_sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayReady,
(lightState & DisposalUnitComponent.LightStates.Ready) != 0);
sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFull,
_sprite.LayerSetVisible((ent, sprite), DisposalUnitVisualLayers.OverlayFull,
(lightState & DisposalUnitComponent.LightStates.Full) != 0);
}
}

View file

@ -21,6 +21,7 @@ public sealed class DoAfterOverlay : Overlay
private readonly MetaDataSystem _meta;
private readonly ProgressColorSystem _progressColor;
private readonly SharedContainerSystem _container;
private readonly SpriteSystem _sprite;
private readonly Texture _barTexture;
private readonly ShaderInstance _unshadedShader;
@ -45,6 +46,7 @@ public sealed class DoAfterOverlay : Overlay
_meta = _entManager.EntitySysManager.GetEntitySystem<MetaDataSystem>();
_container = _entManager.EntitySysManager.GetEntitySystem<SharedContainerSystem>();
_progressColor = _entManager.System<ProgressColorSystem>();
_sprite = _entManager.System<SpriteSystem>();
var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon");
_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
// 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)
// Offset by the texture size for every do_after we have.
@ -135,7 +137,7 @@ public sealed class DoAfterOverlay : Overlay
if (doAfter.CancelledTime != null)
{
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 flash = Math.Floor(cancelElapsed / FlashTime) % 2 == 0;
color = GetProgressColor(0, flash ? alpha : 0);
@ -143,7 +145,7 @@ public sealed class DoAfterOverlay : Overlay
else
{
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);
}

View file

@ -10,6 +10,7 @@ namespace Content.Client.Doors;
public sealed class AirlockSystem : SharedAirlockSystem
{
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
@ -21,7 +22,7 @@ public sealed class AirlockSystem : SharedAirlockSystem
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.
if(!TryComp<DoorComponent>(uid, out var door))
if (!TryComp<DoorComponent>(uid, out var door))
return;
if (comp.OpenUnlitVisible) // Otherwise there are flashes of the fallback sprite between clicking on the door and the door closing animation starting.
@ -57,19 +58,19 @@ public sealed class AirlockSystem : SharedAirlockSystem
}
};
if(!comp.AnimatePanel)
if (!comp.AnimatePanel)
return;
((Animation)door.OpeningAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick()
{
LayerKey = WiresVisualLayers.MaintenancePanel,
KeyFrames = {new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningPanelSpriteState, 0f)},
KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.OpeningPanelSpriteState, 0f) },
});
((Animation)door.ClosingAnimation).AnimationTracks.Add(new AnimationTrackSpriteFlick
{
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;
}
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseBolted, boltedVisible);
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseUnlit, unlitVisible);
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseBolted, boltedVisible);
if (comp.EmergencyAccessLayer)
{
args.Sprite.LayerSetVisible(
_sprite.LayerSetVisible(
(uid, args.Sprite),
DoorVisualLayers.BaseEmergencyAccess,
emergencyLightsVisible
&& state != DoorState.Open
@ -118,12 +120,12 @@ public sealed class AirlockSystem : SharedAirlockSystem
switch (state)
{
case DoorState.Open:
args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.ClosingSpriteState);
args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0);
_sprite.LayerSetRsiState((uid, args.Sprite), DoorVisualLayers.BaseUnlit, comp.ClosingSpriteState);
_sprite.LayerSetAnimationTime((uid, args.Sprite), DoorVisualLayers.BaseUnlit, 0);
break;
case DoorState.Closed:
args.Sprite.LayerSetState(DoorVisualLayers.BaseUnlit, comp.OpeningSpriteState);
args.Sprite.LayerSetAnimationTime(DoorVisualLayers.BaseUnlit, 0);
_sprite.LayerSetRsiState((uid, args.Sprite), DoorVisualLayers.BaseUnlit, comp.OpeningSpriteState);
_sprite.LayerSetAnimationTime((uid, args.Sprite), DoorVisualLayers.BaseUnlit, 0);
break;
}
}

View file

@ -11,6 +11,7 @@ public sealed class DoorSystem : SharedDoorSystem
{
[Dependency] private readonly AnimationPlayerSystem _animationSystem = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
@ -85,7 +86,7 @@ public sealed class DoorSystem : SharedDoorSystem
state = DoorState.Closed;
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))
_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)
{
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)
{
case DoorState.Open:
foreach (var (layer, layerState) in entity.Comp.OpenSpriteStates)
{
sprite.LayerSetState(layer, layerState);
_sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState);
}
return;
case DoorState.Closed:
foreach (var (layer, layerState) in entity.Comp.ClosedSpriteStates)
{
sprite.LayerSetState(layer, layerState);
_sprite.LayerSetRsiState((entity.Owner, sprite), layer, layerState);
}
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))
{
@ -146,6 +147,6 @@ public sealed class DoorSystem : SharedDoorSystem
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
{
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
@ -18,7 +19,7 @@ public sealed class FirelockSystem : SharedFirelockSystem
protected override void OnComponentStartup(Entity<FirelockComponent> ent, ref ComponentStartup args)
{
base.OnComponentStartup(ent, ref args);
if(!TryComp<DoorComponent>(ent.Owner, out var door))
if (!TryComp<DoorComponent>(ent.Owner, out var door))
return;
door.ClosedSpriteStates.Add((DoorVisualLayers.BaseUnlit, ent.Comp.WarningLightSpriteState));
@ -57,7 +58,7 @@ public sealed class FirelockSystem : SharedFirelockSystem
|| state == DoorState.Denying
|| (_appearanceSystem.TryGetData<bool>(uid, DoorVisuals.ClosedLights, out var closedLights, args.Component) && closedLights);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseUnlit, unlitVisible && !boltedVisible);
args.Sprite.LayerSetVisible(DoorVisualLayers.BaseBolted, boltedVisible);
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseUnlit, unlitVisible && !boltedVisible);
_sprite.LayerSetVisible((uid, args.Sprite), DoorVisualLayers.BaseBolted, boltedVisible);
}
}

View file

@ -13,8 +13,9 @@ namespace Content.Client.Doors;
public sealed class TurnstileSystem : SharedTurnstileSystem
{
[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";
@ -33,12 +34,12 @@ public sealed class TurnstileSystem : SharedTurnstileSystem
if (!TryComp<SpriteComponent>(ent, out var sprite))
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)
{
Spawn(_examineArrow, new EntityCoordinates(ent, 0, 0));
Spawn(ExamineArrow, new EntityCoordinates(ent, 0, 0));
}
protected override void PlayAnimation(EntityUid uid, string stateId)

View file

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

View file

@ -2,6 +2,7 @@ using Content.Shared.Drugs;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.Client.Drugs;
@ -12,6 +13,7 @@ public sealed class DrugOverlaySystem : EntitySystem
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private RainbowOverlay _overlay = default!;
@ -45,8 +47,11 @@ public sealed class DrugOverlaySystem : EntitySystem
private void OnInit(EntityUid uid, SeeingRainbowsComponent component, ComponentInit args)
{
if (_player.LocalEntity == uid)
{
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
_overlayMan.AddOverlay(_overlay);
}
}
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 TimeTicker = 0.0f;
public float Phase = 0.0f;
private const float VisualThreshold = 10.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);
public RainbowOverlay()
{
IoCManager.InjectDependencies(this);
_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)
@ -51,7 +62,7 @@ public sealed class RainbowOverlay : Overlay
if (!statusSys.TryGetTime(playerEntity.Value, DrugOverlaySystem.RainbowKey, out var time, status))
return;
var timeLeft = (float) (time.Value.Item2 - time.Value.Item1).TotalSeconds;
var timeLeft = (float)(time.Value.Item2 - time.Value.Item1).TotalSeconds;
TimeTicker += args.DeltaSeconds;
@ -61,7 +72,7 @@ public sealed class RainbowOverlay : Overlay
}
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)
{
// 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)
return;
var handle = args.WorldHandle;
_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.DrawRect(args.WorldBounds, Color.White);
handle.UseShader(null);

View file

@ -13,6 +13,7 @@ public sealed class ColorFlashEffectSystem : SharedColorFlashEffectSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly AnimationPlayerSystem _animation = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/// <summary>
/// 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))
{
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()
{
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))
continue;
if (electrified)
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, true);
else
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
SpriteSystem.LayerSetVisible((uid, spriteComp), ElectrifiedLayers.HUD, electrified);
}
}
@ -70,10 +67,9 @@ public sealed class ElectrocutionHUDVisualizerSystem : VisualizerSystem<Electroc
private void RemoveHUD()
{
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))
{
spriteComp.LayerSetVisible(ElectrifiedLayers.HUD, false);
SpriteSystem.LayerSetVisible((uid, spriteComp), ElectrifiedLayers.HUD, false);
}
}
@ -87,9 +83,6 @@ public sealed class ElectrocutionHUDVisualizerSystem : VisualizerSystem<Electroc
return;
var player = _playerMan.LocalEntity;
if (electrified && HasComp<ShowElectrocutionHUDComponent>(player))
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, true);
else
args.Sprite.LayerSetVisible(ElectrifiedLayers.HUD, false);
SpriteSystem.LayerSetVisible((uid, args.Sprite), ElectrifiedLayers.HUD, electrified && HasComp<ShowElectrocutionHUDComponent>(player));
}
}

View file

@ -1,12 +1,14 @@
using Content.Shared.Ensnaring;
using Content.Shared.Ensnaring.Components;
using Robust.Client.GameObjects;
using Robust.Shared.Utility;
namespace Content.Client.Ensnaring;
public sealed class EnsnareableSystem : SharedEnsnareableSystem
{
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
@ -19,25 +21,25 @@ public sealed class EnsnareableSystem : SharedEnsnareableSystem
{
base.OnEnsnareInit(ent, ref args);
if(!TryComp<SpriteComponent>(ent.Owner, out var sprite))
if (!TryComp<SpriteComponent>(ent.Owner, out var sprite))
return;
// 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)
{
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;
if (_appearance.TryGetData<bool>(uid, EnsnareableVisuals.IsEnsnared, out var isEnsnared, args.Component))
{
if (component.Sprite != null)
{
args.Sprite.LayerSetRSI(layer, component.Sprite);
args.Sprite.LayerSetState(layer, component.State);
args.Sprite.LayerSetVisible(layer, isEnsnared);
_sprite.LayerSetRsi((uid, args.Sprite), layer, new ResPath(component.Sprite));
_sprite.LayerSetRsiState((uid, args.Sprite), layer, component.State);
_sprite.LayerSetVisible((uid, args.Sprite), layer, isEnsnared);
}
}
}

View file

@ -12,6 +12,6 @@ public sealed class ClusterGrenadeVisualizerSystem : VisualizerSystem<ClusterGre
return;
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.Shared.GameStates;
using Robust.Shared.Graphics.RSI;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Client.Explosion;
@ -19,7 +18,7 @@ public sealed class ExplosionOverlaySystem : EntitySystem
[Dependency] private readonly IResourceCache _resCache = default!;
[Dependency] private readonly IOverlayManager _overlayMan = 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!;
public override void Initialize()
@ -69,7 +68,7 @@ public sealed class ExplosionOverlaySystem : EntitySystem
}
// 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
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 SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
/*
* 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))
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.
return;
@ -89,7 +90,7 @@ public sealed partial class TriggerSystem
// Don't interrupt the flash animation
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
_player.Stop(uid, player, AnimKey);
spriteComponent.LayerSetState(layer, "on");
_sprite.LayerSetRsiState((uid, spriteComponent), layer, "on");
break;
case ProximityTriggerVisuals.Active:
if (_player.HasRunningAnimation(uid, player, AnimKey)) return;
@ -98,7 +99,7 @@ public sealed partial class TriggerSystem
case ProximityTriggerVisuals.Off:
default:
_player.Stop(uid, player, AnimKey);
spriteComponent.LayerSetState(layer, "off");
_sprite.LayerSetRsiState((uid, spriteComponent), layer, "off");
break;
}
}

View file

@ -1,45 +1,119 @@
<DefaultWindow xmlns="https://spacestation14.io"
<DefaultWindow
xmlns="https://spacestation14.io"
Title="{Loc 'fax-machine-ui-window'}"
MinWidth="250">
<BoxContainer Orientation="Vertical" VerticalExpand="True">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc 'fax-machine-ui-paper'}" />
<Control MinWidth="4" />
<Label Name="PaperStatusLabel" />
MinSize="380 220">
<BoxContainer Orientation="Vertical"
SeparationOverride="2"
VerticalExpand="True">
<PanelContainer StyleClasses="PanelBackgroundBaseDark" HorizontalExpand="True">
<BoxContainer Orientation="Vertical"
Margin="0 0 0 2">
<!-- From Line -->
<BoxContainer Orientation="Horizontal">
<!-- From Value Name -->
<Label Text="{Loc 'fax-machine-ui-from'}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"/>
<Control HorizontalExpand="True"
MinWidth="8"
HorizontalAlignment="Center"/>
<!-- From Value -->
<Label Name="FromLabel"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Align="Right"/>
</BoxContainer>
<Control HorizontalExpand="True" MinHeight="20" />
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc 'fax-machine-ui-from'}" />
<Control MinWidth="4" />
<Label Name="FromLabel" />
<!-- To Line -->
<BoxContainer
Orientation="Horizontal">
<!-- To Label -->
<Label Text="{Loc 'fax-machine-ui-to'}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"/>
<Control HorizontalExpand="True"
MinWidth="8"
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 Orientation="Horizontal" HorizontalExpand="True">
<Label Text="{Loc 'fax-machine-ui-to'}" />
<Control MinWidth="4" />
<OptionButton Name="PeerSelector" HorizontalExpand="True" />
</BoxContainer>
<Control HorizontalExpand="True" MinHeight="20" />
<PanelContainer StyleClasses="LowDivider" Margin="0 4 0 4"/>
<!-- Send & Copy -->
<BoxContainer Orientation="Vertical">
<!-- Paper Status -->
<Label Name="PaperStatusLabel"
HorizontalAlignment="Center" />
<BoxContainer>
<!--> Sunrise-Edit <-->
<!--> <BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<Button Name="FileButton"
Text="{Loc 'fax-machine-ui-file-button'}"
HorizontalExpand="False"/>
</BoxContainer> <-->
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<!--> Sunrise-Edit <-->
<!--> <Button Name="CopyButton"
<!--><Button Name="CopyButton"
Text="{Loc 'fax-machine-ui-copy-button'}"
HorizontalExpand="False"
Disabled="True" /> <-->
StyleClasses="OpenRight"
HorizontalExpand="True"
Disabled="True" /><-->
<Button Name="SendButton"
Text="{Loc 'fax-machine-ui-send-button'}"
StyleClasses="OpenLeft"
HorizontalExpand="True"
Disabled="True" />
<Button Name="RefreshButton"
Text="{Loc 'fax-machine-ui-refresh-button'}" />
</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'}"
HorizontalExpand="False"/>
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>
</DefaultWindow>

View file

@ -10,6 +10,7 @@ namespace Content.Client.Fluids;
public sealed class PuddleSystem : SharedPuddleSystem
{
[Dependency] private readonly IconSmoothSystem _smooth = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
@ -27,7 +28,7 @@ public sealed class PuddleSystem : SharedPuddleSystem
if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
{
volume = (float) volumeObj;
volume = (float)volumeObj;
}
// Update smoothing and sprite based on volume.
@ -35,19 +36,19 @@ public sealed class PuddleSystem : SharedPuddleSystem
{
if (volume < LowThreshold)
{
args.Sprite.LayerSetState(0, $"{smooth.StateBase}a");
_sprite.LayerSetRsiState((uid, args.Sprite), 0, $"{smooth.StateBase}a");
_smooth.SetEnabled(uid, false, smooth);
}
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);
}
else
{
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.DirtyNeighbours(uid);
}
@ -58,12 +59,12 @@ public sealed class PuddleSystem : SharedPuddleSystem
if (args.AppearanceData.TryGetValue(PuddleVisuals.SolutionColor, out var colorObj))
{
var color = (Color) colorObj;
args.Sprite.Color = color * baseColor;
var color = (Color)colorObj;
_sprite.SetColor((uid, args.Sprite), color * baseColor);
}
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 PointLightSystem _pointLightSystem = default!;
[Dependency] private readonly ContentEyeSystem _contentEye = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
[Dependency] private readonly AudioSystem _audioSystem = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!; // Sunrise-Edit
@ -41,7 +42,7 @@ namespace Content.Client.Ghost
var query = AllEntityQuery<GhostComponent, SpriteComponent>();
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)
{
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)
@ -156,7 +157,7 @@ namespace Content.Client.Ghost
private void OnGhostState(EntityUid uid, GhostComponent component, ref AfterAutoHandleStateEvent args)
{
if (TryComp<SpriteComponent>(uid, out var sprite))
sprite.LayerSetColor(0, component.Color);
_sprite.LayerSetColor((uid, sprite), 0, component.Color);
if (uid != _playerManager.LocalEntity)
return;

View file

@ -25,6 +25,7 @@ public sealed class GhostToggleSelfVisibility : IConsoleCommand
if (!entityManager.TryGetComponent(attachedEntity, out SpriteComponent? spriteComponent))
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
{
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{
base.Initialize();
@ -26,34 +28,34 @@ public sealed partial class GravitySystem : SharedGravitySystem
{
if (comp.SpriteMap.TryGetValue(state, out var spriteState))
{
var layer = args.Sprite.LayerMapGet(GravityGeneratorVisualLayers.Base);
args.Sprite.LayerSetState(layer, spriteState);
var layer = _sprite.LayerMapGet((uid, args.Sprite), GravityGeneratorVisualLayers.Base);
_sprite.LayerSetRsiState((uid, args.Sprite), layer, spriteState);
}
}
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)
{
case < 0.2f:
args.Sprite.LayerSetVisible(layer, false);
_sprite.LayerSetVisible((uid, args.Sprite), layer, false);
break;
case >= 0.2f and < 0.4f:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreStartupState);
_sprite.LayerSetVisible((uid, args.Sprite), layer, true);
_sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreStartupState);
break;
case >= 0.4f and < 0.6f:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreIdleState);
_sprite.LayerSetVisible((uid, args.Sprite), layer, true);
_sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreIdleState);
break;
case >= 0.6f and < 0.8f:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreActivatingState);
_sprite.LayerSetVisible((uid, args.Sprite), layer, true);
_sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreActivatingState);
break;
default:
args.Sprite.LayerSetVisible(layer, true);
args.Sprite.LayerSetState(layer, comp.CoreActivatedState);
_sprite.LayerSetVisible((uid, args.Sprite), layer, true);
_sprite.LayerSetRsiState((uid, args.Sprite), layer, comp.CoreActivatedState);
break;
}
}

View file

@ -28,12 +28,15 @@ public sealed partial class GuideEntityEmbed : BoxContainer, IDocumentTag
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IEntitySystemManager _systemManager = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IUserInterfaceManager _ui = default!;
private readonly TagSystem _tagSystem;
private readonly ExamineSystem _examineSystem;
private readonly GuidebookSystem _guidebookSystem;
private readonly ISawmill _sawmill;
public bool Interactive;
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>();
_examineSystem = _systemManager.GetEntitySystem<ExamineSystem>();
_guidebookSystem = _systemManager.GetEntitySystem<GuidebookSystem>();
_sawmill = _logManager.GetSawmill("guidebook.entity");
MouseFilter = MouseFilterMode.Stop;
}
@ -135,7 +139,7 @@ public sealed partial class GuideEntityEmbed : BoxContainer, IDocumentTag
{
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;
return false;
}

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