Skip to content

Commit

Permalink
Implement the assembly patch of 4zot on SetStat (FAForever#5240)
Browse files Browse the repository at this point in the history
  • Loading branch information
Garanas authored Aug 29, 2023
1 parent 5115d92 commit ab6bde0
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 22 deletions.
8 changes: 4 additions & 4 deletions engine/User/UserUnit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ end
function UserUnit:GetShieldRatio()
end

---
---@generic T
--- Retrieves a statistic that is assigned to a unit by the sim call `unit:UpdateStat`. Returns the default
--- when the value does not exist
---@param name string
---@param defaultVal? T
---@return {Value: T}
---@param defaultVal? number
---@return {Value: number}
function UserUnit:GetStat(name, defaultVal)
end

Expand Down
12 changes: 6 additions & 6 deletions lua/defaultcomponents.lua
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,8 @@ VeterancyComponent = ClassSimple {

-- optionally, these fields are defined too to inform UI of our veterancy status
if blueprint.VetEnabled then
self:SetStat('VetLevel', self:GetStat('VetLevel', 0).Value)
self:SetStat('VetExperience', self:GetStat('VetExperience', 0).Value)
self:UpdateStat('VetLevel', 0)
self:UpdateStat('VetExperience', 0)
self.VetExperience = 0
self.VetLevel = 0
end
Expand Down Expand Up @@ -660,7 +660,7 @@ VeterancyComponent = ClassSimple {
if currLevel > 4 then
currExperience = currExperience + experience
self.VetExperience = currExperience
self:SetStat('VetExperience', currExperience)
self:UpdateStat('VetExperience', currExperience)
return
end

Expand All @@ -675,7 +675,7 @@ VeterancyComponent = ClassSimple {

currExperience = currExperience + experience
self.VetExperience = currExperience
self:SetStat('VetExperience', currExperience)
self:UpdateStat('VetExperience', currExperience)

while currLevel < 5 and upperThreshold and upperThreshold <= experience do
self:AddVetLevel()
Expand All @@ -691,7 +691,7 @@ VeterancyComponent = ClassSimple {

currExperience = currExperience + experience
self.VetExperience = currExperience
self:SetStat('VetExperience', currExperience)
self:UpdateStat('VetExperience', currExperience)

if upperThreshold <= currExperience then
self:AddVetLevel()
Expand All @@ -709,7 +709,7 @@ VeterancyComponent = ClassSimple {

local nextLevel = self.VetLevel + 1
self.VetLevel = nextLevel
self:SetStat('VetLevel', nextLevel)
self:UpdateStat('VetLevel', nextLevel)

-- shared across all units
Buff.ApplyBuff(self, 'VeterancyMaxHealth' .. nextLevel)
Expand Down
6 changes: 3 additions & 3 deletions lua/sim/Projectile.lua
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ Projectile = ClassProjectile(ProjectileMethods) {
launcher:OnMissileIntercepted(self:GetCurrentTargetPosition(), instigator, self:GetPosition())

-- keep track of the number of intercepted missiles
-- if not IsDestroyed(instigator) then
-- instigator:SetStat('KILLS', instigator:GetStat('KILLS', 0).Value + 1)
-- end
if not IsDestroyed(instigator) then
instigator:UpdateStat('KILLS', instigator:GetStat('KILLS', 0).Value + 1)
end
end

self:CreateImpactEffects(self.Army, self.FxOnKilled, self.FxOnKilledScale)
Expand Down
40 changes: 31 additions & 9 deletions lua/sim/Unit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,15 @@ Unit = ClassUnit(moho.unit_methods, IntelComponent, VeterancyComponent) {
end

-- for syncing data to UI
self:GetStat("HitpointsRegeneration", bp.Defense.RegenRate)
self:SetStat("HitpointsRegeneration", bp.Defense.RegenRate)
self:UpdateStat("HitpointsRegeneration", bp.Defense.RegenRate)
self:UpdateStat("HitpointsRegeneration", bp.Defense.RegenRate)

-- add support for keeping track of reclaim statistics
if self.Blueprint.General.CommandCapsHash['RULEUCC_Reclaim'] then
self.ReclaimedMass = 0
self.ReclaimedEnergy = 0
self:GetStat("ReclaimedMass", 0)
self:GetStat("ReclaimedEnergy", 0)
self:UpdateStat("ReclaimedMass", 0)
self:UpdateStat("ReclaimedEnergy", 0)
end

-- add support for automated jamming reset
Expand Down Expand Up @@ -855,8 +855,8 @@ Unit = ClassUnit(moho.unit_methods, IntelComponent, VeterancyComponent) {
end

-- update UI
self:SetStat('ReclaimedMass', self.ReclaimedMass)
self:SetStat('ReclaimedEnergy', self.ReclaimedEnergy)
self:UpdateStat('ReclaimedMass', self.ReclaimedMass)
self:UpdateStat('ReclaimedEnergy', self.ReclaimedEnergy)
end

-- reset reclaiming state
Expand Down Expand Up @@ -4286,7 +4286,7 @@ Unit = ClassUnit(moho.unit_methods, IntelComponent, VeterancyComponent) {
---@param value number
SetRegen = function(self, value)
self:SetRegenRate(value)
self:SetStat("HitpointsRegeneration", value)
self:UpdateStat("HitpointsRegeneration", value)
end,

-------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -4838,6 +4838,28 @@ Unit = ClassUnit(moho.unit_methods, IntelComponent, VeterancyComponent) {
cUnit.GiveNukeSiloAmmo(self, blocks, true)
end,

--- Use `unit:UpdateStat` instead
---@deprecated
SetStat = function(self)
-- this hides the c implementation
end,

--- Updates a statistic that you can retrieve on the UI side using `userunit:GetStat`.
--- Relies on an assembly patch to be functional, without it this setup causes the game to crash.
---@param self Unit
---@param key string
---@param value number
UpdateStat = function(self, key, value)
-- With thanks to 4z0t the `SetStat` function no longer hard-crashes when the value doesn't exist. Instead, it returns 'true'
-- when the stat doesn't exist. If it doesn't exist then we can use `GetStat` to initialize it. This makes no sense, therefore
-- we have this new function to hide the magic
local needsSetup = cUnit.SetStat(self, key, value)
if needsSetup then
cUnit.GetStat(self, key, value)
cUnit.SetStat(self, key, value)
end
end,

---@param self Unit
---@return UnitCommand[]
GetCommandQueue = function(self)
Expand Down Expand Up @@ -4895,7 +4917,7 @@ Unit = ClassUnit(moho.unit_methods, IntelComponent, VeterancyComponent) {
self.EngineCommandCap = { }
end

self.EngineCommandCap[capName] = true
self.EngineCommandCap[capName] = true
cUnit.AddCommandCap(self, capName)
end,

Expand All @@ -4907,7 +4929,7 @@ Unit = ClassUnit(moho.unit_methods, IntelComponent, VeterancyComponent) {
if self.EngineCommandCap then
self.EngineCommandCap[capName] = nil
end

cUnit.RemoveCommandCap(self, capName)
end,

Expand Down

0 comments on commit ab6bde0

Please sign in to comment.