--[[ | 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