mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 23:57:29 +00:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
187980de50 | ||
|
|
b9f100e5dc | ||
|
|
46529ee092 | ||
|
|
4c4572121d | ||
|
|
c5cdc81667 |
@@ -9,6 +9,9 @@
|
||||
# Server config files
|
||||
/Resources/ConfigPresets/ @Toby222
|
||||
|
||||
# Sprites - Direction in lack of art director
|
||||
/Resources/Textures/ @DeltaV-Station/direction
|
||||
|
||||
# Lobby art and music - automatically direction issues since its immediately visible to players
|
||||
/Resources/Audio/Lobby/ @DeltaV-Station/direction
|
||||
/Resources/Textures/LobbyScreens/ @DeltaV-Station/direction
|
||||
|
||||
@@ -7,7 +7,7 @@ concurrency:
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '45 16 * * *'
|
||||
- cron: '0 10 * * *'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
run: dotnet build Content.Packaging --configuration Release --no-restore /m
|
||||
|
||||
- name: Package server
|
||||
run: dotnet run --project Content.Packaging server --platform win-x64 --platform win-arm64 --platform linux-x64 --platform linux-arm64 --platform osx-x64 --platform osx-arm64
|
||||
run: dotnet run --project Content.Packaging server --platform win-x64 --platform linux-x64 --platform osx-x64 --platform linux-arm64
|
||||
|
||||
- name: Package client
|
||||
run: dotnet run --project Content.Packaging client --no-wipe-release
|
||||
|
||||
@@ -20,16 +20,11 @@ jobs:
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
exempt-issue-labels: 'Priority: 1-Urgent,ignore-stale'
|
||||
days-before-stale: 90
|
||||
stale-issue-message: 'This issue will close in 2 days due to inactivity'
|
||||
days-before-close: 2
|
||||
stale-pr-message: 'This Pull Request will close in 2 days due to inactivity'
|
||||
stale-issue-label: 'stale'
|
||||
stale-pr-label: 'stale'
|
||||
remove-stale-when-updated: true
|
||||
|
||||
stale-issue-message: 'This issue has not been triaged for 90 days'
|
||||
only-issue-labels: 'S: Untriaged'
|
||||
stale-issue-label: 'Stale'
|
||||
days-before-issue-close: -1
|
||||
|
||||
stale-pr-message: 'This Pull Request has not seen activity in 90 days, and will be closed in 2 days without activity'
|
||||
exempt-pr-labels: 'Ignore Stale'
|
||||
stale-pr-label: 'Stale'
|
||||
days-before-pr-close: 2
|
||||
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
run: dotnet build Content.Packaging --configuration Release --no-restore /m
|
||||
|
||||
- name: Package server
|
||||
run: dotnet run --project Content.Packaging server --platform win-x64 --platform win-arm64 --platform linux-x64 --platform linux-arm64 --platform osx-x64 --platform osx-arm64
|
||||
run: dotnet run --project Content.Packaging server --platform win-x64 --platform linux-x64 --platform osx-x64 --platform linux-arm64
|
||||
|
||||
- name: Package client
|
||||
run: dotnet run --project Content.Packaging client --no-wipe-release
|
||||
|
||||
+16
-17
@@ -6,15 +6,14 @@ It is highly recommended to read the '''[[Standard Operating Procedure|Standard
|
||||
* '''[[Standard Operating Procedure#Controlled Items|Controlled Items]]:''' If a member of station crew requires access to a Controlled Item for use in their job, or for regular function, they must obtain the signed and stamped approval of a relevant member of Station Command or the CO. The latter is able to override the decisions of Station Command in this regard, however.
|
||||
* '''[[Standard Operating Procedure#Entity Definitions|Entity]]:''' Any thing with distinct, independent existence.
|
||||
* '''[[Standard Operating Procedure#Entity Definitions|Employee]]:''' An entity who has an employment contract with a Company.
|
||||
* '''[[Standard Operating Procedure#Entity Definitions|Pet]]:''' Any Entity that is provided to the Company's Space Stations - either through the station's Logistics Department, or brought on board by the crew - for the purposes of emotional support.
|
||||
* '''[[Standard Operating Procedure#Security Jurisdiction|Security Jurisdiction]]:''' Station law enforcement officers are bound by Space Law; they cannot operate outside of standard accessible areas, or perform searches, unless such action is allowed by either Alert Procedure or a valid warrant.
|
||||
* '''[[Standard Operating Procedure#Arrest|Arrest and Sentencing]]:''' Any entity may be arrested, during which they are restrained, informed of their charges, and taken to the brig for search and processing under '''[[Standard Operating Procedure#Brig Procedure|Brig Procedure]]'''.
|
||||
* '''[[Standard Operating Procedure#Sentencing|Arrest and Sentencing]]:''' Any member of law enforcement is allowed to pass sentence on Misdemeanor, Felony, and Grand Felony charges. The Chief Justice, or in their absence, the Head of Security are allowed to pass sentence on all Charges.
|
||||
* '''[[Standard Operating Procedure#Treatment of Prisoners|Treatment of Prisoners]]:''' Prisoners must be provided with food, water, clothing, free movement within the brig, adequate medical care, access to the Common and Prison radio channels, and moral, spiritual, or legal counseling if requested and available. If the brig becomes uninhabitable, prisoners must be securely and safely relocated to another area until the brig is functional once more. Prisoners sentenced to Permanent Confinement have additional rights and firmer restrictions that must be upheld by law enforcement officials.
|
||||
* '''[[Standard Operating Procedure#Paroles and Pardons|Paroles & Pardons]]:''' Parole may be offered under the discretion of the Warden, Head of Security, or CO. Pardons may be issued by the arresting officer, the Judge of a trial, by the Warden (to those within the permanent brig), or by the CO, when deemed in the best interest of the crew or vessel, or when the circumstances of the crime warrant suspension of sentence.
|
||||
* '''[[Standard Operating Procedure#Pressing Charges|Pressing Charges]]:''' Any Employee may press charges against any other entity. Individuals may only be charged with a crime if it can be proven beyond reasonable doubt that they have committed the crime.
|
||||
* '''[[Standard Operating Procedure#Hearing Procedure|Hearing Procedure]]:''' A criminal hearing’s Judge must be, in sequential order: The Chief Justice, the Court Clerk, an impartial member of Justice or Station Command, or the Warden. The Prosecution should ideally be the Prosecutor, or an available member of Station Command or Station Security in that order. The Defense should ideally be a member of the Justice department assigned to the defendant, though they are allowed to represent themselves if they wish.
|
||||
* '''[[Alert Procedure]]:''' Codes Blue, Red, Gamma, and Delta authorize Security to carry progressively more advanced equipment, and loosen '''[[Standard Operating Procedure#Rules of Engagement|Rules of Engagement]]''' regarding their use. The former two codes discourage openly carrying firearms by personnel; the latter two suspend many rights to privacy, and grant Security the power to do whatever neccessary to retake or scuttle the station.
|
||||
* '''[[Standard Operating Procedure#Detainment and Arrest|Detainment & Arrest]]:''' Members of law enforcement may detain entities under '''[[Standard Operating Procedure#Probable Cause|Probable Cause]]''' of criminal activity. These detainees must be informed of the crime they are suspected of committing, and may be moved to a secure location and/or restrained while law enforcement determine if a crime was committed. Such detention should last no longer than five minutes. Any entity may be arrested, during which they are restrained, informed of their charges, and taken to the brig for search and processing under '''[[Standard Operating Procedure#Brig Procedure|Brig Procedure]]'''.
|
||||
* '''[[Standard Operating Procedure#Sentencing|Sentencing]]:''' Any member of law enforcement is allowed to pass sentence on Misdemeanor, Felony, and Grand Felony charges. The Chief Justice, or in their absence, the Head of Security are allowed to pass sentence on all Charges.
|
||||
* '''[[Standard Operating Procedure#Treatment of Prisoners|Treatment of Prisoners]]:''' Prisoners must be provided with food, water, clothing, free movement within the brig, adequate medical care, access to the Common and Prison radio channels, and moral, spiritual, or legal counseling if requested and available. If the brig becomes uninhabitable, prisoners must be securely and safely relocated to another area until the brig is functional once more. Prisoners sentenced to Extended Confinement have additional rights and firmer restrictions that must be upheld by law enforcement officials.
|
||||
* '''[[Standard Operating Procedure#Paroles and Pardons|Paroles & Pardons]]:''' Parole may be offered under the discretion of the Warden, Head of Security, or CO. A parole hearing requires only a Judge, as discussed within Trial Procedure. Pardons may be issued by the arresting officer, the Judge of a trial, by the Warden (to those within the permanent brig), or by the CO, when deemed in the best interest of the crew or vessel, or when the circumstances of the crime warrant suspension of sentence.
|
||||
* '''[[Standard Operating Procedure#Pressing Charges|Pressing Charges]]:''' Any Employee may press charges against any other entity. Individuals may only be charged with a crime if it can be proveny beyond reasonable doubt that they have committed the crime.
|
||||
* '''[[Standard Operating Procedure#Trial Procedure|Trial Procedure]]:''' A criminal trial’s Judge must be, in sequential order: The Chief Justice, the Court Clerk, an impartial member of Justice or Station Command, or the Warden. The Prosecution should ideally be the Prosecutor, or an available member of Station Command or Station Security in that order. The Defense should ideally be a member of the Justice department assigned to the defendant, though they are allowed to represent themselves if they wish. If insufficient crew are available, the Judge is fully authorized and strongly encouraged to pass a sentence of Extended Confinement until a proper trial can be held.
|
||||
* '''[[Alert Procedure]]:''' Codes Blue, Red, Gamma, and Delta authorize Security to carry progressively more advanced equipment, and loosen '''[[Standard Operating Procedure#Rules of Engagement|Rules of Engagement]]''' regarding their use. The former two codes disallow openly carrying firearms by non-Security personnel; the latter two suspend many rights to privacy, and grant Security the power to do whatever neccessary to retake or scuttle the station.
|
||||
|
||||
==Procedural Defense==
|
||||
If a defendant is accused of a crime, they are granted the privilege to challenge the legitimacy of charges of claims brought against them. Any of the following may be invoked:
|
||||
@@ -165,7 +164,7 @@ Sentencing modifiers are to be applied by the sentencing officer, judge, or arbi
|
||||
| style="border: 1px solid black;" | [[File:SL_Terrorism.png]]
|
||||
! style="border: 1px solid black;" | '''Terrorism'''
|
||||
| style="border: 1px solid black;" | Capital
|
||||
| style="border: 1px solid black;" | To maliciously commit an act or take hostages with reckless indifference to life in order to provoke a state of terror in, intimidate, or otherwise compel an Employee to act or abstain from acting.
|
||||
| style="border: 1px solid black;" | To maliciously commit an act or take hostages with reckless indifference to life in order to provoke a state of terror in, intimidate, or otherwise compel an entity to act or abstain from acting.
|
||||
|-
|
||||
| style="border: 1px solid black;" | 403
|
||||
| style="border: 1px solid black;" | [[File:SL_GrandSabotage.png]]
|
||||
@@ -211,7 +210,7 @@ Sentencing modifiers are to be applied by the sentencing officer, judge, or arbi
|
||||
|style= "border:1px solid black;"| [[File:SL_Kidnapping.png]]
|
||||
|style= "border:1px solid black;"| Kidnapping
|
||||
|style= "border:1px solid black;"| 16 minutes
|
||||
|style= "border:1px solid black;"| To unlawfully confine or restrict the free movement of an Employee against their will.
|
||||
|style= "border:1px solid black;"| To unlawfully confine or restrict the free movement of an entity against its will.
|
||||
|-
|
||||
| style="border:1px solid black;" | 303
|
||||
| style="border:1px solid black;" | WIP
|
||||
@@ -235,13 +234,13 @@ Sentencing modifiers are to be applied by the sentencing officer, judge, or arbi
|
||||
| style="border:1px solid black;" | [[File:SL_AbuseOfPower.png]]
|
||||
| style="border:1px solid black;" | Abuse of Power
|
||||
| style="border:1px solid black;" | 14 minutes
|
||||
| style="border:1px solid black;" | To intentionally misuse or wrongfully exercise one’s own authority, influence, or control, resulting in harm, unjust treatment, or demonstratable loss to another Employee.
|
||||
| style="border:1px solid black;" | To intentionally misuse or wrongfully exercise one’s own authority, influence, or control, resulting in harm, unjust treatment, or demonstratable loss to another entity.
|
||||
|-
|
||||
| style="border:1px solid black;" | 307
|
||||
| style="border:1px solid black;" | [[File:SL_GrandTheft.png]]
|
||||
| style="border:1px solid black;" | Grand Larceny
|
||||
| style="border:1px solid black;" | 12 minutes
|
||||
| style="border:1px solid black;" | To deprive an Employee of any Controlled Item in their lawful possession.
|
||||
| style="border:1px solid black;" | To deprive an entity of any Controlled Item in their lawful possession.
|
||||
|-
|
||||
| style="border:1px solid black;" | 308
|
||||
| style="border:1px solid black;" | [[File:SL_BlackMarketeering.png]]
|
||||
@@ -311,7 +310,7 @@ Sentencing modifiers are to be applied by the sentencing officer, judge, or arbi
|
||||
|style= "border:1px solid black;"| WIP
|
||||
!style= "border:1px solid black;"| Identity Theft
|
||||
|style= "border:1px solid black;"| 5 minutes
|
||||
|style= "border:1px solid black;"| To maliciously assume the identity of an Employee, such as through writing, attire, and/or speech.
|
||||
|style= "border:1px solid black;"| To maliciously assume the identity of an entity, such as through writing, attire, and/or speech.
|
||||
|}
|
||||
|
||||
|
||||
@@ -330,13 +329,13 @@ Sentencing modifiers are to be applied by the sentencing officer, judge, or arbi
|
||||
| style="border: 1px solid black;" | [[File:SL_AnimalCruelty.png]]
|
||||
! style="border: 1px solid black;" | {{anchor|Animal Cruelty}}Animal Cruelty
|
||||
| style="border: 1px solid black;" | 5 minutes
|
||||
| style="border: 1px solid black;" | To inflict unnecessary suffering on a Pet with malicious intent.
|
||||
| style="border: 1px solid black;" | To inflict unnecessary suffering on a sapient being with malicious intent.
|
||||
|-
|
||||
|style= "border:1px solid black;"| 102
|
||||
|style= "border:1px solid black;"| WIP
|
||||
!style= "border:1px solid black;"| Harassment
|
||||
|style= "border:1px solid black;"| 5 minutes
|
||||
|style= "border:1px solid black;"| To verbally demean, humiliate, or harass an Employee with malice; or maliciously spread false information amongst a population.
|
||||
|style= "border:1px solid black;"| To verbally demean, humiliate, or harass an entity with malice; or maliciously spread false information amongst a population.
|
||||
|-
|
||||
|style= "border:1px solid black;"| 103
|
||||
|style= "border:1px solid black;"| WIP
|
||||
@@ -348,7 +347,7 @@ Sentencing modifiers are to be applied by the sentencing officer, judge, or arbi
|
||||
| style="border: 1px solid black;" | [[File:SL_Theft.png]]
|
||||
! style="border: 1px solid black;" | {{anchor|Theft}}Petty Larceny
|
||||
| style="border: 1px solid black;" | 4 minutes
|
||||
| style="border: 1px solid black;" | To deprive an Employee of an item in their lawful property without consent.
|
||||
| style="border: 1px solid black;" | To deprive an entity of an item in their lawful property without consent.
|
||||
|-
|
||||
| style="border: 1px solid black;" | 105
|
||||
| style="border: 1px solid black;" | [[File:SL_Trespass.png]]
|
||||
@@ -360,7 +359,7 @@ Sentencing modifiers are to be applied by the sentencing officer, judge, or arbi
|
||||
| style="border: 1px solid black;" | [[File:SL_Vandalism.png]]
|
||||
! style="border: 1px solid black;" | {{anchor|Vandalism}}Vandalism
|
||||
| style="border: 1px solid black;" | 3 minutes
|
||||
| style="border: 1px solid black;" | To deface or superficially damage public property, or property belonging to another Employee.
|
||||
| style="border: 1px solid black;" | To deface or superficially damage public property, or property belonging to another person.
|
||||
|-
|
||||
| style="border: 1px solid black;" | 107
|
||||
| style="border: 1px solid black;" | [[File:SL_Hooliganism.png]]
|
||||
|
||||
@@ -8,6 +8,7 @@ The terms specified below are defined for further use within the procedures.
|
||||
:* Command Staff/Station Command: Members of the Command department who lead a department aboard the station.
|
||||
:* Crew: All Employees employed by Station Command, or by NT to reside on the station and perform an established function therein. This includes any Employee listed on the Crew Manifest or issued a functional NT identification and access card. Individuals imprisoned by NT, along with those imprisoned during the course of a shift for violations of Space Law, are considered Crew.
|
||||
:* Judge: An individual legally appointed to preside over a hearing, as specified within Hearing Procedure.
|
||||
:* Detainee: Any Employee whose free movement has been curtailed by law enforcement on suspicion of criminal activity. They have not, however, been officially charged with a crime.
|
||||
:* Arrestee: Any Employee who has been formally charged with a crime.
|
||||
:* Prisoner: Any Employee who has been sentenced for the commission of a crime, or awaiting a hearing for a capital offense.
|
||||
:* Permanent Brig/Permabrig/Brig: A secure location for the long-term confinement of Prisoners. Typically outfitted to sustain the basic survival needs of the Prisoners within.
|
||||
@@ -19,9 +20,9 @@ All crew operating within their designated job locations are given the right to
|
||||
The following definitions are provided to clarify the legal protections- and obligations- that Standard Operating Procedures and Space Law provide to any given entity. Unless explicitly covered by a more distinctive term, all Entities are to be treated as such until clarification is provided.
|
||||
|
||||
== Entity ==
|
||||
Any individual with a distinct existence. Entities may also encompass a plurality of identities contained within a single physical form. NanoTrasen does not require Entities be offered the protections of Standard Operating Procedure, Space Law, or Rules of Engagement unless further defined below. Security Officers are encouraged to be reasonable with their use of force regarding circumstances, especially if the Entity's termination would leave lawsuits or tarnish reputation for NanoTrasen.
|
||||
Any individual with a distinct existence. Entities may also encompass a plurality of identities contained within a single physical form. NanoTrasen does not require Entities be offered the protections of Standard Operating Procedure, Space Law, or Rules of Engagement unless further defined below. Security Officers are encouraged to be reasonable with their use of force regarding circumstances, especially if Entity's termination would leave lawsuits or tarnish reputation for NanoTrasen.
|
||||
== Pet ==
|
||||
Any Entity that is provided to NanoTrasen Space Stations - either through the station's Logistics Department, or brought on board by the crew - for the purposes of emotional support. Any harm against such a Pet may render the offender liable to the crime of Animal Cruelty.
|
||||
Any Entity that is provided to NanoTrasen Space Stations- either through the station's Logistics Department, or brought on board by the crew- for the purposes of emotional support. Any harm against such a Pet may render the offender liable to the crime of Animal Cruelty.
|
||||
Examples of Pets include, but are not limited to:
|
||||
:* Renault the Fox
|
||||
:* Smile the Rainbow Slime
|
||||
@@ -100,27 +101,27 @@ A list of such Substances follow:
|
||||
== Controlled Armaments ==
|
||||
|
||||
|
||||
Controlled Armaments are grouped into categories of increasing severity. If the offender possesses several categories of contraband, only the highest severity of said items should be charged.
|
||||
Controlled Armaments are grouped into categories of increasing severity.
|
||||
|
||||
'''Category A:''' ''Illegal possession of Cat. A controlled armaments may incur a sentence of up to 5min brig and further legal action as the situation demands.''
|
||||
'''Category A:''' ''Illegal possession of Cat. A controlled armaments may incur a sentence of up to 5min brig for each separate and distinct item, confiscation of the offending item(s), and further legal action as the situation demands.''
|
||||
|
||||
* Any object or instrument specifically designed, adapted, or used to cause physical harm in close combat
|
||||
* Any object or equipment specifically designed or adapted to protect against physical harm caused by weapons, projectiles, or other forms of direct assault
|
||||
* Any object or instrument specifically designed or adapted to incapacitate or disorient by using light or sound without causing permanent injury
|
||||
* Any object or equipment specifically designed or adapted for explicitly training purposes that would otherwise fall under another category
|
||||
|
||||
'''Category B:''' ''Illegal possession of Cat. B controlled armaments may incur a sentence of up to 10min brig and further legal action as the situation demands.''
|
||||
'''Category B:''' ''Illegal possession of Cat. B controlled armaments may incur a sentence of up to 10min brig for each separate and distinct item, confiscation of the offending item(s), and further legal action as the situation demands.''
|
||||
|
||||
* Any object or instrument specifically designed or adapted to cause physical harm in close combat, which employs a powered system to enhance performance
|
||||
* Any manually-operated ballistic arms that possess an internal magazine or feeding system, or lack an internal magazine or feeding system altogether
|
||||
|
||||
'''Category C:''' ''Illegal possession of Cat. C controlled armaments may incur a sentence of up to 15min brig and further legal action as the situation demands.''
|
||||
'''Category C:''' ''Illegal possession of Cat. C controlled armaments may incur a sentence of up to 15min brig for each separate and distinct item, confiscation of the offending item(s), and further legal action as the situation demands.''
|
||||
|
||||
* Any manually-operated ballistic arms that use an external magazine or feeding system
|
||||
* Any semi-automatic ballistic arms not easily concealable within a pocket or coat
|
||||
* Any object or instrument specifically designed or adapted for explicitly less-lethal purposes that would otherwise fall under another category
|
||||
|
||||
'''Category D:''' ''Illegal possession of Cat. D controlled armaments may incur a sentence of up to 20min brig and further legal action as the situation demands.''
|
||||
'''Category D:''' ''Illegal possession of Cat. D controlled armaments may incur a sentence of up to 20min brig for each separate and distinct item, confiscation of the offending item(s), and further legal action as the situation demands.''
|
||||
|
||||
* Any semi-automatic ballistic arms that are easily concealable
|
||||
* Any fully-automatic ballistic arms
|
||||
@@ -128,7 +129,7 @@ Controlled Armaments are grouped into categories of increasing severity. If the
|
||||
* Any object or device specifically designed or adapted to cause physical harm through detonation of an explosive charge
|
||||
* Any object or equipment specifically designed or adapted to protect against both a space environment and physical harm caused by weapons, projectiles, or other forms of direct assault
|
||||
|
||||
'''Category E:''' ''Illegal possession of Cat. E controlled armaments may incur a sentence of up to 25min brig and further legal action as the situation demands.''
|
||||
'''Category E:''' ''Illegal possession of Cat. E controlled armaments may incur a sentence of up to 25min brig for each separate and distinct item, confiscation of the offending item(s), and further legal action as the situation demands.''
|
||||
|
||||
* Any crew-served or emplaced weapon
|
||||
* Any object or instrument specifically designed or adapted to launch large-calibre explosives or projectiles for offensive or defensive purposes
|
||||
@@ -217,7 +218,7 @@ Should the mutiny be unsuccessful, only the head officer(s) who approved the mut
|
||||
Should the mutiny be successful, the head officer(s) who approved the mutiny must select a new Commanding Officer per Line of Succession. The new CO will then sentence the previous heads of staff for their crimes per Space Law.
|
||||
|
||||
== Foreign Vessels ==
|
||||
Should civilian and military vessels receive a docking request from another neutral vessel, they may approve or deny such a request. Any vessel may, with consent from the docking entity, be searched by law enforcement upon arrival, and its crew granted free movement accompanied by an escort at the discretion of the CO or law enforcement officials. Crew of vessels legally docked on NanoTrasen Stations are considered to be in contract with NanoTrasen and as such are protected by Space Law, Standard operating Procedure and the Rules of Engagement.
|
||||
Should civilian and military vessels receive a docking request from another neutral vessel, they may approve or deny such a request. Any vessel may, with consent from the docking entity, be searched by law enforcement upon arrival, and its crew granted free movement accompanied by an escort at the discretion of the CO or law enforcement officials.
|
||||
|
||||
Crew of foreign vessels may be refused entry, at any time and for any reason, and must be returned to, or be escorted to, their own vessel where applicable. Failure to comply may constitute trespass. Docking vessels bearing a warrant or commission represent an exception, and may not be denied entry or be forced to submit to a search.
|
||||
|
||||
@@ -252,7 +253,7 @@ Martial Law may only be declared by Central Command. Under Martial Law Security
|
||||
* authorised to take whatever actions deemed necessary to neutralise or repel station threats.
|
||||
* authorized to summarily execute station threats.
|
||||
* not bound to the Rules of Engagement.
|
||||
* not obligated to provide any medical care to prisoners, including revival.
|
||||
* not obligated to provide any medical care to prisoners and detainees, including revival.
|
||||
|
||||
== Armory Procedure ==
|
||||
The armory and its usage are governed by the Warden. The Warden is responsible for stocking, distributing, and recording the collection of weapons used by the station during the shift. They are also afforded the authority to arm security at their discretion, so long as the weaponry distributed is in appropriate response to [[Alert Procedure]].
|
||||
|
||||
+24
-76
@@ -22,57 +22,39 @@ Examples:
|
||||
|
||||
# Changes to upstream files
|
||||
|
||||
Follow a few guidelines when modifying non-DeltaV files, to help us manage our project. (files that are not in `_DV` or `Nyano` folders)
|
||||
If you make a change to an upstream C# or YAML file **you must add comments on or around the changed lines**.
|
||||
The comments should clarify what changed, to make conflict resolution simpler when a file is changed upstream.
|
||||
|
||||
Primarily, **add comments on or around all new or changed lines** in upstream files. Explain what was changed to make resolving merge conflicts easier; we regularly merge new upstream changes into our project.
|
||||
For YAML specifically, if you add a new component to a prototype add the comment to the `type: ...` line.
|
||||
If you just modify some fields of a component, comment the fields instead.
|
||||
|
||||
### Changing Upstream YAML .yml files
|
||||
For C# files, if you are adding a lot of code try to put it in a partial class when it makes sense.
|
||||
|
||||
**Add comments on or around any changed lines.**
|
||||
The exception to this is early merging commits that are going to be cherry picked in the future regardless, there's no harm in leaving them as-is.
|
||||
|
||||
If you add a new component to a prototype, add an explanation to the `type: ...` line. Example:
|
||||
As an aside, fluent (.ftl) files **do not support comments on the same line** as a locale value, so be careful when changing them.
|
||||
|
||||
## Examples of comments in upstream files
|
||||
|
||||
A single line comment on a changed yml field:
|
||||
```yml
|
||||
- type: entity
|
||||
parent: MobSiliconBase
|
||||
id: MobSupplyBot
|
||||
components:
|
||||
- type: InteractionPopup # DeltaV - Make supplybots pettable
|
||||
interactSuccessString: petting-success-supplybot
|
||||
interactFailureString: petting-failure-supplybot
|
||||
interactSuccessSound:
|
||||
path: /Audio/Ambience/Objects/periodic_beep.ogg
|
||||
parent: BasePDA
|
||||
id: SciencePDA
|
||||
name: epistemics PDA # DeltaV - Epistemics Department replacing Science
|
||||
```
|
||||
|
||||
Whereas if you just modify some fields of a component, comment the fields instead, using inline or block comments. Examples:
|
||||
|
||||
A pair of comments enclosing a list of added items to starting gear:
|
||||
```yml
|
||||
- type: entityTable
|
||||
id: FillLockerWarden
|
||||
table: !type:AllSelector
|
||||
children:
|
||||
- id: ClothingHandsGlovesCombat
|
||||
- id: ClothingShoesBootsSecurityMagboots # DeltaV - Added security magboots.
|
||||
- id: ClothingShoesBootsJack
|
||||
#- id: ClothingOuterCoatWarden # DeltaV - removed for incongruence
|
||||
#- id: ClothingOuterWinterWarden # DeltaV - removed for incongruence
|
||||
- id: RubberStampWarden
|
||||
- id: DoorRemoteArmory
|
||||
- id: HoloprojectorSecurity
|
||||
storage:
|
||||
back:
|
||||
- EmergencyRollerBedSpawnFolded
|
||||
# Begin DeltaV additions
|
||||
- id: WeaponEnergyShotgun
|
||||
- id: BoxPDAPrisoner
|
||||
- id: LunchboxSecurityFilledRandom
|
||||
prob: 0.3
|
||||
- BodyBagFolded
|
||||
- Portafib
|
||||
# End DeltaV additions
|
||||
```
|
||||
|
||||
### Changing Upstream C# .cs files
|
||||
|
||||
If you are adding a lot of C# code, then take advantage of partial classes. Put the new code in its own file in the `_DV` folder, if it makes sense.
|
||||
|
||||
Otherwise, **add comments on or around any changed lines.**
|
||||
|
||||
A comment on a new imported namespace:
|
||||
```cs
|
||||
using Content.Server.Psionics.Glimmer; // DeltaV
|
||||
@@ -95,40 +77,6 @@ private EntityUid Slice(...)
|
||||
}
|
||||
```
|
||||
|
||||
### Changing Upstream Localization Fluent .ftl files
|
||||
|
||||
**Move all changed locale strings to a new DeltaV file** - use a `.ftl` file in the `_DV` folder. Comment out the old strings in the upstream file, and explain that they were moved.
|
||||
|
||||
Example:
|
||||
|
||||
Commented out old string in `Resources\Locale\en-US\xenoarchaeology\artifact-analyzer.ftl`
|
||||
```
|
||||
# DeltaV - moved to _DV file
|
||||
#analysis-console-info-effect-value = [font="Monospace" size=11][color=gray]{ $state ->
|
||||
# [true] {$info}
|
||||
# *[false] Unlock nodes to gain info
|
||||
#}[/color][/font]
|
||||
```
|
||||
|
||||
The new version of the string in `Resources\Locale\en-US\_DV\xenoarchaeology\artifact-analyzer.ftl`
|
||||
```
|
||||
analysis-console-info-effect-value = [font="Monospace" size=11][color=gray]{ $state ->
|
||||
[vagueandspecific] {$vagueInfo} ({$specificInfo})
|
||||
[vagueonly] {$vagueInfo} (unable to detect details)
|
||||
[simple] {$specificInfo}
|
||||
[hidden] Unable to detect (unlock to discover)
|
||||
*[noinfo] Unlock nodes to gain info
|
||||
}[/color][/font]
|
||||
```
|
||||
|
||||
Also keep in mind that fluent (.ftl) files **do not support comments on the same line** as a locale value, so be careful when commenting.
|
||||
|
||||
### Early merges
|
||||
|
||||
We mostly merge upstream changes in big chunks (e.g. a month of upstream PRs at a time), but urgent changes can be merged early, separately.
|
||||
|
||||
Early merges are an exception to the above rules - if cherry-picking a PR for an early merge, you don't need to add `#DeltaV` comments, since the code is coming directly from upstream without any changes.
|
||||
|
||||
# Mapping
|
||||
|
||||
If you want to make changes to a map, get in touch with its maintainer to make sure you don't both make changes at the same time.
|
||||
@@ -144,11 +92,11 @@ Please limit changelogs on map PRs to **significant** map alterations or additio
|
||||
Format for map PRs looks like:
|
||||
```
|
||||
:cl: Yourname
|
||||
MAPS:
|
||||
- add: Mapname: Added fun!
|
||||
- remove: Mapname: Removed fun!
|
||||
- tweak: Mapname: Changed fun!
|
||||
- fix: Mapname: Fixed fun!
|
||||
MAPS: Mapname
|
||||
- add: Added fun!
|
||||
- remove: Removed fun!
|
||||
- tweak: Changed fun!
|
||||
- fix: Fixed fun!
|
||||
```
|
||||
|
||||
# Before you submit
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Content.IntegrationTests;
|
||||
using Content.IntegrationTests.Pair;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Maps;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Benchmarks;
|
||||
|
||||
[Virtual]
|
||||
[GcServer(true)]
|
||||
[MemoryDiagnoser]
|
||||
public class DestructibleBenchmark
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of destructible entities per prototype to spawn with a <see cref="DestructibleComponent"/>.
|
||||
/// </summary>
|
||||
[Params(1, 10, 100, 1000, 5000)]
|
||||
public int EntityCount;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of blunt damage we do to each entity.
|
||||
/// </summary>
|
||||
[Params(10000)]
|
||||
public FixedPoint2 DamageAmount;
|
||||
|
||||
[Params("Blunt")]
|
||||
public ProtoId<DamageTypePrototype> DamageType;
|
||||
|
||||
private static readonly EntProtoId WindowProtoId = "Window";
|
||||
private static readonly EntProtoId WallProtoId = "WallReinforced";
|
||||
private static readonly EntProtoId HumanProtoId = "MobHuman";
|
||||
|
||||
private static readonly ProtoId<ContentTileDefinition> TileRef = "Plating";
|
||||
|
||||
private readonly EntProtoId[] _prototypes = [WindowProtoId, WallProtoId, HumanProtoId];
|
||||
|
||||
private readonly List<Entity<DamageableComponent>> _damageables = new();
|
||||
private readonly List<Entity<DamageableComponent, DestructibleComponent>> _destructbiles = new();
|
||||
|
||||
private DamageSpecifier _damage;
|
||||
|
||||
private TestPair _pair = default!;
|
||||
private IEntityManager _entMan = default!;
|
||||
private IPrototypeManager _protoMan = default!;
|
||||
private IRobustRandom _random = default!;
|
||||
private ITileDefinitionManager _tileDefMan = default!;
|
||||
private DamageableSystem _damageable = default!;
|
||||
private DestructibleSystem _destructible = default!;
|
||||
private SharedMapSystem _map = default!;
|
||||
|
||||
[GlobalSetup]
|
||||
public async Task SetupAsync()
|
||||
{
|
||||
ProgramShared.PathOffset = "../../../../";
|
||||
PoolManager.Startup();
|
||||
_pair = await PoolManager.GetServerClient();
|
||||
var server = _pair.Server;
|
||||
|
||||
var mapdata = await _pair.CreateTestMap();
|
||||
|
||||
_entMan = server.ResolveDependency<IEntityManager>();
|
||||
_protoMan = server.ResolveDependency<IPrototypeManager>();
|
||||
_random = server.ResolveDependency<IRobustRandom>();
|
||||
_tileDefMan = server.ResolveDependency<ITileDefinitionManager>();
|
||||
_damageable = _entMan.System<DamageableSystem>();
|
||||
_destructible = _entMan.System<DestructibleSystem>();
|
||||
_map = _entMan.System<SharedMapSystem>();
|
||||
|
||||
if (!_protoMan.Resolve(DamageType, out var type))
|
||||
return;
|
||||
|
||||
_damage = new DamageSpecifier(type, DamageAmount);
|
||||
|
||||
_random.SetSeed(69420); // Randomness needs to be deterministic for benchmarking.
|
||||
|
||||
var plating = _tileDefMan[TileRef].TileId;
|
||||
|
||||
// We make a rectangular grid of destructible entities, and then damage them all simultaneously to stress test the system.
|
||||
// Needed for managing the performance of destructive effects and damage application.
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
// Set up a thin line of tiles to place our objects on. They should be anchored for a "realistic" scenario...
|
||||
for (var x = 0; x < EntityCount; x++)
|
||||
{
|
||||
for (var y = 0; y < _prototypes.Length; y++)
|
||||
{
|
||||
_map.SetTile(mapdata.Grid, mapdata.Grid, new Vector2i(x, y), new Tile(plating));
|
||||
}
|
||||
}
|
||||
|
||||
for (var x = 0; x < EntityCount; x++)
|
||||
{
|
||||
var y = 0;
|
||||
foreach (var protoId in _prototypes)
|
||||
{
|
||||
var coords = new EntityCoordinates(mapdata.Grid, x + 0.5f, y + 0.5f);
|
||||
_entMan.SpawnEntity(protoId, coords);
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
var query = _entMan.EntityQueryEnumerator<DamageableComponent, DestructibleComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var damageable, out var destructible))
|
||||
{
|
||||
_damageables.Add((uid, damageable));
|
||||
_destructbiles.Add((uid, damageable, destructible));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task PerformDealDamage()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
_damageable.ApplyDamageToAllEntities(_damageables, _damage);
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task PerformTestTriggers()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
_destructible.TestAllTriggers(_destructbiles);
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task PerformTestBehaviors()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
_destructible.TestAllBehaviors(_destructbiles);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[GlobalCleanup]
|
||||
public async Task CleanupAsync()
|
||||
{
|
||||
await _pair.DisposeAsync();
|
||||
PoolManager.Shutdown();
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using Content.IntegrationTests;
|
||||
using Content.IntegrationTests.Pair;
|
||||
using Content.Server.Atmos;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Reactions;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Content.Benchmarks;
|
||||
|
||||
/// <summary>
|
||||
/// Benchmarks the performance of different gas reactions.
|
||||
/// Tests each reaction type with realistic gas mixtures to measure computational cost.
|
||||
/// </summary>
|
||||
[Virtual]
|
||||
[GcServer(true)]
|
||||
[MemoryDiagnoser]
|
||||
public class GasReactionBenchmark
|
||||
{
|
||||
private const int Iterations = 1000;
|
||||
private TestPair _pair = default!;
|
||||
private AtmosphereSystem _atmosphereSystem = default!;
|
||||
|
||||
// Grid and tile for reactions that need a holder
|
||||
private EntityUid _testGrid = default!;
|
||||
private TileAtmosphere _testTile = default!;
|
||||
// Reaction instances
|
||||
private PlasmaFireReaction _plasmaFireReaction = default!;
|
||||
private TritiumFireReaction _tritiumFireReaction = default!;
|
||||
private FrezonProductionReaction _frezonProductionReaction = default!;
|
||||
private FrezonCoolantReaction _frezonCoolantReaction = default!;
|
||||
private AmmoniaOxygenReaction _ammoniaOxygenReaction = default!;
|
||||
private N2ODecompositionReaction _n2oDecompositionReaction = default!;
|
||||
private WaterVaporReaction _waterVaporReaction = default!;
|
||||
// Gas mixtures for each reaction type
|
||||
private GasMixture _plasmaFireMixture = default!;
|
||||
private GasMixture _tritiumFireMixture = default!;
|
||||
private GasMixture _frezonProductionMixture = default!;
|
||||
private GasMixture _frezonCoolantMixture = default!;
|
||||
private GasMixture _ammoniaOxygenMixture = default!;
|
||||
private GasMixture _n2oDecompositionMixture = default!;
|
||||
private GasMixture _waterVaporMixture = default!;
|
||||
|
||||
[GlobalSetup]
|
||||
public async Task SetupAsync()
|
||||
{
|
||||
ProgramShared.PathOffset = "../../../../";
|
||||
PoolManager.Startup();
|
||||
_pair = await PoolManager.GetServerClient();
|
||||
var server = _pair.Server;
|
||||
|
||||
// Create test map and grid
|
||||
var mapData = await _pair.CreateTestMap();
|
||||
_testGrid = mapData.Grid;
|
||||
|
||||
await server.WaitPost(() =>
|
||||
{
|
||||
var entMan = server.ResolveDependency<IEntityManager>();
|
||||
_atmosphereSystem = entMan.System<AtmosphereSystem>();
|
||||
|
||||
_plasmaFireReaction = new PlasmaFireReaction();
|
||||
_tritiumFireReaction = new TritiumFireReaction();
|
||||
_frezonProductionReaction = new FrezonProductionReaction();
|
||||
_frezonCoolantReaction = new FrezonCoolantReaction();
|
||||
_ammoniaOxygenReaction = new AmmoniaOxygenReaction();
|
||||
_n2oDecompositionReaction = new N2ODecompositionReaction();
|
||||
_waterVaporReaction = new WaterVaporReaction();
|
||||
|
||||
SetupGasMixtures();
|
||||
SetupTile();
|
||||
});
|
||||
}
|
||||
|
||||
private void SetupGasMixtures()
|
||||
{
|
||||
// Plasma Fire: Plasma + Oxygen at high temperature
|
||||
// Temperature must be > PlasmaMinimumBurnTemperature for reaction to occur
|
||||
_plasmaFireMixture = new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.PlasmaMinimumBurnTemperature + 100f // ~673K
|
||||
};
|
||||
_plasmaFireMixture.AdjustMoles(Gas.Plasma, 20f);
|
||||
_plasmaFireMixture.AdjustMoles(Gas.Oxygen, 100f);
|
||||
|
||||
// Tritium Fire: Tritium + Oxygen at high temperature
|
||||
// Temperature must be > FireMinimumTemperatureToExist for reaction to occur
|
||||
_tritiumFireMixture = new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.FireMinimumTemperatureToExist + 100f // ~473K
|
||||
};
|
||||
_tritiumFireMixture.AdjustMoles(Gas.Tritium, 20f);
|
||||
_tritiumFireMixture.AdjustMoles(Gas.Oxygen, 100f);
|
||||
|
||||
// Frezon Production: Oxygen + Tritium + Nitrogen catalyst
|
||||
// Optimal temperature for efficiency (80% of max efficiency temp)
|
||||
_frezonProductionMixture = new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.FrezonProductionMaxEfficiencyTemperature * 0.8f // ~48K
|
||||
};
|
||||
_frezonProductionMixture.AdjustMoles(Gas.Oxygen, 50f);
|
||||
_frezonProductionMixture.AdjustMoles(Gas.Tritium, 50f);
|
||||
_frezonProductionMixture.AdjustMoles(Gas.Nitrogen, 10f);
|
||||
|
||||
// Frezon Coolant: Frezon + Nitrogen
|
||||
// Temperature must be > FrezonCoolLowerTemperature (23.15K) for reaction to occur
|
||||
_frezonCoolantMixture = new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.T20C + 50f // ~343K
|
||||
};
|
||||
_frezonCoolantMixture.AdjustMoles(Gas.Frezon, 30f);
|
||||
_frezonCoolantMixture.AdjustMoles(Gas.Nitrogen, 100f);
|
||||
|
||||
// Ammonia + Oxygen reaction (concentration-dependent, no temp requirement)
|
||||
_ammoniaOxygenMixture = new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.T20C + 100f // ~393K
|
||||
};
|
||||
_ammoniaOxygenMixture.AdjustMoles(Gas.Ammonia, 40f);
|
||||
_ammoniaOxygenMixture.AdjustMoles(Gas.Oxygen, 40f);
|
||||
|
||||
// N2O Decomposition (no temperature requirement, just needs N2O moles)
|
||||
_n2oDecompositionMixture = new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.T20C + 100f // ~393K
|
||||
};
|
||||
_n2oDecompositionMixture.AdjustMoles(Gas.NitrousOxide, 100f);
|
||||
|
||||
// Water Vapor - needs water vapor to condense
|
||||
_waterVaporMixture = new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.T20C
|
||||
};
|
||||
_waterVaporMixture.AdjustMoles(Gas.WaterVapor, 50f);
|
||||
}
|
||||
|
||||
private void SetupTile()
|
||||
{
|
||||
// Create a tile atmosphere to use as holder for all reactions
|
||||
var testIndices = new Vector2i(0, 0);
|
||||
_testTile = new TileAtmosphere(_testGrid, testIndices, new GasMixture(Atmospherics.CellVolume)
|
||||
{
|
||||
Temperature = Atmospherics.T20C
|
||||
});
|
||||
}
|
||||
|
||||
private static GasMixture CloneMixture(GasMixture original)
|
||||
{
|
||||
return new GasMixture(original);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task PlasmaFireReaction()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var mixture = CloneMixture(_plasmaFireMixture);
|
||||
_plasmaFireReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task TritiumFireReaction()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var mixture = CloneMixture(_tritiumFireMixture);
|
||||
_tritiumFireReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task FrezonProductionReaction()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var mixture = CloneMixture(_frezonProductionMixture);
|
||||
_frezonProductionReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task FrezonCoolantReaction()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var mixture = CloneMixture(_frezonCoolantMixture);
|
||||
_frezonCoolantReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task AmmoniaOxygenReaction()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var mixture = CloneMixture(_ammoniaOxygenMixture);
|
||||
_ammoniaOxygenReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task N2ODecompositionReaction()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var mixture = CloneMixture(_n2oDecompositionMixture);
|
||||
_n2oDecompositionReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public async Task WaterVaporReaction()
|
||||
{
|
||||
await _pair.Server.WaitPost(() =>
|
||||
{
|
||||
for (var i = 0; i < Iterations; i++)
|
||||
{
|
||||
var mixture = CloneMixture(_waterVaporMixture);
|
||||
_waterVaporReaction.React(mixture, _testTile, _atmosphereSystem, 1f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[GlobalCleanup]
|
||||
public async Task CleanupAsync()
|
||||
{
|
||||
await _pair.DisposeAsync();
|
||||
PoolManager.Shutdown();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
// Global usings for Content.Benchmarks
|
||||
|
||||
global using Robust.UnitTesting.Pool;
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Linq; // DeltaV
|
||||
using Content.Shared.Access;
|
||||
using Content.Shared.Access.Components;
|
||||
using Content.Shared.Access.Systems;
|
||||
@@ -51,8 +50,8 @@ namespace Content.Client.Access.UI
|
||||
|
||||
if (EntMan.TryGetComponent<AccessOverriderComponent>(Owner, out var accessOverrider))
|
||||
{
|
||||
// DeltaV - Sort Better
|
||||
accessLevels = accessOverrider.AccessLevels.OrderBy(x => _prototypeManager.TryIndex<AccessLevelPrototype>(x.Id, out var access) ? access.GetAccessLevelName() : x.Id).ToList();
|
||||
accessLevels = accessOverrider.AccessLevels;
|
||||
accessLevels.Sort();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -25,11 +25,11 @@ namespace Content.Client.Access.UI
|
||||
public void SetAccessLevels(IPrototypeManager protoManager, List<ProtoId<AccessLevelPrototype>> accessLevels)
|
||||
{
|
||||
_accessButtons.Clear();
|
||||
AccessLevelGrid.RemoveAllChildren();
|
||||
AccessLevelGrid.DisposeAllChildren();
|
||||
|
||||
foreach (var access in accessLevels)
|
||||
{
|
||||
if (!protoManager.Resolve(access, out var accessLevel))
|
||||
if (!protoManager.TryIndex(access, out var accessLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace Content.Client.Access.UI
|
||||
|
||||
public void SetAllowedIcons(string currentJobIconId)
|
||||
{
|
||||
IconGrid.RemoveAllChildren();
|
||||
IconGrid.DisposeAllChildren();
|
||||
|
||||
var jobIconButtonGroup = new ButtonGroup();
|
||||
var i = 0;
|
||||
@@ -84,12 +84,12 @@ namespace Content.Client.Access.UI
|
||||
icons.Sort((x, y) => string.Compare(x.LocalizedJobName, y.LocalizedJobName, StringComparison.CurrentCulture));
|
||||
foreach (var jobIcon in icons)
|
||||
{
|
||||
String styleBase = StyleClass.ButtonOpenBoth;
|
||||
String styleBase = StyleBase.ButtonOpenBoth;
|
||||
var modulo = i % JobIconColumnCount;
|
||||
if (modulo == 0)
|
||||
styleBase = StyleClass.ButtonOpenRight;
|
||||
styleBase = StyleBase.ButtonOpenRight;
|
||||
else if (modulo == JobIconColumnCount - 1)
|
||||
styleBase = StyleClass.ButtonOpenLeft;
|
||||
styleBase = StyleBase.ButtonOpenLeft;
|
||||
|
||||
// Generate buttons
|
||||
var jobIconButton = new Button
|
||||
|
||||
@@ -57,7 +57,7 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||
|
||||
foreach (var accessGroup in _accessGroups)
|
||||
{
|
||||
if (!_protoManager.Resolve(accessGroup, out var accessGroupProto))
|
||||
if (!_protoManager.TryIndex(accessGroup, out var accessGroupProto))
|
||||
continue;
|
||||
|
||||
_groupedAccessLevels.Add(accessGroupProto, new());
|
||||
@@ -65,13 +65,13 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||
|
||||
// Ensure that the 'general' access group is added to handle
|
||||
// misc. access levels that aren't associated with any group
|
||||
if (_protoManager.Resolve(GeneralAccessGroup, out var generalAccessProto))
|
||||
if (_protoManager.TryIndex(GeneralAccessGroup, out var generalAccessProto))
|
||||
_groupedAccessLevels.TryAdd(generalAccessProto, new());
|
||||
|
||||
// Assign known access levels with their associated groups
|
||||
foreach (var accessLevel in _accessLevels)
|
||||
{
|
||||
if (!_protoManager.Resolve(accessLevel, out var accessLevelProto))
|
||||
if (!_protoManager.TryIndex(accessLevel, out var accessLevelProto))
|
||||
continue;
|
||||
|
||||
var assigned = false;
|
||||
@@ -99,8 +99,8 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||
|
||||
private bool TryRebuildAccessGroupControls()
|
||||
{
|
||||
AccessGroupList.RemoveAllChildren();
|
||||
AccessLevelChecklist.RemoveAllChildren();
|
||||
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.
|
||||
@@ -119,11 +119,11 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||
if (_groupedAccessLevels.Count > 1)
|
||||
{
|
||||
if (AccessGroupList.ChildCount == 0)
|
||||
accessGroupButton.AddStyleClass(StyleClass.ButtonOpenLeft);
|
||||
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenLeft);
|
||||
else if (_groupedAccessLevels.Count > 1 && AccessGroupList.ChildCount == (_groupedAccessLevels.Count - 1))
|
||||
accessGroupButton.AddStyleClass(StyleClass.ButtonOpenRight);
|
||||
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenRight);
|
||||
else
|
||||
accessGroupButton.AddStyleClass(StyleClass.ButtonOpenBoth);
|
||||
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenBoth);
|
||||
}
|
||||
|
||||
accessGroupButton.Pressed = _accessGroupTabIndex == orderedAccessGroups.IndexOf(accessGroup);
|
||||
@@ -165,7 +165,7 @@ public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||||
/// </summary>
|
||||
public void RebuildAccessLevelsControls()
|
||||
{
|
||||
AccessLevelChecklist.RemoveAllChildren();
|
||||
AccessLevelChecklist.DisposeAllChildren();
|
||||
_accessLevelEntries.Clear();
|
||||
|
||||
// No access level prototypes were assigned to any of the access level groups
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using System.Linq; // DeltaV
|
||||
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 Content.Shared.Roles;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Content.Shared.Access.Components.IdCardConsoleComponent;
|
||||
@@ -39,8 +37,7 @@ namespace Content.Client.Access.UI
|
||||
|
||||
if (EntMan.TryGetComponent<IdCardConsoleComponent>(Owner, out var idCard))
|
||||
{
|
||||
// DeltaV - Sort the access list
|
||||
accessLevels = idCard.AccessLevels.OrderBy(x => _prototypeManager.TryIndex<AccessLevelPrototype>(x.Id, out var access) ? access.GetAccessLevelName() : x.Id).ToList();
|
||||
accessLevels = idCard.AccessLevels;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -56,6 +53,7 @@ namespace Content.Client.Access.UI
|
||||
_window.CrewManifestButton.OnPressed += _ => SendMessage(new CrewManifestOpenUiMessage());
|
||||
_window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId));
|
||||
_window.TargetIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(TargetIdCardSlotId));
|
||||
_window.OnToggleAccess += id => SendMessage(new IdCardConsoleToggleMessage(id)); // DeltaV
|
||||
|
||||
_window.OnClose += Close;
|
||||
_window.OpenCentered();
|
||||
@@ -77,7 +75,7 @@ namespace Content.Client.Access.UI
|
||||
_window?.UpdateState(castState);
|
||||
}
|
||||
|
||||
public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, ProtoId<JobPrototype> newJobPrototype)
|
||||
public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, string newJobPrototype)
|
||||
{
|
||||
if (newFullName.Length > _maxNameLength)
|
||||
newFullName = newFullName[.._maxNameLength];
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
MinSize="650 290">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<!-- Privileged and target IDs, crew manifest button. -->
|
||||
<GridContainer Columns="2">
|
||||
<GridContainer Columns="3" HorizontalExpand="True">
|
||||
<Label Text="{Loc 'id-card-console-window-privileged-id'}" />
|
||||
@@ -17,7 +16,6 @@
|
||||
</BoxContainer>
|
||||
</GridContainer>
|
||||
<Control MinSize="0 8" />
|
||||
<!-- Full name and job title editing. -->
|
||||
<GridContainer Columns="3" HSeparationOverride="4">
|
||||
<Label Name="FullNameLabel" Text="{Loc 'id-card-console-window-full-name-label'}" />
|
||||
<LineEdit Name="FullNameLineEdit" HorizontalExpand="True" />
|
||||
@@ -28,19 +26,10 @@
|
||||
<Button Name="JobTitleSaveButton" Text="{Loc 'id-card-console-window-save-button'}" Disabled="True" />
|
||||
</GridContainer>
|
||||
<Control MinSize="0 8" />
|
||||
<!-- Job preset selection, grant/revoke all access buttons. -->
|
||||
<BoxContainer Margin="0 8 0 4">
|
||||
<BoxContainer>
|
||||
<Label Text="{Loc 'id-card-console-window-job-selection-label'}" />
|
||||
<OptionButton Name="JobPresetOptionButton" />
|
||||
</BoxContainer>
|
||||
<Control HorizontalExpand="True"/>
|
||||
<BoxContainer>
|
||||
<Button Name="SelectAllButton" Text="{Loc 'id-card-console-window-select-all-button'}" />
|
||||
<Button Name="DeselectAllButton" Text="{Loc 'id-card-console-window-deselect-all-button'}" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
<!-- Individual access buttons -->
|
||||
<GridContainer Columns="2">
|
||||
<Label Text="{Loc 'id-card-console-window-job-selection-label'}" />
|
||||
<OptionButton Name="JobPresetOptionButton" />
|
||||
</GridContainer>
|
||||
<Control Name="AccessLevelControlContainer" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace Content.Client.Access.UI
|
||||
// The job that will be picked if the ID doesn't have a job on the station.
|
||||
private static ProtoId<JobPrototype> _defaultJob = "Passenger";
|
||||
|
||||
public event Action<ProtoId<AccessLevelPrototype>>? OnToggleAccess; // DeltaV
|
||||
|
||||
public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, IPrototypeManager prototypeManager,
|
||||
List<ProtoId<AccessLevelPrototype>> accessLevels)
|
||||
{
|
||||
@@ -79,37 +81,19 @@ namespace Content.Client.Access.UI
|
||||
JobPresetOptionButton.AddItem(Loc.GetString(job.Name), _jobPrototypeIds.Count - 1);
|
||||
}
|
||||
|
||||
SelectAllButton.OnPressed += _ =>
|
||||
{
|
||||
SetAllAccess(true);
|
||||
SubmitData();
|
||||
};
|
||||
|
||||
DeselectAllButton.OnPressed += _ =>
|
||||
{
|
||||
SetAllAccess(false);
|
||||
SubmitData();
|
||||
};
|
||||
|
||||
JobPresetOptionButton.OnItemSelected += SelectJobPreset;
|
||||
_accessButtons.Populate(accessLevels, prototypeManager);
|
||||
AccessLevelControlContainer.AddChild(_accessButtons);
|
||||
|
||||
foreach (var (id, button) in _accessButtons.ButtonsList)
|
||||
{
|
||||
button.OnPressed += _ => SubmitData();
|
||||
var copied = id; // DeltaV
|
||||
button.OnPressed += _ => OnToggleAccess?.Invoke(id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <param name="enabled">If true, every individual access button will be pressed. If false, each will be depressed.</param>
|
||||
private void SetAllAccess(bool enabled)
|
||||
{
|
||||
foreach (var button in _accessButtons.ButtonsList.Values)
|
||||
{
|
||||
if (!button.Disabled && button.Pressed != enabled)
|
||||
button.Pressed = enabled;
|
||||
}
|
||||
}
|
||||
// DeltaV - removed as part of job preset access fix
|
||||
// private void ClearAllAccess()
|
||||
|
||||
private void SelectJobPreset(OptionButton.ItemSelectedEventArgs args)
|
||||
{
|
||||
@@ -121,34 +105,28 @@ namespace Content.Client.Access.UI
|
||||
JobTitleLineEdit.Text = Loc.GetString(job.Name);
|
||||
args.Button.SelectId(args.Id);
|
||||
|
||||
SetAllAccess(false);
|
||||
|
||||
// this is a sussy way to do this
|
||||
foreach (var access in job.Access)
|
||||
{
|
||||
if (_accessButtons.ButtonsList.TryGetValue(access, out var button) && !button.Disabled)
|
||||
{
|
||||
button.Pressed = true;
|
||||
}
|
||||
}
|
||||
// DeltaV - start of job preset access fix
|
||||
SubmitData();
|
||||
|
||||
var targetAccesses = job.Access.ToHashSet();
|
||||
foreach (var group in job.AccessGroups)
|
||||
{
|
||||
if (!_prototypeManager.Resolve(group, out AccessGroupPrototype? groupPrototype))
|
||||
if (!_prototypeManager.TryIndex(group, out AccessGroupPrototype? groupPrototype))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var access in groupPrototype.Tags)
|
||||
{
|
||||
if (_accessButtons.ButtonsList.TryGetValue(access, out var button) && !button.Disabled)
|
||||
{
|
||||
button.Pressed = true;
|
||||
}
|
||||
}
|
||||
targetAccesses.UnionWith(groupPrototype.Tags);
|
||||
}
|
||||
|
||||
SubmitData();
|
||||
// this is a sussy way to do this
|
||||
foreach (var (id, button) in _accessButtons.ButtonsList)
|
||||
{
|
||||
if (!button.Disabled && button.Pressed != targetAccesses.Contains(id))
|
||||
{
|
||||
OnToggleAccess?.Invoke(id);
|
||||
}
|
||||
}
|
||||
// DeltaV - end of job preset access fix
|
||||
}
|
||||
|
||||
public void UpdateState(IdCardConsoleBoundUserInterfaceState state)
|
||||
@@ -222,7 +200,7 @@ namespace Content.Client.Access.UI
|
||||
FullNameLineEdit.Text,
|
||||
JobTitleLineEdit.Text,
|
||||
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
|
||||
_accessButtons.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList(),
|
||||
[], // DeltaV - don't send list of accesses
|
||||
jobProtoDirty ? _jobPrototypeIds[JobPresetOptionButton.SelectedId] : string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace Content.Client.Actions
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IResourceManager _resources = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly ISerializationManager _serialization = default!;
|
||||
|
||||
public event Action<EntityUid>? OnActionAdded;
|
||||
public event Action<EntityUid>? OnActionRemoved;
|
||||
@@ -288,27 +287,8 @@ namespace Content.Client.Actions
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assignmentNode is SequenceDataNode sequenceAssignments)
|
||||
{
|
||||
try
|
||||
{
|
||||
var nodeAssignments = _serialization.Read<List<(byte Hotbar, byte Slot)>>(sequenceAssignments, notNullableOverride: true);
|
||||
|
||||
foreach (var index in nodeAssignments)
|
||||
{
|
||||
assignments.Add(new SlotAssignment(index.Hotbar, index.Slot, actionId));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"Failed to parse action assignments: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
AddActionDirect((user, actions), actionId);
|
||||
}
|
||||
|
||||
AssignSlot?.Invoke(assignments);
|
||||
}
|
||||
|
||||
// DeltaV - begin changes
|
||||
@@ -421,10 +401,10 @@ namespace Content.Client.Actions
|
||||
// this is the actual entity-world targeting magic
|
||||
EntityUid? targetEnt = null;
|
||||
if (TryComp<EntityTargetActionComponent>(ent, out var entity) &&
|
||||
args.Input.EntityUid is { Valid: true } entityUid &&
|
||||
ValidateEntityTarget(user, entityUid, (uid, entity)))
|
||||
args.Input.EntityUid != null &&
|
||||
ValidateEntityTarget(user, args.Input.EntityUid, (uid, entity)))
|
||||
{
|
||||
targetEnt = entityUid;
|
||||
targetEnt = args.Input.EntityUid;
|
||||
}
|
||||
|
||||
if (action.ClientExclusive)
|
||||
|
||||
@@ -23,10 +23,9 @@ namespace Content.Client.Actions.UI
|
||||
|
||||
public ActionAlertTooltip(FormattedMessage name, FormattedMessage? desc, string? requires = null)
|
||||
{
|
||||
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSystem;
|
||||
_gameTiming = IoCManager.Resolve<IGameTiming>();
|
||||
|
||||
SetOnlyStyleClass(StyleClass.TooltipPanel);
|
||||
SetOnlyStyleClass(StyleNano.StyleClassTooltipPanel);
|
||||
|
||||
BoxContainer vbox;
|
||||
AddChild(vbox = new BoxContainer
|
||||
@@ -37,7 +36,7 @@ namespace Content.Client.Actions.UI
|
||||
var nameLabel = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleClass.TooltipTitle }
|
||||
StyleClasses = {StyleNano.StyleClassTooltipActionTitle}
|
||||
};
|
||||
nameLabel.SetMessage(name);
|
||||
vbox.AddChild(nameLabel);
|
||||
@@ -47,7 +46,7 @@ namespace Content.Client.Actions.UI
|
||||
var description = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleClass.TooltipDesc }
|
||||
StyleClasses = {StyleNano.StyleClassTooltipActionDescription}
|
||||
};
|
||||
description.SetMessage(desc);
|
||||
vbox.AddChild(description);
|
||||
@@ -56,7 +55,7 @@ namespace Content.Client.Actions.UI
|
||||
vbox.AddChild(_cooldownLabel = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleClass.TooltipDesc },
|
||||
StyleClasses = {StyleNano.StyleClassTooltipActionCooldown},
|
||||
Visible = false
|
||||
});
|
||||
|
||||
@@ -65,7 +64,7 @@ namespace Content.Client.Actions.UI
|
||||
var requiresLabel = new RichTextLabel
|
||||
{
|
||||
MaxWidth = TooltipTextMaxWidth,
|
||||
StyleClasses = { StyleClass.TooltipDesc }
|
||||
StyleClasses = {StyleNano.StyleClassTooltipActionRequirements}
|
||||
};
|
||||
|
||||
if (!FormattedMessage.TryFromMarkup("[color=#635c5c]" + requires + "[/color]", out var markup))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
Title="{Loc admin-camera-window-title-placeholder}"
|
||||
SetSize="425 550"
|
||||
MinSize="200 225">
|
||||
MinSize="200 225"
|
||||
Name="Window">
|
||||
</DefaultWindow>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<Control HorizontalAlignment="Center" VerticalAlignment="Center" MaxWidth="600">
|
||||
<PanelContainer StyleClasses="BackgroundPanel" />
|
||||
<PanelContainer StyleClasses="AngleRect" />
|
||||
|
||||
<BoxContainer Orientation="Vertical" Margin="4">
|
||||
<RichTextLabel Name="Description" />
|
||||
|
||||
@@ -12,19 +12,17 @@ namespace Content.Client.Administration.UI.AdminRemarks;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class AdminMessagePopupWindow : Control
|
||||
{
|
||||
[Dependency] private readonly IStylesheetManager _styleMan = default!;
|
||||
|
||||
private float _timer = float.MaxValue;
|
||||
|
||||
public event Action? OnDismissPressed;
|
||||
|
||||
public event Action? OnAcceptPressed;
|
||||
|
||||
public AdminMessagePopupWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Stylesheet = _styleMan.SheetSystem;
|
||||
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
|
||||
|
||||
AcceptButton.OnPressed += OnAcceptButtonPressed;
|
||||
DismissButton.OnPressed += OnDismissButtonPressed;
|
||||
@@ -51,8 +49,7 @@ public sealed partial class AdminMessagePopupWindow : Control
|
||||
MessageContainer.AddChild(new AdminMessagePopupMessage(message));
|
||||
}
|
||||
|
||||
Description.SetMessage(
|
||||
FormattedMessage.FromMarkup(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
|
||||
Description.SetMessage(FormattedMessage.FromMarkupOrThrow(Loc.GetString("admin-notes-message-desc", ("count", state.Messages.Length))));
|
||||
}
|
||||
|
||||
private void OnDismissButtonPressed(BaseButton.ButtonEventArgs obj)
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Content.Client.Administration.UI.BanPanel;
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class BanPanel : DefaultWindow
|
||||
{
|
||||
public event Action<Ban>? BanSubmitted;
|
||||
public event Action<string?, (IPAddress, int)?, bool, ImmutableTypedHwid?, bool, uint, string, NoteSeverity, string[]?, bool>? BanSubmitted;
|
||||
public event Action<string>? PlayerChanged;
|
||||
private string? PlayerUsername { get; set; }
|
||||
private (IPAddress, int)? IpAddress { get; set; }
|
||||
@@ -37,8 +37,8 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
// This is less efficient than just holding a reference to the root control and enumerating children, but you
|
||||
// have to know how the controls are nested, which makes the code more complicated.
|
||||
// Role group name -> the role buttons themselves.
|
||||
private readonly Dictionary<string, List<(Button, IPrototype)>> _roleCheckboxes = new();
|
||||
private readonly ISawmill _banPanelSawmill;
|
||||
private readonly Dictionary<string, List<Button>> _roleCheckboxes = new();
|
||||
private readonly ISawmill _banpanelSawmill;
|
||||
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
@@ -79,7 +79,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
_banPanelSawmill = _logManager.GetSawmill("admin.banpanel");
|
||||
_banpanelSawmill = _logManager.GetSawmill("admin.banpanel");
|
||||
PlayerList.OnSelectionChanged += OnPlayerSelectionChanged;
|
||||
PlayerNameLine.OnFocusExit += _ => OnPlayerNameChanged();
|
||||
PlayerCheckbox.OnPressed += _ =>
|
||||
@@ -110,7 +110,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
TypeOption.SelectId(args.Id);
|
||||
OnTypeChanged();
|
||||
};
|
||||
LastConnCheckbox.OnPressed += _ =>
|
||||
LastConnCheckbox.OnPressed += args =>
|
||||
{
|
||||
IpLine.ModulateSelfOverride = null;
|
||||
HwidLine.ModulateSelfOverride = null;
|
||||
@@ -164,7 +164,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
|
||||
var antagRoles = _protoMan.EnumeratePrototypes<AntagPrototype>()
|
||||
.OrderBy(x => x.ID);
|
||||
CreateRoleGroup(AntagPrototype.GroupName, AntagPrototype.GroupColor, antagRoles);
|
||||
CreateRoleGroup("Antagonist", Color.Red, antagRoles);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -226,7 +226,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
var roleGroupCheckbox = new Button
|
||||
{
|
||||
Name = $"{groupName}GroupCheckbox",
|
||||
Text = Loc.GetString("role-bans-ban-group"),
|
||||
Text = "Ban all",
|
||||
Margin = new Thickness(0, 0, 5, 0),
|
||||
ToggleMode = true,
|
||||
};
|
||||
@@ -236,14 +236,14 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
{
|
||||
foreach (var role in _roleCheckboxes[groupName])
|
||||
{
|
||||
role.Item1.Pressed = args.Pressed;
|
||||
role.Pressed = args.Pressed;
|
||||
}
|
||||
|
||||
if (args.Pressed)
|
||||
{
|
||||
if (!Enum.TryParse(_cfg.GetCVar(CCVars.DepartmentBanDefaultSeverity), true, out NoteSeverity newSeverity))
|
||||
{
|
||||
_banPanelSawmill
|
||||
_banpanelSawmill
|
||||
.Warning("Departmental role ban severity could not be parsed from config!");
|
||||
return;
|
||||
}
|
||||
@@ -255,14 +255,14 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
{
|
||||
foreach (var button in roleButtons)
|
||||
{
|
||||
if (button.Item1.Pressed)
|
||||
if (button.Pressed)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Enum.TryParse(_cfg.GetCVar(CCVars.RoleBanDefaultSeverity), true, out NoteSeverity newSeverity))
|
||||
{
|
||||
_banPanelSawmill
|
||||
_banpanelSawmill
|
||||
.Warning("Role ban severity could not be parsed from config!");
|
||||
return;
|
||||
}
|
||||
@@ -294,44 +294,30 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a toggle button specifically for one "role" in a "group"
|
||||
/// Adds a checkbutton specifically for one "role" in a "group"
|
||||
/// E.g. it would add the Chief Medical Officer "role" into the "Medical" group.
|
||||
/// </summary>
|
||||
private void AddRoleCheckbox(string group, string role, GridContainer roleGroupInnerContainer, Button roleGroupCheckbox)
|
||||
{
|
||||
var roleCheckboxContainer = new BoxContainer();
|
||||
var roleToggleButton = new Button
|
||||
var roleCheckButton = new Button
|
||||
{
|
||||
Name = role,
|
||||
Name = $"{role}RoleCheckbox",
|
||||
Text = role,
|
||||
ToggleMode = true,
|
||||
};
|
||||
roleToggleButton.OnToggled += args =>
|
||||
roleCheckButton.OnToggled += args =>
|
||||
{
|
||||
// Checks the role group checkbox if all the children are pressed
|
||||
if (args.Pressed && _roleCheckboxes[group].All(e => e.Item1.Pressed))
|
||||
if (args.Pressed && _roleCheckboxes[group].All(e => e.Pressed))
|
||||
roleGroupCheckbox.Pressed = args.Pressed;
|
||||
else
|
||||
roleGroupCheckbox.Pressed = false;
|
||||
};
|
||||
|
||||
IPrototype rolePrototype;
|
||||
|
||||
if (_protoMan.TryIndex<JobPrototype>(role, out var jobPrototype))
|
||||
rolePrototype = jobPrototype;
|
||||
else if (_protoMan.TryIndex<AntagPrototype>(role, out var antagPrototype))
|
||||
rolePrototype = antagPrototype;
|
||||
else
|
||||
{
|
||||
_banPanelSawmill.Error($"Adding a role checkbox for role {role}: role is not a JobPrototype or AntagPrototype.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// This is adding the icon before the role name
|
||||
// TODO: This should not be using raw strings for prototypes as it means it won't be validated at all.
|
||||
// // I know the ban manager is doing the same thing, but that should not leak into UI code.
|
||||
if (jobPrototype is not null && _protoMan.TryIndex(jobPrototype.Icon, out var iconProto))
|
||||
// Yeah, this is sus, but having to split the functions up and stuff is worse imo.
|
||||
if (_protoMan.TryIndex<JobPrototype>(role, out var jobPrototype) && _protoMan.TryIndex(jobPrototype.Icon, out var iconProto))
|
||||
{
|
||||
var jobIconTexture = new TextureRect
|
||||
{
|
||||
@@ -343,12 +329,12 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
roleCheckboxContainer.AddChild(jobIconTexture);
|
||||
}
|
||||
|
||||
roleCheckboxContainer.AddChild(roleToggleButton);
|
||||
roleCheckboxContainer.AddChild(roleCheckButton);
|
||||
|
||||
roleGroupInnerContainer.AddChild(roleCheckboxContainer);
|
||||
|
||||
_roleCheckboxes.TryAdd(group, []);
|
||||
_roleCheckboxes[group].Add((roleToggleButton, rolePrototype));
|
||||
_roleCheckboxes[group].Add(roleCheckButton);
|
||||
}
|
||||
|
||||
public void UpdateBanFlag(bool newFlag)
|
||||
@@ -391,7 +377,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
TimeLine.Text = args.Text;
|
||||
if (!double.TryParse(args.Text, out var result))
|
||||
{
|
||||
ExpiresLabel.Text = Loc.GetString("ban-panel-expiry-error");
|
||||
ExpiresLabel.Text = "err";
|
||||
ErrorLevel |= ErrorLevelEnum.Minutes;
|
||||
TimeLine.ModulateSelfOverride = Color.Red;
|
||||
UpdateSubmitEnabled();
|
||||
@@ -501,7 +487,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
newSeverity = serverSeverity;
|
||||
else
|
||||
{
|
||||
_banPanelSawmill
|
||||
_banpanelSawmill
|
||||
.Warning("Server ban severity could not be parsed from config!");
|
||||
}
|
||||
|
||||
@@ -514,7 +500,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
}
|
||||
else
|
||||
{
|
||||
_banPanelSawmill
|
||||
_banpanelSawmill
|
||||
.Warning("Role ban severity could not be parsed from config!");
|
||||
}
|
||||
break;
|
||||
@@ -559,51 +545,34 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
|
||||
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
ProtoId<JobPrototype>[]? jobs = null;
|
||||
ProtoId<AntagPrototype>[]? antags = null;
|
||||
|
||||
string[]? roles = null;
|
||||
if (TypeOption.SelectedId == (int) Types.Role)
|
||||
{
|
||||
var jobList = new List<ProtoId<JobPrototype>>();
|
||||
var antagList = new List<ProtoId<AntagPrototype>>();
|
||||
|
||||
var rolesList = new List<string>();
|
||||
if (_roleCheckboxes.Count == 0)
|
||||
throw new DebugAssertException("RoleCheckboxes was empty");
|
||||
|
||||
foreach (var button in _roleCheckboxes.Values.SelectMany(departmentButtons => departmentButtons))
|
||||
{
|
||||
if (button.Item1 is { Pressed: true, Name: not null })
|
||||
if (button is { Pressed: true, Text: not null })
|
||||
{
|
||||
switch (button.Item2)
|
||||
{
|
||||
case JobPrototype:
|
||||
jobList.Add(button.Item2.ID);
|
||||
|
||||
break;
|
||||
case AntagPrototype:
|
||||
antagList.Add(button.Item2.ID);
|
||||
|
||||
break;
|
||||
}
|
||||
rolesList.Add(button.Text);
|
||||
}
|
||||
}
|
||||
|
||||
if (jobList.Count + antagList.Count == 0)
|
||||
if (rolesList.Count == 0)
|
||||
{
|
||||
Tabs.CurrentTab = (int) TabNumbers.Roles;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
jobs = jobList.ToArray();
|
||||
antags = antagList.ToArray();
|
||||
roles = rolesList.ToArray();
|
||||
}
|
||||
|
||||
if (TypeOption.SelectedId == (int) Types.None)
|
||||
{
|
||||
TypeOption.ModulateSelfOverride = Color.Red;
|
||||
Tabs.CurrentTab = (int) TabNumbers.BasicInfo;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -615,7 +584,6 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
ReasonTextEdit.GrabKeyboardFocus();
|
||||
ReasonTextEdit.ModulateSelfOverride = Color.Red;
|
||||
ReasonTextEdit.OnKeyBindDown += ResetTextEditor;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -624,7 +592,6 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
ButtonResetOn = _gameTiming.CurTime.Add(TimeSpan.FromSeconds(3));
|
||||
SubmitButton.ModulateSelfOverride = Color.Red;
|
||||
SubmitButton.Text = Loc.GetString("ban-panel-confirm");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -633,22 +600,7 @@ public sealed partial class BanPanel : DefaultWindow
|
||||
var useLastHwid = HwidCheckbox.Pressed && LastConnCheckbox.Pressed && Hwid is null;
|
||||
var severity = (NoteSeverity) SeverityOption.SelectedId;
|
||||
var erase = EraseCheckbox.Pressed;
|
||||
|
||||
var ban = new Ban(
|
||||
player,
|
||||
IpAddress,
|
||||
useLastIp,
|
||||
Hwid,
|
||||
useLastHwid,
|
||||
(uint)(TimeEntered * Multiplier),
|
||||
reason,
|
||||
severity,
|
||||
jobs,
|
||||
antags,
|
||||
erase
|
||||
);
|
||||
|
||||
BanSubmitted?.Invoke(ban);
|
||||
BanSubmitted?.Invoke(player, IpAddress, useLastIp, Hwid, useLastHwid, (uint) (TimeEntered * Multiplier), reason, severity, roles, erase);
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
|
||||
@@ -14,7 +14,8 @@ public sealed class BanPanelEui : BaseEui
|
||||
{
|
||||
BanPanel = new BanPanel();
|
||||
BanPanel.OnClose += () => SendMessage(new CloseEuiMessage());
|
||||
BanPanel.BanSubmitted += ban => SendMessage(new BanPanelEuiStateMsg.CreateBanRequest(ban));
|
||||
BanPanel.BanSubmitted += (player, ip, useLastIp, hwid, useLastHwid, minutes, reason, severity, roles, erase)
|
||||
=> SendMessage(new BanPanelEuiStateMsg.CreateBanRequest(player, ip, useLastIp, hwid, useLastHwid, minutes, reason, severity, roles, erase));
|
||||
BanPanel.PlayerChanged += player => SendMessage(new BanPanelEuiStateMsg.GetPlayerInfoRequest(player));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<Button Visible="True" Name="PopOut" Access="Public" Text="{Loc 'admin-logs-pop-out'}" StyleClasses="OpenBoth" HorizontalAlignment="Left" />
|
||||
<Control HorizontalExpand="True" />
|
||||
<Button Visible="False" Name="Bans" Text="{Loc 'admin-player-actions-bans'}" StyleClasses="OpenRight" />
|
||||
<Button Visible="False" Access="Public" Name="Notes" Text="{Loc 'admin-player-actions-notes'}" StyleClasses="OpenBoth" />
|
||||
<Button Visible="False" Name="Notes" Text="{Loc 'admin-player-actions-notes'}" StyleClasses="OpenBoth" />
|
||||
<controls:ConfirmButton Visible="False" Name="Kick" Text="{Loc 'admin-player-actions-kick'}" ConfirmationText="{Loc 'admin-player-actions-confirm'}" StyleClasses="OpenBoth" />
|
||||
<Button Visible="False" Name="Ban" Text="{Loc 'admin-player-actions-ban'}" StyleClasses="OpenBoth" />
|
||||
<controls:ConfirmButton Visible="False" Name="Respawn" Text="{Loc 'admin-player-actions-respawn'}" ConfirmationText="{Loc 'admin-player-actions-confirm'}" StyleClasses="OpenBoth" />
|
||||
|
||||
@@ -3,16 +3,12 @@ using Content.Shared.Administration;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Administration.UI.CustomControls;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class PlayerListEntry : BoxContainer
|
||||
{
|
||||
private readonly ResPath _pinnedResPath = new("/Textures/Interface/Bwoink/pinned.png");
|
||||
private readonly ResPath _unPinnedResPath = new("/Textures/Interface/Bwoink/un_pinned.png");
|
||||
|
||||
public PlayerListEntry()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
@@ -46,6 +42,15 @@ public sealed partial class PlayerListEntry : BoxContainer
|
||||
|
||||
private void UpdatePinButtonTexture(bool isPinned)
|
||||
{
|
||||
PlayerEntryPinButton.TexturePath = isPinned ? _pinnedResPath.CanonPath : _unPinnedResPath.CanonPath;
|
||||
if (isPinned)
|
||||
{
|
||||
PlayerEntryPinButton?.RemoveStyleClass(StyleNano.StyleClassPinButtonUnpinned);
|
||||
PlayerEntryPinButton?.AddStyleClass(StyleNano.StyleClassPinButtonPinned);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerEntryPinButton?.RemoveStyleClass(StyleNano.StyleClassPinButtonPinned);
|
||||
PlayerEntryPinButton?.AddStyleClass(StyleNano.StyleClassPinButtonUnpinned);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ public sealed class AdminLogsEui : BaseEui
|
||||
ClydeWindow = _clyde.CreateWindow(new WindowCreateParameters
|
||||
{
|
||||
Maximized = false,
|
||||
Title = Loc.GetString("admin-logs-title"),
|
||||
Title = "Admin Logs",
|
||||
Monitor = monitor,
|
||||
Width = 1100,
|
||||
Height = 400
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
||||
/// </summary>
|
||||
public void UpdateReagents()
|
||||
{
|
||||
ReagentList.RemoveAllChildren();
|
||||
ReagentList.DisposeAllChildren();
|
||||
|
||||
if (_selectedSolution == null || _solutions == null)
|
||||
return;
|
||||
@@ -92,7 +92,7 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
||||
/// <param name="solution">The selected solution.</param>
|
||||
private void UpdateVolumeBox(Solution solution)
|
||||
{
|
||||
VolumeBox.RemoveAllChildren();
|
||||
VolumeBox.DisposeAllChildren();
|
||||
|
||||
var volumeLabel = new Label();
|
||||
volumeLabel.HorizontalExpand = true;
|
||||
@@ -131,7 +131,7 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
||||
/// <param name="solution">The selected solution.</param>
|
||||
private void UpdateThermalBox(Solution solution)
|
||||
{
|
||||
ThermalBox.RemoveAllChildren();
|
||||
ThermalBox.DisposeAllChildren();
|
||||
var heatCap = solution.GetHeatCapacity(null);
|
||||
var specificHeatLabel = new Label();
|
||||
specificHeatLabel.HorizontalExpand = true;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<BoxContainer Orientation="Vertical" Name="Notes" Access="Public" VerticalExpand="True"/>
|
||||
</ScrollContainer>
|
||||
<Button Name="ShowMoreButton" Text="{Loc admin-notes-show-more}" Visible="False" HorizontalAlignment="Center" />
|
||||
<Button Name="NewNoteButton" Access="Public" Text="{Loc admin-notes-new-note}" Disabled="True" />
|
||||
<Button Name="NewNoteButton" Text="{Loc admin-notes-new-note}" Disabled="True" />
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</Control>
|
||||
|
||||
@@ -82,11 +82,7 @@ public sealed partial class AdminNotesLine : BoxContainer
|
||||
|
||||
if (Note.UnbannedTime is not null)
|
||||
{
|
||||
ExtraLabel.Text = Loc.GetString(
|
||||
"admin-notes-unbanned",
|
||||
("admin", Note.UnbannedByName ?? "[error]"),
|
||||
("date", Note.UnbannedTime.Value.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"))
|
||||
);
|
||||
ExtraLabel.Text = Loc.GetString("admin-notes-unbanned", ("admin", Note.UnbannedByName ?? "[error]"), ("date", Note.UnbannedTime));
|
||||
ExtraLabel.Visible = true;
|
||||
}
|
||||
else if (Note.ExpiryTime is not null)
|
||||
@@ -143,7 +139,7 @@ public sealed partial class AdminNotesLine : BoxContainer
|
||||
|
||||
private string FormatRoleBanMessage()
|
||||
{
|
||||
var banMessage = new StringBuilder($"{Loc.GetString("admin-notes-banned-from")} {string.Join(", ", Note.BannedRoles ?? new[] { "unknown" })} ");
|
||||
var banMessage = new StringBuilder($"{Loc.GetString("admin-notes-banned-from")} {string.Join(", ", Note.BannedRoles ?? new []{"unknown"})} ");
|
||||
return FormatBanMessageCommon(banMessage);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Title="Loading..."
|
||||
MinSize="400 200">
|
||||
<BoxContainer Orientation="Vertical" Margin="4">
|
||||
<TextEdit Name="NoteTextEdit" Access="Public" HorizontalExpand="True" VerticalExpand="True" />
|
||||
<TextEdit Name="NoteTextEdit" HorizontalExpand="True" VerticalExpand="True" />
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Label Name="ExpiryLabel" Text="{Loc admin-note-editor-expiry-label}" Visible="False" />
|
||||
<HistoryLineEdit Name="ExpiryLineEdit" PlaceHolder="{Loc admin-note-editor-expiry-placeholder}"
|
||||
@@ -17,7 +17,7 @@
|
||||
ToolTip="{Loc admin-note-editor-secret-tooltip}" />
|
||||
<CheckBox Name="PermanentCheckBox" Pressed="True" Text="{Loc admin-note-editor-expiry-checkbox}"
|
||||
ToolTip="{Loc admin-note-editor-expiry-checkbox-tooltip}" />
|
||||
<Button Name="SubmitButton" Access="Public" Text="{Loc admin-note-editor-submit}" HorizontalAlignment="Right" />
|
||||
<Button Name="SubmitButton" Text="{Loc admin-note-editor-submit}" HorizontalAlignment="Right" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
|
||||
@@ -133,7 +133,7 @@ public sealed partial class NoteEdit : FancyWindow
|
||||
private bool IsSecret { get; set; }
|
||||
private NoteType NoteType { get; set; }
|
||||
|
||||
public NoteSeverity? NoteSeverity
|
||||
private NoteSeverity? NoteSeverity
|
||||
{
|
||||
get => _noteSeverity;
|
||||
set
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Content.Client.Administration.UI
|
||||
[Dependency] private readonly IClientAdminManager _adminManager = default!;
|
||||
|
||||
private readonly Menu _menu;
|
||||
private readonly List<BaseWindow> _subWindows = new();
|
||||
private readonly List<DefaultWindow> _subWindows = new();
|
||||
|
||||
private Dictionary<int, PermissionsEuiState.AdminRankData> _ranks =
|
||||
new();
|
||||
@@ -216,7 +216,7 @@ namespace Content.Client.Administration.UI
|
||||
var titleControl = new Label { Text = admin.Title ?? Loc.GetString("permissions-eui-edit-admin-title-control-text").ToLowerInvariant() };
|
||||
if (admin.Title == null) // none
|
||||
{
|
||||
titleControl.StyleClasses.Add(StyleClass.Italic);
|
||||
titleControl.StyleClasses.Add(StyleBase.StyleClassItalic);
|
||||
}
|
||||
|
||||
al.AddChild(titleControl);
|
||||
@@ -240,7 +240,7 @@ namespace Content.Client.Administration.UI
|
||||
var rankControl = new Label { Text = rank };
|
||||
if (italic)
|
||||
{
|
||||
rankControl.StyleClasses.Add(StyleClass.Italic);
|
||||
rankControl.StyleClasses.Add(StyleBase.StyleClassItalic);
|
||||
}
|
||||
|
||||
al.AddChild(rankControl);
|
||||
@@ -340,9 +340,10 @@ namespace Content.Client.Administration.UI
|
||||
tab.AddChild(adminVBox);
|
||||
tab.AddChild(rankVBox);
|
||||
|
||||
ContentsContainer.AddChild(tab);
|
||||
ContentsContainer.MinSize = new(600, 400);
|
||||
Contents.AddChild(tab);
|
||||
}
|
||||
|
||||
protected override Vector2 ContentsMinimumSize => new Vector2(600, 400);
|
||||
}
|
||||
|
||||
private sealed class EditAdminWindow : DefaultWindow
|
||||
@@ -418,21 +419,21 @@ namespace Content.Client.Administration.UI
|
||||
var inherit = new Button
|
||||
{
|
||||
Text = "I",
|
||||
StyleClasses = { StyleClass.ButtonOpenRight },
|
||||
StyleClasses = { StyleBase.ButtonOpenRight },
|
||||
Disabled = disable,
|
||||
Group = group,
|
||||
};
|
||||
var sub = new Button
|
||||
{
|
||||
Text = "-",
|
||||
StyleClasses = { StyleClass.ButtonOpenBoth },
|
||||
StyleClasses = { StyleBase.ButtonOpenBoth },
|
||||
Disabled = disable,
|
||||
Group = group
|
||||
};
|
||||
var plus = new Button
|
||||
{
|
||||
Text = "+",
|
||||
StyleClasses = { StyleClass.ButtonOpenLeft },
|
||||
StyleClasses = { StyleBase.ButtonOpenLeft },
|
||||
Disabled = disable,
|
||||
Group = group
|
||||
};
|
||||
@@ -478,7 +479,7 @@ namespace Content.Client.Administration.UI
|
||||
|
||||
bottomButtons.AddChild(SaveButton);
|
||||
|
||||
ContentsContainer.AddChild(new BoxContainer
|
||||
Contents.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Children =
|
||||
@@ -604,7 +605,7 @@ namespace Content.Client.Administration.UI
|
||||
|
||||
bottomButtons.AddChild(SaveButton);
|
||||
|
||||
ContentsContainer.AddChild(new BoxContainer
|
||||
Contents.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Children =
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
MinSize="50 50">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<GridContainer Columns="3">
|
||||
<cc:UICommandButton Command="kick" Text="{Loc admin-player-actions-window-title}" WindowType="{x:Type at:PlayerActionsWindow}" />
|
||||
<cc:CommandButton Command="banpanel" Text="{Loc admin-player-actions-window-ban}" />
|
||||
<cc:CommandButton Command="aghost" Text="{Loc admin-player-actions-window-admin-ghost}" />
|
||||
<cc:UICommandButton Command="tpto" Text="{Loc admin-player-actions-window-teleport}" WindowType="{x:Type at:TeleportWindow}" />
|
||||
<cc:CommandButton Command="permissions" Text="{Loc admin-player-actions-window-permissions}" />
|
||||
<cc:CommandButton Command="announceui" Text="{Loc admin-player-actions-window-announce}"/>
|
||||
<cc:UICommandButton Command="callshuttle" Text="{Loc admin-player-actions-window-shuttle}" WindowType="{x:Type at:AdminShuttleWindow}"/>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc admin-player-actions-window-title}" MinSize="425 272">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc admin-player-actions-reason}" MinWidth="100" />
|
||||
<Control MinWidth="50" />
|
||||
<LineEdit Name="ReasonLine" MinWidth="100" HorizontalExpand="True" />
|
||||
</BoxContainer>
|
||||
<cc:PlayerListControl Name="PlayerList" VerticalExpand="True" />
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<controls:ConfirmButton Name="SubmitKickButton" Text="{Loc admin-player-actions-kick}" ConfirmationText="{Loc 'admin-player-actions-confirm'}" Disabled="True"/>
|
||||
<Button Name="SubmitAHelpButton" Text="{Loc admin-player-actions-ahelp}" Disabled="True"/>
|
||||
<controls:ConfirmButton Name="SubmitRespawnButton" Text="{Loc admin-player-actions-respawn}" ConfirmationText="{Loc 'admin-player-actions-confirm'}" Disabled="True"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
@@ -0,0 +1,64 @@
|
||||
using Content.Shared.Administration;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Administration.UI.Tabs.AdminTab
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
[UsedImplicitly]
|
||||
public sealed partial class PlayerActionsWindow : DefaultWindow
|
||||
{
|
||||
private PlayerInfo? _selectedPlayer;
|
||||
|
||||
public PlayerActionsWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
SubmitKickButton.OnPressed += SubmitKickButtonOnPressed;
|
||||
SubmitAHelpButton.OnPressed += SubmitAhelpButtonOnPressed;
|
||||
SubmitRespawnButton.OnPressed += SubmitRespawnButtonOnPressed;
|
||||
PlayerList.OnSelectionChanged += OnListOnOnSelectionChanged;
|
||||
}
|
||||
|
||||
private void OnListOnOnSelectionChanged(PlayerInfo? obj)
|
||||
{
|
||||
_selectedPlayer = obj;
|
||||
var disableButtons = _selectedPlayer == null;
|
||||
SubmitKickButton.Disabled = disableButtons;
|
||||
SubmitAHelpButton.Disabled = disableButtons;
|
||||
SubmitRespawnButton.Disabled = disableButtons;
|
||||
}
|
||||
|
||||
private void SubmitKickButtonOnPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (_selectedPlayer == null)
|
||||
return;
|
||||
|
||||
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
|
||||
$"kick \"{_selectedPlayer.Username}\" \"{CommandParsing.Escape(ReasonLine.Text)}\"");
|
||||
}
|
||||
|
||||
private void SubmitAhelpButtonOnPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (_selectedPlayer == null)
|
||||
return;
|
||||
|
||||
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
|
||||
$"openahelp \"{_selectedPlayer.SessionId}\"");
|
||||
}
|
||||
|
||||
private void SubmitRespawnButtonOnPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (_selectedPlayer == null)
|
||||
return;
|
||||
|
||||
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
|
||||
$"respawn \"{_selectedPlayer.Username}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
Title="{Loc admin-ui-teleport}" MinSize="425 230">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<cc:PlayerListControl Name="PlayerList" />
|
||||
<Button Name="SubmitButton" Text="{Loc admin-ui-teleport}" />
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
@@ -0,0 +1,38 @@
|
||||
using Content.Shared.Administration;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Console;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.IoC;
|
||||
|
||||
namespace Content.Client.Administration.UI.Tabs.AdminTab
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
[UsedImplicitly]
|
||||
public sealed partial class TeleportWindow : DefaultWindow
|
||||
{
|
||||
private PlayerInfo? _selectedPlayer;
|
||||
|
||||
protected override void EnteredTree()
|
||||
{
|
||||
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
|
||||
PlayerList.OnSelectionChanged += OnListOnOnSelectionChanged;
|
||||
}
|
||||
|
||||
private void OnListOnOnSelectionChanged(PlayerInfo? obj)
|
||||
{
|
||||
_selectedPlayer = obj;
|
||||
SubmitButton.Disabled = _selectedPlayer == null;
|
||||
}
|
||||
|
||||
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
|
||||
{
|
||||
if (_selectedPlayer == null)
|
||||
return;
|
||||
// Execute command
|
||||
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
|
||||
$"tpto \"{_selectedPlayer.Username}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using Robust.Client.Graphics;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace Content.Client.Anomaly;
|
||||
|
||||
/// <summary>
|
||||
/// This component creates and handles the drawing of a ScreenTexture to be used on the Anomaly Scanner
|
||||
/// for an indicator of Anomaly Severity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the future I would like to make this a more generic "DynamicTextureComponent" that can contain a dictionary
|
||||
/// of texture components like "Bar(offset, size, minimumValue, maximumValue, AppearanceKey, LayerMapKey)" that can
|
||||
/// just draw a bar or other basic drawn element that will show up on a texture layer.
|
||||
/// </remarks>
|
||||
[RegisterComponent]
|
||||
[Access(typeof(AnomalyScannerSystem))]
|
||||
public sealed partial class AnomalyScannerScreenComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the texture drawn as a layer on the Anomaly Scanner device.
|
||||
/// </summary>
|
||||
public OwnedTexture? ScreenTexture;
|
||||
|
||||
/// <summary>
|
||||
/// A small buffer that we can reuse to draw the severity bar.
|
||||
/// </summary>
|
||||
public Rgba32[]? BarBuf;
|
||||
|
||||
/// <summary>
|
||||
/// The position of the top-left of the severity bar in pixels.
|
||||
/// </summary>
|
||||
[DataField(readOnly: true)]
|
||||
public Vector2i Offset = new Vector2i(12, 17);
|
||||
|
||||
/// <summary>
|
||||
/// The width and height of the severity bar in pixels.
|
||||
/// </summary>
|
||||
[DataField(readOnly: true)]
|
||||
public Vector2i Size = new Vector2i(10, 3);
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared.Anomaly;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
|
||||
namespace Content.Client.Anomaly;
|
||||
|
||||
/// <inheritdoc cref="SharedAnomalyScannerSystem"/>
|
||||
public sealed class AnomalyScannerSystem : SharedAnomalyScannerSystem
|
||||
{
|
||||
[Dependency] private readonly IClyde _clyde = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
|
||||
private const float MaxHueDegrees = 360f;
|
||||
private const float GreenHueDegrees = 110f;
|
||||
private const float RedHueDegrees = 0f;
|
||||
private const float GreenHue = GreenHueDegrees / MaxHueDegrees;
|
||||
private const float RedHue = RedHueDegrees / MaxHueDegrees;
|
||||
|
||||
|
||||
// Just an array to initialize the pixels of a new OwnedTexture
|
||||
private static readonly Rgba32[] EmptyTexture = new Rgba32[32*32];
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<AnomalyScannerScreenComponent, ComponentInit>(OnComponentInit);
|
||||
SubscribeLocalEvent<AnomalyScannerScreenComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<AnomalyScannerScreenComponent, AppearanceChangeEvent>(OnScannerAppearanceChanged);
|
||||
}
|
||||
|
||||
private void OnComponentInit(Entity<AnomalyScannerScreenComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
if(!_sprite.TryGetLayer(ent.Owner, AnomalyScannerVisualLayers.Base, out var layer, true))
|
||||
return;
|
||||
|
||||
// Allocate the OwnedTexture
|
||||
ent.Comp.ScreenTexture = _clyde.CreateBlankTexture<Rgba32>(layer.PixelSize);
|
||||
|
||||
if (layer.PixelSize.X < ent.Comp.Offset.X + ent.Comp.Size.X ||
|
||||
layer.PixelSize.Y < ent.Comp.Offset.Y + ent.Comp.Size.Y)
|
||||
{
|
||||
// If the bar doesn't fit, just bail here, ScreenTexture and BarBuf will remain null, and appearance updates
|
||||
// will do nothing.
|
||||
DebugTools.Assert(false, "AnomalyScannerScreenComponent: Bar does not fit within sprite");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Initialize the texture
|
||||
ent.Comp.ScreenTexture.SetSubImage((0, 0), layer.PixelSize, new ReadOnlySpan<Rgba32>(EmptyTexture));
|
||||
|
||||
// Initialize bar drawing buffer
|
||||
ent.Comp.BarBuf = new Rgba32[ent.Comp.Size.X * ent.Comp.Size.Y];
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<AnomalyScannerScreenComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(ent, out var sprite))
|
||||
return;
|
||||
|
||||
_sprite.LayerSetTexture((ent, sprite), AnomalyScannerVisualLayers.Screen, ent.Comp.ScreenTexture);
|
||||
}
|
||||
|
||||
private void OnScannerAppearanceChanged(Entity<AnomalyScannerScreenComponent> ent, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite is null || ent.Comp.ScreenTexture is null || ent.Comp.BarBuf is null)
|
||||
return;
|
||||
|
||||
args.AppearanceData.TryGetValue(AnomalyScannerVisuals.AnomalySeverity, out var severityObj);
|
||||
if (severityObj is not float severity)
|
||||
severity = 0;
|
||||
|
||||
// Get the bar length
|
||||
var barLength = (int)(severity * ent.Comp.Size.X);
|
||||
|
||||
// Calculate the bar color
|
||||
// Hue "angle" of two colors to interpolate between depending on severity
|
||||
// Just a lerp from Green hue at severity = 0.5 to Red hue at 1.0
|
||||
var hue = Math.Clamp(2*GreenHue * (1 - severity), RedHue, GreenHue);
|
||||
var color = new Rgba32(Color.FromHsv(new Vector4(hue, 1f, 1f, 1f)).RGBA);
|
||||
|
||||
var transparent = new Rgba32(0, 0, 0, 255);
|
||||
|
||||
for(var y = 0; y < ent.Comp.Size.Y; y++)
|
||||
{
|
||||
for (var x = 0; x < ent.Comp.Size.X; x++)
|
||||
{
|
||||
ent.Comp.BarBuf[y*ent.Comp.Size.X + x] = x < barLength ? color : transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the buffer to the texture
|
||||
try
|
||||
{
|
||||
ent.Comp.ScreenTexture.SetSubImage(
|
||||
ent.Comp.Offset,
|
||||
ent.Comp.Size,
|
||||
new ReadOnlySpan<Rgba32>(ent.Comp.BarBuf)
|
||||
);
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
Log.Warning($"Bar dimensions out of bounds with the texture on entity {ent.Owner}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Anomaly;
|
||||
|
||||
public sealed partial class AnomalySystem : SharedAnomalySystem
|
||||
public sealed class AnomalySystem : SharedAnomalySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly FloatingVisualizerSystem _floating = default!;
|
||||
@@ -24,7 +24,6 @@ public sealed partial class AnomalySystem : SharedAnomalySystem
|
||||
|
||||
SubscribeLocalEvent<AnomalySupercriticalComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
private void OnStartup(EntityUid uid, AnomalyComponent component, ComponentStartup args)
|
||||
{
|
||||
_floating.FloatAnimation(uid, component.FloatingOffset, component.AnimationKey, component.AnimationTime);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
VerticalExpand="True"
|
||||
Margin="0 0 0 0"
|
||||
VerticalAlignment="Center">
|
||||
<Label Text="{Loc 'anomaly-generator-fuel-display'}" StyleClasses="highlight" />
|
||||
<Label Text="{Loc 'anomaly-generator-fuel-display'}" StyleClasses="StatusFieldTitle" />
|
||||
<ProgressBar Name="FuelBar"
|
||||
HorizontalExpand="True"
|
||||
MaxValue="1"
|
||||
@@ -27,8 +27,8 @@
|
||||
Text="0 %" />
|
||||
</ProgressBar>
|
||||
</BoxContainer>
|
||||
<RichTextLabel Name="CooldownLabel" StyleClasses="highlight" />
|
||||
<RichTextLabel Name="ReadyLabel" StyleClasses="highlight" />
|
||||
<RichTextLabel Name="CooldownLabel" StyleClasses="StatusFieldTitle" />
|
||||
<RichTextLabel Name="ReadyLabel" StyleClasses="StatusFieldTitle" />
|
||||
</BoxContainer>
|
||||
<!--Sprite View-->
|
||||
<PanelContainer Margin="12 0 0 0"
|
||||
|
||||
@@ -338,7 +338,7 @@ namespace Content.Client.Arcade
|
||||
menuInnerPanel.AddChild(menuContainer);
|
||||
#endregion
|
||||
|
||||
ContentsContainer.AddChild(_mainPanel);
|
||||
Contents.AddChild(_mainPanel);
|
||||
|
||||
CanKeyboardFocus = true;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Content.Client.Arcade
|
||||
newGame.OnPressed += _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.NewGame);
|
||||
grid.AddChild(newGame);
|
||||
|
||||
ContentsContainer.AddChild(grid);
|
||||
Contents.AddChild(grid);
|
||||
}
|
||||
|
||||
private void UpdateMetadata(SharedSpaceVillainArcadeComponent.SpaceVillainArcadeMetaDataUpdateMessage message)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Content.Tests")]
|
||||
[assembly: InternalsVisibleTo("Content.IntegrationTests")]
|
||||
|
||||
@@ -134,7 +134,7 @@ public sealed class AlignAtmosPipeLayers : SnapgridCenter
|
||||
|
||||
var newProtoId = altPrototypes[(int)layer];
|
||||
|
||||
if (!_protoManager.Resolve(newProtoId, out var newProto))
|
||||
if (!_protoManager.TryIndex(newProtoId, out var newProto))
|
||||
return;
|
||||
|
||||
if (newProto.Type != ConstructionType.Structure)
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
using Content.Shared.Atmos.EntitySystems;
|
||||
|
||||
namespace Content.Client.Atmos.EntitySystems;
|
||||
|
||||
public sealed class DeltaPressureSystem : SharedDeltaPressureSystem;
|
||||
@@ -1,6 +1,6 @@
|
||||
using Content.Client.Atmos.Monitor.UI.Widgets;
|
||||
using Content.Client.Message;
|
||||
using Content.Client.Stylesheets.Palette;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
@@ -17,7 +17,7 @@ namespace Content.Client.Atmos.Monitor.UI;
|
||||
public sealed partial class AirAlarmWindow : FancyWindow
|
||||
{
|
||||
public event Action<string, IAtmosDeviceData>? AtmosDeviceDataChanged;
|
||||
public event Action<IAtmosDeviceData>? AtmosDeviceDataCopied;
|
||||
public event Action<IAtmosDeviceData>? AtmosDeviceDataCopied;
|
||||
public event Action<string, AtmosMonitorThresholdType, AtmosAlarmThreshold, Gas?>? AtmosAlarmThresholdChanged;
|
||||
public event Action<AirAlarmMode>? AirAlarmModeChanged;
|
||||
public event Action<bool>? AutoModeChanged;
|
||||
@@ -131,7 +131,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
case GasVentPumpData pump:
|
||||
if (!_pumps.TryGetValue(addr, out var pumpControl))
|
||||
{
|
||||
var control = new PumpControl(pump, addr);
|
||||
var control= new PumpControl(pump, addr);
|
||||
control.PumpDataChanged += AtmosDeviceDataChanged;
|
||||
control.PumpDataCopied += AtmosDeviceDataCopied;
|
||||
_pumps.Add(addr, control);
|
||||
@@ -186,9 +186,11 @@ public sealed partial class AirAlarmWindow : FancyWindow
|
||||
{
|
||||
return curAlarm switch
|
||||
{
|
||||
AtmosAlarmType.Danger => Palettes.Status.Critical,
|
||||
AtmosAlarmType.Warning => Palettes.Status.Warning,
|
||||
_ => Palettes.Status.Good,
|
||||
AtmosAlarmType.Danger => StyleNano.DangerousRedFore,
|
||||
AtmosAlarmType.Warning => StyleNano.ConcerningOrangeFore,
|
||||
_ => StyleNano.GoodGreenFore,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -31,10 +30,7 @@ public sealed partial class ThresholdBoundControl : BoxContainer
|
||||
public void SetValue(float value)
|
||||
{
|
||||
_value = value;
|
||||
if (!CSpinner.HasKeyboardFocus())
|
||||
{
|
||||
CSpinner.Value = ScaledValue;
|
||||
}
|
||||
CSpinner.Value = ScaledValue;
|
||||
}
|
||||
|
||||
public void SetEnabled(bool enabled)
|
||||
@@ -43,11 +39,11 @@ public sealed partial class ThresholdBoundControl : BoxContainer
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
CBoundLabel.RemoveStyleClass(StyleClass.LabelWeak);
|
||||
CBoundLabel.RemoveStyleClass("Disabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
CBoundLabel.SetOnlyStyleClass(StyleClass.LabelWeak);
|
||||
CBoundLabel.SetOnlyStyleClass("Disabled");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
MinSize="480 400" Title="Canister">
|
||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
<Label Text="{Loc comp-gas-canister-ui-canister-status}" StyleClasses="LabelHeading"/>
|
||||
<Label Text="{Loc comp-gas-canister-ui-canister-status}" FontColorOverride="{x:Static s:StyleNano.NanoGold}" StyleClasses="LabelBig"/>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc comp-gas-canister-ui-canister-pressure}"/>
|
||||
<Label Name="CanisterPressureLabel" Align="Center" HorizontalExpand="True"/>
|
||||
@@ -16,7 +16,7 @@
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
<Label Text="{Loc comp-gas-canister-ui-holding-tank-status}" StyleClasses="LabelHeading"/>
|
||||
<Label Text="{Loc comp-gas-canister-ui-holding-tank-status}" FontColorOverride="{x:Static s:StyleNano.NanoGold}" StyleClasses="LabelBig"/>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc comp-gas-canister-ui-holding-tank-label}"/>
|
||||
<Label Name="TankLabelLabel" Text="{Loc comp-gas-canister-ui-holding-tank-label-empty}" Align="Center" HorizontalExpand="True"/>
|
||||
@@ -29,7 +29,7 @@
|
||||
</BoxContainer>
|
||||
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
<Label Text="{Loc comp-gas-canister-ui-release-valve-status}" StyleClasses="LabelHeading"/>
|
||||
<Label Text="{Loc comp-gas-canister-ui-release-valve-status}" FontColorOverride="{x:Static s:StyleNano.NanoGold}" StyleClasses="LabelBig"/>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Text="{Loc comp-gas-canister-ui-release-pressure}"/>
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
|
||||
|
||||
_menu.SetAudioStream(jukebox.AudioStream);
|
||||
|
||||
if (_protoManager.Resolve(jukebox.SelectedSongId, out var songProto))
|
||||
if (_protoManager.TryIndex(jukebox.SelectedSongId, out var songProto))
|
||||
{
|
||||
var length = EntMan.System<AudioSystem>().GetAudioLength(songProto.Path.Path.ToString());
|
||||
_menu.SetSelectedSong(songProto.Name, (float) length.TotalSeconds);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Linq; // DeltaV
|
||||
using Content.Shared.Audio.Jukebox;
|
||||
using Robust.Client.Audio;
|
||||
using Robust.Client.AutoGenerated;
|
||||
@@ -89,7 +88,7 @@ public sealed partial class JukeboxMenu : FancyWindow
|
||||
{
|
||||
MusicList.Clear();
|
||||
|
||||
foreach (var entry in jukeboxProtos.OrderBy(x => x.Name)) // DeltaV - Sort the jukebox list
|
||||
foreach (var entry in jukeboxProtos)
|
||||
{
|
||||
MusicList.AddItem(entry.Name, metadata: entry.ID);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed class BarSignSystem : VisualizerSystem<BarSignComponent>
|
||||
|
||||
if (powered
|
||||
&& sign.Current != null
|
||||
&& _prototypeManager.Resolve(sign.Current, out var proto))
|
||||
&& _prototypeManager.TryIndex(sign.Current, out var proto))
|
||||
{
|
||||
SpriteSystem.LayerSetSprite((id, sprite), 0, proto.Icon);
|
||||
sprite.LayerSetShader(0, "unshaded");
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed class BarSignBoundUserInterface(EntityUid owner, Enum uiKey) : Bou
|
||||
|
||||
public void Update(ProtoId<BarSignPrototype>? sign)
|
||||
{
|
||||
if (_prototype.Resolve(sign, out var signPrototype))
|
||||
if (_prototype.TryIndex(sign, out var signPrototype))
|
||||
_menu?.UpdateState(signPrototype);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
Orientation="Vertical"
|
||||
HorizontalExpand="True"
|
||||
Margin="0 0 0 5">
|
||||
<PanelContainer StyleClasses="PanelDark">
|
||||
<PanelContainer>
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="{xNamespace:Static style:StyleNano.ButtonColorDisabled}" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<Collapsible Name="Collapsible">
|
||||
<CollapsibleHeading Name="Heading" MinHeight="35"/>
|
||||
<CollapsibleBody Name="Body">
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
<PanelContainer
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
Margin="15"
|
||||
StyleClasses="PanelDark">
|
||||
Margin="15">
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="{xNamespace:Static style:StyleNano.PanelDark}" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<ScrollContainer VerticalExpand="True" HorizontalExpand="True">
|
||||
<Control>
|
||||
<Label Text="{Loc 'cryostorage-ui-label-no-bodies'}" Name="EmptyLabel" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<DefaultWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
Title="{Loc 'ui-bql-results-title'}">
|
||||
<BoxContainer Orientation="Vertical" MinSize="500 700">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Name="StatusLabel" />
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" Name="ItemList" VerticalExpand="True" />
|
||||
|
||||
@@ -21,6 +21,8 @@ internal sealed partial class ToolshedVisualizeWindow : DefaultWindow
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
protected override Vector2 ContentsMinimumSize => new(500, 700);
|
||||
|
||||
public void Update((string name, NetEntity entity)[] entities)
|
||||
{
|
||||
StatusLabel.Text = _loc.GetString("ui-bql-results-status", ("count", entities.Length));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Margin="10 10 10 0"
|
||||
HorizontalExpand="True"
|
||||
Visible="True">
|
||||
<PanelContainer StyleClasses="BackgroundPanel" HorizontalExpand="True">
|
||||
<PanelContainer StyleClasses="AngleRect" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed partial class BountyEntry : BoxContainer
|
||||
|
||||
UntilNextSkip = untilNextSkip;
|
||||
|
||||
if (!_prototype.Resolve<CargoBountyPrototype>(bounty.Bounty, out var bountyPrototype))
|
||||
if (!_prototype.TryIndex<CargoBountyPrototype>(bounty.Bounty, out var bountyPrototype))
|
||||
return;
|
||||
|
||||
var items = new List<string>();
|
||||
|
||||
@@ -19,7 +19,7 @@ public sealed partial class BountyHistoryEntry : BoxContainer
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
if (!_prototype.Resolve(bounty.Bounty, out var bountyPrototype))
|
||||
if (!_prototype.TryIndex(bounty.Bounty, out var bountyPrototype))
|
||||
return;
|
||||
|
||||
var items = new List<string>();
|
||||
|
||||
@@ -206,7 +206,7 @@ namespace Content.Client.Cargo.UI
|
||||
if (!_orderConsoleQuery.TryComp(_owner, out var orderConsole))
|
||||
return;
|
||||
|
||||
Requests.RemoveAllChildren();
|
||||
Requests.DisposeAllChildren();
|
||||
|
||||
foreach (var order in orders)
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Content.Client.Cargo.UI
|
||||
|
||||
public void SetOrders(SpriteSystem sprites, IPrototypeManager protoManager, List<CargoOrderData> orders)
|
||||
{
|
||||
Orders.RemoveAllChildren();
|
||||
Orders.DisposeAllChildren();
|
||||
|
||||
foreach (var order in orders)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Client.CrewManifest.UI;
|
||||
using Content.Client.CrewManifest.UI;
|
||||
using Content.Shared.CrewManifest;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -21,6 +21,7 @@ public sealed partial class CrewManifestUiFragment : BoxContainer
|
||||
|
||||
public void UpdateState(string stationName, CrewManifestEntries? entries)
|
||||
{
|
||||
CrewManifestListing.DisposeAllChildren();
|
||||
CrewManifestListing.RemoveAllChildren();
|
||||
|
||||
StationNameContainer.Visible = entries != null;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using Content.Client.Message;
|
||||
using Content.Client.UserInterface.RichText; // DeltaV - Sanitize markup; see https://github.com/space-wizards/space-station-14/pull/41799
|
||||
using Content.Shared.MassMedia.Systems;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.RichText; // DeltaV - Sanitize markup; see https://github.com/space-wizards/space-station-14/pull/41799
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility; // DeltaV - Sanitize markup; see https://github.com/space-wizards/space-station-14/pull/41799
|
||||
|
||||
namespace Content.Client.CartridgeLoader.Cartridges;
|
||||
|
||||
@@ -17,18 +14,6 @@ public sealed partial class NewsReaderUiFragment : BoxContainer
|
||||
|
||||
public event Action? OnNotificationSwithPressed;
|
||||
|
||||
// DeltaV - Sanitize markup; see https://github.com/space-wizards/space-station-14/pull/41799
|
||||
private static readonly Type[] AllowedTags =
|
||||
[
|
||||
typeof(BoldItalicTag),
|
||||
typeof(BoldTag),
|
||||
typeof(BulletTag),
|
||||
typeof(ColorTag),
|
||||
typeof(HeadingTag),
|
||||
typeof(ItalicTag),
|
||||
typeof(MonoTag),
|
||||
];
|
||||
|
||||
public NewsReaderUiFragment()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
@@ -46,17 +31,16 @@ public sealed partial class NewsReaderUiFragment : BoxContainer
|
||||
Author.Visible = true;
|
||||
|
||||
PageName.Text = article.Title;
|
||||
PageText.SetMessage(FormattedMessage.FromMarkupPermissive(article.Content), AllowedTags); // DeltaV - Sanitize markup; see https://github.com/space-wizards/space-station-14/pull/41799
|
||||
PageText.SetMarkupPermissive(article.Content);
|
||||
|
||||
PageNum.Text = $"{targetNum}/{totalNum}";
|
||||
|
||||
NotificationSwitch.Text = Loc.GetString(notificationOn ? "news-read-ui-notification-on" : "news-read-ui-notification-off");
|
||||
|
||||
var shareTime = article.ShareTime.ToString(@"hh\:mm\:ss");
|
||||
string shareTime = article.ShareTime.ToString(@"hh\:mm\:ss");
|
||||
ShareTime.SetMarkup(Loc.GetString("news-read-ui-time-prefix-text") + " " + shareTime);
|
||||
|
||||
var author = Loc.GetString("news-read-ui-author-prefix") + " " + (article.Author ?? Loc.GetString("news-read-ui-no-author")); // DeltaV - Sanitize markup; see https://github.com/space-wizards/space-station-14/pull/41799
|
||||
Author.SetMessage(FormattedMessage.FromMarkupPermissive(author), AllowedTags); // DeltaV - Sanitize markup; see https://github.com/space-wizards/space-station-14/pull/41799
|
||||
Author.SetMarkup(Loc.GetString("news-read-ui-author-prefix") + " " + (article.Author != null ? article.Author : Loc.GetString("news-read-ui-no-author")));
|
||||
|
||||
Prev.Disabled = targetNum <= 1;
|
||||
Next.Disabled = targetNum >= totalNum;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using Content.Client.Stylesheets.Palette;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Changeling.Components;
|
||||
using Content.Shared.Changeling.Systems;
|
||||
using Content.Shared.Changeling.Systems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
@@ -10,58 +7,28 @@ namespace Content.Client.Changeling.UI;
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ChangelingTransformBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
|
||||
{
|
||||
private SimpleRadialMenu? _menu;
|
||||
private static readonly Color SelectedOptionBackground = Palettes.Green.Element.WithAlpha(128);
|
||||
private static readonly Color SelectedOptionHoverBackground = Palettes.Green.HoveredElement.WithAlpha(128);
|
||||
private ChangelingTransformMenu? _window;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<SimpleRadialMenu>();
|
||||
Update();
|
||||
_menu.OpenOverMouseScreenPosition();
|
||||
}
|
||||
_window = this.CreateWindow<ChangelingTransformMenu>();
|
||||
|
||||
_window.OnIdentitySelect += SendIdentitySelect;
|
||||
|
||||
_window.Update(Owner);
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (_menu == null)
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
if (!EntMan.TryGetComponent<ChangelingIdentityComponent>(Owner, out var lingIdentity))
|
||||
return;
|
||||
|
||||
var models = ConvertToButtons(lingIdentity.ConsumedIdentities, lingIdentity?.CurrentIdentity);
|
||||
|
||||
_menu.SetButtons(models);
|
||||
_window.Update(Owner);
|
||||
}
|
||||
|
||||
private IEnumerable<RadialMenuOptionBase> ConvertToButtons(
|
||||
IEnumerable<EntityUid> identities,
|
||||
EntityUid? currentIdentity
|
||||
)
|
||||
{
|
||||
var buttons = new List<RadialMenuOptionBase>();
|
||||
foreach (var identity in identities)
|
||||
{
|
||||
if (!EntMan.TryGetComponent<MetaDataComponent>(identity, out var metadata))
|
||||
continue;
|
||||
|
||||
var option = new RadialMenuActionOption<NetEntity>(SendIdentitySelect, EntMan.GetNetEntity(identity))
|
||||
{
|
||||
IconSpecifier = RadialMenuIconSpecifier.With(identity),
|
||||
ToolTip = metadata.EntityName,
|
||||
BackgroundColor = (currentIdentity == identity) ? SelectedOptionBackground : null,
|
||||
HoverBackgroundColor = (currentIdentity == identity) ? SelectedOptionHoverBackground : null
|
||||
};
|
||||
buttons.Add(option);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private void SendIdentitySelect(NetEntity identityId)
|
||||
public void SendIdentitySelect(NetEntity identityId)
|
||||
{
|
||||
SendPredictedMessage(new ChangelingTransformIdentitySelectMessage(identityId));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<ui:RadialMenu
|
||||
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
CloseButtonStyleClass="RadialMenuCloseButton"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True">
|
||||
<ui:RadialContainer Name="Main">
|
||||
</ui:RadialContainer>
|
||||
</ui:RadialMenu>
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.Numerics;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Changeling.Components;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Changeling.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class ChangelingTransformMenu : RadialMenu
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
public event Action<NetEntity>? OnIdentitySelect;
|
||||
|
||||
public ChangelingTransformMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
public void Update(EntityUid uid)
|
||||
{
|
||||
Main.DisposeAllChildren();
|
||||
|
||||
if (!_entity.TryGetComponent<ChangelingIdentityComponent>(uid, out var identityComp))
|
||||
return;
|
||||
|
||||
foreach (var identityUid in identityComp.ConsumedIdentities)
|
||||
{
|
||||
if (!_entity.TryGetComponent<MetaDataComponent>(identityUid, out var metadata))
|
||||
continue;
|
||||
|
||||
var identityName = metadata.EntityName;
|
||||
|
||||
var button = new ChangelingTransformMenuButton()
|
||||
{
|
||||
StyleClasses = { "RadialMenuButton" },
|
||||
SetSize = new Vector2(64, 64),
|
||||
ToolTip = identityName,
|
||||
};
|
||||
|
||||
var entView = new SpriteView()
|
||||
{
|
||||
SetSize = new Vector2(48, 48),
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
Stretch = SpriteView.StretchMode.Fill,
|
||||
};
|
||||
entView.SetEntity(identityUid);
|
||||
button.OnButtonUp += _ =>
|
||||
{
|
||||
OnIdentitySelect?.Invoke(_entity.GetNetEntity(identityUid));
|
||||
Close();
|
||||
};
|
||||
button.AddChild(entView);
|
||||
Main.AddChild(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ChangelingTransformMenuButton : RadialMenuTextureButtonWithSector;
|
||||
@@ -36,12 +36,12 @@ namespace Content.Client.Changelog
|
||||
if (_changelogManager.NewChangelogEntries)
|
||||
{
|
||||
Text = Loc.GetString("changelog-button-new-entries");
|
||||
StyleClasses.Add(StyleClass.Negative);
|
||||
StyleClasses.Add(StyleBase.ButtonCaution);
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = Loc.GetString("changelog-button");
|
||||
StyleClasses.Remove(StyleClass.Negative);
|
||||
StyleClasses.Remove(StyleBase.ButtonCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ namespace Content.Client.Changelog
|
||||
// Open changelog purely to compare to the last viewed date.
|
||||
var changelogs = await LoadChangelog();
|
||||
UpdateChangelogs(changelogs);
|
||||
_configManager.OnValueChanged(CCVars.ServerId, OnServerIdCVarChanged);
|
||||
}
|
||||
|
||||
private void UpdateChangelogs(List<Changelog> changelogs)
|
||||
@@ -82,11 +81,6 @@ namespace Content.Client.Changelog
|
||||
|
||||
MaxId = changelog.Entries.Max(c => c.Id);
|
||||
|
||||
CheckLastSeenEntry();
|
||||
}
|
||||
|
||||
private void CheckLastSeenEntry()
|
||||
{
|
||||
var path = new ResPath($"/changelog_last_seen_{_configManager.GetCVar(CCVars.ServerId)}");
|
||||
if (_resource.UserData.TryReadAllText(path, out var lastReadIdText))
|
||||
{
|
||||
@@ -98,11 +92,6 @@ namespace Content.Client.Changelog
|
||||
NewChangelogEntriesChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void OnServerIdCVarChanged(string newValue)
|
||||
{
|
||||
CheckLastSeenEntry();
|
||||
}
|
||||
|
||||
public Task<List<Changelog>> LoadChangelog()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed partial class ChangelogTab : Control
|
||||
ChangelogBody.AddChild(new Label
|
||||
{
|
||||
Text = dayNice,
|
||||
StyleClasses = { StyleClass.LabelHeading },
|
||||
StyleClasses = { StyleBase.StyleClassLabelHeading },
|
||||
Margin = new Thickness(4, 6, 0, 0)
|
||||
});
|
||||
|
||||
@@ -117,7 +117,7 @@ public sealed partial class ChangelogTab : Control
|
||||
};
|
||||
|
||||
readDivider.AddChild(hBox);
|
||||
readDivider.AddChild(new PanelContainer { StyleClasses = { StyleClass.LowDivider } });
|
||||
readDivider.AddChild(new PanelContainer { StyleClasses = { StyleBase.ClassLowDivider } });
|
||||
ChangelogBody.AddChild(readDivider);
|
||||
|
||||
if (first)
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
xmlns:ui="clr-namespace:Content.Client.Changelog"
|
||||
Title="{Loc 'changelog-window-title'}"
|
||||
MinSize="500 400"
|
||||
SetSize="500 400"
|
||||
Stylesheet="Interface">
|
||||
<PanelContainer StyleClasses="BackgroundPanel" />
|
||||
SetSize="500 400">
|
||||
<PanelContainer StyleClasses="AngleRect" />
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<TabContainer Name="Tabs" Access="Public" HorizontalExpand="True" VerticalExpand="True" />
|
||||
<PanelContainer StyleClasses="LowDivider" />
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace Content.Client.Changelog
|
||||
public ChangelogWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
WindowTitle.AddStyleClass(StyleClass.LabelHeading);
|
||||
WindowTitle.AddStyleClass(StyleBase.StyleClassLabelHeading);
|
||||
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
|
||||
}
|
||||
|
||||
protected override void Opened()
|
||||
@@ -54,7 +55,7 @@ namespace Content.Client.Changelog
|
||||
// Changelog is not kept in memory so load it again.
|
||||
var changelogs = await _changelog.LoadChangelog();
|
||||
|
||||
Tabs.RemoveAllChildren();
|
||||
Tabs.DisposeAllChildren();
|
||||
|
||||
var i = 0;
|
||||
foreach (var changelog in changelogs)
|
||||
|
||||
@@ -32,11 +32,6 @@ internal sealed class ChatManager : IChatManager
|
||||
// See server-side manager. This just exists for shared code.
|
||||
}
|
||||
|
||||
public void SendAdminAlertNoFormatOrEscape(string message)
|
||||
{
|
||||
// See server-side manager. This just exists for shared code.
|
||||
}
|
||||
|
||||
public void SendMessage(string text, ChatSelectChannel channel)
|
||||
{
|
||||
var str = text.ToString();
|
||||
|
||||
@@ -35,7 +35,7 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
|
||||
}
|
||||
// End DeltaV Additions
|
||||
|
||||
if (!_prototypeManager.Resolve(currentTypingIndicator, out var proto))
|
||||
if (!_prototypeManager.TryIndex(currentTypingIndicator, out var proto))
|
||||
{
|
||||
Log.Error($"Unknown typing indicator id: {component.TypingIndicatorPrototype}");
|
||||
return;
|
||||
@@ -45,7 +45,7 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
|
||||
if (!layerExists)
|
||||
layer = SpriteSystem.LayerMapReserve((uid, args.Sprite), TypingIndicatorLayers.Base);
|
||||
|
||||
SpriteSystem.LayerSetRsi((uid, args.Sprite), layer, proto.SpritePath, proto.TypingState);
|
||||
SpriteSystem.LayerSetRsi((uid, args.Sprite), layer, proto.SpritePath, proto.TypingState); // DeltaV - Combine path and state calls to avoid missing state error on alternate indicators
|
||||
args.Sprite.LayerSetShader(layer, proto.Shader);
|
||||
SpriteSystem.LayerSetOffset((uid, args.Sprite), layer, proto.Offset);
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Content.Client.Chemistry.UI;
|
||||
using Content.Client.Items;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
|
||||
namespace Content.Client.Chemistry.EntitySystems;
|
||||
|
||||
public sealed class HyposprayStatusControlSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainers = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
Subs.ItemStatus<HyposprayComponent>(ent => new HyposprayStatusControl(ent, _solutionContainers));
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Content.Client.Chemistry.UI;
|
||||
using Content.Client.Items;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.Chemistry.EntitySystems;
|
||||
|
||||
public sealed class InjectorStatusControlSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainers = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
Subs.ItemStatus<InjectorComponent>(injector => new InjectorStatusControl(injector, _solutionContainers, _prototypeManager));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Content.Client.Chemistry.UI;
|
||||
using Content.Client.Items;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
|
||||
namespace Content.Client.Chemistry.EntitySystems;
|
||||
|
||||
public sealed class InjectorSystem : SharedInjectorSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Subs.ItemStatus<InjectorComponent>(ent => new InjectorStatusControl(ent, SolutionContainer));
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,10 @@
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'chem-master-window-buffer-text'}" />
|
||||
<Control HorizontalExpand="True" />
|
||||
<Button MinSize="80 0" Margin="0 0 10 0" Name="BufferSortButton" Access="Public" Text="{Loc 'chem-master-window-sort-type-none'}" />
|
||||
<!-- DeltaV - Removed discarding
|
||||
<Button MinSize="80 0" Name="BufferTransferButton" Access="Public" Text="{Loc 'chem-master-window-transfer-button'}" ToggleMode="True" StyleClasses="OpenRight" />
|
||||
-->
|
||||
<Button MinSize="80 0" Name="BufferSortButton" Access="Public" Text="{Loc 'chem-master-window-sort-type-none'}" StyleClasses="OpenBoth" />
|
||||
<!-- DeltaV - Removed discarding
|
||||
<Button MinSize="80 0" Name="BufferDiscardButton" Access="Public" Text="{Loc 'chem-master-window-discard-button'}" ToggleMode="True" StyleClasses="OpenLeft" />
|
||||
-->
|
||||
@@ -86,7 +86,7 @@
|
||||
<Label Text="{Loc 'chem-master-window-packaging-text'}" />
|
||||
<Control HorizontalExpand="True"/>
|
||||
<Label Text="{Loc 'chem-master-window-container-label'}" /> <!-- DeltaV-->
|
||||
<Label Name="BufferCurrentVolume" StyleClasses="LabelWeak" />
|
||||
<Label Name="BufferCurrentVolume" StyleClasses="LabelSecondaryColor" />
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Wrap the packaging info-->
|
||||
@@ -116,9 +116,9 @@
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'chem-master-window-pills-label'}" />
|
||||
<Control HorizontalExpand="True" MinSize="50 0" />
|
||||
<Label Text="{Loc 'chem-master-window-pills-number-label'}" Margin="5 0 0 0" StyleClasses="LabelWeak" />
|
||||
<Label Text="{Loc 'chem-master-window-pills-number-label'}" Margin="5 0 0 0" StyleClasses="LabelSecondaryColor" />
|
||||
<SpinBox MinSize="100 0" Name="PillNumber" Access="Public" Value="0" />
|
||||
<Label Text="{Loc 'chem-master-window-dose-label'}" Margin="5 0 0 0" StyleClasses="LabelWeak" />
|
||||
<Label Text="{Loc 'chem-master-window-dose-label'}" Margin="5 0 0 0" StyleClasses="LabelSecondaryColor" />
|
||||
<SpinBox MinSize="100 0" Name="PillDosage" Access="Public" Value="1" />
|
||||
<Button MinSize="80 0" Name="CreatePillButton" Access="Public" Text="{Loc 'chem-master-window-create-button'}" />
|
||||
</BoxContainer>
|
||||
@@ -126,7 +126,7 @@
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc 'chem-master-window-bottles-label'}" />
|
||||
<Control HorizontalExpand="True" MinSize="50 0" />
|
||||
<Label Text="{Loc 'chem-master-window-dose-label'}" Margin="5 0 0 0" StyleClasses="LabelWeak" />
|
||||
<Label Text="{Loc 'chem-master-window-dose-label'}" Margin="5 0 0 0" StyleClasses="LabelSecondaryColor" />
|
||||
<SpinBox MinSize="100 0" Name="BottleDosage" Access="Public" Value="0" />
|
||||
<Button MinSize="80 0" Name="CreateBottleButton" Access="Public" Text="{Loc 'chem-master-window-create-button'}" />
|
||||
</BoxContainer>
|
||||
|
||||
@@ -53,14 +53,14 @@ namespace Content.Client.Chemistry.UI
|
||||
{
|
||||
// For every button decide which stylebase to have
|
||||
// Every row has 10 buttons
|
||||
String styleBase = StyleClass.ButtonOpenBoth;
|
||||
String styleBase = StyleBase.ButtonOpenBoth;
|
||||
uint modulo = i % 10;
|
||||
if (i > 0 && modulo == 0)
|
||||
styleBase = StyleClass.ButtonOpenRight;
|
||||
styleBase = StyleBase.ButtonOpenRight;
|
||||
else if (i > 0 && modulo == 9)
|
||||
styleBase = StyleClass.ButtonOpenLeft;
|
||||
styleBase = StyleBase.ButtonOpenLeft;
|
||||
else if (i == 0)
|
||||
styleBase = StyleClass.ButtonOpenRight;
|
||||
styleBase = StyleBase.ButtonOpenRight;
|
||||
|
||||
// Generate buttons
|
||||
PillTypeButtons[i] = new Button
|
||||
@@ -113,16 +113,13 @@ namespace Content.Client.Chemistry.UI
|
||||
|
||||
var buttonConfigs = new (string text, ChemMasterReagentAmount amount, string styleClass)[]
|
||||
{
|
||||
("1", ChemMasterReagentAmount.U1, StyleClass.ButtonOpenBoth),
|
||||
("5", ChemMasterReagentAmount.U5, StyleClass.ButtonOpenBoth),
|
||||
("10", ChemMasterReagentAmount.U10, StyleClass.ButtonOpenBoth),
|
||||
("15", ChemMasterReagentAmount.U15, StyleClass.ButtonOpenBoth),
|
||||
("20", ChemMasterReagentAmount.U20, StyleClass.ButtonOpenBoth),
|
||||
("25", ChemMasterReagentAmount.U25, StyleClass.ButtonOpenBoth),
|
||||
("30", ChemMasterReagentAmount.U30, StyleClass.ButtonOpenBoth),
|
||||
("50", ChemMasterReagentAmount.U50, StyleClass.ButtonOpenBoth),
|
||||
("100", ChemMasterReagentAmount.U100, StyleClass.ButtonOpenBoth),
|
||||
(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, StyleClass.ButtonOpenLeft),
|
||||
("1", ChemMasterReagentAmount.U1, StyleBase.ButtonOpenBoth),
|
||||
("5", ChemMasterReagentAmount.U5, StyleBase.ButtonOpenBoth),
|
||||
("10", ChemMasterReagentAmount.U10, StyleBase.ButtonOpenBoth),
|
||||
("25", ChemMasterReagentAmount.U25, StyleBase.ButtonOpenBoth),
|
||||
("50", ChemMasterReagentAmount.U50, StyleBase.ButtonOpenBoth),
|
||||
("100", ChemMasterReagentAmount.U100, StyleBase.ButtonOpenBoth),
|
||||
(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, StyleBase.ButtonOpenLeft),
|
||||
};
|
||||
|
||||
var buttons = new List<ReagentButton>();
|
||||
@@ -249,7 +246,7 @@ namespace Content.Client.Chemistry.UI
|
||||
var bufferVol = new Label
|
||||
{
|
||||
Text = $"{state.BufferCurrentVolume}u",
|
||||
StyleClasses = { StyleClass.LabelWeak }
|
||||
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
|
||||
};
|
||||
bufferHBox.AddChild(bufferVol);
|
||||
|
||||
@@ -318,7 +315,7 @@ namespace Content.Client.Chemistry.UI
|
||||
new Label
|
||||
{
|
||||
Text = $"{info.CurrentVolume}/{info.MaxVolume}",
|
||||
StyleClasses = { StyleClass.LabelWeak }
|
||||
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -373,7 +370,7 @@ namespace Content.Client.Chemistry.UI
|
||||
new Label
|
||||
{
|
||||
Text = $"{quantity}u",
|
||||
StyleClasses = { StyleClass.LabelWeak }
|
||||
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
|
||||
},
|
||||
|
||||
// Padding
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using Content.Client.Message;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Chemistry.UI;
|
||||
|
||||
public sealed class HyposprayStatusControl : Control
|
||||
{
|
||||
private readonly Entity<HyposprayComponent> _parent;
|
||||
private readonly RichTextLabel _label;
|
||||
private readonly SharedSolutionContainerSystem _solutionContainers;
|
||||
|
||||
private FixedPoint2 PrevVolume;
|
||||
private FixedPoint2 PrevMaxVolume;
|
||||
private bool PrevOnlyAffectsMobs;
|
||||
|
||||
public HyposprayStatusControl(Entity<HyposprayComponent> parent, SharedSolutionContainerSystem solutionContainers)
|
||||
{
|
||||
_parent = parent;
|
||||
_solutionContainers = solutionContainers;
|
||||
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
|
||||
AddChild(_label);
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
if (!_solutionContainers.TryGetSolution(_parent.Owner, _parent.Comp.SolutionName, out _, out var solution))
|
||||
return;
|
||||
|
||||
// only updates the UI if any of the details are different than they previously were
|
||||
if (PrevVolume == solution.Volume
|
||||
&& PrevMaxVolume == solution.MaxVolume
|
||||
&& PrevOnlyAffectsMobs == _parent.Comp.OnlyAffectsMobs)
|
||||
return;
|
||||
|
||||
PrevVolume = solution.Volume;
|
||||
PrevMaxVolume = solution.MaxVolume;
|
||||
PrevOnlyAffectsMobs = _parent.Comp.OnlyAffectsMobs;
|
||||
|
||||
var modeStringLocalized = Loc.GetString((_parent.Comp.OnlyAffectsMobs && _parent.Comp.CanContainerDraw) switch
|
||||
{
|
||||
false => "hypospray-all-mode-text",
|
||||
true => "hypospray-mobs-only-mode-text",
|
||||
});
|
||||
|
||||
_label.SetMarkup(Loc.GetString("hypospray-volume-label",
|
||||
("currentVolume", solution.Volume),
|
||||
("totalVolume", solution.MaxVolume),
|
||||
("modeString", modeStringLocalized)));
|
||||
}
|
||||
}
|
||||
@@ -2,35 +2,29 @@ using Content.Client.Message;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Chemistry.UI;
|
||||
|
||||
public sealed class InjectorStatusControl : Control
|
||||
{
|
||||
private readonly IPrototypeManager _prototypeManager;
|
||||
|
||||
private readonly Entity<InjectorComponent> _parent;
|
||||
private readonly SharedSolutionContainerSystem _solutionContainers;
|
||||
private readonly RichTextLabel _label;
|
||||
|
||||
private FixedPoint2 _prevVolume;
|
||||
private FixedPoint2 _prevMaxVolume;
|
||||
private FixedPoint2? _prevTransferAmount;
|
||||
private InjectorBehavior _prevBehavior;
|
||||
private FixedPoint2 PrevVolume;
|
||||
private FixedPoint2 PrevMaxVolume;
|
||||
private FixedPoint2 PrevTransferAmount;
|
||||
private InjectorToggleMode PrevToggleState;
|
||||
|
||||
public InjectorStatusControl(Entity<InjectorComponent> parent, SharedSolutionContainerSystem solutionContainers, IPrototypeManager prototypeManager)
|
||||
public InjectorStatusControl(Entity<InjectorComponent> parent, SharedSolutionContainerSystem solutionContainers)
|
||||
{
|
||||
_prototypeManager = prototypeManager;
|
||||
|
||||
_parent = parent;
|
||||
_solutionContainers = solutionContainers;
|
||||
_label = new RichTextLabel { StyleClasses = { StyleClass.ItemStatus } };
|
||||
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
|
||||
AddChild(_label);
|
||||
}
|
||||
|
||||
@@ -38,38 +32,33 @@ public sealed class InjectorStatusControl : Control
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
if (!_solutionContainers.TryGetSolution(_parent.Owner, _parent.Comp.SolutionName, out _, out var solution)
|
||||
|| !_prototypeManager.Resolve(_parent.Comp.ActiveModeProtoId, out var activeMode))
|
||||
if (!_solutionContainers.TryGetSolution(_parent.Owner, _parent.Comp.SolutionName, out _, out var solution))
|
||||
return;
|
||||
|
||||
// only updates the UI if any of the details are different than they previously were
|
||||
if (_prevVolume == solution.Volume
|
||||
&& _prevMaxVolume == solution.MaxVolume
|
||||
&& _prevTransferAmount == _parent.Comp.CurrentTransferAmount
|
||||
&& _prevBehavior == activeMode.Behavior)
|
||||
if (PrevVolume == solution.Volume
|
||||
&& PrevMaxVolume == solution.MaxVolume
|
||||
&& PrevTransferAmount == _parent.Comp.CurrentTransferAmount
|
||||
&& PrevToggleState == _parent.Comp.ToggleState)
|
||||
return;
|
||||
|
||||
_prevVolume = solution.Volume;
|
||||
_prevMaxVolume = solution.MaxVolume;
|
||||
_prevTransferAmount = _parent.Comp.CurrentTransferAmount;
|
||||
_prevBehavior = activeMode.Behavior;
|
||||
PrevVolume = solution.Volume;
|
||||
PrevMaxVolume = solution.MaxVolume;
|
||||
PrevTransferAmount = _parent.Comp.CurrentTransferAmount;
|
||||
PrevToggleState = _parent.Comp.ToggleState;
|
||||
|
||||
// Update current volume and injector state
|
||||
// Seeing transfer volume is only important for injectors that can change it.
|
||||
if (activeMode.TransferAmounts.Count > 1 && _parent.Comp.CurrentTransferAmount.HasValue)
|
||||
var modeStringLocalized = Loc.GetString(_parent.Comp.ToggleState switch
|
||||
{
|
||||
_label.SetMarkup(Loc.GetString("injector-volume-transfer-label",
|
||||
("currentVolume", solution.Volume),
|
||||
("totalVolume", solution.MaxVolume),
|
||||
("modeString", Loc.GetString(activeMode.Name)),
|
||||
("transferVolume", _parent.Comp.CurrentTransferAmount.Value)));
|
||||
}
|
||||
else
|
||||
{
|
||||
_label.SetMarkup(Loc.GetString("injector-volume-label",
|
||||
("currentVolume", solution.Volume),
|
||||
("totalVolume", solution.MaxVolume),
|
||||
("modeString", Loc.GetString(activeMode.Name))));
|
||||
}
|
||||
InjectorToggleMode.Draw => "injector-draw-text",
|
||||
InjectorToggleMode.Inject => "injector-inject-text",
|
||||
_ => "injector-invalid-injector-toggle-mode"
|
||||
});
|
||||
|
||||
_label.SetMarkup(Loc.GetString("injector-volume-label",
|
||||
("currentVolume", solution.Volume),
|
||||
("totalVolume", solution.MaxVolume),
|
||||
("modeString", modeStringLocalized),
|
||||
("transferVolume", _parent.Comp.CurrentTransferAmount)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace Content.Client.Chemistry.UI
|
||||
var quantityLabel = new Label
|
||||
{
|
||||
Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity)),
|
||||
StyleClasses = { StyleClass.LabelWeak },
|
||||
StyleClasses = { StyleNano.StyleClassLabelSecondaryColor },
|
||||
};
|
||||
|
||||
ContainerInfo.Children.Add(new BoxContainer
|
||||
|
||||
@@ -29,7 +29,7 @@ public sealed class SolutionStatusControl : PollingItemStatusControl<SolutionSta
|
||||
_parent = parent;
|
||||
_entityManager = entityManager;
|
||||
_solutionContainers = solutionContainers;
|
||||
_label = new RichTextLabel { StyleClasses = { StyleClass.ItemStatus } };
|
||||
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
|
||||
AddChild(_label);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Content.Client.Cloning.UI
|
||||
|
||||
Title = Loc.GetString("accept-cloning-window-title");
|
||||
|
||||
ContentsContainer.AddChild(new BoxContainer
|
||||
Contents.AddChild(new BoxContainer
|
||||
{
|
||||
Orientation = LayoutOrientation.Vertical,
|
||||
Children =
|
||||
|
||||
@@ -45,7 +45,7 @@ public sealed class ChameleonBoundUserInterface : BoundUserInterface
|
||||
var newTargets = new List<EntProtoId>();
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (string.IsNullOrEmpty(target) || !_proto.Resolve(target, out EntityPrototype? proto))
|
||||
if (string.IsNullOrEmpty(target) || !_proto.TryIndex(target, out EntityPrototype? proto))
|
||||
continue;
|
||||
|
||||
if (!proto.TryGetComponent(out TagComponent? tag, EntMan.ComponentFactory) || !_tag.HasTag(tag, st.RequiredTag))
|
||||
@@ -58,13 +58,6 @@ public sealed class ChameleonBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
_menu?.UpdateState(targets, st.SelectedId);
|
||||
}
|
||||
|
||||
// Begin Delta-V: Override for the name of the chameleon stuff, so you can have items use the chameleon system without being illegal.
|
||||
if (_menu is { } menu && EntMan.TryGetComponent<ChameleonClothingComponent>(Owner, out var chameleon) && chameleon.WindowTitleOverride is { } titleOverride)
|
||||
{
|
||||
_menu.Title = Loc.GetString(titleOverride);
|
||||
}
|
||||
// End Delta-V
|
||||
}
|
||||
|
||||
private void OnIdSelected(string selectedId)
|
||||
|
||||
@@ -54,7 +54,7 @@ public sealed partial class ChameleonMenu : DefaultWindow
|
||||
|
||||
foreach (var id in _possibleIds)
|
||||
{
|
||||
if (!_prototypeManager.Resolve(id, out EntityPrototype? proto))
|
||||
if (!_prototypeManager.TryIndex(id, out EntityPrototype? proto))
|
||||
continue;
|
||||
|
||||
var lowId = id.Id.ToLowerInvariant();
|
||||
@@ -67,7 +67,7 @@ public sealed partial class ChameleonMenu : DefaultWindow
|
||||
MinSize = new Vector2(48, 48),
|
||||
HorizontalExpand = true,
|
||||
Group = group,
|
||||
StyleClasses = {StyleClass.ButtonSquare},
|
||||
StyleClasses = {StyleBase.ButtonSquare},
|
||||
ToggleMode = true,
|
||||
Pressed = _selectedId == id,
|
||||
ToolTip = proto.Name
|
||||
|
||||
@@ -68,7 +68,7 @@ namespace Content.Client.Configurable.UI
|
||||
outerColumn.AddChild(Column);
|
||||
baseContainer.AddChild(outerColumn);
|
||||
baseContainer.AddChild(confirmButton);
|
||||
ContentsContainer.AddChild(baseContainer);
|
||||
Contents.AddChild(baseContainer);
|
||||
}
|
||||
|
||||
private void OnConfirm(ButtonEventArgs args)
|
||||
|
||||
@@ -80,7 +80,7 @@ namespace Content.Client.Construction
|
||||
{
|
||||
foreach (var constructionProto in PrototypeManager.EnumeratePrototypes<ConstructionPrototype>())
|
||||
{
|
||||
if (!PrototypeManager.Resolve(constructionProto.Graph, out var graphProto))
|
||||
if (!PrototypeManager.TryIndex(constructionProto.Graph, out var graphProto))
|
||||
continue;
|
||||
|
||||
if (constructionProto.TargetNode is not { } targetNodeId)
|
||||
@@ -121,14 +121,17 @@ namespace Content.Client.Construction
|
||||
// If we got the id of the prototype, we exit the “recursion” by clearing the stack.
|
||||
stack.Clear();
|
||||
|
||||
if (!PrototypeManager.Resolve(entityId, out var proto))
|
||||
if (!PrototypeManager.TryIndex(constructionProto.ID, out ConstructionPrototype? recipe))
|
||||
continue;
|
||||
|
||||
var name = constructionProto.SetName.HasValue ? Loc.GetString(constructionProto.SetName) : proto.Name;
|
||||
var desc = constructionProto.SetDescription.HasValue ? Loc.GetString(constructionProto.SetDescription) : proto.Description;
|
||||
if (!PrototypeManager.TryIndex(entityId, out var proto))
|
||||
continue;
|
||||
|
||||
constructionProto.Name = name;
|
||||
constructionProto.Description = desc;
|
||||
var name = recipe.SetName.HasValue ? Loc.GetString(recipe.SetName) : proto.Name;
|
||||
var desc = recipe.SetDescription.HasValue ? Loc.GetString(recipe.SetDescription) : proto.Description;
|
||||
|
||||
recipe.Name = name;
|
||||
recipe.Description = desc;
|
||||
|
||||
_recipesMetadataCache.Add(constructionProto.ID, entityId);
|
||||
} while (stack.Count > 0);
|
||||
@@ -169,7 +172,7 @@ namespace Content.Client.Construction
|
||||
"construction-ghost-examine-message",
|
||||
("name", component.Prototype.Name)));
|
||||
|
||||
if (!PrototypeManager.Resolve(component.Prototype.Graph, out var graph))
|
||||
if (!PrototypeManager.TryIndex(component.Prototype.Graph, out var graph))
|
||||
return;
|
||||
|
||||
var startNode = graph.Nodes[component.Prototype.StartNode];
|
||||
|
||||
@@ -510,7 +510,7 @@ namespace Content.Client.Construction.UI
|
||||
|
||||
foreach (var id in favorites)
|
||||
{
|
||||
if (_prototypeManager.TryIndex(id, out ConstructionPrototype? recipe))
|
||||
if (_prototypeManager.TryIndex(id, out ConstructionPrototype? recipe, logError: false))
|
||||
_favoritedRecipes.Add(recipe);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
Name="IconLabel"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
StyleClasses="LabelSubText"
|
||||
Align="Right"
|
||||
StyleClasses="contextMenuIconLabel"
|
||||
Visible="false"/>
|
||||
</SpriteView>
|
||||
<RichTextLabel
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
{
|
||||
public const string StyleClassContextMenuButton = "contextMenuButton";
|
||||
public const string StyleClassContextMenuExpansionTexture = "contextMenuExpansionTexture";
|
||||
public const string StyleClassEntityMenuIconLabel = "contextMenuIconLabel";
|
||||
|
||||
public const float ElementMargin = 2;
|
||||
public const float ElementHeight = 32;
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
RootMenu.MenuBody.RemoveAllChildren();
|
||||
RootMenu.MenuBody.DisposeAllChildren();
|
||||
CancelOpen?.Cancel();
|
||||
CancelClose?.Cancel();
|
||||
OnContextClosed?.Invoke();
|
||||
|
||||
@@ -293,7 +293,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
var element = new EntityMenuElement(entity);
|
||||
element.SubMenu = new ContextMenuPopup(_context, element);
|
||||
element.SubMenu.OnPopupOpen += () => _verb.OpenVerbMenu(entity, popup: element.SubMenu);
|
||||
element.SubMenu.OnPopupHide += element.SubMenu.MenuBody.RemoveAllChildren;
|
||||
element.SubMenu.OnPopupHide += element.SubMenu.MenuBody.DisposeAllChildren;
|
||||
_context.AddElement(menu, element);
|
||||
Elements.TryAdd(entity, element);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using Content.Shared.Crayon;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Client.Crayon
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class CrayonComponent : SharedCrayonComponent
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite)] public bool UIUpdateNeeded;
|
||||
[ViewVariables] public int Charges { get; set; }
|
||||
[ViewVariables] public int Capacity { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,62 +1,78 @@
|
||||
using Content.Client.Items;
|
||||
using Content.Client.Message;
|
||||
using Content.Client.Stylesheets;
|
||||
using Content.Shared.Charges.Components;
|
||||
using Content.Shared.Charges.Systems;
|
||||
using Content.Shared.Crayon;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client.Crayon;
|
||||
|
||||
public sealed class CrayonSystem : SharedCrayonSystem
|
||||
{
|
||||
[Dependency] private readonly SharedChargesSystem _charges = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
|
||||
// Didn't do in shared because I don't think most of the server stuff can be predicted.
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<CrayonComponent, ComponentHandleState>(OnCrayonHandleState);
|
||||
Subs.ItemStatus<CrayonComponent>(ent => new StatusControl(ent));
|
||||
}
|
||||
|
||||
Subs.ItemStatus<CrayonComponent>(ent => new StatusControl(ent, _charges, _entityManager));
|
||||
private static void OnCrayonHandleState(EntityUid uid, CrayonComponent component, ref ComponentHandleState args)
|
||||
{
|
||||
if (args.Current is not CrayonComponentState state) return;
|
||||
|
||||
component.Color = state.Color;
|
||||
component.SelectedState = state.State;
|
||||
component.Charges = state.Charges;
|
||||
component.Capacity = state.Capacity;
|
||||
|
||||
component.UIUpdateNeeded = true;
|
||||
}
|
||||
|
||||
private sealed class StatusControl : Control
|
||||
{
|
||||
private readonly Entity<CrayonComponent> _crayon;
|
||||
private readonly SharedChargesSystem _charges;
|
||||
private readonly CrayonComponent _parent;
|
||||
private readonly RichTextLabel _label;
|
||||
private readonly int _capacity;
|
||||
|
||||
public StatusControl(Entity<CrayonComponent> crayon, SharedChargesSystem charges, EntityManager entityManage)
|
||||
public StatusControl(CrayonComponent parent)
|
||||
{
|
||||
_crayon = crayon;
|
||||
_charges = charges;
|
||||
_capacity = entityManage.GetComponent<LimitedChargesComponent>(_crayon.Owner).MaxCharges;
|
||||
_label = new RichTextLabel { StyleClasses = { StyleClass.ItemStatus } };
|
||||
_parent = parent;
|
||||
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
|
||||
AddChild(_label);
|
||||
|
||||
parent.UIUpdateNeeded = true;
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
if (!_parent.UIUpdateNeeded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_parent.UIUpdateNeeded = false;
|
||||
|
||||
// Frontier: unlimited crayon, Delta V Port
|
||||
if (_charges.GetCurrentCharges(_crayon.Owner) == int.MaxValue)
|
||||
if (_parent.Capacity == int.MaxValue)
|
||||
{
|
||||
_label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label-unlimited",
|
||||
("color", _crayon.Comp.Color),
|
||||
("state", _crayon.Comp.SelectedState)));
|
||||
("color", _parent.Color),
|
||||
("state", _parent.SelectedState)));
|
||||
return;
|
||||
}
|
||||
// End Frontier, Delta V Port
|
||||
|
||||
_label.SetMarkup(Robust.Shared.Localization.Loc.GetString("crayon-drawing-label",
|
||||
("color",_crayon.Comp.Color),
|
||||
("state",_crayon.Comp.SelectedState),
|
||||
("charges", _charges.GetCurrentCharges(_crayon.Owner)),
|
||||
("capacity", _capacity)));
|
||||
("color",_parent.Color),
|
||||
("state",_parent.SelectedState),
|
||||
("charges", _parent.Charges),
|
||||
("capacity",_parent.Capacity)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Content.Client.Crayon.UI
|
||||
private void RefreshList()
|
||||
{
|
||||
// Clear
|
||||
Grids.RemoveAllChildren();
|
||||
Grids.DisposeAllChildren();
|
||||
|
||||
if (_decals == null || _allDecals == null)
|
||||
return;
|
||||
@@ -137,8 +137,7 @@ namespace Content.Client.Crayon.UI
|
||||
|
||||
private void ButtonOnPressed(ButtonEventArgs obj)
|
||||
{
|
||||
if (obj.Button.Name == null)
|
||||
return;
|
||||
if (obj.Button.Name == null) return;
|
||||
|
||||
_selected = obj.Button.Name;
|
||||
_autoSelected = null;
|
||||
|
||||
@@ -103,11 +103,11 @@ public sealed partial class CreditsWindow : DefaultWindow
|
||||
|
||||
var container = new BoxContainer { Orientation = LayoutOrientation.Horizontal };
|
||||
|
||||
var previousPageButton = new Button { Text = Loc.GetString("credits-window-previous-page-button") };
|
||||
var previousPageButton = new Button { Text = "Previous Page" };
|
||||
previousPageButton.OnPressed +=
|
||||
_ => PopulateAttributions(attributionsContainer, count - AttributionsSourcesPerPage);
|
||||
|
||||
var nextPageButton = new Button { Text = Loc.GetString("credits-window-next-page-button") };
|
||||
var nextPageButton = new Button { Text = "Next Page" };
|
||||
nextPageButton.OnPressed +=
|
||||
_ => PopulateAttributions(attributionsContainer, count + AttributionsSourcesPerPage);
|
||||
|
||||
@@ -261,7 +261,7 @@ public sealed partial class CreditsWindow : DefaultWindow
|
||||
foreach (var entry in CreditsManager.GetLicenses(_resourceManager).OrderBy(p => p.Name))
|
||||
{
|
||||
licensesContainer.AddChild(new Label
|
||||
{ StyleClasses = { StyleClass.LabelHeading }, Text = entry.Name });
|
||||
{ StyleClasses = { StyleBase.StyleClassLabelHeading }, Text = entry.Name });
|
||||
|
||||
// We split these line by line because otherwise
|
||||
// the LGPL causes Clyde to go out of bounds in the rendering code.
|
||||
@@ -302,7 +302,7 @@ public sealed partial class CreditsWindow : DefaultWindow
|
||||
|
||||
first = false;
|
||||
patronsContainer.AddChild(new Label
|
||||
{ StyleClasses = { StyleClass.LabelHeading }, Text = $"{tier.Key}" });
|
||||
{ StyleClasses = { StyleBase.StyleClassLabelHeading }, Text = $"{tier.Key}" });
|
||||
|
||||
var msg = string.Join(", ", tier.OrderBy(p => p.Name).Select(p => p.Name));
|
||||
|
||||
@@ -350,7 +350,7 @@ public sealed partial class CreditsWindow : DefaultWindow
|
||||
|
||||
first = false;
|
||||
ss14ContributorsContainer.AddChild(new Label
|
||||
{ StyleClasses = { StyleClass.LabelHeading }, Text = title });
|
||||
{ StyleClasses = { StyleBase.StyleClassLabelHeading }, Text = title });
|
||||
|
||||
var label = new RichTextLabel();
|
||||
var text = _resourceManager.ContentFileReadAllText($"/Credits/{path}");
|
||||
|
||||
@@ -18,6 +18,7 @@ public sealed partial class CrewManifestUi : DefaultWindow
|
||||
|
||||
public void Populate(string name, CrewManifestEntries? entries)
|
||||
{
|
||||
CrewManifestListing.DisposeAllChildren();
|
||||
CrewManifestListing.RemoveAllChildren();
|
||||
|
||||
StationNameContainer.Visible = entries != null;
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
StyleClasses="LabelBig" />
|
||||
<BoxContainer Orientation="Horizontal"
|
||||
Margin="0 0 0 5">
|
||||
<Label Text="{Loc 'crew-monitoring-ui-job-label'}"
|
||||
<Label Text="{Loc 'crew-monitoring-user-interface-job'}"
|
||||
FontColorOverride="DarkGray" />
|
||||
<TextureRect Name="PersonJobIcon"
|
||||
TextureScale="2 2"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user