Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
99e005e
zoomslider validity check
pingu7867 Jun 1, 2025
b106e42
cleanup damagezone hit markers more
pingu7867 Jun 1, 2025
a613a66
proxy optimization
pingu7867 Jun 1, 2025
e87ec47
fix a quicksetup variable
pingu7867 Jun 2, 2025
1fb34d5
clamp multiline text editor on screen height
pingu7867 Jun 3, 2025
1e4e91c
Update command.lua
pingu7867 Jun 6, 2025
556fc95
Add spawnmenu icon to hands SWEP (#1415)
thecraftianman Jun 7, 2025
adff17e
better part-hidden navigation
pingu7867 Jun 8, 2025
97fbcaa
restructure bookmarks/favourite assets
pingu7867 Jun 8, 2025
0888512
restructure bookmarks/favourite assets (part 2)
pingu7867 Jun 8, 2025
9e8961a
fix wrong variable
pingu7867 Jun 9, 2025
dd3ae0d
property link to create proxy
pingu7867 Jun 14, 2025
2d85eff
add part lookup to proxy property function
pingu7867 Jun 14, 2025
ed9b996
inject proxy functions for use in luapad
pingu7867 Jun 14, 2025
f132f0a
proxy: sample_and_hold duration is seeded
pingu7867 Jun 14, 2025
f339571
add property "apply proxy" links to booleans
pingu7867 Jun 15, 2025
b7ac694
sort outfit folders in the load/save editor menu
pingu7867 Jul 6, 2025
b36f32b
sort folders in save menu
pingu7867 Jul 7, 2025
488a2bb
owner validity check for viewer_steamid event
textstack Jul 24, 2025
7461c93
change method for viewer_steamid owner
textstack Jul 24, 2025
8d1d3e7
Merge pull request #1416 from textstack/develop
CapsAdmin Jul 25, 2025
3154d51
right click shortcut: edit sprite/particle/beam material
pingu7867 Aug 1, 2025
3f44d6d
fix quick setup's edit materials option
pingu7867 Aug 1, 2025
77a7afd
fix sprite material initialization
pingu7867 Aug 3, 2025
b4b480c
nil string check
pingu7867 Aug 14, 2025
34318e9
is_turning events
pingu7867 Aug 16, 2025
d9e7d6b
add some partmenu actions from the doubleclick actions
pingu7867 Aug 17, 2025
5ca3c51
Update parts.lua
pingu7867 Aug 17, 2025
5168420
optimize event uid search
pingu7867 Aug 20, 2025
84df765
expand text newline support
pingu7867 Aug 24, 2025
92d5d4e
limit the cache part fail warnings to after wear is done
pingu7867 Aug 24, 2025
c069de0
remove DoT instances on death
pingu7867 Aug 29, 2025
91091f4
auto-link special tracked parts on creation
pingu7867 Aug 31, 2025
30d9909
fix damagezone initialization in hitparts
pingu7867 Sep 6, 2025
941c2ca
mdl "vararg" content length theoretical fix
pingu7867 Sep 26, 2025
1a0ec83
suppress blacklisted players from post-filter wears
pingu7867 Sep 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lua/pac3/core/client/part_pool.lua
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,7 @@ function pac.EnablePartsByClass(classname, enable)
end
end

local known_special_link_parts = {}
function pac.LinkSpecialTrackedPartsForEvent(part, ply)
part.erroring_cached_parts = {}
part.found_cached_parts = {}
Expand All @@ -654,11 +655,27 @@ function pac.LinkSpecialTrackedPartsForEvent(part, ply)
["damage_zone"] = true,
["lock"] = true
}
known_special_link_parts[ply] = known_special_link_parts[ply] or {}
known_special_link_parts[ply][part] = part.specialtrackedparts
for _,part2 in pairs(all_parts) do
if ply == part2:GetPlayerOwner() and tracked_classes[part2.ClassName] then
table.insert(part.specialtrackedparts,part2)
end
end
known_special_link_parts[ply][part] = part.specialtrackedparts
end
function pac.InsertSpecialTrackedPart(ply, append_part, remove)
if append_part then
if known_special_link_parts[ply] then
for part,tbl in pairs(known_special_link_parts[ply]) do
if remove then table.RemoveByValue(part.specialtrackedparts, append_part) continue end
if part:IsValid() then
table.insert(part.specialtrackedparts, append_part)
end
end
end
return
end
end

