# Description
This PR gently reworks the traits and loadouts system to where both
systems have a new Datafield for "Slots", which declares how many
selections the trait/loadout occupies. The actual implementation of
these differs between the two, since Traits has an actual selection
limit, while Loadouts do not(but instead respect CharacterItemGroups).
In both cases, Slots are defaulted to 1, and can be omitted in most
cases.
Where this shines particularly is in Traits, where it serves as a new
second line for trait balancing. Traits such as Accents, which are
completely worthless, otherwise would never be taken at all since they
compete with other traits for Opportunity Cost. Conversely, there's only
so many points we can increase a powerful trait to, (literally, they
cannot cost more than the current trait maximum). So traits can be made
to occupy >1 slot selections.
Slots can be defined for Item Groups as well, which is what this
datafield does on Loadouts, which both of these share. But since Traits
have two different places that their slots are used, I've opted to
create a split slot datafield for Traits. To simplify things, their
ItemGroupSlots defaults to their Slots datafield, but can be
independently changed as desired.
<details><summary><h1>Media</h1></summary>
<p>
https://github.com/user-attachments/assets/99dddfe1-76d2-445a-a94a-1998d3d39c51
</p>
</details>
# Changelog
🆑
- tweak: Accents no longer cost trait slots.
(cherry picked from commit d760c5813d5dd29b3eddebd8d671bf3ed6e86b3e)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
https://github.com/DeltaV-Station/Delta-v/pull/2948 and a bunch of other
PR's
---
# TODO
<!--
A list of everything you have to do before this PR is "complete"
You probably won't have to complete everything before merging but it's
good to leave future references
-->
- [x] fix markings causing a crash
- [x] fix displacement maps causing a crash
---
<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->
<details><summary><h1>Media</h1></summary>
<p>

https://github.com/user-attachments/assets/033bec46-24c5-44ad-8e5c-7aae2ed85b03https://github.com/user-attachments/assets/6fd647b5-2ee0-45e6-a124-9b90c35e2153

</p>
</details>
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- add: Port Thaven from DeltaV, who ported it from Impstation
(cherry picked from commit 86a8e4d940eac038505c66a1649b376f6956cade)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
Fixed up the penlights again. Made it so that the UI messages stored,
because there was an issue with the UI opening blank since the diagnoses
were already done beforehand, and they weren't readable. Further, I
updated the system to properly detect eye damage and blindess.
---
# TODO
<!--
A list of everything you have to do before this PR is "complete"
You probably won't have to complete everything before merging but it's
good to leave future references
-->
- [x] Fixed Penlights
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑 SleepyScarecrow
- fix: Fixed penlights.
(cherry picked from commit bb7e69c8ac34eab72f6b03e99ee54efff96342a1)
# Description
Removed duplicate using statements, removed unused using statements.
this will decrease the number of warnings a small bit, and decrease
unused dependency references in general.
---
# TODO
- [x] Remove double references.
- [x] Remove unused references.
---
# Changelog
🆑
- remove: double references in code
- remove: unused references in code that had double references.
Co-authored-by: ilmenwe <no@mail.com>
(cherry picked from commit 9b73c88feefff68223f083893505826dc021ddee)
# Description
This tweaks glimmer to be properly time differentiated, such that the
linear decay CVar directly corresponds 1:1 with 1 glimmer decayed
linearly per second.
(cherry picked from commit 983d3e8685622b78322895ada552d257d4c421f7)
# Description

