mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
912
lua/pac3/core/client/part_pool.lua
Normal file
912
lua/pac3/core/client/part_pool.lua
Normal file
@@ -0,0 +1,912 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local pac = pac
|
||||
|
||||
local render_SetColorModulation = render.SetColorModulation
|
||||
local render_SetBlend = render.SetBlend
|
||||
local render_ModelMaterialOverride = render.ModelMaterialOverride
|
||||
local render_MaterialOverride = render.MaterialOverride
|
||||
local SysTime = SysTime
|
||||
local NULL = NULL
|
||||
local pairs = pairs
|
||||
local force_rendering = false
|
||||
local forced_rendering = false
|
||||
local IsEntity = IsEntity
|
||||
local next = next
|
||||
|
||||
local entMeta = FindMetaTable('Entity')
|
||||
local plyMeta = FindMetaTable('Player')
|
||||
local IsValid = entMeta.IsValid
|
||||
local Alive = plyMeta.Alive
|
||||
|
||||
local function IsActuallyValid(ent)
|
||||
return IsEntity(ent) and pcall(ent.GetPos, ent)
|
||||
end
|
||||
|
||||
local function IsActuallyPlayer(ent)
|
||||
return IsEntity(ent) and pcall(ent.UniqueID, ent)
|
||||
end
|
||||
|
||||
local function IsActuallyRemoved(ent, cb)
|
||||
timer.Simple(0, function()
|
||||
if not ent:IsValid() then
|
||||
cb()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function pac.ForceRendering(b)
|
||||
force_rendering = b
|
||||
if b then
|
||||
forced_rendering = b
|
||||
end
|
||||
end
|
||||
|
||||
local ent_parts = _G.pac_local_parts or {}
|
||||
local all_parts = _G.pac_all_parts or {}
|
||||
local uid_parts = _G.pac_uid_parts or {}
|
||||
|
||||
if game.SinglePlayer() or (player.GetCount() == 1 and LocalPlayer():IsSuperAdmin()) then
|
||||
_G.pac_local_parts = ent_parts
|
||||
_G.pac_all_parts = all_parts
|
||||
_G.pac_uid_parts = uid_parts
|
||||
end
|
||||
|
||||
local function parts_from_uid(owner_id)
|
||||
return uid_parts[owner_id] or {}
|
||||
end
|
||||
|
||||
local function parts_from_ent(ent)
|
||||
local owner_id = IsValid(ent) and pac.Hash(ent)
|
||||
return uid_parts[owner_id] or {}
|
||||
end
|
||||
|
||||
do
|
||||
local function render_override(ent, type)
|
||||
local parts = ent_parts[ent]
|
||||
|
||||
if parts == nil or next(parts) == nil then
|
||||
pac.UnhookEntityRender(ent)
|
||||
goto CEASE_FUNCTION
|
||||
end
|
||||
|
||||
if type == "update_legacy_bones" then
|
||||
pac.ResetBones(ent)
|
||||
|
||||
for key, part in next, parts do
|
||||
if part:IsValid() then
|
||||
if not part:HasParent() then
|
||||
part:CallRecursive("BuildBonePositions")
|
||||
end
|
||||
else
|
||||
parts[key] = nil
|
||||
end
|
||||
end
|
||||
elseif type == "update" then
|
||||
for key, part in next, parts do
|
||||
if part:IsValid() then
|
||||
if not part:HasParent() then
|
||||
part:CallRecursive("Think")
|
||||
end
|
||||
else
|
||||
parts[key] = nil
|
||||
end
|
||||
end
|
||||
else
|
||||
for key, part in next, parts do
|
||||
if part:IsValid() then
|
||||
if not part:HasParent() then
|
||||
if
|
||||
part.OwnerName == "viewmodel" and type == "viewmodel" or
|
||||
part.OwnerName == "hands" and type == "hands" or
|
||||
part.OwnerName ~= "viewmodel" and part.OwnerName ~= "hands" and type ~= "viewmodel" and type ~= "hands"
|
||||
then
|
||||
if not part:IsDrawHidden() then
|
||||
part:CallRecursive("Draw", type)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
parts[key] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
::CEASE_FUNCTION::
|
||||
|
||||
render_SetColorModulation(1, 1, 1)
|
||||
render_SetBlend(1)
|
||||
|
||||
render_MaterialOverride()
|
||||
render_ModelMaterialOverride()
|
||||
end
|
||||
|
||||
local function on_error(msg)
|
||||
ErrorNoHalt(debug.traceback(msg))
|
||||
end
|
||||
|
||||
function pac.RenderOverride(ent, type)
|
||||
if ent.pac_error then return end
|
||||
|
||||
if pac.IsRenderTimeExceeded(ent) then
|
||||
if type == "opaque" then
|
||||
pac.DrawRenderTimeExceeded(ent)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local start = SysTime()
|
||||
local ok, err = xpcall(render_override, on_error, ent, type)
|
||||
pac.RecordRenderTime(ent, type, start)
|
||||
|
||||
if not ok then
|
||||
pac.Message("failed to render ", tostring(ent), ":")
|
||||
|
||||
if ent == pac.LocalPlayer then
|
||||
chat.AddText("your pac3 outfit failed to render!")
|
||||
chat.AddText(err)
|
||||
chat.AddText("hiding your outfit to prevent further errors")
|
||||
end
|
||||
|
||||
ent.pac_error = err
|
||||
table.insert(pac.Errors, err)
|
||||
pac.HideEntityParts(ent)
|
||||
else
|
||||
ent.pac_error = nil
|
||||
end
|
||||
end
|
||||
|
||||
function pac.GetRenderTimeInfo(ent)
|
||||
return ent.pac_rendertime or {}
|
||||
end
|
||||
end
|
||||
|
||||
function pac.HideEntityParts(ent)
|
||||
if ent_parts[ent] and ent.pac_drawing then
|
||||
for _, part in pairs(ent_parts[ent]) do
|
||||
part:HideFromRendering()
|
||||
end
|
||||
|
||||
pac.ResetBones(ent)
|
||||
ent.pac_drawing = false
|
||||
end
|
||||
end
|
||||
|
||||
function pac.ShowEntityParts(ent)
|
||||
if not ent_parts[ent] or ent.pac_shouldnotdraw or ent.pac_ignored then return end
|
||||
|
||||
if not ent.pac_drawing then
|
||||
for _, part in pairs(ent_parts[ent]) do
|
||||
part:ShowFromRendering()
|
||||
end
|
||||
|
||||
pac.ResetBones(ent)
|
||||
ent.pac_drawing = true
|
||||
ent.pac_error = nil
|
||||
elseif ent.pac_fix_show_from_render and ent.pac_fix_show_from_render < SysTime() then
|
||||
for _, part in pairs(ent_parts[ent]) do
|
||||
part:ShowFromRendering()
|
||||
end
|
||||
|
||||
ent.pac_fix_show_from_render = nil
|
||||
end
|
||||
end
|
||||
|
||||
function pac.EnableDrawnEntities(bool)
|
||||
for ent in next, pac.drawn_entities do
|
||||
if ent:IsValid() then
|
||||
if bool then
|
||||
pac.ShowEntityParts(ent)
|
||||
else
|
||||
pac.HideEntityParts(ent)
|
||||
end
|
||||
else
|
||||
pac.drawn_entities[ent] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pac.HookEntityRender(ent, part)
|
||||
local parts = ent_parts[ent]
|
||||
|
||||
if not parts then
|
||||
parts = {}
|
||||
ent_parts[ent] = parts
|
||||
end
|
||||
|
||||
if parts[part] then
|
||||
return false
|
||||
end
|
||||
|
||||
pac.dprint("hooking render on %s to draw part %s", tostring(ent), tostring(part))
|
||||
|
||||
pac.drawn_entities[ent] = true
|
||||
|
||||
parts[part] = part
|
||||
|
||||
ent.pac_has_parts = true
|
||||
|
||||
part:ShowFromRendering()
|
||||
return true
|
||||
end
|
||||
|
||||
function pac.UnhookEntityRender(ent, part)
|
||||
if part and ent_parts[ent] then
|
||||
ent_parts[ent][part] = nil
|
||||
end
|
||||
|
||||
if (ent_parts[ent] and not next(ent_parts[ent])) or not part then
|
||||
ent_parts[ent] = nil
|
||||
ent.pac_has_parts = nil
|
||||
pac.drawn_entities[ent] = nil
|
||||
|
||||
if ent.pac_bones_once then
|
||||
pac.ResetBones(ent)
|
||||
ent.pac_bones_once = nil
|
||||
end
|
||||
end
|
||||
|
||||
if part then
|
||||
part:HideFromRendering()
|
||||
end
|
||||
end
|
||||
|
||||
pac.AddHook("Think", "events", function()
|
||||
for _, ply in ipairs(player.GetAll()) do
|
||||
if not ent_parts[ply] then continue end
|
||||
if pac.IsEntityIgnored(ply) then continue end
|
||||
|
||||
if Alive(ply) then
|
||||
if ply.pac_revert_ragdoll then
|
||||
ply.pac_revert_ragdoll()
|
||||
ply.pac_revert_ragdoll = nil
|
||||
end
|
||||
continue
|
||||
end
|
||||
|
||||
local rag = ply:GetRagdollEntity()
|
||||
if not IsValid(rag) then
|
||||
pac.HideEntityParts(ply)
|
||||
continue
|
||||
end
|
||||
|
||||
-- so it only runs once
|
||||
if ply.pac_ragdoll == rag then continue end
|
||||
ply.pac_ragdoll = rag
|
||||
rag.pac_ragdoll_owner = ply
|
||||
|
||||
rag = hook.Run("PACChooseDeathRagdoll", ply, rag) or rag
|
||||
|
||||
if ply.pac_death_physics_parts then
|
||||
if ply.pac_physics_died then return end
|
||||
|
||||
for _, part in pairs(parts_from_uid(pac.Hash(ply))) do
|
||||
if part.is_model_part then
|
||||
local ent = part:GetOwner()
|
||||
if ent:IsValid() then
|
||||
rag:SetNoDraw(true)
|
||||
|
||||
part.skip_orient = true
|
||||
|
||||
ent:SetParent(NULL)
|
||||
ent:SetNoDraw(true)
|
||||
ent:PhysicsInitBox(Vector(1,1,1) * -5, Vector(1,1,1) * 5)
|
||||
ent:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
|
||||
local phys = ent:GetPhysicsObject()
|
||||
phys:AddAngleVelocity(VectorRand() * 1000)
|
||||
phys:AddVelocity(ply:GetVelocity() + VectorRand() * 30)
|
||||
phys:Wake()
|
||||
|
||||
function ent.RenderOverride()
|
||||
if part:IsValid() then
|
||||
if not part.HideEntity then
|
||||
part:PreEntityDraw(ent, ent, ent:GetPos(), ent:GetAngles())
|
||||
ent:DrawModel()
|
||||
part:PostEntityDraw(ent, ent, ent:GetPos(), ent:GetAngles())
|
||||
end
|
||||
else
|
||||
ent.RenderOverride = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ply.pac_physics_died = true
|
||||
elseif ply.pac_death_ragdollize or ply.pac_death_ragdollize == nil then
|
||||
|
||||
pac.HideEntityParts(ply)
|
||||
|
||||
for _, part in pairs(ent_parts[ply]) do
|
||||
part:SetOwner(rag)
|
||||
end
|
||||
rag:SetOwner(ply)
|
||||
pac.ShowEntityParts(rag)
|
||||
|
||||
ply.pac_revert_ragdoll = function()
|
||||
ply.pac_ragdoll = nil
|
||||
|
||||
if not ent_parts[ply] then return end
|
||||
|
||||
pac.HideEntityParts(rag)
|
||||
|
||||
for _, part in pairs(ent_parts[ply]) do
|
||||
part:SetOwner(ply)
|
||||
end
|
||||
|
||||
pac.ShowEntityParts(ply)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if pac.last_flashlight_on ~= pac.LocalPlayer:FlashlightIsOn() then
|
||||
local lamp = ProjectedTexture()
|
||||
|
||||
lamp:SetTexture( "effects/flashlight001" )
|
||||
lamp:SetFarZ( 5000 )
|
||||
lamp:SetColor(Color(0,0,0,255))
|
||||
|
||||
lamp:SetPos( pac.LocalPlayer:EyePos() - pac.LocalPlayer:GetAimVector()*400 )
|
||||
lamp:SetAngles( pac.LocalPlayer:EyeAngles() )
|
||||
lamp:Update()
|
||||
|
||||
hook.Add("PostRender", "pac_flashlight_stuck_fix", function()
|
||||
hook.Remove("PostRender", "pac_flashlight_stuck_fix")
|
||||
lamp:Remove()
|
||||
end)
|
||||
|
||||
pac.last_flashlight_on = pac.LocalPlayer:FlashlightIsOn()
|
||||
end
|
||||
|
||||
for ent in next, pac.drawn_entities do
|
||||
if IsValid(ent) then
|
||||
if ent.pac_drawing and ent:IsPlayer() then
|
||||
|
||||
ent.pac_traceres = util.QuickTrace(ent:EyePos(), ent:GetAimVector() * 32000, {ent, ent:GetVehicle(), ent:GetOwner()})
|
||||
ent.pac_hitpos = ent.pac_traceres.HitPos
|
||||
|
||||
end
|
||||
else
|
||||
pac.drawn_entities[ent] = nil
|
||||
end
|
||||
end
|
||||
|
||||
if pac.next_frame_funcs then
|
||||
for k, fcall in pairs(pac.next_frame_funcs) do
|
||||
fcall()
|
||||
end
|
||||
|
||||
-- table.Empty is also based on undefined behavior
|
||||
-- god damnit
|
||||
for i, key in ipairs(table.GetKeys(pac.next_frame_funcs)) do
|
||||
pac.next_frame_funcs[key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
if pac.next_frame_funcs_simple and #pac.next_frame_funcs_simple ~= 0 then
|
||||
for i, fcall in ipairs(pac.next_frame_funcs_simple) do
|
||||
fcall()
|
||||
end
|
||||
|
||||
for i = #pac.next_frame_funcs_simple, 1, -1 do
|
||||
pac.next_frame_funcs_simple[i] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
pac.AddHook("EntityRemoved", "change_owner", function(ent)
|
||||
if IsActuallyValid(ent) then
|
||||
if IsActuallyPlayer(ent) then
|
||||
local parts = parts_from_ent(ent)
|
||||
if next(parts) ~= nil then
|
||||
IsActuallyRemoved(ent, function()
|
||||
for _, part in pairs(parts) do
|
||||
if part.dupe_remove then
|
||||
part:Remove()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
else
|
||||
local owner = ent:GetOwner()
|
||||
if IsActuallyPlayer(owner) then
|
||||
local parts = parts_from_ent(owner)
|
||||
if next(parts) ~= nil then
|
||||
IsActuallyRemoved(ent, function()
|
||||
for _, part in pairs(parts) do
|
||||
if part.ClassName == "group" then
|
||||
if part:GetOwnerName() == "hands" then
|
||||
part:UpdateOwnerName()
|
||||
end
|
||||
part:HideInvalidOwners()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
pac.AddHook("OnEntityCreated", "change_owner", function(ent)
|
||||
if not IsActuallyValid(ent) then return end
|
||||
|
||||
local owner = ent:GetOwner()
|
||||
|
||||
if IsActuallyValid(owner) and (not owner:IsPlayer() or IsActuallyPlayer(owner)) then
|
||||
for _, part in pairs(parts_from_ent(owner)) do
|
||||
if part.ClassName == "group" then
|
||||
part:UpdateOwnerName(ent, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function pac.RemovePartsFromUniqueID(uid)
|
||||
for _, part in pairs(parts_from_uid(uid)) do
|
||||
if not part:HasParent() then
|
||||
part:Remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pac.UpdatePartsWithMetatable(META)
|
||||
for _, part in pairs(all_parts) do
|
||||
if META.ClassName == part.ClassName then
|
||||
for k, v in pairs(META) do
|
||||
-- update part functions only
|
||||
-- updating variables might mess things up
|
||||
if isfunction(v) then
|
||||
part[k] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pac.GetPropertyFromName(func, name, ent_owner)
|
||||
for _, part in pairs(parts_from_ent(ent_owner)) do
|
||||
if part[func] and name == part.Name then
|
||||
return part[func](part)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pac.RemoveUniqueIDPart(owner_uid, uid)
|
||||
if not uid_parts[owner_uid] then return end
|
||||
uid_parts[owner_uid][uid] = nil
|
||||
end
|
||||
|
||||
function pac.SetUniqueIDPart(owner_uid, uid, part)
|
||||
uid_parts[owner_uid] = uid_parts[owner_uid] or {}
|
||||
uid_parts[owner_uid][uid] = part
|
||||
|
||||
pac.NotifyPartCreated(part)
|
||||
end
|
||||
|
||||
function pac.AddPart(part)
|
||||
all_parts[part.Id] = part
|
||||
end
|
||||
|
||||
function pac.RemovePart(part)
|
||||
all_parts[part.Id] = nil
|
||||
end
|
||||
|
||||
function pac.GetLocalParts()
|
||||
return uid_parts[pac.Hash(pac.LocalPlayer)] or {}
|
||||
end
|
||||
|
||||
function pac.GetPartFromUniqueID(owner_id, id)
|
||||
return uid_parts[owner_id] and uid_parts[owner_id][id] or NULL
|
||||
end
|
||||
|
||||
function pac.FindPartByName(owner_id, str, exclude)
|
||||
if uid_parts[owner_id] then
|
||||
if uid_parts[owner_id][str] then
|
||||
return uid_parts[owner_id][str]
|
||||
end
|
||||
|
||||
for _, part in pairs(uid_parts[owner_id]) do
|
||||
if part == exclude then continue end
|
||||
if part:GetName() == str then
|
||||
return part
|
||||
end
|
||||
end
|
||||
|
||||
for _, part in pairs(uid_parts[owner_id]) do
|
||||
if part == exclude then continue end
|
||||
if pac.StringFind(part:GetName(), str) then
|
||||
return part
|
||||
end
|
||||
end
|
||||
|
||||
for _, part in pairs(uid_parts[owner_id]) do
|
||||
if part == exclude then continue end
|
||||
if pac.StringFind(part:GetName(), str, true) then
|
||||
return part
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return NULL
|
||||
end
|
||||
|
||||
function pac.GetLocalPart(id)
|
||||
local owner_id = pac.Hash(pac.LocalPlayer)
|
||||
return uid_parts[owner_id] and uid_parts[owner_id][id] or NULL
|
||||
end
|
||||
|
||||
function pac.RemoveAllParts(owned_only, server)
|
||||
if server and pace then
|
||||
pace.RemovePartOnServer("__ALL__")
|
||||
end
|
||||
|
||||
for _, part in pairs(owned_only and pac.GetLocalParts() or all_parts) do
|
||||
if part:IsValid() then
|
||||
local status, err = pcall(part.Remove, part)
|
||||
if not status then pac.Message('Failed to remove part: ' .. err .. '!') end
|
||||
end
|
||||
end
|
||||
|
||||
if not owned_only then
|
||||
all_parts = {}
|
||||
uid_parts = {}
|
||||
end
|
||||
end
|
||||
|
||||
function pac.UpdateMaterialParts(how, uid, self, val)
|
||||
pac.RunNextFrame("material " .. how .. " " .. self.Id, function()
|
||||
for _, part in pairs(parts_from_uid(uid)) do
|
||||
if how == "update" or how == "remove" then
|
||||
if part.Materialm == val and self ~= part then
|
||||
if how == "update" then
|
||||
part.force_translucent = self.Translucent
|
||||
else
|
||||
part.force_translucent = nil
|
||||
part.Materialm = nil
|
||||
end
|
||||
end
|
||||
elseif how == "show" then
|
||||
if part.Material and part.Material ~= "" and part.Material == val then
|
||||
part:SetMaterial(val)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function pac.NotifyPartCreated(part)
|
||||
local owner_id = part:GetPlayerOwnerId()
|
||||
if not uid_parts[owner_id] then return end
|
||||
|
||||
for _, p in pairs(uid_parts[owner_id]) do
|
||||
p:OnOtherPartCreated(part)
|
||||
|
||||
if part:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.CallHook("OnPartCreated", part)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pac.CallRecursiveOnAllParts(func_name, ...)
|
||||
for _, part in pairs(all_parts) do
|
||||
if part[func_name] then
|
||||
local ret = part[func_name](part, ...)
|
||||
if ret ~= nil then
|
||||
return ret
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pac.CallRecursiveOnOwnedParts(ent, func_name, ...)
|
||||
local owned_parts = parts_from_ent(ent)
|
||||
for _, part in pairs(owned_parts) do
|
||||
if part[func_name] then
|
||||
local ret = part[func_name](part, ...)
|
||||
if ret ~= nil then
|
||||
return ret
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pac.EnablePartsByClass(classname, enable)
|
||||
for _, part in pairs(all_parts) do
|
||||
if part.ClassName == classname then
|
||||
part:SetEnabled(enable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cvars.AddChangeCallback("pac_hide_disturbing", function()
|
||||
for _, part in pairs(all_parts) do
|
||||
if part:IsValid() then
|
||||
part:UpdateIsDisturbing()
|
||||
end
|
||||
end
|
||||
end, "PAC3")
|
||||
|
||||
do -- drawing
|
||||
local pac = pac
|
||||
|
||||
local FrameNumber = FrameNumber
|
||||
local RealTime = RealTime
|
||||
local GetConVar = GetConVar
|
||||
local EF_BONEMERGE = EF_BONEMERGE
|
||||
local RENDERMODE_TRANSALPHA = RENDERMODE_TRANSALPHA
|
||||
|
||||
local cvar_distance = CreateClientConVar("pac_draw_distance", "500")
|
||||
|
||||
pac.Errors = {}
|
||||
pac.firstperson_parts = pac.firstperson_parts or {}
|
||||
pac.EyePos = vector_origin
|
||||
pac.drawn_entities = pac.drawn_entities or {}
|
||||
pac.RealTime = 0
|
||||
pac.FrameNumber = 0
|
||||
|
||||
local skip_frames = CreateConVar('pac_optimization_render_once_per_frame', '0', {FCVAR_ARCHIVE}, 'render only once per frame (will break water reflections and vr)')
|
||||
|
||||
local function setup_suppress()
|
||||
local last_framenumber = 0
|
||||
local current_frame = 0
|
||||
local current_frame_count = 0
|
||||
|
||||
return function(force)
|
||||
if not force then
|
||||
if force_rendering then return end
|
||||
if not skip_frames:GetBool() then return end
|
||||
end
|
||||
|
||||
local frame_number = FrameNumber()
|
||||
|
||||
if frame_number == last_framenumber then
|
||||
current_frame = current_frame + 1
|
||||
else
|
||||
last_framenumber = frame_number
|
||||
|
||||
if current_frame_count ~= current_frame then
|
||||
current_frame_count = current_frame
|
||||
end
|
||||
|
||||
current_frame = 1
|
||||
end
|
||||
|
||||
return current_frame < current_frame_count
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local draw_dist = 0
|
||||
local sv_draw_dist = 0
|
||||
local radius = 0
|
||||
local dst = 0
|
||||
local pac_sv_draw_distance
|
||||
|
||||
pac.AddHook("Think", "update_parts", function()
|
||||
-- commonly used variables
|
||||
pac.LocalPlayer = LocalPlayer()
|
||||
pac.LocalViewModel = pac.LocalPlayer:GetViewModel()
|
||||
pac.LocalHands = pac.LocalPlayer:GetHands()
|
||||
pac.RealTime = RealTime()
|
||||
pac.FrameNumber = pac.FrameNumber + 1
|
||||
|
||||
draw_dist = cvar_distance:GetInt()
|
||||
pac_sv_draw_distance = pac_sv_draw_distance or GetConVar("pac_sv_draw_distance")
|
||||
sv_draw_dist = pac_sv_draw_distance:GetFloat()
|
||||
radius = 0
|
||||
|
||||
if draw_dist <= 0 then
|
||||
draw_dist = 32768
|
||||
end
|
||||
|
||||
if sv_draw_dist <= 0 then
|
||||
sv_draw_dist = 32768
|
||||
end
|
||||
|
||||
draw_dist = math.min(sv_draw_dist, draw_dist)
|
||||
|
||||
for ent in next, pac.drawn_entities do
|
||||
if not IsValid(ent) then
|
||||
pac.drawn_entities[ent] = nil
|
||||
goto CONTINUE
|
||||
end
|
||||
|
||||
if ent:IsDormant() then goto CONTINUE end
|
||||
|
||||
pac.ResetRenderTime(ent)
|
||||
|
||||
dst = ent:EyePos():Distance(pac.EyePos)
|
||||
radius = ent:BoundingRadius() * 3 * (ent:GetModelScale() or 1)
|
||||
|
||||
if ent:IsPlayer() or IsValid(ent.pac_ragdoll_owner) then
|
||||
local ply = ent.pac_ragdoll_owner or ent
|
||||
local rag = ply.pac_ragdoll
|
||||
|
||||
if IsValid(rag) and (ply.pac_death_hide_ragdoll or ply.pac_draw_player_on_death) then
|
||||
rag:SetRenderMode(RENDERMODE_TRANSALPHA)
|
||||
|
||||
local c = rag:GetColor()
|
||||
c.a = 0
|
||||
rag:SetColor(c)
|
||||
rag:SetNoDraw(true)
|
||||
if rag:GetParent() ~= ply then
|
||||
rag:SetParent(ent)
|
||||
rag:AddEffects(EF_BONEMERGE)
|
||||
end
|
||||
|
||||
if ply.pac_draw_player_on_death then
|
||||
ply:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
if radius < 32 then
|
||||
radius = 128
|
||||
end
|
||||
elseif not ent:IsNPC() then
|
||||
radius = radius * 4
|
||||
end
|
||||
|
||||
-- if it's a world entity always draw
|
||||
local cond = ent.IsPACWorldEntity
|
||||
|
||||
-- if the entity is the hands, check if we should not draw the localplayer
|
||||
if (ent == pac.LocalHands or ent == pac.LocalViewModel) and not pac.LocalPlayer:ShouldDrawLocalPlayer() then
|
||||
cond = true
|
||||
end
|
||||
|
||||
-- if it's a player, draw if we can see them
|
||||
if not cond and ent == pac.LocalPlayer then
|
||||
cond = ent:ShouldDrawLocalPlayer()
|
||||
end
|
||||
|
||||
-- if the entity has a camera part, draw if it's valid
|
||||
if not cond and ent.pac_camera then
|
||||
cond = ent.pac_camera:IsValid()
|
||||
end
|
||||
|
||||
-- if the condition is not satisified, check draw distance
|
||||
if not cond and ent ~= pac.LocalPlayer then
|
||||
if ent.pac_draw_distance then
|
||||
-- custom draw distance
|
||||
cond = ent.pac_draw_distance <= 0 or dst <= ent.pac_draw_distance
|
||||
else
|
||||
-- otherwise check the cvar
|
||||
cond = dst <= draw_dist
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
ent.pac_is_drawing = cond
|
||||
|
||||
if cond then
|
||||
pac.ShowEntityParts(ent)
|
||||
pac.RenderOverride(ent, "update")
|
||||
else
|
||||
if forced_rendering then
|
||||
forced_rendering = false
|
||||
return
|
||||
end
|
||||
|
||||
pac.HideEntityParts(ent)
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
-- we increment the framenumber here because we want to invalidate any FrameNumber caches when we draw
|
||||
-- this prevents functions like movable:GetWorldMatrix() from caching the matrix in the update hook
|
||||
pac.FrameNumber = pac.FrameNumber + 1
|
||||
end)
|
||||
end
|
||||
|
||||
local setupBonesGuard = false
|
||||
function pac.SetupBones(ent)
|
||||
-- Reentrant protection
|
||||
if setupBonesGuard then return end
|
||||
setupBonesGuard = true
|
||||
local ok, err = pcall(ent.SetupBones, ent)
|
||||
setupBonesGuard = false
|
||||
if not ok then error(err) end
|
||||
end
|
||||
|
||||
do
|
||||
local should_suppress = setup_suppress()
|
||||
|
||||
pac.AddHook("PreDrawOpaqueRenderables", "draw_opaque", function(bDrawingDepth, bDrawingSkybox)
|
||||
if should_suppress(true) then return end
|
||||
|
||||
for ent in next, pac.drawn_entities do
|
||||
if ent.pac_is_drawing and ent_parts[ent] and not ent:IsDormant() then
|
||||
pac.RenderOverride(ent, "update_legacy_bones")
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local should_suppress = setup_suppress()
|
||||
|
||||
pac.AddHook("PostDrawOpaqueRenderables", "draw_opaque", function(bDrawingDepth, bDrawingSkybox, isDraw3DSkybox)
|
||||
if should_suppress() then return end
|
||||
|
||||
for ent in next, pac.drawn_entities do
|
||||
if ent.pac_is_drawing and ent_parts[ent] and not ent:IsDormant() then
|
||||
|
||||
if isDraw3DSkybox and not ent:GetNW2Bool("pac_in_skybox") then
|
||||
continue
|
||||
end
|
||||
|
||||
pac.RenderOverride(ent, "opaque")
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
do
|
||||
local should_suppress = setup_suppress()
|
||||
|
||||
pac.AddHook("PostDrawTranslucentRenderables", "draw_translucent", function(bDrawingDepth, bDrawingSkybox, isDraw3DSkybox)
|
||||
if should_suppress() then return end
|
||||
|
||||
for ent in next, pac.drawn_entities do
|
||||
if ent.pac_is_drawing and ent_parts[ent] and not ent:IsDormant() then -- accessing table of NULL doesn't do anything
|
||||
|
||||
if isDraw3DSkybox and not ent:GetNW2Bool("pac_in_skybox") then
|
||||
continue
|
||||
end
|
||||
|
||||
pac.RenderOverride(ent, "translucent")
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
pac.AddHook("UpdateAnimation", "update_animation_parts", function(ply)
|
||||
if ply.pac_is_drawing and ent_parts[ply] then -- accessing table of NULL doesn't do anything
|
||||
local parts = ent_parts[ply]
|
||||
for _, part in pairs(parts) do
|
||||
part:CallRecursive("OnUpdateAnimation", ply)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local drawing_viewmodel = false
|
||||
|
||||
pac.AddHook("PostDrawViewModel", "draw_firstperson", function(viewmodelIn, playerIn, weaponIn)
|
||||
if drawing_viewmodel then return end
|
||||
for ent in next, pac.drawn_entities do
|
||||
if IsValid(ent) then
|
||||
if ent.pac_drawing and ent_parts[ent] then
|
||||
drawing_viewmodel=true
|
||||
pac.RenderOverride(ent, "viewmodel")
|
||||
drawing_viewmodel=false
|
||||
end
|
||||
else
|
||||
pac.drawn_entities[ent] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local drawing_hands = false
|
||||
pac.AddHook("PostDrawPlayerHands", "draw_firstperson_hands", function(handsIn, viewmodelIn, playerIn, weaponIn)
|
||||
if drawing_hands then return end
|
||||
for ent in next, pac.drawn_entities do
|
||||
if IsValid(ent) then
|
||||
if ent.pac_drawing and ent_parts[ent] then
|
||||
drawing_hands = true
|
||||
pac.RenderOverride(ent, "hands")
|
||||
drawing_hands = false
|
||||
end
|
||||
else
|
||||
pac.drawn_entities[ent] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
Reference in New Issue
Block a user