--a centralized function to cache a part in a prebuilt list so we can access relevant parts already narrowed down instead of searching through all parts / localparts
Expand Down
2 changes: 1 addition & 1 deletion lua/pac3/core/client/parts/command.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ end
function PART:SetAppendedNumber(val)
if self.AppendedNumber ~= val then
self.AppendedNumber = val
if self:GetPlayerOwner() == pac.LocalPlayer and self.DynamicMode then
if self:GetPlayerOwner() == pac.LocalPlayer and self.DynamicMode and not self:IsHidden() then
self:Execute()
end
end
Expand Down
82 changes: 75 additions & 7 deletions lua/pac3/core/client/parts/damage_zone.lua
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,12 @@ BUILDER:StartStorableVars()
:GetSet("CriticalHealth",1, {editor_onchange = function(self,num) return math.floor(math.Clamp(num,0,65535)) end})
:GetSet("MaxHpScaling", 0, {editor_clamp = {0,1}})
:SetPropertyGroup("DamageOverTime")
:GetSet("DOTMode", false, {editor_friendly = "DoT mode",
description = "Repeats your damage a few times. Subject to serverside convar."})
:GetSet("DOTTime", 0, {editor_friendly = "DoT time", editor_clamp = {0,32}, description = "delay between each repeated damage"})
:GetSet("DOTCount", 0, {editor_friendly = "DoT count", editor_onchange = function(self,num) return math.floor(math.Clamp(num,0,127)) end, description = "number of repeated damage instances"})
:GetSet("DOTMode", false, {description = "Damage over Time\nRepeats your damage a few times. Subject to serverside convar."})
:GetSet("DOTMethod", "Debuff", {
enums = {["Debuff"] = "Debuff", ["RefreshZone"] = "RefreshZone"},
description = "Whether the DoT means to repeat the damage on the target (handled by the server, starting from one damagezone action), or it means to retrigger the zone (handled by you, the client, throughout multiple damagezone actions).\nDebuff is like the target is burning, RefreshZone is like the area is on fire (but doesn't \"ignite\" targets)"})
:GetSet("DOTTime", 0, {editor_clamp = {0,32}, description = "delay between each repeated damage"})
:GetSet("DOTCount", 0, {editor_onchange = function(self,num) return math.floor(math.Clamp(num,0,127)) end, description = "number of repeated damage instances"})
:GetSet("NoInitialDOT", false, {description = "Skips the first instance (the instant one) of damage to achieve a delayed damage for example."})
:SetPropertyGroup("HitOutcome")
:GetSetPart("HitSoundPart")
Expand Down Expand Up @@ -221,6 +223,7 @@ local global_hitmarker_CSEnt_seed = 0
local spawn_queue = {}
local tick = 0

local hitparts_dump = {}
--multiple entities targeted + hit marker creating parts and setting up every time = FRAME DROPS
--so we tried the budget method, it didn't change the fact that it costs a lot.

Expand Down Expand Up @@ -288,6 +291,8 @@ function PART:FindOrCreateFloatingPart(owner, ent, part_uid, id, parent_ent)
--what if we don't!
local tbl = pac.GetPartFromUniqueID(pac.Hash(owner), part_uid):ToTable()
local group = pac.CreatePart("group", owner) --print("\tcreated a group for " .. id)
table.insert(hitparts_dump, {self, group, ent})
self.force_cleanup_hitparts = CurTime() + math.max(self.HitMarkerLifetime, self.KillMarkerLifetime)

group:SetShowInEditor(false)

Expand Down Expand Up @@ -515,6 +520,21 @@ function PART:ClearHitMarkers()
end
ply.hitmarker_partpool = nil
ply.hitparts = nil
--second pass
local remaining_parts = {}
for i,v in ipairs(hitparts_dump) do
if v[2]:IsValid() then
if self == v[1] then
v[2]:Remove()
hitparts_dump[i] = nil
end
else
hitparts_dump[i] = nil
end
--if it survives, reinsert it
if hitparts_dump[i] then table.insert(remaining_parts, v) end
end
hitparts_dump = remaining_parts
end

local function RecursedHitmarker(part)
Expand Down Expand Up @@ -649,8 +669,8 @@ function PART:SendNetMessage()
net.WriteBool(self.ReverseDoNotKill)
net.WriteUInt(self.CriticalHealth, 16)
net.WriteBool(self.RemoveNPCWeaponsOnKill)
net.WriteBool(self.DOTMode)
net.WriteBool(self.NoInitialDOT)
net.WriteBool(self.DOTMode and (self.DOTMethod == "Debuff"))
net.WriteBool(self.NoInitialDOT and (self.DOTMethod == "Debuff"))
net.WriteUInt(self.DOTCount, 7)
net.WriteUInt(math.ceil(math.Clamp(64*self.DOTTime, 0, 2047)), 11)
net.WriteString(string.sub(self.UniqueID,0,6))
Expand All @@ -660,6 +680,9 @@ function PART:SendNetMessage()
end

function PART:OnShow()
self.remaining_DOT_count = self.DOTCount
self.next_DOT = self.NoInitialDOT and CurTime() + self.DOTTime or CurTime() - 1

if pace.still_loading_wearing then return end
if self.validTime > SysTime() then return end