Mfw a downstream fixes things only for themselves, leaving me to hear
hundreds of complaints constantly about bugs that I don't have the time
or manpower to fix upstream.
# Changelog
🆑
- fix: Fixed an issue that prevented players from saving item
customizations if they didn't have enough loadout points to buy the item
a second time.
- add: Traits can now define the order in which they are applied.
- fix: Fixed RGBee pushie not working.
(cherry picked from commit bf3a0ec705acb9781ca5f5c2d200857b6a964a07)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
Some coats and scrubs in loadout are branded with specific corporation
logo's.
This PR restricts specifically those items to the employers that they
are from.
Note that we have coats from other companies currently not listed as
available employers too. Perhaps we should consider adding them?
# Updated:
This PR now also includes CCVars that can disable a part, or the
entirety, of Contractors for downstreams that prefer free-form RP over
gameplay.
While I was at it, I made it so that AI and Borgs don't get Passports.
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- tweak: Restricted some corporate jackets and scrubs to that specific
corporation.
- tweak: Downstreams can now disable Contractors entirely or partially
if they prefer freeform-rp over gameplay facilitating RP
- tweak: Station AI and Borg are no longer people and don't get
passports.
(cherry picked from commit 445bdc5c1b04c9f41460fb1cc6986e736732508e)
# Description
Adds the watches, smuggler satchel, and rings from wizden.
If I fucked anything up, tell me and I'll do my best to fix it, IF I
CAN. I'll probably need some help.
Yell at me really loudly if I managed to delete the entire repo or
something
---
# TODO
- [x] Smuggler satchel
- [x] Watches
- [x] Rings
---
https://github.com/user-attachments/assets/7d1e06a7-a049-4d74-9f7e-2b8f04d1e5d1
---
# Changelog
🆑
- add: Ported Smuggler Satchels from Wizden
- add: Ported watches (both normal and gold) from Wizden
- Ported rings from Wizden
---------
Signed-off-by: bruhmogus <104110869+bruhmogus@users.noreply.github.com>
Signed-off-by: VMSolidus <evilexecutive@gmail.com>
Signed-off-by: Timfa <timfalken@hotmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: VMSolidus <evilexecutive@gmail.com>
Co-authored-by: Timfa <timfalken@hotmail.com>
(cherry picked from commit 667013f9f82b3b291641b5501421653d7f79ddbd)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
Originally started because I wanted to add some stuff to salvage, but
ended up with me porting over whitelisted borg hands, the PKA module,
and some other stuff.
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- add: Engi borgs can now carry electronics, and medical borgs can carry
organs
- add: Salvage borgs now get a PKA module
- tweak: All mining drills have had their damage turned to piercing and
have received a moderate damage buff
- tweak: Exosuit drills now swing at the same speed as normal drills
(why were they worse???)
- tweak: The RPD and RCD modules for borg have been merged into one
- tweak: Salvage can now purchase drills from their vendor
- tweak: Salvage borgs mining module no longer contains a shovel
---------
Co-authored-by: Your Name <EctoplasmIsGood@users.noreply.github.com>
Co-authored-by: Whatstone <whatston3@gmail.com>
Co-authored-by: RatherUncreative <RatherUncreativeName@proton.me>
Co-authored-by: Aidenkrz <aiden@djkraz.com>
(cherry picked from commit ed8850e551bd9c0d533d69cad262a8743442a62a)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
Adds a description to your chosen lifepath, employer or nationality.
---
<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->
<details><summary><h1>Media</h1></summary>
<p>

