From 0f8461820db2c5cd12f1a05d86897da8ec924044 Mon Sep 17 00:00:00 2001 From: comradeshook Date: Sat, 7 Dec 2024 13:58:15 +0100 Subject: [PATCH 1/3] Optimise laser rifle --- .../Devices/Weapons/LaserRifle/LaserRifle.lua | 130 ++++++++++-------- 1 file changed, 76 insertions(+), 54 deletions(-) diff --git a/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua b/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua index 484a06c7e6..ffde2c0e2b 100644 --- a/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua +++ b/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua @@ -1,36 +1,51 @@ +local function InsertParticle(var, particle) + var.addedParticleCount = var.addedParticleCount + 1; + var.addedParticles[var.addedParticleCount] = particle; +end + +local function emitSmoke(self, particleCount) + local var = self.var; + local MuzzlePos = self.MuzzlePos; + for i = 1, particleCount do + local smoke = CreateMOSParticle("Tiny Smoke Ball 1" .. (math.random() < 0.5 and " Glow Blue" or ""), "Base.rte"); + smoke.Pos = MuzzlePos; + smoke.Lifetime = smoke.Lifetime * RangeRand(0.5, 1.0); + smoke.Vel = var.Vel * 0.5 + Vector(RangeRand(0, i), 0):RadRotate(RangeRand(-math.pi, math.pi)); + InsertParticle(var, smoke); + end + self:RequestSyncedUpdate(); +end + function Create(self) - self.range = math.sqrt(FrameMan.PlayerScreenWidth^2 + FrameMan.PlayerScreenHeight^2)/2; - self.penetrationStrength = 170; - self.strengthVariation = 5; + -- Create local table to store variables for performance + local var = {}; + + var.range = math.sqrt(FrameMan.PlayerScreenWidth^2 + FrameMan.PlayerScreenHeight^2)/2; + var.penetrationStrength = 170; + var.strengthVariation = 5; --This value tracks the shots and varies the penetration strength to create a "resistance" effect on tougher materials - self.shotCounter = 0; --TODO: Rename/describe this variable better - self.activity = ActivityMan:GetActivity(); + var.shotCounter = 0; --TODO: Rename/describe this variable better + var.activity = ActivityMan:GetActivity(); - self.cooldown = Timer(); - self.cooldownSpeed = 0.5; + var.cooldown = Timer(); + var.cooldownSpeed = 0.5; - self.addedParticles = {}; + var.addedParticles = {}; + var.addedParticleCount = 0; - self.addedWound = nil; - self.addedWoundOffset = nil; - self.addedWoundToUniqueID = nil; + var.addedWound = nil; + var.addedWoundOffset = nil; + var.addedWoundToUniqueID = nil; + var.Vel = self.Vel; - function self.emitSmoke(particleCount) - for i = 1, particleCount do - local smoke = CreateMOSParticle("Tiny Smoke Ball 1" .. (math.random() < 0.5 and " Glow Blue" or ""), "Base.rte"); - smoke.Pos = self.MuzzlePos; - smoke.Lifetime = smoke.Lifetime * RangeRand(0.5, 1.0); - smoke.Vel = self.Vel * 0.5 + Vector(RangeRand(0, i), 0):RadRotate(RangeRand(-math.pi, math.pi)); - table.insert(self.addedParticles, smoke); - end - self:RequestSyncedUpdate(); - end + self.var = var; end function ThreadedUpdate(self) + local var = self.var; if self.FiredFrame then local actor = self:GetRootParent(); - local range = self.range + math.random(8); + local range = var.range + math.random(8); if IsActor(actor) then actor = ToActor(actor); range = range + actor.AimDistance; @@ -52,12 +67,12 @@ function ThreadedUpdate(self) skipPx = 1; local shortRay = SceneMan:CastObstacleRay(gapPos, Vector(trace.X, trace.Y):SetMagnitude(range - rayLength + skipPx), hitPos, gapPos, actor.ID, self.Team, rte.airID, skipPx); gapPos = gapPos - Vector(trace.X, trace.Y):SetMagnitude(skipPx); - local strengthFactor = math.max(1 - rayLength/self.range, math.random()) * (self.shotCounter + 1)/self.strengthVariation; + local strengthFactor = math.max(1 - rayLength/var.range, math.random()) * (var.shotCounter + 1)/var.strengthVariation; - self.addedWoundToMOID = SceneMan:GetMOIDPixel(hitPos.X, hitPos.Y); - if self.addedWoundToMOID ~= rte.NoMOID and self.addedWoundToMOID ~= self.ID then - local mo = ToMOSRotating(MovableMan:GetMOFromID(self.addedWoundToMOID)); - if self.penetrationStrength * strengthFactor >= mo.Material.StructuralIntegrity then + local addedWoundToMOID = SceneMan:GetMOIDPixel(hitPos.X, hitPos.Y); + if addedWoundToMOID ~= rte.NoMOID and addedWoundToMOID ~= self.ID then + local mo = ToMOSRotating(MovableMan:GetMOFromID(addedWoundToMOID)); + if var.penetrationStrength * strengthFactor >= mo.Material.StructuralIntegrity then local moAngle = -mo.RotAngle * mo.FlipFactor; local woundName = mo:GetEntryWoundPresetName(); @@ -68,9 +83,9 @@ function ThreadedUpdate(self) local woundOffset = Vector(dist.X * mo.FlipFactor, dist.Y):RadRotate(moAngle):SetMagnitude(dist.Magnitude - (wound.Radius - 1) * wound.Scale); wound.InheritedRotAngleOffset = woundOffset.AbsRadAngle; woundOffset = woundOffset:RadRotate(-mo.RotAngle); - self.addedWound = wound; - self.addedWoundOffset = woundOffset; - self.addedWoundToUniqueID = mo.UniqueID; + var.addedWound = wound; + var.addedWoundOffset = woundOffset; + var.addedWoundToUniqueID = mo.UniqueID; self:RequestSyncedUpdate(); end end @@ -80,19 +95,19 @@ function ThreadedUpdate(self) smoke.Pos = gapPos; smoke.Vel = Vector(-trace.X, -trace.Y):SetMagnitude(math.random(3, 6)):RadRotate(RangeRand(-1.5, 1.5)); smoke.Lifetime = smoke.Lifetime * strengthFactor; - table.insert(self.addedParticles, smoke); + InsertParticle(var, smoke); local pix = CreateMOPixel("Laser Rifle Glow " .. math.floor(strengthFactor * 4 + 0.5), "Techion.rte"); pix.Pos = gapPos; - pix.Sharpness = self.penetrationStrength/6; + pix.Sharpness = var.penetrationStrength/6; pix.Vel = Vector(trace.X, trace.Y):SetMagnitude(6); - table.insert(self.addedParticles, pix); + InsertParticle(var, pix); end if rayLength ~= 0 then trace = SceneMan:ShortestDistance(startPos, gapPos, SceneMan.SceneWrapsX); for player = Activity.PLAYER_1, Activity.MAXPLAYERCOUNT - 1 do - local team = self.activity:GetTeamOfPlayer(player); - local screen = self.activity:ScreenOfPlayer(player); + local team = var.activity:GetTeamOfPlayer(player); + local screen = var.activity:ScreenOfPlayer(player); if screen ~= -1 and not (SceneMan:IsUnseen(startPos.X, startPos.Y, team) or SceneMan:IsUnseen(hitPos.X, hitPos.Y, team)) then PrimitiveMan:DrawLinePrimitive(screen, startPos, startPos + trace, 254); end @@ -101,48 +116,55 @@ function ThreadedUpdate(self) for i = 0, particleCount do local pix = CreateMOPixel("Laser Rifle Glow 0", "Techion.rte"); pix.Pos = startPos + trace * i/particleCount; - pix.Vel = self.Vel; - table.insert(self.addedParticles, pix); + pix.Vel = var.Vel; + InsertParticle(var, pix); end end - self.shotCounter = (self.shotCounter + 1) % self.strengthVariation; - self.cooldown:Reset(); + var.shotCounter = (var.shotCounter + 1) % var.strengthVariation; + var.cooldown:Reset(); end if self.Magazine and self.Magazine.RoundCount > 0 then local ammoRatio = 1 - self.Magazine.RoundCount/self.Magazine.Capacity; - self.emitSmoke(math.floor(ammoRatio * RangeRand(0.5, 2.0) + RangeRand(0.25, 0.50))); - self.cooldown:SetSimTimeLimitMS(self.ReloadTime * ammoRatio); + emitSmoke(self, math.floor(ammoRatio * RangeRand(0.5, 2.0) + RangeRand(0.25, 0.50))); + var.cooldown:SetSimTimeLimitMS(self.ReloadTime * ammoRatio); - local cooldownRate = math.floor(self.cooldown.ElapsedSimTimeMS/(60000/(self.RateOfFire * self.cooldownSpeed))); + local cooldownRate = math.floor(var.cooldown.ElapsedSimTimeMS/(60000/(self.RateOfFire * var.cooldownSpeed))); if ammoRatio ~= 0 and cooldownRate >= 1 then self.Magazine.RoundCount = math.min(self.Magazine.RoundCount + cooldownRate, self.Magazine.Capacity); - self.cooldown:Reset(); + var.cooldown:Reset(); end self.FireSound.Pitch = (1.0 - ammoRatio * 0.1)^2; elseif self:IsReloading() then - self.emitSmoke(math.floor((self.cooldown:LeftTillSimTimeLimitMS()/self.ReloadTime) * RangeRand(0.5, 2.0) + RangeRand(0.50, 0.75))); + emitSmoke(self, math.floor((var.cooldown:LeftTillSimTimeLimitMS()/self.ReloadTime) * RangeRand(0.5, 2.0) + RangeRand(0.50, 0.75))); elseif self.RoundInMagCount >= 0 then self:Reload(); end end +-- Localize function to improve performance +local AddParticle = MovableMan.AddParticle; + function SyncedUpdate(self) - if self.addedWound then - local mo = MovableMan:FindObjectByUniqueID(self.addedWoundToUniqueID); + local var = self.var; + if var.addedWound then + local mo = MovableMan:FindObjectByUniqueID(var.addedWoundToUniqueID); if mo then mo = ToMOSRotating(mo); - mo:AddWound(self.addedWound, self.addedWoundOffset, true); + mo:AddWound(var.addedWound, var.addedWoundOffset, true); end - self.addedWound = nil; - self.addedWoundOffset = nil; - self.addedWoundToMOID = nil; - self.addedWoundToUniqueID = nil; + var.addedWound = nil; + var.addedWoundOffset = nil; + var.addedWoundToUniqueID = nil; end - for i = 1, #self.addedParticles do - MovableMan:AddParticle(self.addedParticles[i]); + if (var.addedParticleCount > 0) then + for i = 1, var.addedParticleCount do + -- Remember to add function caller as first argument to localized function + AddParticle(MovableMan, var.addedParticles[i]); + end + var.addedParticles = {}; + var.addedParticleCount = 0; end - self.addedParticles = {}; end \ No newline at end of file From 397d4cdd7109a7bebf42ab7de88730eed5ee5dfa Mon Sep 17 00:00:00 2001 From: comradeshook Date: Sat, 7 Dec 2024 16:13:30 +0100 Subject: [PATCH 2/3] Optimised Techion laser rifle performance dramatically, and dihelical cannon/disintegration effect slightly --- .../Devices/Shared/Scripts/Disintegrator.lua | 5 +- .../Weapons/DihelicalCannon/DihelicalShot.lua | 86 ++++++++++--------- .../Devices/Weapons/LaserRifle/LaserRifle.lua | 22 +++-- 3 files changed, 64 insertions(+), 49 deletions(-) diff --git a/Data/Techion.rte/Devices/Shared/Scripts/Disintegrator.lua b/Data/Techion.rte/Devices/Shared/Scripts/Disintegrator.lua index 5ce31b1a51..afb4149336 100644 --- a/Data/Techion.rte/Devices/Shared/Scripts/Disintegrator.lua +++ b/Data/Techion.rte/Devices/Shared/Scripts/Disintegrator.lua @@ -124,10 +124,13 @@ function Update(self) for i = 1, radius do if math.random(radius) > i then - local piece = CreateMOSParticle("Techion.rte/White Goo Particle"); + local piece; if math.random() < 0.3 then piece = CreateMOPixel("Techion.rte/Nanogoo " .. math.random(6)); + else + piece = CreateMOSParticle("Techion.rte/White Goo Particle"); end + local offset = Vector(mo.Radius * mo.Scale * RangeRand(0, 0.5), 0):RadRotate(6.28 * math.random()); piece.Pos = mo.Pos + offset; piece.Vel = mo.Vel + offset:SetMagnitude(RangeRand(radius, radius * 2)/math.sqrt(1 + offset.Magnitude)); diff --git a/Data/Techion.rte/Devices/Weapons/DihelicalCannon/DihelicalShot.lua b/Data/Techion.rte/Devices/Weapons/DihelicalCannon/DihelicalShot.lua index c8bb178bbb..1cfc03b0a7 100644 --- a/Data/Techion.rte/Devices/Weapons/DihelicalCannon/DihelicalShot.lua +++ b/Data/Techion.rte/Devices/Weapons/DihelicalCannon/DihelicalShot.lua @@ -1,53 +1,59 @@ function Create(self) + local var = {}; + --Range of the shot. - self.range = 600; + var.range = 600; --Amplitude of the wave. - self.maxAmplitude = math.floor(1 + math.sqrt(self.Vel.Magnitude) + 0.5); + var.maxAmplitude = math.floor(1 + math.sqrt(self.Vel.Magnitude) + 0.5); --Wavelength of the wave. - self.flaceLength = math.floor(3 + math.sqrt(self.Vel.Magnitude) + 0.5); + var.flaceLength = math.floor(3 + math.sqrt(self.Vel.Magnitude) + 0.5); --Track intersecting beams - self.lastAmplitude = 1; + var.lastAmplitude = 1; --Speed of the wave (pixels per second). - self.speed = self.Vel.Magnitude * 10; + var.speed = self.Vel.Magnitude * 10; --Speed of damage particles. - self.damageSpeed = 50 + self.Vel.Magnitude * 0.1; + var.damageSpeed = 50 + self.Vel.Magnitude * 0.1; --Maximum strength for material penetration (both MOs and terrain). - self.strengthThreshold = 50 + self.Vel.Magnitude * 0.3; + var.strengthThreshold = 50 + self.Vel.Magnitude * 0.3; --Direction of the wave. - self.direction = Vector(self.Vel.X, self.Vel.Y); - self.direction:SetMagnitude(1); - self.up = Vector(self.direction.X, self.direction.Y); - self.up:RadRotate(math.pi * 0.5); + var.direction = Vector(self.Vel.X, self.Vel.Y); + var.direction:SetMagnitude(1); + var.up = Vector(var.direction.X, var.direction.Y); + var.up:RadRotate(math.pi * 0.5); --Interval at which to create damage particles. - self.damageInterval = 3; + var.damageInterval = 3; --Timer for the wave. - self.timer = Timer(); + var.timer = Timer(); --The last starting position along the line. - self.lastI = 0; + var.lastI = 0; --Count MO and terrain hits. - self.hits = 0; + var.hits = 0; --Disintegration strength. - self.disintegrationStrength = 500; + var.disintegrationStrength = 500; - self.melter = CreateMOPixel("Disintegrator", "Techion.rte"); + var.melter = CreateMOPixel("Disintegrator", "Techion.rte"); + + var.Pos = self.Pos; + self.var = var; end function Update(self) - local endPoint = self.timer.ElapsedSimTimeS * self.speed; - if endPoint > self.range then - endPoint = self.range; + local var = self.var; + local endPoint = var.timer.ElapsedSimTimeS * var.speed; + if endPoint > var.range then + endPoint = var.range; self.ToDelete = true; else self.ToDelete = false; @@ -57,21 +63,21 @@ function Update(self) endPoint = math.floor(endPoint); --Draw out the path. - for i = self.lastI, endPoint, 1 do - local amplitude = math.sin((i/self.flaceLength) * 2 * math.pi) * self.maxAmplitude; - local waveOffset = Vector(self.up.X, self.up.Y); + for i = var.lastI, endPoint, 1 do + local amplitude = math.sin((i/var.flaceLength) * 2 * math.pi) * var.maxAmplitude; + local waveOffset = Vector(var.up.X, var.up.Y); waveOffset:SetMagnitude(amplitude); - local linePos = self.Pos + Vector(self.direction.X, self.direction.Y):SetMagnitude(i * 2); - local fireVector = Vector(self.direction.X, self.direction.Y):SetMagnitude(self.damageSpeed); + local linePos = var.Pos + Vector(var.direction.X, var.direction.Y):SetMagnitude(i * 2); + local fireVector = Vector(var.direction.X, var.direction.Y):SetMagnitude(var.damageSpeed); local upPos = linePos + waveOffset; local downPos = linePos - waveOffset * 0.2; --Cancel the beam if there's a terrain collision. - local trace = Vector(fireVector.X, fireVector.Y):SetMagnitude(self.damageSpeed * 0.1); + local trace = Vector(fireVector.X, fireVector.Y):SetMagnitude(var.damageSpeed * 0.1); local strSumRay = SceneMan:CastStrengthSumRay(downPos, downPos + trace, 3, 160); - self.hits = self.hits + math.sqrt(strSumRay); + var.hits = var.hits + math.sqrt(strSumRay); if SceneMan:GetTerrMatter(upPos.X, upPos.Y) == rte.airID then --Add the blue wave effect. @@ -99,7 +105,7 @@ function Update(self) frontB.Vel = (fireVector + waveOffset) * 0.04; MovableMan:AddParticle(frontB); - if i % self.damageInterval == 0 then + if i % var.damageInterval == 0 then local pos = {upPos, downPos}; local hitID = rte.NoMOID; for i = 1, #pos do @@ -126,15 +132,15 @@ function Update(self) local rootMO = mo:GetRootParent(); if i == 2 and IsActor(rootMO) then - local melter = self.melter:Clone(); + local melter = var.melter:Clone(); melter.Pos = hitPos; melter.Team = self.Team; melter.Sharpness = rootMO.ID; - melter.PinStrength = self.disintegrationStrength; + melter.PinStrength = var.disintegrationStrength; MovableMan:AddMO(melter); end - self.hits = self.hits + (i == 2 and math.sqrt(mo.Material.StructuralIntegrity) + math.sqrt(mo.Radius + mo.Mass) * 0.1 or 1); + var.hits = var.hits + (i == 2 and math.sqrt(mo.Material.StructuralIntegrity) + math.sqrt(mo.Radius + mo.Mass) * 0.1 or 1); --Add the dissipate effect. local effect = CreateAEmitter("Techion.rte/Laser Dissipate Effect"); @@ -145,18 +151,18 @@ function Update(self) end end - if (self.lastAmplitude > 0 and amplitude < 0) or (self.lastAmplitude < 0 and amplitude > 0) then + if (var.lastAmplitude > 0 and amplitude < 0) or (var.lastAmplitude < 0 and amplitude > 0) then local part = CreateMOPixel("Techion.rte/Dihelical Cannon Large Effect Particle"); - part.Pos = linePos - Vector(self.direction.X, self.direction.Y):SetMagnitude(2); + part.Pos = linePos - Vector(var.direction.X, var.direction.Y):SetMagnitude(2); part.Vel = fireVector * 0.1; MovableMan:AddParticle(part); end - self.lastAmplitude = amplitude; - if self.hits > self.strengthThreshold then + var.lastAmplitude = amplitude; + if var.hits > var.strengthThreshold then local effect = CreateAEmitter("Techion.rte/Dihelical Cannon Impact Particle"); - effect.Pos = linePos - Vector(self.direction.X, self.direction.Y):SetMagnitude(2); + effect.Pos = linePos - Vector(var.direction.X, var.direction.Y):SetMagnitude(2); effect.Team = self.Team; effect.IgnoresTeamHits = true; MovableMan:AddParticle(effect); @@ -164,12 +170,12 @@ function Update(self) self.ToDelete = true; break; else - self.hits = self.hits * 0.9; + var.hits = var.hits * 0.9; end - self.flaceLength = self.flaceLength * (1 + 0.05/self.flaceLength); - self.maxAmplitude = self.flaceLength * 0.5; + var.flaceLength = var.flaceLength * (1 + 0.05/var.flaceLength); + var.maxAmplitude = var.flaceLength * 0.5; end - self.lastI = endPoint; + var.lastI = endPoint; end \ No newline at end of file diff --git a/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua b/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua index ffde2c0e2b..5700516440 100644 --- a/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua +++ b/Data/Techion.rte/Devices/Weapons/LaserRifle/LaserRifle.lua @@ -16,11 +16,23 @@ local function emitSmoke(self, particleCount) self:RequestSyncedUpdate(); end +local function drawThiccWobblyLine(screen, startPos, endPos, thiccness, color) + local dirVector = SceneMan:ShortestDistance(startPos, endPos, true):Perpendicularize() + local pos1 = startPos + dirVector:SetMagnitude((thiccness - 1) / 2 + math.random(-1, 0)) + local pos2 = startPos - dirVector:SetMagnitude((thiccness - 1) / 2 + math.random(-1, 0)) + local pos3 = endPos + dirVector:SetMagnitude((thiccness - 1) / 2 + math.random(-1, 0)) + local pos4 = endPos - dirVector:SetMagnitude((thiccness - 1) / 2 + math.random(-1, 0)) + + PrimitiveMan:DrawTriangleFillPrimitive(screen, pos1, pos2, pos3, color) + PrimitiveMan:DrawTriangleFillPrimitive(screen, pos3, pos4, pos2, color) +end + function Create(self) -- Create local table to store variables for performance local var = {}; - var.range = math.sqrt(FrameMan.PlayerScreenWidth^2 + FrameMan.PlayerScreenHeight^2)/2; + -- var.range = math.sqrt(FrameMan.PlayerScreenWidth^2 + FrameMan.PlayerScreenHeight^2)/2; + var.range = 1000; var.penetrationStrength = 170; var.strengthVariation = 5; --This value tracks the shots and varies the penetration strength to create a "resistance" effect on tougher materials @@ -109,16 +121,10 @@ function ThreadedUpdate(self) local team = var.activity:GetTeamOfPlayer(player); local screen = var.activity:ScreenOfPlayer(player); if screen ~= -1 and not (SceneMan:IsUnseen(startPos.X, startPos.Y, team) or SceneMan:IsUnseen(hitPos.X, hitPos.Y, team)) then + drawThiccWobblyLine(screen, startPos, startPos + trace, 3, 198); PrimitiveMan:DrawLinePrimitive(screen, startPos, startPos + trace, 254); end end - local particleCount = trace.Magnitude * RangeRand(0.4, 0.8); - for i = 0, particleCount do - local pix = CreateMOPixel("Laser Rifle Glow 0", "Techion.rte"); - pix.Pos = startPos + trace * i/particleCount; - pix.Vel = var.Vel; - InsertParticle(var, pix); - end end var.shotCounter = (var.shotCounter + 1) % var.strengthVariation; var.cooldown:Reset(); From b60fb97fd6edb608af50461ff90e9a27026cad8c Mon Sep 17 00:00:00 2001 From: comradeshook Date: Sat, 7 Dec 2024 16:16:32 +0100 Subject: [PATCH 3/3] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c88eb0c3fa..5bb1a4c802 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - `MOSRotating` Lua function `AddWound` now additionally accepts the format `MOSRotating:AddWound(AEmitter* woundToAdd, const Vector& parentOffsetToSet, bool checkGibWoundLimit, bool isEntryWound, bool isExitWound)`, allowing modders to specify added wounds as entry- or exit wounds, for the purpose of not playing multiple burst sounds on the same frame. These new arguments are optional. +- Techion Laser Rifle now has a constant range rather than being dependent on game resolution. + - Various performance improvements.