Expand All @@ -670,6 +693,8 @@ function PART:OnShow()
if self.stop_until then self:GetPlayerOwner().stop_hit_markers_admonishment_message_up = nil end
if (self:GetPlayerOwner().stop_hit_markers_admonishment_message_up) or self.stop_until > CurTime() then return end

if self.DOTMethod == "RefreshZone" then return end --handle with Think

if self:GetRootPart():GetOwner() ~= self:GetPlayerOwner() then --dumb workaround for when it activates before it realizes it needs to be hidden first
timer.Simple(0.01, function() --wait to check if needs to be hidden first
if self:IsHidden() or self:IsDrawHidden() then return end
Expand Down Expand Up @@ -709,7 +734,6 @@ function PART:SetAttachPartsToTargetEntity(b)
end

--revertable to projectile part's version which wastes time creating new parts but has less issues
local_hitmarks = {}
function PART:LegacyAttachToEntity(part, ent)
if not part:IsValid() then return false end

Expand All @@ -718,6 +742,8 @@ function PART:LegacyAttachToEntity(part, ent)
local tbl = part:ToTable()

local group = pac.CreatePart("group", self:GetPlayerOwner())
table.insert(hitparts_dump, {self, group, ent})
self.force_cleanup_hitparts = CurTime() + math.max(self.HitMarkerLifetime, self.KillMarkerLifetime)
group:SetShowInEditor(false)

local part_clone = pac.CreatePart(tbl.self.ClassName, self:GetPlayerOwner(), tbl, tostring(tbl))
Expand Down Expand Up @@ -795,6 +821,7 @@ net.Receive("pac_hit_results", function(len)
local cs_ent = false
if not self.AttachPartsToTargetEntity then
ent = pac.CreateEntity("models/props_junk/popcan01a.mdl")
ent.is_pac_hitmarker = true
cs_ent = true
ent:SetNoDraw(true)
ent:SetPos(pos)
Expand Down Expand Up @@ -939,6 +966,14 @@ net.Receive("pac_hit_results", function(len)
end)

concommand.Add("pac_cleanup_damagezone_hitmarks", function()
print(hitparts_dump, #hitparts_dump .. " parts detected")
for i,v in ipairs(hitparts_dump) do
if v[2]:IsValid() then
v[2]:Remove()
end
hitparts_dump[i] = nil
end

if LocalPlayer().hitparts then
for i,v in pairs(LocalPlayer().hitparts) do
v.specimen_part:Remove()
Expand All @@ -963,6 +998,9 @@ function PART:OnRemove()
for _,v in pairs(renderhooks) do
pac.RemoveHook(v, "pace_draw_hitbox")
end
self:ClearHitMarkers()
--remove itself
pac.InsertSpecialTrackedPart(self:GetPlayerOwner(), self, true)
end

local previousRenderingHook
Expand Down Expand Up @@ -1151,6 +1189,34 @@ end

function PART:OnThink()
if self.Preview then self:PreviewHitbox() end
if self.DOTMethod == "RefreshZone" then
if self.DOTTime == 0 then return end --get outta here with those zero delays
if (CurTime() > self.next_DOT) and (self.remaining_DOT_count > 0) then
self:SendNetMessage()
self.remaining_DOT_count = self.remaining_DOT_count - 1
self.next_DOT = CurTime() + self.DOTTime
end
end
if self.force_cleanup_hitparts < CurTime() then self:ClearHitMarkers() end
end

function PART:GetNiceName()
local str = ""
if self.DOTMode then
str = str .. " [DoT " .. self.DOTCount .. "x : " .. self.DOTTime .. "s]"
end
str = str .. " " .. self.DamageType .. " " .. self.Damage
if self.MaxHpScaling ~= 0 then str = str .. " + " .. 100*self.MaxHpScaling .. "% max HP" end
if self.ReverseDoNotKill then
if self.DamageType == "heal" then
str = str .. " [if HP > " .. self.CriticalHealth .. "]"
else
str = str .. " [if HP < " .. self.CriticalHealth .. "]"
end
elseif self.DoNotKill then
str = str .. " [stop at " .. self.CriticalHealth .. " HP]"
end
return "damage zone" .. str
end

function PART:BuildCylinder(obj)
Expand Down Expand Up @@ -1219,6 +1285,7 @@ function PART:BuildCone(obj)
end

function PART:Initialize()
self.force_cleanup_hitparts = 0
self.hitmarkers = {}
if not GetConVar("pac_sv_damage_zone"):GetBool() or pac.Blocked_Combat_Parts[self.ClassName] then self:SetError("damage zones are disabled on this server!") end
self.validTime = SysTime() + 5 --jank fix to try to stop activation on load
Expand All @@ -1231,6 +1298,7 @@ function PART:Initialize()
end
end)

pac.InsertSpecialTrackedPart(self:GetPlayerOwner(), self)
end

function PART:SetRadius(val)
Expand Down
Loading
Loading