</p>
</details>
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- add: Moved Nationality, Employer, and Lifepath to a new Background
tab. They now also show descriptions for the chosen selections.
(cherry picked from commit 862b95e92b44f34379187111c8505395ff9f3473)
* bingle
* text change
* flash stuff
* make self heal noticable
* remove catwalk blacklist
* added ion damage
* bingle floor
* added tile spawn, but its not working correctly
* bingle pit gets more healt. for got i set it low for testing. chenges to take structual damge. added passinv healing
* bingles have less hp
* bingles have 5% less damage resistance
* added updater to sprite
* the bingle pit will now embrace its dead bingles for new life and you now need to keep humans alive for more points
* change to bingle point. bunus point if alive or crit
* sprite fix combat mode
* fix ghostrole not stacking
* for players aswell
* changed the whole upbrade to a polymorf action
* sprite for amrored dead
* bingle plushie
* bingle tile spread
* cleanup
* normal bingle no2 have 10% armor ,upgraded 20%
* more cleanup
* coderabbit recomendations
* yml linter error
* added antirotting to pit
* stuff
* removed unused code
---------
Co-authored-by: Fishbait <Fishbait@git.ml>
Co-authored-by: Aidenkrz <aiden@djkraz.com>
(cherry picked from commit 2c28b55a90f735955210b24ae4b3cdf295f0b5e4)
* bingle
* text change
* flash stuff
* make self heal noticable
* remove catwalk blacklist
* added ion damage
* bingle floor
* added tile spawn, but its not working correctly
* bingle pit gets more healt. for got i set it low for testing. chenges to take structual damge. added passinv healing
* bingles have less hp
* bingles have 5% less damage resistance
* added updater to sprite
* the bingle pit will now embrace its dead bingles for new life and you now need to keep humans alive for more points
* change to bingle point. bunus point if alive or crit
* sprite fix combat mode
* fix ghostrole not stacking
* for players aswell
* changed the whole upbrade to a polymorf action
* sprite for amrored dead
* bingle plushie
* bingle tile spread
* cleanup
* normal bingle no2 have 10% armor ,upgraded 20%
* more cleanup
* coderabbit recomendations
* yml linter error
* added antirotting to pit
* stuff
* removed unused code
---------
Co-authored-by: Fishbait <Fishbait@git.ml>
Co-authored-by: Aidenkrz <aiden@djkraz.com>
(cherry picked from commit aa50652bcc43da05670fa7ae809ef27dd00941bd)
* bingle
* text change
* flash stuff
* make self heal noticable
* remove catwalk blacklist
* added ion damage
* bingle floor
* added tile spawn, but its not working correctly
* bingle pit gets more healt. for got i set it low for testing. chenges to take structual damge. added passinv healing
* bingles have less hp
* bingles have 5% less damage resistance
* added updater to sprite
* the bingle pit will now embrace its dead bingles for new life and you now need to keep humans alive for more points
* change to bingle point. bunus point if alive or crit
* sprite fix combat mode
* fix ghostrole not stacking
* for players aswell
* changed the whole upbrade to a polymorf action
* sprite for amrored dead
* bingle plushie
* bingle tile spread
* cleanup
* normal bingle no2 have 10% armor ,upgraded 20%
* more cleanup
* coderabbit recomendations
* yml linter error
* added antirotting to pit
* stuff
* removed unused code
---------
Co-authored-by: Fishbait <Fishbait@git.ml>
Co-authored-by: Aidenkrz <aiden@djkraz.com>
(cherry picked from commit 0fd6f52c5a579a598b7f62b5bae53d4f0243c420)
* bingle
* text change
* flash stuff
* make self heal noticable
* remove catwalk blacklist
* added ion damage
* bingle floor
* added tile spawn, but its not working correctly
* bingle pit gets more healt. for got i set it low for testing. chenges to take structual damge. added passinv healing
* bingles have less hp
* bingles have 5% less damage resistance
* added updater to sprite
* the bingle pit will now embrace its dead bingles for new life and you now need to keep humans alive for more points
* change to bingle point. bunus point if alive or crit
* sprite fix combat mode
* fix ghostrole not stacking
* for players aswell
* changed the whole upbrade to a polymorf action
* sprite for amrored dead
* bingle plushie
* bingle tile spread
* cleanup
* normal bingle no2 have 10% armor ,upgraded 20%
* more cleanup
* coderabbit recomendations
* yml linter error
* added antirotting to pit
* stuff
* removed unused code
---------
Co-authored-by: Fishbait <Fishbait@git.ml>
Co-authored-by: Aidenkrz <aiden@djkraz.com>
(cherry picked from commit bc3f9319c11bcbe7fd266fee87044ad96f74d640)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
Contractors v1 is the first version of a system that will allow you to
set a nationality and an employer to your character. Initially, this
will determine the availability of some loadout items, jobs and traits,
but this is built to expand upon later.
As of this moment, the PR will let you select a nationality, an employer
and a lifepath. Nationalities give you a language and a passport, while
the other two don't do a lot yet. (except Command can only be NanoTrasen
and most other jobs can't be unemployed)
The passport functions, and the CharacterRequirements do as well.
there's still a lot more that can be done--tying jobs to certain
employers, items or traits to nationalities or lifepaths, but the reason
I want to merge it before that's done is primarily so that I don't need
to be the sole person working on it anymore. The C# is done, the rest is
YAML, and we have a bunch of competent YAML warriors who will do great
stuff with this, no doubt.
---
# TODO
<!--
A list of everything you have to do before this PR is "complete"
You probably won't have to complete everything before merging but it's
good to leave future references
-->
- [x] Create Nationality and Employer Prototype code
- [x] Create Nationality and Employer Character Requirements
- [x] Add both fields to the Character Creation menu
- [x] Create Nationality and Employer Prototypes
- [x] Create Nationality and Employer Prototypes YAML
- [x] Add requirements to a few jobs
- [ ] Add requirements to a few traits
- [ ] Add requirements to a few loadout items
- [x] create a passport item that can be opened and closed
- [x] Give each nationality a passport item valid for their species
---
<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->
<details><summary><h1>Media</h1></summary>
<p>

https://github.com/user-attachments/assets/9e61aed8-2e07-4d44-89c7-595a170df8c7
</p>
</details>
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- add: Contractors. Be sure to edit your character to set an employer
and nationality!
- add: Nationality, Lifepath, and Employer have been added to character
creation. These don't currently do much except spawn a passport
containing information about where your character is from and who they
are, but they are fully integrated with Character Requirements, and by
extension can be used for and alongside Traits, Loadouts, Jobs,
Antagonists, etc.
---------
Signed-off-by: Timfa <timfalken@hotmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: VMSolidus <evilexecutive@gmail.com>
(cherry picked from commit c3b12c62ee3bd226b57022690d1b24cb7cf54e3f)
* prevent borgs from using locks
* e
* bru
* a
* blacklist borgs and robotics console
* frogro
* add IsAllowed to EntityWhitelistSystem
* use IsAllowed
* move thing to new LockingWhitelistSystem
* :trollface:
* review
* use renamed CheckBoth in locking whitelist
* remove unused stuff and add more to doc
* Use target entity instead to remove self check
* Rename to _whitelistSystem
* Add deny lock toggle popup
* Prevent duplicate checks and popups
* Fix wrong entity in popup when toggling another borg
* Make new event
* Update comment to user for new event
---------
Co-authored-by: deltanedas <@deltanedas:kde.org>
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
(cherry picked from commit 8f6326c3e0b04af30171d2435962b89105d67f31)
(cherry picked from commit 78afbb211026afeefc20c253de5e8d03f8d0f9b0)
* Give jobs & antags prototypes a guide field
* A
* space
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
* Add todo
* Fix merge errors
---------
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
(cherry picked from commit e7f2ae52ab24dddc8f3c94cb84b751482700e3da)
(cherry picked from commit 4cee20b913a1de0cd6f8ee7d02c2bf55e3e75298)
* Borg type switching.
This allows borgs (new spawn or constructed) to select their chassis type on creation, like in SS13. This removes the need for the many different chassis types, and means round-start borgs can actually play the game immediately instead of waiting for science to unlock everything.
New borgs have an additional action that allows them to select their type. This opens a nice window with basic information about the borgs and a select button. Once a type has been selected it is permanent for that borg chassis.
These borg types also immediately start the borg with specific modules, so they do not need to be printed. Additional modules can still be inserted for upgrades, though this is now less critical. The built-in modules cannot be removed, but are shown in the UI.
The modules that each borg type starts with:
* Generic: tools
* Engineering: advanced tools, construction, RCD, cable
* Salvage: Grappling gun, appraisal, mining
* Janitor: cleaning, light replacer
* Medical: treatment
* Service: music, service, clowning
Specialized borgs have 3 additional module slots available on top of the ones listed above, generic borgs have 5.
Borg types are specified in a new BorgTypePrototype. These prototypes specify all information about the borg type. It is assigned to the borg entity through a mix of client side, server, and shared code. Some of the involved components were made networked, others are just ensured they're set on both sides of the wire.
The most gnarly change is the inventory template prototype, which needs to change purely to modify the borg hat offset. I managed to bodge this in with an API that *probably* won't explode for specifically for this use case, but it's still not the most clean of API designs.
Parts for specific borg chassis have been removed (so much deleted YAML) and specialized borg modules that are in the base set of a type have been removed from the exosuit fab as there's no point to printing those.
The ability to "downgrade" a borg so it can select a new chassis, like in SS13, is something that would be nice, but was not high enough priority for me to block the feature on. I did keep it in mind with some of the code, so it may be possible in the future.
There is no fancy animation when selecting borg types like in SS13, because I didn't think it was high priority, and it would add a lot of complex code.
* Fix sandbox failure due to collection expression.
* Module tweak
Fix salvage borg modules still having research/lathe recipes
Engie borg has regular tool module, not advanced.
* Fix inventory system breakage
* Fix migrations
Some things were missing
* Guidebook rewordings & review
* MinWidth on confirm selection button
(cherry picked from commit 1bebb3390ccedfdae173f0f681be6578146057ca)
(cherry picked from commit 44ca0d5228e4b3faf507a5915007f956c8475541)
# Description
This PR fixes all remaining bugs with Space Wind, while providing
extremely significant performance improvements by way of aggressive
early exits, and also completely reworking how pressure moved entities
are tracked(The server now caches entities under active air movements).
I haven't profiled it yet, but the performance improvements are
extremely noticeable on the machine I'm running in comparison to before,
which is particularly noteworthy since previous versions of space wind
caused significant frame drops in testing on my monster rig. While this
new update to space wind straight up doesn't even budge the tickrate on
my machine anymore.
I had to also rip out some of Monstermos' Guts, and deprecate the
tileripping system. In the future, Tile-ripping will be handled by MAS.
Also, MAS outright no longer requires Monstermos to work, and can
operate entirely off of the much cheaper LINDA system. However, while
LINDA is cheaper, Monstermos is needed for handling "Extra violent air".
Eventually I can do away with Monstermos entirely, and have it replaced
with an airflow system that outright does not require pathfinding
algorithms.
# Changelog
🆑
- fix: Fixed a bug where items thrown by space wind could remain in air
for as long as 500 seconds. Items thrown by space wind can now remain in
the air for a maximum of 2 seconds past the last time they were thrown.
- fix: DRAMATICALLY IMPROVED SPACE WIND PERFORMANCE.
- tweak: ShowAtmos command now shows vectors representing the exact
direction space wind at a given tile is trying to throw objects! The
length of the lines shown directly correspond to how powerful the flow
of air is at that tile. Shorter lines = shorter throws. Longer lines =
more powerful throws. These are also no longer restricted to compass
directions, and can point in arbitrarily any direction on a circle.
- tweak: Space Wind now no longer has Monstermos as a hard requirement.
It'll be as weak as a toddler without it, but if you're running your
server on a toaster, you can turn off Monstermos and still have working
space wind.
- tweak: Wreckages in space are now never airtight. I'm sorry, but this
was basically the cost I had to pay in exchange for making Atmos no
longer even on the top 20 systems for server tickrate cost.
(cherry picked from commit 2fcc806423a259fd75977b78350c2232a823739b)
* Кто такой Игорь Спичкин igorsaux?
* чуть чуть поменьше интенсивности
* slider feat SentryPrimies + small refactor
* revert ccvars.cs
* ladno max 250 eto mnoga
* AMerika burger truck freedom gun
* I hate it
* Added ability to choose target body part on item throwing
* забыл
* WeaponRandom works with throwable weapon
* RadialEntityMorph & RadialBUI fix
* ru&en localization
* Я себя зарежу нахуй за такое
* Правки рисованной хуйни и прототипы с лодаутами
* fuck
* ну хорошо блять, убедил, одну пустую строчку уберу
* loadout move to _White
* Я после тех 3х банок не помню нахуй это нужно было
* 1 more fix
Rather than doing goofy hacks we just use what sprites are near the
mouse.
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->
# Description
<!--
Explain this PR in as much detail as applicable
Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->
https://github.com/space-wizards/space-station-14/pull/31792
<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->
<details><summary><h1>Media</h1></summary>
<p>

</p>
</details>
---
# Changelog
<!--
You can add an author after the `🆑` to change the name that appears
in the changelog (ex: `🆑 Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->
🆑
- tweak: Make context menu uses spritetree
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
(cherry picked from commit fb2416bab432486114e8904304fb76b3323fe95b)