mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-18 14:13:46 +03:00
Upload
This commit is contained in:
145
lua/pac3/core/client/parts/legacy/bodygroup.lua
Normal file
145
lua/pac3/core/client/parts/legacy/bodygroup.lua
Normal file
@@ -0,0 +1,145 @@
|
||||
--[[
|
||||
| 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 BUILDER, PART = pac.PartTemplate("base")
|
||||
|
||||
PART.ClassName = "bodygroup"
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/user.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("BodyGroupName", "", {
|
||||
enums = function()
|
||||
return pace.current_part:GetBodyGroupNameList()
|
||||
end
|
||||
})
|
||||
BUILDER:GetSet("ModelIndex", 0)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:OnShow()
|
||||
self:SetBodyGroupName(self:GetBodyGroupName())
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self.BodyGroupName ~= "" and self.BodyGroupName or "no bodygroup"
|
||||
end
|
||||
|
||||
function PART:SetBodyGroupName(str)
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() and not self.markedFailed and self.bodygroup_index and self.oldBodygroup then
|
||||
owner:SetBodygroup(self.bodygroup_index, self.oldBodygroup)
|
||||
|
||||
if owner:IsPlayer() then
|
||||
owner.pac_bodygroups_torender = owner.pac_bodygroups_torender or {}
|
||||
owner.pac_bodygroups_torender[self.bodygroup_index] = self.oldBodygroup
|
||||
end
|
||||
|
||||
self.oldBodygroup = nil
|
||||
end
|
||||
|
||||
self.BodyGroupName = str
|
||||
self.markedFailed = false
|
||||
self:UpdateBodygroupData()
|
||||
end
|
||||
|
||||
function PART:SetModelIndex(i)
|
||||
self.ModelIndex = math.floor(tonumber(i) or 0)
|
||||
self.markedFailed = false
|
||||
self:UpdateBodygroupData()
|
||||
end
|
||||
|
||||
function PART:UpdateBodygroupData()
|
||||
self.bodygroup_index = nil
|
||||
self.minIndex = 0
|
||||
self.maxIndex = 0
|
||||
self:SetError()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not IsValid(ent) or not ent:GetBodyGroups() then return end
|
||||
local fName = self.BodyGroupName:lower():Trim()
|
||||
|
||||
if fName == '' then
|
||||
return
|
||||
end
|
||||
|
||||
for i, info in ipairs(ent:GetBodyGroups()) do
|
||||
if info.name:lower():Trim() == fName then
|
||||
self.bodygroup_index = info.id
|
||||
self.maxIndex = info.num - 1
|
||||
self.markedFailed = false
|
||||
self.oldBodygroup = ent:GetBodygroup(info.id)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if not self.markedFailed then
|
||||
pac.Message(self, ' - Unable to find bodygroup ' .. fName .. ' on ', ent)
|
||||
self:SetError("Unable to find bodygroup " .. fName .. " on " .. tostring(ent))
|
||||
self.markedFailed = true
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
if self.markedFailed then return end
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not owner:IsValid() then return end
|
||||
if not self.bodygroup_index then
|
||||
self:UpdateBodygroupData()
|
||||
return
|
||||
end
|
||||
|
||||
owner:SetBodygroup(self.bodygroup_index, self.ModelIndex)
|
||||
|
||||
if owner:IsPlayer() then
|
||||
owner.pac_bodygroups_torender = owner.pac_bodygroups_torender or {}
|
||||
owner.pac_bodygroups_torender[self.bodygroup_index] = self.ModelIndex
|
||||
end
|
||||
end
|
||||
|
||||
-- for the editor
|
||||
|
||||
function PART:GetModelIndexList()
|
||||
local out = {}
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
for _, info in pairs(ent:GetBodyGroups()) do
|
||||
if info.id == self.bodygroup_info.id then
|
||||
for _, model in pairs(info.submodels) do
|
||||
table.insert(out, model)
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
function PART:GetBodyGroupNameList()
|
||||
local out = {}
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
for _, info in pairs(ent:GetBodyGroups()) do
|
||||
out[info.name] = info.name
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
297
lua/pac3/core/client/parts/legacy/bone.lua
Normal file
297
lua/pac3/core/client/parts/legacy/bone.lua
Normal file
@@ -0,0 +1,297 @@
|
||||
--[[
|
||||
| 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 NULL = NULL
|
||||
local pairs = pairs
|
||||
|
||||
for _, v in pairs(ents.GetAll()) do
|
||||
v.pac_bone_setup_data = nil
|
||||
end
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "legacy bone"
|
||||
PART.ClassName = "bone"
|
||||
PART.Group = "legacy"
|
||||
PART.is_bone_part = true
|
||||
|
||||
PART.Icon = 'icon16/connect.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Jiggle", false)
|
||||
BUILDER:GetSet("ScaleChildren", false)
|
||||
BUILDER:GetSet("AlternativeBones", false)
|
||||
BUILDER:GetSet("MoveChildrenToOrigin", false)
|
||||
BUILDER:GetSet("FollowAnglesOnly", false)
|
||||
--BUILDER:GetSet("HideMesh", false)
|
||||
--BUILDER:GetSet("InvertHideMesh", false)
|
||||
BUILDER:GetSetPart("FollowPart")
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1), {editor_sensitivity = 0.25})
|
||||
BUILDER:PropertyOrder("PositionOffset")
|
||||
BUILDER:PropertyOrder("AngleOffset")
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
|
||||
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
BUILDER:RemoveProperty("Translucent")
|
||||
BUILDER:RemoveProperty("IgnoreZ")
|
||||
BUILDER:RemoveProperty("BlendMode")
|
||||
BUILDER:RemoveProperty("NoTextureFiltering")
|
||||
|
||||
local BaseClass_GetOwner = PART.GetOwner
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self:GetBone()
|
||||
end
|
||||
|
||||
PART.ThinkTime = 0
|
||||
|
||||
function PART:OnShow()
|
||||
self:SetBone(self:GetBone())
|
||||
end
|
||||
PART.OnParent = PART.OnShow
|
||||
|
||||
function PART:OnThink()
|
||||
-- this is to setup the cached values
|
||||
if not self.first_getbpos and self:GetOwner():IsValid() then
|
||||
self:GetBonePosition()
|
||||
self.first_getbpos = true
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:GetBonePosition()
|
||||
local owner = self:GetOwner()
|
||||
local pos, ang
|
||||
|
||||
pos, ang = pac.GetBonePosAng(owner, self.Bone, true)
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
local function manpos(ent, id, pos, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].pos = part.Position + part.PositionOffset
|
||||
else
|
||||
ent:ManipulateBonePosition(id, ent:GetManipulateBonePosition(id) + pos)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function manang(ent, id, ang, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].ang = part.Angles + part.AngleOffset
|
||||
else
|
||||
ent:ManipulateBoneAngles(id, ent:GetManipulateBoneAngles(id) + ang)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local inf_scale = Vector(math.huge, math.huge, math.huge)
|
||||
local inf_scale_tempcrashfix = Vector(1,1,1)*0.001
|
||||
|
||||
local function manscale(ent, id, scale, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].scale = scale
|
||||
else
|
||||
ent:ManipulateBoneScale(id, ent:GetManipulateBoneScale(id) * scale)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function scale_children(owner, id, scale, origin, ownerScale)
|
||||
local count = owner:GetBoneCount()
|
||||
ownerScale = ownerScale or owner.pac3_Scale or 1
|
||||
|
||||
if count == 0 or count < id then return end
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if owner:GetBoneParent(i) ~= id then goto CONTINUE end
|
||||
|
||||
local mat = owner:GetBoneMatrix(i)
|
||||
|
||||
if mat then
|
||||
if origin then
|
||||
mat:SetTranslation(origin)
|
||||
end
|
||||
|
||||
mat:Scale(mat:GetScale() * scale / ownerScale)
|
||||
owner:SetBoneMatrix(i, mat)
|
||||
end
|
||||
|
||||
scale_children(owner, i, scale, origin, ownerScale)
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
local in_build = false
|
||||
function pac.build_bone_callback(ent)
|
||||
if in_build then return end
|
||||
|
||||
in_build = true
|
||||
if ent.pac_matrixhack then
|
||||
pac.LegacyScale(ent)
|
||||
end
|
||||
|
||||
if ent.pac_bone_setup_data then
|
||||
for uid, data in pairs(ent.pac_bone_setup_data) do
|
||||
local part = data.part or NULL
|
||||
|
||||
if part:IsValid() then
|
||||
local mat = ent:GetBoneMatrix(data.bone)
|
||||
if mat then
|
||||
if part.FollowPart:IsValid() and part.FollowPart.GetWorldAngles and part.FollowPart.GetWorldPosition then
|
||||
if part.FollowAnglesOnly then
|
||||
local pos = mat:GetTranslation()
|
||||
mat:SetAngles(part.Angles + part.AngleOffset + part.FollowPart:GetWorldAngles())
|
||||
mat:SetTranslation(pos)
|
||||
else
|
||||
mat:SetAngles(part.Angles + part.AngleOffset + part.FollowPart:GetWorldAngles())
|
||||
mat:SetTranslation(part.Position + part.PositionOffset + part.FollowPart:GetWorldPosition())
|
||||
end
|
||||
else
|
||||
if data.pos then
|
||||
mat:Translate(data.pos)
|
||||
end
|
||||
|
||||
if data.ang then
|
||||
mat:Rotate(data.ang)
|
||||
end
|
||||
end
|
||||
|
||||
if data.scale then
|
||||
mat:Scale(mat:GetScale() * data.scale)
|
||||
end
|
||||
|
||||
if part.ScaleChildren then
|
||||
local scale = part.Scale * part.Size
|
||||
scale_children(ent, data.bone, scale, data.origin)
|
||||
end
|
||||
|
||||
ent:SetBoneMatrix(data.bone, mat)
|
||||
end
|
||||
else
|
||||
ent.pac_bone_setup_data[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
in_build = false
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
local index = self:GetModelBoneIndex()
|
||||
|
||||
if not index then
|
||||
index = 0
|
||||
end
|
||||
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
|
||||
if self.AlternativeBones or self.ScaleChildren or self.FollowPart:IsValid() then
|
||||
owner.pac_bone_setup_data[self.UniqueID] = owner.pac_bone_setup_data[self.UniqueID] or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID].bone = index
|
||||
owner.pac_bone_setup_data[self.UniqueID].part = self
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
local ang = self:CalcAngles(self.Angles) or self.Angles
|
||||
|
||||
if not owner.pac_follow_bones_function then
|
||||
owner.pac_follow_bones_function = pac.build_bone_callback
|
||||
local id
|
||||
id = owner:AddCallback("BuildBonePositions", function(ent)
|
||||
if not self:IsValid() then
|
||||
owner:RemoveCallback("BuildBonePositions", id)
|
||||
return
|
||||
end
|
||||
pac.build_bone_callback(ent)
|
||||
end)
|
||||
end
|
||||
|
||||
if not self.FollowPart:IsValid() then
|
||||
if self.EyeAngles or self.AimPart:IsValid() then
|
||||
ang.r = ang.y
|
||||
ang.y = -ang.p
|
||||
end
|
||||
|
||||
manpos(owner, index, self.Position + self.PositionOffset, self)
|
||||
manang(owner, index, ang + self.AngleOffset, self)
|
||||
end
|
||||
|
||||
if owner.pac_bone_setup_data[self.UniqueID] then
|
||||
if self.MoveChildrenToOrigin then
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = self:GetBonePosition()
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = nil
|
||||
end
|
||||
end
|
||||
|
||||
owner:ManipulateBoneJiggle(index, isnumber(self.Jiggle) and self.Jiggle or (self.Jiggle and 1 or 0)) -- afaik anything but 1 is not doing anything at all
|
||||
|
||||
local scale
|
||||
|
||||
if self.HideMesh then
|
||||
scale = inf_scale
|
||||
|
||||
owner.pac_inf_scale = true
|
||||
|
||||
if self.InvertHideMesh then
|
||||
local count = owner:GetBoneCount()
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if i ~= index then
|
||||
manscale(owner, i, inf_scale, self)
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
else
|
||||
|
||||
owner.pac_inf_scale = false
|
||||
|
||||
scale = self.Scale * self.Size
|
||||
end
|
||||
|
||||
manscale(owner, index, scale, self)
|
||||
|
||||
owner.needs_setupbones_from_legacy_bone_parts = true
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
297
lua/pac3/core/client/parts/legacy/bone2.lua
Normal file
297
lua/pac3/core/client/parts/legacy/bone2.lua
Normal file
@@ -0,0 +1,297 @@
|
||||
--[[
|
||||
| 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 NULL = NULL
|
||||
local pairs = pairs
|
||||
|
||||
for _, v in pairs(ents.GetAll()) do
|
||||
v.pac_bone_setup_data = nil
|
||||
end
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "legacy experimental bone"
|
||||
PART.ClassName = "bone2"
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/connect.png'
|
||||
PART.is_bone_part = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Jiggle", false)
|
||||
BUILDER:GetSet("ScaleChildren", false)
|
||||
BUILDER:GetSet("AlternativeBones", false)
|
||||
BUILDER:GetSet("MoveChildrenToOrigin", false)
|
||||
BUILDER:GetSet("FollowAnglesOnly", false)
|
||||
BUILDER:GetSet("HideMesh", false)
|
||||
BUILDER:GetSet("InvertHideMesh", false)
|
||||
BUILDER:GetSetPart("FollowPart")
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1), {editor_sensitivity = 0.25})
|
||||
BUILDER:PropertyOrder("PositionOffset")
|
||||
BUILDER:PropertyOrder("AngleOffset")
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
|
||||
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
BUILDER:RemoveProperty("Translucent")
|
||||
BUILDER:RemoveProperty("IgnoreZ")
|
||||
BUILDER:RemoveProperty("BlendMode")
|
||||
BUILDER:RemoveProperty("NoTextureFiltering")
|
||||
|
||||
function PART:GetNiceName()
|
||||
return self:GetBone()
|
||||
end
|
||||
|
||||
PART.ThinkTime = 0
|
||||
|
||||
function PART:OnShow()
|
||||
self:SetBone(self:GetBone())
|
||||
end
|
||||
|
||||
PART.OnParent = PART.OnShow
|
||||
|
||||
function PART:OnThink()
|
||||
-- this is to setup the cached values
|
||||
if not self.first_getbpos and self:GetOwner():IsValid() then
|
||||
self:GetBonePosition()
|
||||
self.first_getbpos = true
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:GetBonePosition()
|
||||
local owner = self:GetOwner()
|
||||
return pac.GetBonePosAng(owner, self.Bone, true)
|
||||
end
|
||||
|
||||
local function manpos(ent, id, pos, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].pos = part.Position + part.PositionOffset
|
||||
else
|
||||
ent:ManipulateBonePosition(id, ent:GetManipulateBonePosition(id) + pos)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function manang(ent, id, ang, part)
|
||||
if part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].ang = part.Angles + part.AngleOffset
|
||||
else
|
||||
ent:ManipulateBoneAngles(id, ent:GetManipulateBoneAngles(id) + ang)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local inf_scale = Vector(math.huge, math.huge, math.huge)
|
||||
|
||||
local function manscale(ent, id, scale, part)
|
||||
if part and part.AlternativeBones then
|
||||
ent.pac_bone_setup_data[part.UniqueID].scale = scale
|
||||
else
|
||||
ent:ManipulateBoneScale(id, ent:GetManipulateBoneScale(id) * scale)
|
||||
part.modified_bones = true
|
||||
end
|
||||
end
|
||||
|
||||
local function scale_children(owner, id, scale, origin, ownerScale)
|
||||
local count = owner:GetBoneCount()
|
||||
ownerScale = ownerScale or owner.pac3_Scale or 1
|
||||
|
||||
if count == 0 or count < id then return end
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if owner:GetBoneParent(i) ~= id then goto CONTINUE end
|
||||
|
||||
local mat = owner:GetBoneMatrix(i)
|
||||
|
||||
if mat then
|
||||
if origin then
|
||||
mat:SetTranslation(origin)
|
||||
end
|
||||
|
||||
mat:Scale(mat:GetScale() * scale / ownerScale)
|
||||
owner:SetBoneMatrix(i, mat)
|
||||
end
|
||||
|
||||
scale_children(owner, i, scale, origin, ownerScale)
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function pac.build_bone_callback(ent)
|
||||
if ent.pac_matrixhack then
|
||||
pac.LegacyScale(ent)
|
||||
end
|
||||
|
||||
if ent.pac_bone_setup_data then
|
||||
for uid, data in pairs(ent.pac_bone_setup_data) do
|
||||
local part = data.part or NULL
|
||||
|
||||
if part:IsValid() then
|
||||
local mat = ent:GetBoneMatrix(data.bone)
|
||||
if mat then
|
||||
if part.FollowPart:IsValid() and part.FollowPart.GetWorldPosition then
|
||||
|
||||
mat:SetAngles(part.FollowPart:GetWorldAngles())
|
||||
|
||||
if not part.FollowAnglesOnly then
|
||||
mat:SetTranslation(part.FollowPart:GetWorldPosition())
|
||||
end
|
||||
|
||||
else
|
||||
if data.pos then
|
||||
mat:Translate(data.pos)
|
||||
end
|
||||
|
||||
if data.ang then
|
||||
mat:Rotate(data.ang)
|
||||
end
|
||||
end
|
||||
|
||||
if data.scale then
|
||||
mat:Scale(mat:GetScale() * data.scale)
|
||||
end
|
||||
|
||||
if part.ScaleChildren then
|
||||
local scale = part.Scale * part.Size
|
||||
scale_children(ent, data.bone, scale, data.origin)
|
||||
end
|
||||
|
||||
ent:SetBoneMatrix(data.bone, mat)
|
||||
end
|
||||
else
|
||||
ent.pac_bone_setup_data[uid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnBuildBonePositions()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if not owner:IsValid() then return end
|
||||
|
||||
local index = self:GetModelBoneIndex()
|
||||
|
||||
if not index then return end
|
||||
|
||||
owner.pac_bone_setup_data = owner.pac_bone_setup_data or {}
|
||||
|
||||
if self.AlternativeBones or self.ScaleChildren or self.FollowPart:IsValid() then
|
||||
owner.pac_bone_setup_data[self.UniqueID] = owner.pac_bone_setup_data[self.UniqueID] or {}
|
||||
owner.pac_bone_setup_data[self.UniqueID].bone = index
|
||||
owner.pac_bone_setup_data[self.UniqueID].part = self
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
local ang = self:CalcAngles(self.Angles) or self.Angles
|
||||
|
||||
if not owner.pac_follow_bones_function then
|
||||
owner.pac_follow_bones_function = pac.build_bone_callback
|
||||
local id
|
||||
id = owner:AddCallback("BuildBonePositions", function(ent)
|
||||
if pac and pac.build_bone_callback then
|
||||
pac.build_bone_callback(ent)
|
||||
else
|
||||
owner:RemoveCallback("BuildBonePositions", id)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if not self.FollowPart:IsValid() then
|
||||
if self.EyeAngles or self.AimPart:IsValid() then
|
||||
ang.r = ang.y
|
||||
ang.y = -ang.p
|
||||
end
|
||||
|
||||
local pos2, ang2 = self.Position + self.PositionOffset, ang + self.AngleOffset
|
||||
|
||||
local parent = self:GetParent()
|
||||
|
||||
if parent and parent:IsValid() and parent.ClassName == 'jiggle' then
|
||||
local pos3, ang3 = parent.Position, parent.Angles
|
||||
|
||||
if parent.pos then
|
||||
pos2 = pos2 + parent.pos - pos3
|
||||
end
|
||||
|
||||
if parent.ang then
|
||||
ang2 = ang2 + parent.ang - ang3
|
||||
end
|
||||
end
|
||||
|
||||
manpos(owner, index, pos2, self)
|
||||
manang(owner, index, ang2, self)
|
||||
end
|
||||
|
||||
if owner.pac_bone_setup_data[self.UniqueID] then
|
||||
if self.MoveChildrenToOrigin then
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = self:GetBonePosition()
|
||||
else
|
||||
owner.pac_bone_setup_data[self.UniqueID].origin = nil
|
||||
end
|
||||
end
|
||||
|
||||
owner:ManipulateBoneJiggle(index, isnumber(self.Jiggle) and self.Jiggle or (self.Jiggle and 1 or 0)) -- afaik anything but 1 is not doing anything at all
|
||||
|
||||
local scale
|
||||
|
||||
if self.HideMesh then
|
||||
scale = inf_scale
|
||||
owner.pac_inf_scale = true
|
||||
|
||||
if self.InvertHideMesh then
|
||||
local count = owner:GetBoneCount()
|
||||
|
||||
for i = 0, count - 1 do
|
||||
if i ~= index then
|
||||
manscale(owner, i, inf_scale, self)
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
else
|
||||
owner.pac_inf_scale = false
|
||||
|
||||
scale = self.Scale * self.Size
|
||||
end
|
||||
|
||||
manscale(owner, index, scale, self)
|
||||
|
||||
owner.needs_setupbones_from_legacy_bone_parts = true
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
77
lua/pac3/core/client/parts/legacy/clip.lua
Normal file
77
lua/pac3/core/client/parts/legacy/clip.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
--[[
|
||||
| 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 render_EnableClipping = render.EnableClipping
|
||||
local render_PushCustomClipPlane = render.PushCustomClipPlane
|
||||
local LocalToWorld = LocalToWorld
|
||||
local IsEntity = IsEntity
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy clip"
|
||||
PART.ClassName = "clip"
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/cut.png'
|
||||
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
|
||||
BUILDER:RemoveProperty("IgnoreZ")
|
||||
BUILDER:RemoveProperty("BlendMode")
|
||||
BUILDER:RemoveProperty("NoTextureFiltering")
|
||||
|
||||
|
||||
function PART:OnParent(part)
|
||||
if not part.AddModifier then return end
|
||||
|
||||
part:AddModifier(self)
|
||||
|
||||
-- this is only really for halos..
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
function ent.pacDrawModel(ent)
|
||||
self:PreOnDraw()
|
||||
ent:DrawModel()
|
||||
self:PostOnDraw()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnUnParent(part)
|
||||
if not part:IsValid() then return end
|
||||
if not part.RemoveModifier then return end
|
||||
part:RemoveModifier(self)
|
||||
end
|
||||
|
||||
do
|
||||
local bclip
|
||||
|
||||
function PART:PreOnDraw()
|
||||
bclip = render_EnableClipping(true)
|
||||
|
||||
local pos, ang = LocalToWorld(self.Position + self.PositionOffset, self:CalcAngles(self.Angles + self.AngleOffset), self:GetBonePosition())
|
||||
local normal = ang:Forward()
|
||||
|
||||
render_PushCustomClipPlane(normal, normal:Dot(pos + normal))
|
||||
end
|
||||
|
||||
local render_PopCustomClipPlane = render.PopCustomClipPlane
|
||||
|
||||
function PART:PostOnDraw()
|
||||
render_PopCustomClipPlane()
|
||||
|
||||
render_EnableClipping(bclip)
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
628
lua/pac3/core/client/parts/legacy/entity.lua
Normal file
628
lua/pac3/core/client/parts/legacy/entity.lua
Normal file
@@ -0,0 +1,628 @@
|
||||
--[[
|
||||
| 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 render_CullMode = render.CullMode
|
||||
local render_SuppressEngineLighting = render.SuppressEngineLighting
|
||||
local render_SetBlend = render.SetBlend
|
||||
local render_SetColorModulation = render.SetColorModulation
|
||||
local render_MaterialOverride = render.MaterialOverride
|
||||
local game_SinglePlayer = game.SinglePlayer
|
||||
local Angle = Angle
|
||||
local Vector = Vector
|
||||
local NULL = NULL
|
||||
local Color = Color
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy entity"
|
||||
PART.ClassName = "entity"
|
||||
PART.Group = 'legacy'
|
||||
PART.Icon = 'icon16/brick.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:GetSet("Model", "")
|
||||
BUILDER:GetSet("Material", "")
|
||||
BUILDER:GetSet("HideEntity", false)
|
||||
BUILDER:GetSet("DrawWeapon", true)
|
||||
BUILDER:GetSet("MuteSounds", false)
|
||||
BUILDER:GetSet("AllowOggWhenMuted", false)
|
||||
BUILDER:GetSet("HideBullets", false)
|
||||
BUILDER:GetSet("DrawPlayerOnDeath", false)
|
||||
BUILDER:GetSet("HidePhysgunBeam", false)
|
||||
BUILDER:GetSet("UseLegacyScale", false)
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Brightness", 1)
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
BUILDER:GetSet("Fullbright", false)
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
BUILDER:PropertyOrder("Translucent")
|
||||
BUILDER:GetSet("Invert", false)
|
||||
BUILDER:GetSet("DoubleFace", false)
|
||||
BUILDER:GetSet("Skin", 0, {editor_onchange = function(self, num) return math.Round(math.max(tonumber(num), 0)) end})
|
||||
BUILDER:GetSet("DrawShadow", true)
|
||||
BUILDER:GetSet("LodOverride", -1)
|
||||
BUILDER:SetPropertyGroup("movement")
|
||||
BUILDER:GetSet("SprintSpeed", 0)
|
||||
BUILDER:GetSet("RunSpeed", 0)
|
||||
BUILDER:GetSet("WalkSpeed", 0)
|
||||
BUILDER:GetSet("CrouchSpeed", 0)
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1))
|
||||
BUILDER:SetPropertyGroup("behavior")
|
||||
BUILDER:GetSet("RelativeBones", true)
|
||||
BUILDER:GetSet("Weapon", false)
|
||||
BUILDER:GetSet("InverseKinematics", false)
|
||||
BUILDER:GetSet("MuteFootsteps", false)
|
||||
BUILDER:GetSet("SuppressFrames", false)
|
||||
BUILDER:GetSet("AnimationRate", 1)
|
||||
BUILDER:GetSet("FallApartOnDeath", false)
|
||||
BUILDER:GetSet("DeathRagdollizeParent", false)
|
||||
BUILDER:GetSet("HideRagdollOnDeath", false)
|
||||
BUILDER:GetSetPart("EyeTarget")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
local ent_fields = {}
|
||||
|
||||
function BUILDER:EntityField(name, field)
|
||||
|
||||
field = "pac_" .. field
|
||||
|
||||
ent_fields[field] = name
|
||||
|
||||
self.PART["Set" .. name] = function(self, val)
|
||||
self[name] = val
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if owner:IsValid() then
|
||||
owner[field] = val
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
BUILDER:EntityField("InverseKinematics", "enable_ik")
|
||||
BUILDER:EntityField("MuteFootsteps", "mute_footsteps")
|
||||
BUILDER:EntityField("AnimationRate", "global_animation_rate")
|
||||
|
||||
BUILDER:EntityField("RunSpeed", "run_speed")
|
||||
BUILDER:EntityField("WalkSpeed", "walk_speed")
|
||||
BUILDER:EntityField("CrouchSpeed", "crouch_speed")
|
||||
BUILDER:EntityField("SprintSpeed", "sprint_speed")
|
||||
|
||||
BUILDER:EntityField("FallApartOnDeath", "death_physics_parts")
|
||||
BUILDER:EntityField("DeathRagdollizeParent", "death_ragdollize")
|
||||
BUILDER:EntityField("HideRagdollOnDeath", "death_hide_ragdoll")
|
||||
BUILDER:EntityField("DrawPlayerOnDeath", "draw_player_on_death")
|
||||
BUILDER:EntityField("HidePhysgunBeam", "hide_physgun_beam")
|
||||
|
||||
BUILDER:EntityField("MuteSounds", "mute_sounds")
|
||||
BUILDER:EntityField("AllowOggWhenMuted", "allow_ogg_sounds")
|
||||
BUILDER:EntityField("HideBullets", "hide_bullets")
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if ent:IsPlayer() then
|
||||
return ent:Nick()
|
||||
else
|
||||
return language.GetPhrase(ent:GetClass())
|
||||
end
|
||||
end
|
||||
|
||||
if self.Weapon then
|
||||
return "Weapon"
|
||||
end
|
||||
|
||||
return self.ClassName
|
||||
end
|
||||
|
||||
|
||||
function PART:SetUseLegacyScale(b)
|
||||
self.UseLegacyScale = b
|
||||
self:UpdateScale()
|
||||
end
|
||||
|
||||
function PART:SetWeapon(b)
|
||||
self.Weapon = b
|
||||
if b then
|
||||
self:OnShow()
|
||||
else
|
||||
self:OnHide()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetDrawShadow(b)
|
||||
self.DrawShadow = b
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
ent:DrawShadow(b)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateScale(ent)
|
||||
ent = ent or self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if not self.UseLegacyScale then
|
||||
ent.pac3_Scale = self.Size
|
||||
end
|
||||
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "size", ent, self.Size)
|
||||
end
|
||||
pac.SetModelScale(ent, self.Scale)
|
||||
else
|
||||
pac.SetModelScale(ent, self.Scale * self.Size)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSize(val)
|
||||
self.Size = val
|
||||
self:UpdateScale()
|
||||
end
|
||||
|
||||
function PART:SetScale(val)
|
||||
self.Scale = val
|
||||
self:UpdateScale()
|
||||
end
|
||||
|
||||
function PART:SetColor(var)
|
||||
var = var or Vector(255, 255, 255)
|
||||
|
||||
self.Color = var
|
||||
self.Colorf = Vector(var.r, var.g, var.b) / 255
|
||||
|
||||
self.Colorc = self.Colorc or Color(var.r, var.g, var.b, self.Alpha)
|
||||
self.Colorc.r = var.r
|
||||
self.Colorc.g = var.g
|
||||
self.Colorc.b = var.b
|
||||
end
|
||||
|
||||
function PART:SetAlpha(var)
|
||||
self.Alpha = var
|
||||
|
||||
self.Colorc = self.Colorc or Color(self.Color.r, self.Color.g, self.Color.b, self.Alpha)
|
||||
self.Colorc.a = var
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var) then
|
||||
if var == "" then
|
||||
self.Materialm = nil
|
||||
else
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
self.Material = var
|
||||
end
|
||||
|
||||
function PART:SetRelativeBones(b)
|
||||
self.RelativeBones = b
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
self:UpdateScale(ent)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateWeaponDraw(ent)
|
||||
local wep = ent and ent:IsValid() and ent.GetActiveWeapon and ent:GetActiveWeapon() or NULL
|
||||
|
||||
if wep:IsWeapon() then
|
||||
if not wep.pac_weapon_class then
|
||||
wep:SetNoDraw(not self.DrawWeapon)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateColor()
|
||||
render_SetColorModulation(self.Colorf.r * self.Brightness, self.Colorf.g * self.Brightness, self.Colorf.b * self.Brightness)
|
||||
if pac.drawing_motionblur_alpha then return end
|
||||
render_SetBlend(self.Alpha)
|
||||
end
|
||||
|
||||
function PART:UpdateMaterial()
|
||||
local mat = self.MaterialOverride or self.Materialm
|
||||
if mat then
|
||||
render_MaterialOverride(mat)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:UpdateAll(ent)
|
||||
self:UpdateColor(ent)
|
||||
self:UpdateMaterial(ent)
|
||||
self:UpdateScale(ent)
|
||||
end
|
||||
|
||||
local angle_origin = Angle()
|
||||
|
||||
local function setup_suppress()
|
||||
local last_framenumber = 0
|
||||
local current_frame = 0
|
||||
local current_frame_count = 0
|
||||
|
||||
return function()
|
||||
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
|
||||
|
||||
function PART:OnShow()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
self:SetModel(self:GetModel())
|
||||
|
||||
if self.Weapon and ent.GetActiveWeapon and ent:GetActiveWeapon():IsValid() then
|
||||
ent = ent:GetActiveWeapon()
|
||||
end
|
||||
|
||||
for _, field in pairs(ent_fields) do
|
||||
self["Set" .. field](self, self[field])
|
||||
end
|
||||
|
||||
self:SetColor(self:GetColor())
|
||||
ent:SetColor(self.Colorc)
|
||||
self:UpdateWeaponDraw(self:GetOwner())
|
||||
|
||||
function ent.RenderOverride()
|
||||
if self:IsValid() then
|
||||
if not self.HideEntity then
|
||||
if self.SuppressFrames then
|
||||
if not self.should_suppress then
|
||||
self.should_suppress = setup_suppress()
|
||||
end
|
||||
|
||||
if self.should_suppress() then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self:ModifiersPostEvent("PreDraw")
|
||||
self:PreEntityDraw(ent)
|
||||
|
||||
local modpos = not self.Position:IsZero() or not self.Angles:IsZero()
|
||||
local pos
|
||||
|
||||
self.BoneOverride = nil
|
||||
|
||||
if modpos then
|
||||
pos = ent:GetPos()
|
||||
|
||||
self.BoneOverride = "none"
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
ent:SetPos(pos)
|
||||
ent:SetRenderAngles(ang)
|
||||
pac.SetupBones(ent)
|
||||
end
|
||||
|
||||
ent:SetSkin(self.Skin)
|
||||
|
||||
if ent.pac_bodygroups_torender then
|
||||
for bgID, bgVal in pairs(ent.pac_bodygroups_torender) do
|
||||
ent:SetBodygroup(bgID, bgVal)
|
||||
end
|
||||
end
|
||||
|
||||
ent.pac_bodygroups_torender = nil
|
||||
|
||||
if self.EyeTarget.GetWorldPosition then
|
||||
ent:SetEyeTarget(self.EyeTarget:GetWorldPosition())
|
||||
end
|
||||
|
||||
ent:DrawModel()
|
||||
|
||||
if modpos then
|
||||
ent:SetPos(pos)
|
||||
ent:SetRenderAngles(angle_origin)
|
||||
end
|
||||
|
||||
self:PostEntityDraw(ent)
|
||||
self:ModifiersPostEvent("OnDraw")
|
||||
end
|
||||
else
|
||||
ent.RenderOverride = nil
|
||||
end
|
||||
end
|
||||
|
||||
self.current_ro = ent.RenderOverride
|
||||
|
||||
self:UpdateScale()
|
||||
|
||||
if self.LodOverride ~= -1 then self:SetLodOverride(self.LodOverride) end
|
||||
end
|
||||
|
||||
local ALLOW_TO_MDL = CreateConVar('pac_allow_mdl', '1', CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, 'Allow to use custom MDLs')
|
||||
local ALLOW_TO_USE_MDL = CreateConVar('pac_allow_mdl_entity', '1', CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, 'Allow to use custom MDLs as Entity')
|
||||
|
||||
function PART:SetModel(path)
|
||||
self.Model = path
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
pac.ResetBoneCache(ent)
|
||||
|
||||
if path:find("^http") then
|
||||
local status, reason = hook.Run('PAC3AllowMDLDownload', self:GetPlayerOwner(), self, path)
|
||||
local status2, reason2 = hook.Run('PAC3AllowEntityMDLDownload', self:GetPlayerOwner(), self, path)
|
||||
|
||||
if ALLOW_TO_USE_MDL:GetBool() and ALLOW_TO_MDL:GetBool() and status ~= false and status2 ~= false then
|
||||
if ent == pac.LocalPlayer then
|
||||
pac.Message("downloading ", path, " to use as player model")
|
||||
end
|
||||
|
||||
pac.DownloadMDL(path, function(real_path)
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.Message("finished downloading ", path)
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", ent, self.Model)
|
||||
end
|
||||
|
||||
ent:SetModel(real_path)
|
||||
|
||||
ent:SetSubMaterial()
|
||||
|
||||
for i = 0, #ent:GetBodyGroups() - 1 do
|
||||
ent:SetBodygroup(i, 0)
|
||||
end
|
||||
|
||||
pac.ResetBoneCache(ent)
|
||||
|
||||
for _, child in ipairs(self:GetChildrenList()) do
|
||||
child:OnShow(true)
|
||||
end
|
||||
end, function(err)
|
||||
pac.Message(err)
|
||||
self:SetError(err)
|
||||
end, self:GetPlayerOwner())
|
||||
|
||||
self.mdl_zip = true
|
||||
else
|
||||
local msg = reason2 or reason or "mdl is not allowed"
|
||||
self.loading = msg
|
||||
self:SetError(msg)
|
||||
pac.Message(self:GetPlayerOwner(), ' - mdl files are not allowed')
|
||||
end
|
||||
elseif self.Model ~= "" then
|
||||
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", ent, self.Model)
|
||||
end
|
||||
|
||||
ent:SetModel(self.Model)
|
||||
|
||||
|
||||
pac.RunNextFrame('entity updatemat ' .. tostring(ent), function()
|
||||
if not ent:IsValid() or not self:IsValid() then return end
|
||||
pac.ResetBoneCache(ent)
|
||||
ent:SetSubMaterial()
|
||||
|
||||
for i = 0, #ent:GetBodyGroups() - 1 do
|
||||
ent:SetBodygroup(i, 0)
|
||||
end
|
||||
|
||||
self:CallRecursive("CalcShowHide", true)
|
||||
end)
|
||||
|
||||
self.mdl_zip = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetLodOverride(num)
|
||||
self.LodOverride = num
|
||||
local owner = self:GetOwner()
|
||||
if owner:IsValid() then
|
||||
owner:SetLOD(num)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.pac_mute_footsteps = self.MuteFootsteps
|
||||
|
||||
if self.Weapon and ent.GetActiveWeapon and ent:GetActiveWeapon():IsValid() then
|
||||
ent = ent:GetActiveWeapon()
|
||||
end
|
||||
|
||||
-- holy shit why does shooting reset the scale in singleplayer
|
||||
-- dumb workaround
|
||||
if game_SinglePlayer() and ent:IsPlayer() and ent:GetModelScale() ~= self.Size then
|
||||
self:UpdateScale(ent)
|
||||
end
|
||||
|
||||
if (self.HideEntity or self.Weapon) and self.current_ro ~= ent.RenderOverride then
|
||||
self:OnShow()
|
||||
end
|
||||
|
||||
ent.pac_material = self.Material
|
||||
ent.pac_materialm = self.Materialm
|
||||
ent.pac_color = self.Colorf
|
||||
ent.pac_alpha = self.Alpha
|
||||
ent.pac_brightness = self.Brightness
|
||||
|
||||
ent.pac_hide_entity = self.HideEntity
|
||||
ent.pac_fullbright = self.Fullbright
|
||||
ent.pac_invert = self.Invert
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
pac.emut.RestoreMutations(self:GetPlayerOwner(), "model", ent)
|
||||
pac.emut.RestoreMutations(self:GetPlayerOwner(), "size", ent)
|
||||
end
|
||||
|
||||
pac.SetModelScale(ent)
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then return end
|
||||
|
||||
if self.Weapon and ent.GetActiveWeapon and ent:GetActiveWeapon():IsValid() then
|
||||
ent = ent:GetActiveWeapon()
|
||||
end
|
||||
|
||||
ent.RenderOverride = nil
|
||||
ent:SetColor(Color(255, 255, 255, 255))
|
||||
|
||||
ent.pac_material = nil
|
||||
ent.pac_materialm = nil
|
||||
ent.pac_color = nil
|
||||
ent.pac_alpha = nil
|
||||
ent.pac_brightness = nil
|
||||
|
||||
ent.pac_hide_entity = nil
|
||||
ent.pac_fullbright = nil
|
||||
ent.pac_invert = nil
|
||||
|
||||
for key in pairs(ent_fields) do
|
||||
ent[key] = nil
|
||||
end
|
||||
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
-- do nothing, we want the player to feel small even on hide
|
||||
else
|
||||
pac.SetModelScale(ent, Vector(1,1,1))
|
||||
end
|
||||
|
||||
local weps = ent.GetWeapons and ent:GetWeapons()
|
||||
|
||||
if weps then
|
||||
for _, wep in pairs(weps) do
|
||||
if not wep.pac_weapon_class then
|
||||
wep:SetNoDraw(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.LodOverride ~= -1 then
|
||||
ent:SetLOD(-1)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetHideEntity(b)
|
||||
self.HideEntity = b
|
||||
if b then
|
||||
self:OnHide()
|
||||
else
|
||||
self:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PreEntityDraw(ent)
|
||||
self:UpdateWeaponDraw(ent)
|
||||
|
||||
self:UpdateColor(ent)
|
||||
self:UpdateMaterial(ent)
|
||||
|
||||
if self.Invert then
|
||||
render_CullMode(1) -- MATERIAL_CULLMODE_CW
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(true)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PostEntityDraw()
|
||||
if self.Invert then
|
||||
render_CullMode(0) -- MATERIAL_CULLMODE_CCW
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(false)
|
||||
end
|
||||
|
||||
render_SetBlend(1)
|
||||
render_SetColorModulation(1,1,1)
|
||||
|
||||
render_MaterialOverride()
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
|
||||
do
|
||||
local IN_SPEED = IN_SPEED
|
||||
local IN_WALK = IN_WALK
|
||||
local IN_DUCK = IN_DUCK
|
||||
|
||||
local function mod_speed(cmd, speed)
|
||||
if speed and speed ~= 0 then
|
||||
local forward = cmd:GetForwardMove()
|
||||
forward = forward > 0 and speed or forward < 0 and -speed or 0
|
||||
|
||||
local side = cmd:GetSideMove()
|
||||
side = side > 0 and speed or side < 0 and -speed or 0
|
||||
|
||||
|
||||
cmd:SetForwardMove(forward)
|
||||
cmd:SetSideMove(side)
|
||||
end
|
||||
end
|
||||
|
||||
pac.AddHook("CreateMove", "legacy_entity_part_speed_modifier", function(cmd)
|
||||
if cmd:KeyDown(IN_SPEED) then
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_sprint_speed)
|
||||
elseif cmd:KeyDown(IN_WALK) then
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_walk_speed)
|
||||
elseif cmd:KeyDown(IN_DUCK) then
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_crouch_speed)
|
||||
else
|
||||
mod_speed(cmd, pac.LocalPlayer.pac_run_speed)
|
||||
end
|
||||
end)
|
||||
end
|
||||
63
lua/pac3/core/client/parts/legacy/light.lua
Normal file
63
lua/pac3/core/client/parts/legacy/light.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
--[[
|
||||
| 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 BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy light"
|
||||
PART.ClassName = "light"
|
||||
PART.Group = "legacy"
|
||||
|
||||
PART.Icon = 'icon16/lightbulb.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("Brightness", 1)
|
||||
BUILDER:GetSet("Size", 5, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Style", 0, {editor_clamp = {0, 16}})
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local hue = pac.ColorToNames(self:GetColor())
|
||||
return hue .. " light"
|
||||
end
|
||||
|
||||
local DynamicLight = DynamicLight
|
||||
|
||||
function PART:OnDraw()
|
||||
local pos = self:GetDrawPosition()
|
||||
local light = self.light or DynamicLight(tonumber(self.UniqueID))
|
||||
|
||||
light.Pos = pos
|
||||
|
||||
light.MinLight = self.Brightness
|
||||
light.Size = self.Size
|
||||
light.Style = self.Style
|
||||
|
||||
light.r = self.Color.r
|
||||
light.g = self.Color.g
|
||||
light.b = self.Color.b
|
||||
|
||||
-- 100000000 constant is better than calling pac.RealTime
|
||||
light.DieTime = 1000000000000 -- pac.RealTime
|
||||
|
||||
self.light = light
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local light = self.light
|
||||
if light then
|
||||
light.DieTime = 0
|
||||
light.Size = 0
|
||||
light.MinLight = 0
|
||||
light.Pos = Vector()
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
484
lua/pac3/core/client/parts/legacy/material.lua
Normal file
484
lua/pac3/core/client/parts/legacy/material.lua
Normal file
@@ -0,0 +1,484 @@
|
||||
--[[
|
||||
| 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 BUILDER, PART = pac.PartTemplate("base")
|
||||
|
||||
PART.FriendlyName = "legacy material"
|
||||
PART.ClassName = "material"
|
||||
|
||||
PART.Icon = 'icon16/paintcan.png'
|
||||
PART.Group = "legacy"
|
||||
|
||||
local group_ordering = {
|
||||
{pattern = "phong", group = "phong"},
|
||||
{pattern = "envmap", group = "env map"},
|
||||
{pattern = {"ambientocclusion", "halflambert"}, group = "ambient occlusion"},
|
||||
{pattern = "detail", group = "detail"},
|
||||
{pattern = "rimlight", group = "rimlight"},
|
||||
{pattern = {"cloak", "refract"}, group = "cloak"},
|
||||
{pattern = "color", group = "colors"},
|
||||
{pattern = {"bumpmap", "basetexture", "^envmapmask$", "lightwarptexture"}, group = "textures"},
|
||||
{pattern = "flesh", group = "flesh"},
|
||||
{pattern = "selfillum", group = "selfillum"},
|
||||
{pattern = "emissive", group ="emissive"},
|
||||
}
|
||||
|
||||
PART.ShaderParams =
|
||||
{
|
||||
BaseTexture = "ITexture",
|
||||
|
||||
CloakPassEnabled = "boolean",
|
||||
CloakFactor = {type = "number", extra = {editor_sensitivity = 0.25, editor_clamp = {0, 1}}},
|
||||
CloakColorTint = "Vector",
|
||||
RefractAmount = "number",
|
||||
|
||||
BumpMap = "ITexture",
|
||||
LightWarpTexture = "ITexture",
|
||||
|
||||
Detail = "ITexture",
|
||||
DetailTint = "Vector",
|
||||
DetailScale = "number",
|
||||
DetailBlendMode = {type = "number", extra = {editor_onchange = function(pnl, num) return math.Round(math.max(num, 0)) end}},
|
||||
DetailBlendFactor = "number",
|
||||
|
||||
Phong = "boolean",
|
||||
PhongBoost = "number",
|
||||
PhongExponent = "number",
|
||||
PhongTint = "Vector",
|
||||
PhongFresnelRanges = {type = "Vector", extra = {editor_panel = "color"}},
|
||||
PhongWarpTexture = "ITexture",
|
||||
PhongAlbedoTint = "boolean",
|
||||
PhongExponentTexture = "ITexture",
|
||||
|
||||
Rimlight = "boolean",
|
||||
RimlightBoost = "number",
|
||||
RimlightExponent = "number",
|
||||
|
||||
-- doesn't do anything i think
|
||||
EnvMap = "ITexture",
|
||||
EnvMapMask = "ITexture",
|
||||
EnvMapTint = "Vector",
|
||||
EnvMapMode = "number",
|
||||
EnvMapContrast = "number",
|
||||
EnvMapMaskScale = "number",
|
||||
EnvMapSaturation = "Vector",
|
||||
NormalMapAlphaEnvMapMask = "boolean",
|
||||
BaseAlphaEnvMapMask = "boolean",
|
||||
Selfillum_EnvMapMask_Alpha = "number",
|
||||
|
||||
AmbientOcclusion = "boolean",
|
||||
AmbientOcclusionColor = "Vector",
|
||||
AmbientOcclusionTexture = "ITexture",
|
||||
|
||||
BlendTintByBaseAlpha = "boolean",
|
||||
BlendTintColorOverBase = "Vector",
|
||||
ColorTint_Base = "Vector",
|
||||
ColorTint_Tmp = "Vector",
|
||||
Color = "Vector",
|
||||
Color2 = "Vector",
|
||||
Additive = "boolean",
|
||||
AlphaTest = "boolean",
|
||||
TranslucentX = "boolean",
|
||||
|
||||
|
||||
HalfLambert = "boolean",
|
||||
|
||||
Selfillum = "boolean",
|
||||
SelfillumTint = "Vector",
|
||||
SelfillumMask = "ITexture",
|
||||
Selfillum_Envmapmask_Alpha = "ITexture",
|
||||
SelfillumFresnel = "boolean",
|
||||
SelfillumFresnlenMinMaxExp = "Vector",
|
||||
|
||||
FleshInteriorEnabled = "boolean", --"0", "Enable Flesh interior blend pass" )
|
||||
FleshInteriorTexture = "ITexture", --"", "Flesh color texture" )
|
||||
FleshInteriorNoiseTexture = "ITexture", --"", "Flesh noise texture" )
|
||||
FleshBorderTexture1D = "ITexture", --"", "Flesh border 1D texture" )
|
||||
FleshNormalTexture = "ITexture", --"", "Flesh normal texture" )
|
||||
FleshSubsurfaceTexture = "ITexture", --"", "Flesh subsurface texture" )
|
||||
FleshCubeTexture = "ITexture", --"", "Flesh cubemap texture" )
|
||||
FleshBorderNoiseScale = "number", --"1.5", "Flesh Noise UV scalar for border" )
|
||||
FleshDebugForceFleshOn = "boolean", --"0", "Flesh Debug full flesh" )
|
||||
|
||||
--FleshEFFECTCENTERRADIUS1, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
--FleshEFFECTCENTERRADIUS2, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
--FleshEFFECTCENTERRADIUS3, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
--FleshEFFECTCENTERRADIUS4, SHADER_PARAM_TYPE_VEC4, "[0 0 0 0.001]", "Flesh effect center and radius" )
|
||||
|
||||
FleshSubsurfaceTint = "Vector", --"[1 1 1]", "Subsurface Color" )
|
||||
FleshBorderWidth = "number", --"0.3", "Flesh border" )
|
||||
FleshBorderSoftness = "number", --"0.42", "Flesh border softness (> 0.0 && <= 0.5)" )
|
||||
FleshBorderTint = "Vector", --"[1 1 1]", "Flesh border Color" )
|
||||
FleshGlobalOpacity = "number", --"1.0", "Flesh global opacity" )
|
||||
FleshGlossBrightness = "number", --"0.66", "Flesh gloss brightness" )
|
||||
FleshScrollSpeed = "number", --"1.0", "Flesh scroll speed" )
|
||||
|
||||
EmissiveBlendEnabled = "boolean",
|
||||
EmissiveBlendTexture = "ITexture",
|
||||
EmissiveBlendBaseTexture = "ITexture",
|
||||
EmissiveBlendFlowTexture = "ITexture",
|
||||
EmissiveBlendTint = "Vector",
|
||||
EmissiveBlendScrollVector = "Vector",
|
||||
|
||||
DistanceAlpha = "number",
|
||||
VertexAlpha = "boolean",
|
||||
Alpha = "number",
|
||||
}
|
||||
|
||||
function PART:OnThink()
|
||||
if self.delay_set and self.Parent then
|
||||
self.delay_set()
|
||||
self.delay_set = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function setup(PART)
|
||||
local sorted = {}
|
||||
for k,v in pairs(PART.ShaderParams) do
|
||||
table.insert(sorted, {k = k, v = v})
|
||||
end
|
||||
table.sort(sorted, function(a, b) return a.k > b.k end)
|
||||
|
||||
for pass = 1, 2 do
|
||||
for _, info in ipairs(group_ordering) do
|
||||
for _, v in ipairs(sorted) do
|
||||
local name, T = v.k, v.v
|
||||
|
||||
local found
|
||||
|
||||
if istable(info.pattern) then
|
||||
for k,v in pairs(info.pattern) do
|
||||
if name:lower():find(v) then
|
||||
found = true
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
found = name:lower():find(info.pattern)
|
||||
end
|
||||
|
||||
if pass == 1 then
|
||||
if found then
|
||||
BUILDER:SetPropertyGroup(info.group)
|
||||
else
|
||||
goto CONTINUE
|
||||
end
|
||||
elseif pass == 2 then
|
||||
if not found then
|
||||
BUILDER:SetPropertyGroup()
|
||||
else
|
||||
goto CONTINUE
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local extra
|
||||
if istable(T) then
|
||||
extra = T.extra
|
||||
T = T.type
|
||||
end
|
||||
if T == "ITexture" then
|
||||
BUILDER:GetSet(name, "", {editor_panel = "textures"})
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
if
|
||||
self.SKIP or
|
||||
pac.Handleurltex(
|
||||
self,
|
||||
var,
|
||||
function(_, tex)
|
||||
local mat = self:GetMaterialFromParent()
|
||||
if mat then
|
||||
mat:SetTexture("$" .. name, tex)
|
||||
|
||||
self.SKIP = true
|
||||
self:UpdateMaterial()
|
||||
self.SKIP = false
|
||||
else
|
||||
self.delay_set = function()
|
||||
local mat = self:GetMaterialFromParent()
|
||||
if mat then
|
||||
mat:SetTexture("$" .. name, tex)
|
||||
self.SKIP = true
|
||||
self:UpdateMaterial()
|
||||
self.SKIP = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
if var ~= "" then
|
||||
local _mat = Material(var)
|
||||
local tex = _mat:GetTexture("$" .. name)
|
||||
|
||||
if not tex or tex:GetName() == "error" then
|
||||
tex = pac.CreateMaterial("pac3_tex_" .. var .. "_" .. self.Id, "VertexLitGeneric", {["$basetexture"] = var}):GetTexture("$basetexture")
|
||||
|
||||
if not tex or tex:GetName() == "error" then
|
||||
tex = _mat:GetTexture("$basetexture")
|
||||
end
|
||||
end
|
||||
|
||||
if tex then
|
||||
mat:SetTexture("$" .. name, tex)
|
||||
end
|
||||
else
|
||||
mat:SetUndefined("$" .. name)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif T == "boolean" then
|
||||
BUILDER:GetSet(name, false)
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
if name == "TranslucentX" then
|
||||
name = "Translucent"
|
||||
end
|
||||
|
||||
mat:SetInt("$" .. name, var and 1 or 0) -- setint crashes?
|
||||
end
|
||||
end
|
||||
elseif T == "number" then
|
||||
BUILDER:GetSet(name, 0)
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
mat:SetFloat("$" .. name, var)
|
||||
end
|
||||
end
|
||||
elseif T == "Vector" then
|
||||
local def = Vector(0,0,0)
|
||||
|
||||
-- hack
|
||||
local key = name:lower()
|
||||
if key == "color" or key == "color2" then
|
||||
def = Vector(1,1,1)
|
||||
end
|
||||
|
||||
BUILDER:GetSet(name, def)
|
||||
|
||||
PART["Set" .. name] = function(self, var)
|
||||
self[name] = var
|
||||
|
||||
local mat = self:GetMaterialFromParent()
|
||||
|
||||
if mat then
|
||||
if key == "color" or key == "color2" then
|
||||
timer.Simple(0.1, function() mat:SetVector("$" .. name, var) end)
|
||||
end
|
||||
|
||||
mat:SetVector("$" .. name, var)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function add_transform(texture_name)
|
||||
local position_key = texture_name.."Position"
|
||||
local scale_key = texture_name.."Scale"
|
||||
local angle_key = texture_name.."Angle"
|
||||
local angle_center_key = texture_name.."AngleCenter"
|
||||
|
||||
BUILDER:GetSet(position_key, Vector(0, 0, 0))
|
||||
BUILDER:GetSet(scale_key, Vector(1, 1, 1))
|
||||
BUILDER:GetSet(angle_key, 0, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet(angle_center_key, Vector(0.5, 0.5, 0))
|
||||
|
||||
PART.TransformVars = PART.TransformVars or {}
|
||||
PART.TransformVars[position_key] = true
|
||||
PART.TransformVars[scale_key] = true
|
||||
PART.TransformVars[angle_key] = true
|
||||
PART.TransformVars[angle_center_key] = true
|
||||
|
||||
local shader_key = "$"..texture_name.."transform"
|
||||
|
||||
local function setup_matrix(self)
|
||||
self.matrix = self.matrix or Matrix()
|
||||
self.translation_vector = self.translation_vector or Vector(0, 0, 0)
|
||||
self.rotation_angle = self.rotation_angle or Angle(0, 0, 0)
|
||||
|
||||
self.matrix:Identity()
|
||||
self.matrix:Translate(self.translation_vector)
|
||||
|
||||
self.matrix:Translate(self[angle_center_key])
|
||||
self.matrix:Rotate(self.rotation_angle)
|
||||
self.matrix:Translate(-self[angle_center_key])
|
||||
|
||||
self.matrix:SetScale(self[scale_key])
|
||||
end
|
||||
|
||||
PART["Set" .. position_key] = function(self, vec)
|
||||
self[position_key] = vec
|
||||
setup_matrix(self)
|
||||
|
||||
self.translation_vector.x = self[position_key].x%1
|
||||
self.translation_vector.y = self[position_key].y%1
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. scale_key] = function(self, vec)
|
||||
self[scale_key] = vec
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. angle_key] = function(self, num)
|
||||
self[angle_key] = num
|
||||
setup_matrix(self)
|
||||
|
||||
self.rotation_angle.y = self[angle_key]*360
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
PART["Set" .. angle_center_key] = function(self, vec)
|
||||
self[angle_center_key] = vec
|
||||
setup_matrix(self)
|
||||
|
||||
self:GetRawMaterial():SetMatrix(shader_key, self.matrix)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
|
||||
setup(PART)
|
||||
add_transform("BaseTexture")
|
||||
--add_transform("Bump") -- doesn't work
|
||||
--add_transform("EnvMapMask")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetMaterialFromParent()
|
||||
if self:GetParent():IsValid() then
|
||||
if not self.Materialm then
|
||||
local mat = pac.CreateMaterial(pac.uid"pac_material_", "VertexLitGeneric", {})
|
||||
|
||||
if self.Parent.Materialm then
|
||||
local tex
|
||||
tex = self.Parent.Materialm:GetTexture("$bumpmap")
|
||||
if tex and not tex:IsError() then
|
||||
mat:SetTexture("$bumpmap", tex)
|
||||
end
|
||||
|
||||
local tex = self.Parent.Materialm:GetTexture("$basetexture")
|
||||
if tex and not tex:IsError() then
|
||||
mat:SetTexture("$basetexture", tex)
|
||||
end
|
||||
end
|
||||
|
||||
self.Materialm = mat
|
||||
end
|
||||
|
||||
self.Parent.Materialm = self.Materialm
|
||||
|
||||
if self.Parent.UpdateSubMaterialId then
|
||||
self.Parent:UpdateSubMaterialId()
|
||||
end
|
||||
|
||||
return self.Materialm
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetTranslucent(b)
|
||||
self.Translucent = b
|
||||
self:UpdateMaterial()
|
||||
end
|
||||
|
||||
function PART:GetRawMaterial()
|
||||
if not self.Materialm then
|
||||
local mat = pac.CreateMaterial(pac.uid"pac_material_", "VertexLitGeneric", {})
|
||||
self.Materialm = mat
|
||||
end
|
||||
|
||||
return self.Materialm
|
||||
end
|
||||
|
||||
function PART:OnParent(parent)
|
||||
self:GetMaterialFromParent()
|
||||
end
|
||||
|
||||
function PART:UpdateMaterial(now)
|
||||
if not self:GetPlayerOwner():IsValid() then return end
|
||||
self:GetMaterialFromParent()
|
||||
|
||||
for key, val in pairs(self.StorableVars) do
|
||||
if self.ShaderParams[key] or self.TransformVars[key] then
|
||||
self["Set" .. key](self, self["Get"..key](self))
|
||||
end
|
||||
end
|
||||
|
||||
pac.UpdateMaterialParts("update", self:GetPlayerOwnerId(), self, self.Materialm)
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
if self:GetPlayerOwner():IsValid() then
|
||||
pac.UpdateMaterialParts("remove", self:GetPlayerOwnerId(), self, self.Materialm)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnMaterialChanged()
|
||||
if self.suppress_event then return end
|
||||
self:UpdateMaterial()
|
||||
end
|
||||
|
||||
function PART:OnParent(parent)
|
||||
self:UpdateMaterial()
|
||||
end
|
||||
|
||||
function PART:OnUnParent(parent)
|
||||
self.Materialm = nil
|
||||
self.updated = false
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
local parent = self:GetParent()
|
||||
|
||||
if parent:IsValid() and parent.SetMaterial then
|
||||
self.suppress_event = true
|
||||
parent:SetMaterial(parent.Material)
|
||||
self.suppress_event = nil
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self:UpdateMaterial()
|
||||
|
||||
local name = self.Name
|
||||
|
||||
pac.UpdateMaterialParts("show", self:GetPlayerOwnerId(), self, self.Name)
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
900
lua/pac3/core/client/parts/legacy/model.lua
Normal file
900
lua/pac3/core/client/parts/legacy/model.lua
Normal file
@@ -0,0 +1,900 @@
|
||||
--[[
|
||||
| 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 math_max = math.max
|
||||
local math_min = math.min
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
|
||||
local Matrix = Matrix
|
||||
local Vector = Vector
|
||||
|
||||
local cam_PushModelMatrix = cam.PushModelMatrix
|
||||
local cam_PopModelMatrix = cam.PopModelMatrix
|
||||
|
||||
local render = render
|
||||
local render_CullMode = render.CullMode
|
||||
local render_SetColorModulation = render.SetColorModulation
|
||||
local render_SetBlend = render.SetBlend
|
||||
local render_SetMaterial = render.SetMaterial
|
||||
local render_ModelMaterialOverride = render.MaterialOverride
|
||||
local render_MaterialOverride = render.ModelMaterialOverride
|
||||
local render_PopFilterMag = render.PopFilterMag
|
||||
local render_PopFilterMin = render.PopFilterMin
|
||||
local render_PopFlashlightMode = render.PopFlashlightMode
|
||||
local render_PushFilterMag = render.PushFilterMag
|
||||
local render_PushFilterMin = render.PushFilterMin
|
||||
local render_PushFlashlightMode = render.PushFlashlightMode
|
||||
local render_SuppressEngineLighting = render.SuppressEngineLighting
|
||||
|
||||
local IMaterial_GetFloat = FindMetaTable("IMaterial").GetFloat
|
||||
local IMaterial_GetVector = FindMetaTable("IMaterial").GetVector
|
||||
local IMaterial_SetFloat = FindMetaTable("IMaterial").SetFloat
|
||||
local IMaterial_SetVector = FindMetaTable("IMaterial").SetVector
|
||||
|
||||
local EF_BONEMERGE = EF_BONEMERGE
|
||||
|
||||
local MATERIAL_CULLMODE_CW = MATERIAL_CULLMODE_CW
|
||||
local MATERIAL_CULLMODE_CCW = MATERIAL_CULLMODE_CCW
|
||||
|
||||
local TEXFILTER = TEXFILTER
|
||||
local NULL = NULL
|
||||
local Color = Color
|
||||
|
||||
pac.DisableColoring = false
|
||||
pac.DisableDoubleFace = false
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy model"
|
||||
PART.ClassName = "model"
|
||||
PART.Category = "model"
|
||||
PART.ManualDraw = true
|
||||
PART.HandleModifiersManually = true
|
||||
PART.Icon = 'icon16/shape_square.png'
|
||||
PART.Group = "legacy"
|
||||
PART.ThinkTime = 0.5
|
||||
|
||||
PART.is_model_part = true
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("Model", "models/dav0r/hoverball.mdl", {editor_panel = "model"})
|
||||
BUILDER:GetSet("Material", "", {editor_panel = "material"})
|
||||
BUILDER:GetSet("UseLegacyScale", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:PropertyOrder("AimPartName")
|
||||
BUILDER:PropertyOrder("Bone")
|
||||
BUILDER:GetSet("BoneMerge", false)
|
||||
BUILDER:PropertyOrder("Position")
|
||||
BUILDER:PropertyOrder("Angles")
|
||||
BUILDER:PropertyOrder("EyeAngles")
|
||||
BUILDER:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Scale", Vector(1,1,1))
|
||||
BUILDER:PropertyOrder("PositionOffset")
|
||||
BUILDER:PropertyOrder("AngleOffset")
|
||||
BUILDER:GetSet("AlternativeScaling", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Brightness", 1)
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
BUILDER:GetSet("Fullbright", false)
|
||||
BUILDER:GetSet("CellShade", 0, {editor_sensitivity = 0.1})
|
||||
BUILDER:PropertyOrder("Translucent")
|
||||
BUILDER:GetSet("Invert", false)
|
||||
BUILDER:GetSet("DoubleFace", false)
|
||||
BUILDER:GetSet("Skin", 0, {editor_onchange = function(self, num) return math.Round(math.max(tonumber(num), 0)) end})
|
||||
BUILDER:GetSet("LodOverride", -1)
|
||||
BUILDER:GetSet("Passes", 1)
|
||||
BUILDER:GetSet("TintColor", Vector(0, 0, 0), {editor_panel = "color"})
|
||||
BUILDER:GetSet("LightBlend", 1)
|
||||
BUILDER:GetSet("ModelFallback", "", {editor_panel = "model"})
|
||||
BUILDER:GetSet("TextureFilter", 3)
|
||||
BUILDER:GetSet("BlurLength", 0)
|
||||
BUILDER:GetSet("BlurSpacing", 0)
|
||||
BUILDER:GetSet("UsePlayerColor", false)
|
||||
BUILDER:GetSet("UseWeaponColor", false)
|
||||
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
BUILDER:GetSet("OwnerEntity", false)
|
||||
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName(("/" .. self:GetModel()):match(".+/(.-)%."))
|
||||
|
||||
return str and str:gsub("%d", "") or "error"
|
||||
end
|
||||
|
||||
function PART:Reset()
|
||||
self:Initialize(self.is_obj)
|
||||
for _, key in pairs(self:GetStorableVars()) do
|
||||
if PART[key] then
|
||||
self["Set" .. key](self, self["Get" .. key](self))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetUseLegacyScale(b)
|
||||
self.UseLegacyScale = b
|
||||
if not b then
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetTextureFilter(num)
|
||||
self.TextureFilter = num
|
||||
|
||||
self.texfilter_enum = math.Clamp(math.Round(num), 0, 3)
|
||||
end
|
||||
|
||||
function PART:Initialize(is_obj)
|
||||
self.Owner = pac.CreateEntity(self:GetModel(), is_obj)
|
||||
if not self.Owner:IsValid() then
|
||||
pac.Message("pac3 failed to create entity!")
|
||||
return
|
||||
end
|
||||
self.Owner:SetNoDraw(true)
|
||||
self.Owner.PACPart = self
|
||||
self.is_obj = is_obj
|
||||
end
|
||||
|
||||
|
||||
function PART:OnBecomePhysics()
|
||||
local ent = self:GetOwner()
|
||||
if not ent:IsValid() then return end
|
||||
ent:PhysicsInit(SOLID_NONE)
|
||||
ent:SetMoveType(MOVETYPE_NONE)
|
||||
ent:SetNoDraw(true)
|
||||
ent.RenderOverride = nil
|
||||
|
||||
self.skip_orient = false
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
local owner = self:GetParentOwner()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and owner:IsValid() and owner ~= ent then
|
||||
ent:SetPos(owner:EyePos())
|
||||
|
||||
if self.OwnerEntity then
|
||||
self:SetOwnerEntity(self.OwnerEntity)
|
||||
end
|
||||
end
|
||||
|
||||
if self.BlurLength > 0 then
|
||||
self.blur_history = {}
|
||||
self.blur_last_add = 0
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
|
||||
function PART:OnThink()
|
||||
pac.SetModelScale(self:GetOwner(), self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
|
||||
self:CheckScale()
|
||||
self:CheckBoneMerge()
|
||||
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() then
|
||||
ent.pac_matproxies = ent.pac_matproxies or {}
|
||||
ent.pac_matproxies.ItemTintColor = self.TintColor / 255
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local NULL = NULL
|
||||
|
||||
local function BIND_MATPROXY(NAME, TYPE)
|
||||
|
||||
local set = "Set" .. TYPE
|
||||
|
||||
matproxy.Add(
|
||||
{
|
||||
name = NAME,
|
||||
|
||||
init = function(self, mat, values)
|
||||
self.result = values.resultvar
|
||||
end,
|
||||
|
||||
bind = function(self, mat, ent)
|
||||
ent = ent or NULL
|
||||
if ent:IsValid() then
|
||||
if ent.pac_matproxies and ent.pac_matproxies[NAME] then
|
||||
mat[set](mat, self.result, ent.pac_matproxies[NAME])
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
-- tf2
|
||||
BIND_MATPROXY("ItemTintColor", "Vector")
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetOwnerEntity(b)
|
||||
local ent = self:GetParentOwner()
|
||||
if ent:IsValid() then
|
||||
if b then
|
||||
self.Owner = ent
|
||||
|
||||
function ent.RenderOverride()
|
||||
if self:IsValid() then
|
||||
if not self.HideEntity then
|
||||
self:PreEntityDraw(ent, ent:GetPos(), ent:GetAngles())
|
||||
ent:DrawModel()
|
||||
self:PostEntityDraw(ent, ent:GetPos(), ent:GetAngles())
|
||||
end
|
||||
else
|
||||
ent.RenderOverride = nil
|
||||
end
|
||||
end
|
||||
elseif self.OwnerEntity then
|
||||
self.Owner = NULL
|
||||
|
||||
ent.RenderOverride = nil
|
||||
pac.SetModelScale(ent, Vector(1,1,1), nil, self.UseLegacyScale)
|
||||
|
||||
self:Initialize()
|
||||
end
|
||||
end
|
||||
|
||||
self.OwnerEntity = b
|
||||
end
|
||||
|
||||
function PART:PreEntityDraw(ent, pos, ang)
|
||||
if not ent:IsPlayer() and pos and ang then
|
||||
if not self.skip_orient then
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
end
|
||||
end
|
||||
|
||||
if self.Alpha ~= 0 and self.Size ~= 0 then
|
||||
self:ModifiersPreEvent("OnDraw")
|
||||
|
||||
if not pac.DisableDoubleFace and (self.DoubleFace or self.Invert) then
|
||||
render_CullMode(MATERIAL_CULLMODE_CW)
|
||||
end
|
||||
|
||||
if not pac.DisableColoring then
|
||||
if not self.Colorf then
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
if self.UseWeaponColor or self.UsePlayerColor then
|
||||
local ply = self:GetPlayerOwner()
|
||||
if ply:IsValid() then
|
||||
local c
|
||||
|
||||
c = ply:GetPlayerColor()
|
||||
if c ~= self.last_playercolor then
|
||||
self:SetColor(self:GetColor())
|
||||
self.last_playercolor = c
|
||||
end
|
||||
|
||||
c = ply:GetWeaponColor()
|
||||
if c ~= self.last_weaponcolor then
|
||||
self:SetColor(self:GetColor())
|
||||
self.last_weaponcolor = c
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Save existing material color and alpha
|
||||
if self.Materialm then
|
||||
-- this is so bad for GC performance
|
||||
self.OriginalMaterialColor = self.OriginalMaterialColor or IMaterial_GetVector (self.Materialm, "$color")
|
||||
self.OriginalMaterialAlpha = self.OriginalMaterialAlpha or IMaterial_GetFloat (self.Materialm, "$alpha")
|
||||
end
|
||||
|
||||
local r, g, b = self.Colorf[1], self.Colorf[2], self.Colorf[3]
|
||||
|
||||
if self.LightBlend ~= 1 then
|
||||
local v = render.GetLightColor(pos)
|
||||
r = r * v.r * self.LightBlend
|
||||
g = g * v.g * self.LightBlend
|
||||
b = b * v.b * self.LightBlend
|
||||
|
||||
v = render.GetAmbientLightColor(pos)
|
||||
r = r * v.r * self.LightBlend
|
||||
g = g * v.g * self.LightBlend
|
||||
b = b * v.b * self.LightBlend
|
||||
end
|
||||
|
||||
-- render.SetColorModulation and render.SetAlpha set the material $color and $alpha.
|
||||
render_SetColorModulation(r,g,b)
|
||||
render_SetBlend(self.Alpha)
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local DEFAULT_COLOR = Vector(1, 1, 1)
|
||||
local WHITE = Material("models/debug/debugwhite")
|
||||
|
||||
function PART:PostEntityDraw(ent, pos, ang)
|
||||
if self.Alpha ~= 0 and self.Size ~= 0 then
|
||||
if not pac.DisableDoubleFace then
|
||||
if self.DoubleFace then
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
elseif self.Invert then
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
end
|
||||
end
|
||||
|
||||
if self.Fullbright then
|
||||
render_SuppressEngineLighting(false)
|
||||
end
|
||||
|
||||
if self.CellShade > 0 then
|
||||
self:CheckScale()
|
||||
self:CheckBoneMerge()
|
||||
|
||||
pac.SetModelScale(ent, self.Scale * self.Size * (1 + self.CellShade), nil, self.UseLegacyScale)
|
||||
render_CullMode(MATERIAL_CULLMODE_CW)
|
||||
render_SetColorModulation(0,0,0)
|
||||
render_SuppressEngineLighting(true)
|
||||
render_MaterialOverride(WHITE)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
render_MaterialOverride()
|
||||
render_SuppressEngineLighting(false)
|
||||
render_CullMode(MATERIAL_CULLMODE_CCW)
|
||||
pac.SetModelScale(ent, self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
end
|
||||
|
||||
-- Restore material color and alpha
|
||||
if self.Materialm then
|
||||
IMaterial_SetVector (self.Materialm, "$color", self.OriginalMaterialColor or DEFAULT_COLOR)
|
||||
IMaterial_SetFloat (self.Materialm, "$alpha", self.OriginalMaterialAlpha or 1)
|
||||
self.OriginalMaterialColor = nil
|
||||
self.OriginalMaterialAlpha = nil
|
||||
end
|
||||
|
||||
self:ModifiersPostEvent("OnDraw")
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if not ent:IsValid() then
|
||||
self:Reset()
|
||||
ent = self:GetOwner()
|
||||
if not ent:IsValid() then
|
||||
pac.Message("WTF", ent, self:GetOwner())
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
self:PreEntityDraw(ent, pos, ang)
|
||||
self:DrawModel(ent, pos, ang)
|
||||
self:PostEntityDraw(ent, pos, ang)
|
||||
|
||||
pac.SetupBones(ent)
|
||||
pac.ResetBones(ent)
|
||||
|
||||
if ent.pac_can_legacy_scale ~= false then
|
||||
ent.pac_can_legacy_scale = not not ent.pac_can_legacy_scale
|
||||
end
|
||||
end
|
||||
|
||||
surface.CreateFont("pac_urlobj_loading",
|
||||
{
|
||||
font = "Arial",
|
||||
size = 20,
|
||||
weight = 10,
|
||||
antialias = true,
|
||||
outline = true,
|
||||
}
|
||||
)
|
||||
|
||||
-- ugh lol
|
||||
local function RealDrawModel(self, ent, pos, ang)
|
||||
if self.Mesh then
|
||||
ent:SetModelScale(0,0)
|
||||
ent:DrawModel()
|
||||
|
||||
local matrix = Matrix()
|
||||
|
||||
matrix:SetAngles(ang)
|
||||
matrix:SetTranslation(pos)
|
||||
|
||||
if ent.pac_model_scale then
|
||||
matrix:Scale(ent.pac_model_scale)
|
||||
else
|
||||
matrix:Scale(self.Scale * self.Size)
|
||||
end
|
||||
|
||||
cam_PushModelMatrix(matrix)
|
||||
self.Mesh:Draw()
|
||||
cam_PopModelMatrix()
|
||||
else
|
||||
ent:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local _self, _ent, _pos, _ang
|
||||
local _return_status = false
|
||||
|
||||
local function protected_real_draw_model()
|
||||
RealDrawModel(_self, _ent, _pos, _ang)
|
||||
end
|
||||
|
||||
local function protected_inner_draw_model()
|
||||
local mat = _self.MaterialOverride or _self.Materialm
|
||||
|
||||
render_MaterialOverride(mat)
|
||||
|
||||
if mat then
|
||||
render_SetMaterial(mat)
|
||||
end
|
||||
|
||||
pac.render_material = mat
|
||||
|
||||
-- Render model
|
||||
local passCount = math_max (1, _self.Passes)
|
||||
|
||||
if _self.Alpha >= 1 then
|
||||
passCount = math_min (passCount, 1)
|
||||
end
|
||||
|
||||
for _ = 1, passCount do
|
||||
local status = ProtectedCall(protected_real_draw_model)
|
||||
|
||||
if not status then
|
||||
_return_status = false
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
render_PushFlashlightMode(true)
|
||||
|
||||
ProtectedCall(protected_real_draw_model)
|
||||
|
||||
render_PopFlashlightMode()
|
||||
|
||||
_return_status = true
|
||||
end
|
||||
|
||||
function PART:DrawModel(ent, pos, ang)
|
||||
if self.Alpha == 0 or self.Size == 0 then return end
|
||||
|
||||
if self.loading_obj then
|
||||
self:DrawLoadingText(ent, pos, ang)
|
||||
end
|
||||
|
||||
if self.loading_obj and not self.Mesh then return end
|
||||
|
||||
local textureFilter = self.texfilter_enum or TEXFILTER.ANISOTROPIC
|
||||
local filter_updated = textureFilter ~= TEXFILTER.ANISOTROPIC or self.Mesh
|
||||
|
||||
if filter_updated then
|
||||
render_PushFilterMin(textureFilter)
|
||||
render_PushFilterMag(textureFilter)
|
||||
end
|
||||
|
||||
_self, _ent, _pos, _ang = self, ent, pos, ang
|
||||
|
||||
ProtectedCall(protected_inner_draw_model)
|
||||
|
||||
if filter_updated then
|
||||
render_PopFilterMag()
|
||||
render_PopFilterMin()
|
||||
end
|
||||
|
||||
-- Render "blur"
|
||||
if self.BlurLength > 0 and _return_status then
|
||||
self:DrawBlur(ent, pos, ang)
|
||||
end
|
||||
|
||||
render_MaterialOverride()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:DrawLoadingText(ent, pos, ang)
|
||||
cam.Start2D()
|
||||
cam.IgnoreZ(true)
|
||||
local pos2d = pos:ToScreen()
|
||||
|
||||
surface.SetFont("pac_urlobj_loading")
|
||||
surface.SetTextColor(255, 255, 255, 255)
|
||||
|
||||
local str = self.loading_obj .. string.rep(".", pac.RealTime * 3 % 3)
|
||||
local w, h = surface.GetTextSize(self.loading_obj .. "...")
|
||||
|
||||
surface.SetTextPos(pos2d.x - w / 2, pos2d.y - h / 2)
|
||||
surface.DrawText(str)
|
||||
cam.IgnoreZ(false)
|
||||
cam.End2D()
|
||||
end
|
||||
|
||||
function PART:DrawBlur(ent, pos, ang)
|
||||
if pac.drawing_motionblur_alpha then return end
|
||||
self.blur_history = self.blur_history or {}
|
||||
|
||||
local blurSpacing = self.BlurSpacing
|
||||
|
||||
if not self.blur_last_add or blurSpacing == 0 or self.blur_last_add < pac.RealTime then
|
||||
table_insert(self.blur_history, {pos, ang})
|
||||
self.blur_last_add = pac.RealTime + blurSpacing / 1000
|
||||
end
|
||||
|
||||
local blurHistoryLength = #self.blur_history
|
||||
for i = 1, blurHistoryLength do
|
||||
pos, ang = self.blur_history[i][1], self.blur_history[i][2]
|
||||
|
||||
render_SetBlend(self.Alpha * (i / blurHistoryLength))
|
||||
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
pac.SetupBones(ent)
|
||||
|
||||
RealDrawModel(self, ent, pos, ang)
|
||||
end
|
||||
|
||||
local maximumBlurHistoryLength = math.min(self.BlurLength, 20)
|
||||
while #self.blur_history >= maximumBlurHistoryLength do
|
||||
table_remove(self.blur_history, 1)
|
||||
end
|
||||
end
|
||||
|
||||
local function set_mesh(part, mesh)
|
||||
local owner = part:GetOwner()
|
||||
part.Mesh = mesh
|
||||
pac.ResetBoneCache(owner)
|
||||
|
||||
if not part.Materialm then
|
||||
part.Materialm = Material("error")
|
||||
end
|
||||
|
||||
function owner.pacDrawModel(ent, simple)
|
||||
if simple then
|
||||
RealDrawModel(part, ent, ent:GetPos(), ent:GetAngles())
|
||||
else
|
||||
part:ModifiersPreEvent("OnDraw")
|
||||
part:DrawModel(ent, ent:GetPos(), ent:GetAngles())
|
||||
part:ModifiersPostEvent("OnDraw")
|
||||
end
|
||||
end
|
||||
|
||||
-- temp
|
||||
owner:SetRenderBounds(Vector(1, 1, 1) * -300, Vector(1, 1, 1) * 300)
|
||||
end
|
||||
|
||||
do
|
||||
pac.urlobj = include("pac3/libraries/urlobj/urlobj.lua")
|
||||
|
||||
function PART:SetModel(modelPath)
|
||||
if modelPath:find("^mdlhttp") then
|
||||
self.Model = modelPath
|
||||
|
||||
modelPath = modelPath:gsub("^mdl", "")
|
||||
|
||||
pac.DownloadMDL(modelPath, function(path)
|
||||
if self:IsValid() and self:GetOwner():IsValid() then
|
||||
local ent = self:GetOwner()
|
||||
self.loading = nil
|
||||
pac.ResetBoneCache(ent)
|
||||
ent:SetModel(path)
|
||||
end
|
||||
end, function(err)
|
||||
pac.Message(err)
|
||||
if self:IsValid() and self:GetOwner():IsValid() then
|
||||
local ent = self:GetOwner()
|
||||
self.loading = nil
|
||||
pac.ResetBoneCache(ent)
|
||||
ent:SetModel("models/error.mdl")
|
||||
end
|
||||
end, self:GetPlayerOwner())
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if modelPath and modelPath:find("http") and pac.urlobj then
|
||||
self.loading_obj = "downloading"
|
||||
|
||||
if not self.is_obj then
|
||||
self:Initialize(true)
|
||||
end
|
||||
|
||||
pac.urlobj.GetObjFromURL(modelPath, false, false,
|
||||
function(meshes, err)
|
||||
if not self:IsValid() then return end
|
||||
|
||||
self.loading_obj = false
|
||||
|
||||
if not meshes and err then
|
||||
self:GetOwner():SetModel("models/error.mdl")
|
||||
self.Mesh = nil
|
||||
return
|
||||
end
|
||||
|
||||
if table.Count(meshes) == 1 then
|
||||
set_mesh(self, select(2, next(meshes)))
|
||||
else
|
||||
for key, mesh in pairs(meshes) do
|
||||
local part = pac.CreatePart("model", self:GetParentOwnerName())
|
||||
part:SetName(key)
|
||||
part:SetParent(self)
|
||||
part:SetMaterial(self:GetMaterial())
|
||||
set_mesh(part, mesh)
|
||||
end
|
||||
|
||||
self:SetAlpha(0)
|
||||
end
|
||||
end,
|
||||
function(finished, statusMessage)
|
||||
if finished then
|
||||
self.loading_obj = nil
|
||||
else
|
||||
self.loading_obj = statusMessage
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
self.Model = modelPath
|
||||
return
|
||||
end
|
||||
|
||||
if self.is_obj or not self.Owner:IsValid() then
|
||||
self:Initialize(false)
|
||||
end
|
||||
|
||||
self.Mesh = nil
|
||||
|
||||
local real_model = modelPath
|
||||
local ret = hook.Run("pac_model:SetModel", self, modelPath, self.ModelFallback)
|
||||
if ret == nil then
|
||||
real_model = pac.FilterInvalidModel(real_model,self.ModelFallback)
|
||||
else
|
||||
modelPath = ret or modelPath
|
||||
real_model = modelPath
|
||||
real_model = pac.FilterInvalidModel(real_model,self.ModelFallback)
|
||||
end
|
||||
|
||||
self.Model = modelPath
|
||||
pac.ResetBoneCache(self.Owner)
|
||||
self.Owner:SetModel(real_model)
|
||||
|
||||
if not self:IsHidden() and not self:IsDrawHidden() then
|
||||
-- notify children about model change
|
||||
self:ShowFromRendering()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local NORMAL = Vector(1,1,1)
|
||||
|
||||
function PART:CheckScale()
|
||||
-- RenderMultiply doesn't work with this..
|
||||
if (self.UseLegacyScale or self.BoneMerge) and self.Owner:IsValid() and self.Owner:GetBoneCount() and self.Owner:GetBoneCount() > 1 then
|
||||
if self.Scale * self.Size ~= NORMAL then
|
||||
if not self.requires_bone_model_scale then
|
||||
self.requires_bone_model_scale = true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetAlternativeScaling(b)
|
||||
self.AlternativeScaling = b
|
||||
self:SetScale(self.Scale)
|
||||
end
|
||||
|
||||
function PART:SetScale(var)
|
||||
var = var or Vector(1,1,1)
|
||||
|
||||
self.Scale = var
|
||||
|
||||
if self.AlternativeScaling then
|
||||
if not self:CheckScale() then
|
||||
pac.SetModelScale(self.Owner, self.Scale, nil, self.UseLegacyScale)
|
||||
self.used_alt_scale = true
|
||||
end
|
||||
else
|
||||
if self.used_alt_scale then
|
||||
pac.SetModelScale(self.Owner, nil, 1, self.UseLegacyScale)
|
||||
self.used_alt_scale = false
|
||||
end
|
||||
if not self:CheckScale() then
|
||||
pac.SetModelScale(self.Owner, self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetSize(var)
|
||||
var = var or 1
|
||||
|
||||
self.Size = var
|
||||
|
||||
if self.AlternativeScaling then
|
||||
pac.SetModelScale(self.Owner, nil, self.Size, self.UseLegacyScale)
|
||||
self.used_alt_scale = true
|
||||
else
|
||||
if self.used_alt_scale then
|
||||
pac.SetModelScale(self.Owner, nil, 1, self.UseLegacyScale)
|
||||
self.used_alt_scale = false
|
||||
end
|
||||
if not self:CheckScale() then
|
||||
pac.SetModelScale(self.Owner, self.Scale * self.Size, nil, self.UseLegacyScale)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetBrightness(num)
|
||||
self.Brightness = num
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:SetColor(var)
|
||||
self.Color = var
|
||||
local owner = self:GetPlayerOwner()
|
||||
|
||||
if self.UsePlayerColor and owner:IsValid() then
|
||||
local c = owner:GetPlayerColor() * self.Brightness
|
||||
self.Colorf = {c.x, c.y, c.z}
|
||||
elseif self.UseWeaponColor and owner:IsValid() then
|
||||
local c = owner:GetWeaponColor() * self.Brightness
|
||||
self.Colorf = {c.x, c.y, c.z}
|
||||
else
|
||||
self.Colorf = {(var.r / 255) * self.Brightness, (var.g / 255) * self.Brightness, (var.b / 255) * self.Brightness}
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetUseWeaponColor(b)
|
||||
self.UseWeaponColor = b
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:SetUsePlayerColor(b)
|
||||
self.UsePlayerColor = b
|
||||
self:SetColor(self:GetColor())
|
||||
end
|
||||
|
||||
function PART:FixMaterial()
|
||||
local mat = self.Materialm
|
||||
|
||||
if not mat then return end
|
||||
|
||||
local shader = mat:GetShader()
|
||||
|
||||
if shader == "UnlitGeneric" then
|
||||
local tex_path = mat:GetString("$basetexture")
|
||||
|
||||
if tex_path then
|
||||
local params = {}
|
||||
|
||||
params["$basetexture"] = tex_path
|
||||
params["$vertexcolor"] = 1
|
||||
params["$additive"] = 1
|
||||
|
||||
self.Materialm = pac.CreateMaterial(pac.uid"pac_fixmat_", "VertexLitGeneric", params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var) then
|
||||
if var == "" then
|
||||
self.Materialm = nil
|
||||
else
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:FixMaterial()
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
self.Material = var
|
||||
end
|
||||
|
||||
function PART:SetSkin(var)
|
||||
var = var or 0
|
||||
|
||||
self.Skin = var
|
||||
self.Owner:SetSkin(var)
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
if not self.OwnerEntity then
|
||||
timer.Simple(0, function()
|
||||
SafeRemoveEntity(self.Owner)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetLodOverride(num)
|
||||
local ent = self.Owner
|
||||
if ent:IsValid() then
|
||||
ent:SetLOD(num)
|
||||
self.LodOverride = num
|
||||
end
|
||||
end
|
||||
|
||||
function PART:CheckBoneMerge()
|
||||
local ent = self.Owner
|
||||
|
||||
if self.skip_orient then return end
|
||||
|
||||
if ent:IsValid() and not ent:IsPlayer() then
|
||||
if self.BoneMerge then
|
||||
local owner = self:GetParentOwner()
|
||||
|
||||
if ent:GetParent() ~= owner then
|
||||
ent:SetParent(owner)
|
||||
|
||||
if not ent:IsEffectActive(EF_BONEMERGE) then
|
||||
ent:AddEffects(EF_BONEMERGE)
|
||||
end
|
||||
end
|
||||
else
|
||||
if ent:GetParent():IsValid() then
|
||||
ent:SetParent(NULL)
|
||||
|
||||
if ent:IsEffectActive(EF_BONEMERGE) then
|
||||
ent:RemoveEffects(EF_BONEMERGE)
|
||||
end
|
||||
|
||||
self.requires_bone_model_scale = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local SCALE_NORMAL = Vector(1, 1, 1)
|
||||
function PART:OnBuildBonePositions()
|
||||
if self.AlternativeScaling then return end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
local owner = self:GetParentOwner()
|
||||
|
||||
if not ent:IsValid() or not owner:IsValid() or not ent:GetBoneCount() or ent:GetBoneCount() < 1 then return end
|
||||
|
||||
if self.requires_bone_model_scale then
|
||||
local scale = self.Scale * self.Size
|
||||
|
||||
for i = 0, ent:GetBoneCount() - 1 do
|
||||
if i == 0 then
|
||||
ent:ManipulateBoneScale(i, ent:GetManipulateBoneScale(i) * Vector(scale.x ^ 0.25, scale.y ^ 0.25, scale.z ^ 0.25))
|
||||
else
|
||||
ent:ManipulateBonePosition(i, ent:GetManipulateBonePosition(i) + Vector((scale.x-1) ^ 4, 0, 0))
|
||||
ent:ManipulateBoneScale(i, ent:GetManipulateBoneScale(i) * scale)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
266
lua/pac3/core/client/parts/legacy/ogg.lua
Normal file
266
lua/pac3/core/client/parts/legacy/ogg.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
include("pac3/libraries/webaudio/urlogg.lua")
|
||||
include("pac3/libraries/webaudio/browser.lua")
|
||||
include("pac3/libraries/webaudio/stream.lua")
|
||||
include("pac3/libraries/webaudio/streams.lua")
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "legacy ogg"
|
||||
PART.ClassName = "ogg"
|
||||
|
||||
PART.Group = "legacy"
|
||||
PART.Icon = 'icon16/music.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("URL", "")
|
||||
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Pitch", 1, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("Radius", 1500)
|
||||
BUILDER:GetSet("PlayCount", 1, {editor_onchange = function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(math.max(num, 0))
|
||||
end})
|
||||
BUILDER:GetSet("Doppler", false)
|
||||
BUILDER:GetSet("StopOnHide", false)
|
||||
BUILDER:GetSet("PauseOnHide", false)
|
||||
BUILDER:GetSet("Overlapping", false)
|
||||
|
||||
BUILDER:GetSet("FilterType", 0, {editor_onchange = function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(math.Clamp(num, 0, 2))
|
||||
end})
|
||||
BUILDER:GetSet("FilterFraction", 1, {editor_sensitivity = 0.125, editor_clamp = {0, 1}})
|
||||
|
||||
--BUILDER:GetSet("Echo", false)
|
||||
--BUILDER:GetSet("EchoDelay", 0.5)
|
||||
--BUILDER:GetSet("EchoFeedback", 0.75)
|
||||
|
||||
BUILDER:GetSet("PlayOnFootstep", false)
|
||||
BUILDER:GetSet("MinPitch", 0, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MaxPitch", 0, {editor_sensitivity = 0.125})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:Initialize()
|
||||
self.streams = {}
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/".. self:GetURL())
|
||||
return str and str:match(".+/(.-)%.") or "no sound"
|
||||
end
|
||||
|
||||
local stream_vars = {"Doppler", "Radius"}
|
||||
|
||||
local BIND = function(propertyName, setterMethodName, check)
|
||||
table.insert(stream_vars, propertyName)
|
||||
setterMethodName = setterMethodName or "Set" .. propertyName
|
||||
PART["Set" .. propertyName] = function(self, value)
|
||||
if check then
|
||||
value = check(value)
|
||||
end
|
||||
|
||||
for url, stream in pairs(self.streams) do
|
||||
if stream:IsValid() then
|
||||
stream[setterMethodName](stream, value)
|
||||
else
|
||||
self.streams[url] = nil
|
||||
end
|
||||
end
|
||||
|
||||
self[propertyName] = value
|
||||
end
|
||||
end
|
||||
|
||||
BIND("Pitch", "SetPlaybackSpeed")
|
||||
BIND("PlayCount", "SetMaxLoopCount" )
|
||||
BIND("Volume", nil, function(n) return math.Clamp(n, 0, 4) end)
|
||||
BIND("Radius", "SetSourceRadius" )
|
||||
|
||||
BIND("FilterType")
|
||||
BIND("FilterFraction")
|
||||
|
||||
--BIND("Echo")
|
||||
--BIND("EchoDelay")
|
||||
--BIND("EchoFeedback", nil, function(n) return math.Clamp(n, 0, 0.99) end)
|
||||
|
||||
function PART:OnThink()
|
||||
local owner = self:GetRootPart():GetOwner()
|
||||
|
||||
for url, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[url] = nil goto CONTINUE end
|
||||
|
||||
if self.PlayCount == 0 then
|
||||
stream:Resume()
|
||||
end
|
||||
|
||||
if stream.owner_set ~= owner and owner:IsValid() then
|
||||
stream:SetSourceEntity(owner, true)
|
||||
stream.owner_set = owner
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
if self.last_playonfootstep ~= self.PlayOnFootstep then
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
|
||||
if self.PlayOnFootstep then
|
||||
ent.pac_footstep_override[self.UniqueID] = self
|
||||
else
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
if table.Count(ent.pac_footstep_override) == 0 then
|
||||
ent.pac_footstep_override = nil
|
||||
end
|
||||
|
||||
self.last_playonfootstep = self.PlayOnFootstep
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetURL(URL)
|
||||
|
||||
local urls = {}
|
||||
|
||||
for _, url in pairs(URL:Split(";")) do
|
||||
local min, max = url:match(".+%[(.-),(.-)%]")
|
||||
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
|
||||
if min and max then
|
||||
for i = min, max do
|
||||
table.insert(urls, (url:gsub("%[.-%]", i)))
|
||||
end
|
||||
else
|
||||
table.insert(urls, url)
|
||||
end
|
||||
end
|
||||
|
||||
for _, stream in pairs(self.streams) do
|
||||
if stream:IsValid() then
|
||||
stream:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.streams = {}
|
||||
|
||||
self:SetError()
|
||||
|
||||
for _, url in pairs(urls) do
|
||||
local stream = pac.webaudio.Streams.CreateStream(url)
|
||||
self.streams[url] = stream
|
||||
|
||||
stream:Enable3D(true)
|
||||
stream.OnLoad = function()
|
||||
for _, key in ipairs(stream_vars) do
|
||||
self["Set" .. key](self, self["Get" .. key](self))
|
||||
end
|
||||
end
|
||||
stream.OnError = function(err, info)
|
||||
pac.Message("OGG error: ", err, " reason: ", info or "none")
|
||||
self:SetError(str)
|
||||
end
|
||||
|
||||
if pace and pace.Editor:IsValid() and pace.current_part:IsValid() and pace.current_part.ClassName == "ogg" and self:GetPlayerOwner() == pac.LocalPlayer then
|
||||
stream:Play()
|
||||
end
|
||||
end
|
||||
|
||||
self.URL = URL
|
||||
end
|
||||
|
||||
PART.last_stream = NULL
|
||||
|
||||
function PART:PlaySound(_, additiveVolumeFraction)
|
||||
additiveVolumeFraction = additiveVolumeFraction or 0
|
||||
local stream = table.Random(self.streams) or NULL
|
||||
|
||||
if pac.webaudio.sample_rate and pac.webaudio.sample_rate > 48000 then
|
||||
pac.Message(Color(255, 0, 0), "The ogg part (custom sounds) might not work because you have your sample rate set to ", pac.webaudio.sample_rate, " Hz. Set it to 48000 or below if you experience any issues.")
|
||||
self:SetInfo("The ogg part (custom sounds) might not work because you have your sample rate set to " .. pac.webaudio.sample_rate .. " Hz. Set it to 48000 or below if you experience any issues.")
|
||||
end
|
||||
|
||||
if not stream:IsValid() then return end
|
||||
|
||||
stream:SetAdditiveVolumeModifier (additiveVolumeFraction)
|
||||
|
||||
if self.last_stream:IsValid() and not self.Overlapping then
|
||||
self.last_stream:Stop()
|
||||
end
|
||||
|
||||
if self.MinPitch ~= self.MaxPitch then
|
||||
stream:SetAdditivePitchModifier(math.Rand(self.MinPitch, self.MaxPitch))
|
||||
else
|
||||
stream:SetAdditivePitchModifier(0)
|
||||
end
|
||||
|
||||
if self.PauseOnHide then
|
||||
stream:Resume()
|
||||
else
|
||||
stream:Start()
|
||||
end
|
||||
|
||||
self.last_stream = stream
|
||||
end
|
||||
|
||||
function PART:StopSound()
|
||||
for key, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
||||
|
||||
if not self.StopOnHide then
|
||||
if self.PauseOnHide then
|
||||
stream:Pause()
|
||||
else
|
||||
stream:Stop()
|
||||
end
|
||||
end
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
self:PlaySound()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self:StopSound()
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
for key, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
||||
|
||||
stream:Remove()
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetDoppler(num)
|
||||
for key, stream in pairs(self.streams) do
|
||||
if not stream:IsValid() then self.streams[key] = nil goto CONTINUE end
|
||||
|
||||
stream:EnableDoppler(num)
|
||||
::CONTINUE::
|
||||
end
|
||||
|
||||
self.Doppler = num
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
320
lua/pac3/core/client/parts/legacy/sound.lua
Normal file
320
lua/pac3/core/client/parts/legacy/sound.lua
Normal file
@@ -0,0 +1,320 @@
|
||||
--[[
|
||||
| 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 BUILDER, PART = pac.PartTemplate("base_movable")
|
||||
|
||||
PART.FriendlyName = "legacy sound"
|
||||
PART.Group = "legacy"
|
||||
PART.ClassName = "sound"
|
||||
|
||||
PART.ThinkTime = 0
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/sound.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:GetSet("Sound", "")
|
||||
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.25})
|
||||
BUILDER:GetSet("Pitch", 0.4, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MinPitch", 100, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MaxPitch", 100, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("RootOwner", true)
|
||||
BUILDER:GetSet("SoundLevel", 100)
|
||||
BUILDER:GetSet("LocalPlayerOnly", false)
|
||||
BUILDER:SetPropertyGroup("playback")
|
||||
BUILDER:GetSet("PlayOnFootstep", false)
|
||||
BUILDER:GetSet("Overlapping", false)
|
||||
BUILDER:GetSet("Loop", false)
|
||||
BUILDER:GetSet("Sequential", false, {description = "if there are multiple sounds (separated by ; or using [min,max] notation), plays these sounds in sequential order instead of randomly"})
|
||||
BUILDER:GetSet("SequentialStep",1,
|
||||
{editor_onchange =
|
||||
function(self, num)
|
||||
self.sens = 0.25
|
||||
num = tonumber(num)
|
||||
return math.Round(num)
|
||||
end})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/" .. self:GetSound())
|
||||
return str and str:match(".+/(.-)%.") or "no sound"
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
--self:PlaySound()
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
self.played_overlapping = false
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
if self.PlayOnFootstep then
|
||||
ent.pac_footstep_override[self.UniqueID] = self
|
||||
else
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self.played_overlapping = false
|
||||
self:StopSound()
|
||||
|
||||
if self.PlayOnFootstep then
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
ent.pac_footstep_override = nil
|
||||
|
||||
if ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
|
||||
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
if not self.csptch then
|
||||
self:PlaySound()
|
||||
else
|
||||
if self.Loop then
|
||||
pac.playing_sound = true
|
||||
if not self.csptch:IsPlaying() then self.csptch:Play() end
|
||||
self.csptch:ChangePitch((self.Pitch * 255) + math.sin(pac.RealTime) / 2, 0)
|
||||
pac.playing_sound = false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- fixes by Python 1320
|
||||
|
||||
-- Sound protection. TODO: MAKE A BETTER FIX. Iterative removal of the special characters?
|
||||
-- This will make special sound effects break if used directly from lua, but I doubt this is common.
|
||||
-- Won't protect engine but engine shouldn't do this anyway.
|
||||
-- TODO: Beta new sound functions
|
||||
|
||||
-- https://developer.valvesoftware.com/wiki/Soundscripts#Sound_Characters
|
||||
-- we are using this for bad replacements as it won't break stuff too badly ["*"]=true,
|
||||
|
||||
local bad =
|
||||
{
|
||||
["#"] = true,
|
||||
["@"] = true,
|
||||
[">"] = true,
|
||||
["<"] = true,
|
||||
["^"] = true,
|
||||
[")"] = true,
|
||||
["}"] = true,
|
||||
["$"] = true,
|
||||
["!"] = true,
|
||||
["?"] = true, -- especially bad
|
||||
}
|
||||
|
||||
local function fix(snd)
|
||||
if bad[snd:sub(1,1)] then
|
||||
snd = snd:gsub("^(.)",function() return "*" end)
|
||||
end
|
||||
if bad[snd:sub(2,2)] then
|
||||
snd = snd:gsub("^(..)",function(a) return a[1] .. "*" end)
|
||||
end
|
||||
return snd
|
||||
end
|
||||
|
||||
function PART:SetSound(str)
|
||||
if not isstring(str) then self.Sound = "" return end
|
||||
|
||||
if bad[str:sub(1,1)] or bad[str:sub(2,2)] then
|
||||
str = fix(str)
|
||||
end
|
||||
|
||||
self.Sound = str:gsub("\\", "/")
|
||||
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
function PART:SetVolume(num)
|
||||
self.Volume = num
|
||||
|
||||
if not self.csptch then
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
if self.csptch then
|
||||
self.csptch:ChangeVolume(math.Clamp(self.Volume, 0.001, 1), 0)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetPitch(num)
|
||||
self.Pitch = num
|
||||
|
||||
if not self.csptch then
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
if self.csptch then
|
||||
self.csptch:ChangePitch(math.Clamp(self.Pitch * 255, 1, 255), 0)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PlaySound(osnd, ovol)
|
||||
local ent = self.RootOwner and self:GetRootPart():GetOwner() or self:GetOwner()
|
||||
|
||||
if ent:IsValid() then
|
||||
if ent:GetClass() == "viewmodel" or ent == pac.LocalHands then
|
||||
ent = pac.LocalPlayer
|
||||
end
|
||||
|
||||
if self:GetLocalPlayerOnly() and ent ~= pac.LocalPlayer then return end
|
||||
|
||||
local snd
|
||||
|
||||
if osnd and self.Sound == "" then
|
||||
snd = osnd
|
||||
else
|
||||
local sounds = self.Sound:Split(";")
|
||||
|
||||
--case 1: proper semicolon list
|
||||
if #sounds > 1 then
|
||||
if self.Sequential then
|
||||
self.seq_index = self.seq_index or 1
|
||||
|
||||
snd = sounds[self.seq_index]
|
||||
|
||||
self.seq_index = self.seq_index + self.SequentialStep
|
||||
self.seq_index = self.seq_index % (#sounds+1)
|
||||
if self.seq_index == 0 then self.seq_index = 1 end
|
||||
else snd = table.Random(sounds) end
|
||||
|
||||
--case 2: one sound, which may or may not be bracket notation
|
||||
elseif #sounds == 1 then
|
||||
--bracket notation
|
||||
if string.match(sounds[1],"%[(%d-),(%d-)%]") then
|
||||
local function minmaxpath(minmax,str)
|
||||
local min, max = minmax:match("%[(%d-),(%d-)%]")
|
||||
if minmax:match("%[(%d-),(%d-)%]") == nil then return 1 end
|
||||
if max < min then
|
||||
max = min
|
||||
end
|
||||
if str == "min" then return tonumber(min)
|
||||
elseif str == "max" then return tonumber(max) else return tonumber(max) end
|
||||
end
|
||||
if self.Sequential then
|
||||
self.seq_index = self.seq_index or minmaxpath(self.Sound,"min")
|
||||
snd = self.Sound:gsub(
|
||||
"(%[%d-,%d-%])",self.seq_index
|
||||
)
|
||||
self.seq_index = self.seq_index + self.SequentialStep
|
||||
|
||||
local span = minmaxpath(self.Sound,"max") - minmaxpath(self.Sound,"min") + 1
|
||||
if self.seq_index > minmaxpath(self.Sound,"max") then
|
||||
self.seq_index = self.seq_index - span
|
||||
elseif self.seq_index < minmaxpath(self.Sound,"min") then
|
||||
self.seq_index = self.seq_index + span
|
||||
end
|
||||
else
|
||||
snd = self.Sound:gsub(
|
||||
"(%[%d-,%d-%])",
|
||||
function(minmax)
|
||||
local min, max = minmax:match("%[(%d-),(%d-)%]")
|
||||
if max < min then
|
||||
max = min
|
||||
end
|
||||
return math.random(min, max)
|
||||
end
|
||||
)
|
||||
end
|
||||
--single sound
|
||||
else snd = sounds[1] or osnd end
|
||||
end
|
||||
end
|
||||
|
||||
local vol
|
||||
|
||||
if osnd and self.Volume == -1 then
|
||||
vol = ovol or 1
|
||||
else
|
||||
vol = self.Volume
|
||||
end
|
||||
|
||||
local pitch
|
||||
|
||||
if self.MinPitch == self.MaxPitch then
|
||||
pitch = self.Pitch * 255
|
||||
else
|
||||
pitch = math.random(self.MinPitch, self.MaxPitch)
|
||||
end
|
||||
|
||||
pac.playing_sound = true
|
||||
|
||||
if self.Overlapping then
|
||||
if not self.played_overlapping then
|
||||
ent:EmitSound(snd, vol * 160, pitch)
|
||||
self.played_overlapping = true
|
||||
end
|
||||
else
|
||||
if self.csptch then
|
||||
self.csptch:Stop()
|
||||
end
|
||||
|
||||
local csptch = CreateSound(ent, snd)
|
||||
|
||||
|
||||
csptch:SetSoundLevel(self.SoundLevel)
|
||||
csptch:PlayEx(vol, pitch)
|
||||
ent.pac_csptch = csptch
|
||||
self.csptch = csptch
|
||||
end
|
||||
|
||||
pac.playing_sound = false
|
||||
end
|
||||
end
|
||||
|
||||
function PART:StopSound()
|
||||
if self.csptch then
|
||||
self.csptch:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
local channels =
|
||||
{
|
||||
CHAN_AUTO = 0,
|
||||
CHAN_WEAPON = 1,
|
||||
CHAN_VOICE = 2,
|
||||
CHAN_ITEM = 3,
|
||||
CHAN_BODY = 4,
|
||||
CHAN_STREAM = 5,
|
||||
CHAN_STATIC = 6,
|
||||
}
|
||||
|
||||
for key, CHAN in pairs(channels) do
|
||||
sound.Add(
|
||||
{
|
||||
name = "pac_silence_" .. key:lower(),
|
||||
channel = CHAN,
|
||||
volume = 0,
|
||||
soundlevel = 0,
|
||||
pitchstart = 0,
|
||||
pitchend = 0,
|
||||
sound = "ambient/_period.wav"
|
||||
} )
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
186
lua/pac3/core/client/parts/legacy/trail.lua
Normal file
186
lua/pac3/core/client/parts/legacy/trail.lua
Normal file
@@ -0,0 +1,186 @@
|
||||
--[[
|
||||
| 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 Lerp = Lerp
|
||||
local tonumber = tonumber
|
||||
local table_insert = table.insert
|
||||
local table_remove = table.remove
|
||||
local math_ceil = math.ceil
|
||||
local math_abs = math.abs
|
||||
local render_StartBeam = render.StartBeam
|
||||
local cam_IgnoreZ = cam.IgnoreZ
|
||||
local render_EndBeam = render.EndBeam
|
||||
local render_AddBeam = render.AddBeam
|
||||
local render_SetMaterial = render.SetMaterial
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "legacy trail"
|
||||
PART.ClassName = "trail"
|
||||
PART.Group = "legacy"
|
||||
|
||||
PART.Icon = 'icon16/arrow_undo.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:SetPropertyGroup("generic")
|
||||
BUILDER:PropertyOrder("Name")
|
||||
BUILDER:PropertyOrder("Hide")
|
||||
BUILDER:PropertyOrder("ParentName")
|
||||
BUILDER:GetSet("TrailPath", "trails/laser", {editor_panel = "material"})
|
||||
BUILDER:GetSet("StartSize", 3)
|
||||
BUILDER:GetSet("EndSize", 0)
|
||||
BUILDER:GetSet("Length", 100)
|
||||
BUILDER:GetSet("Spacing", 1)
|
||||
|
||||
BUILDER:SetPropertyGroup("orientation")
|
||||
BUILDER:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("StartColor", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("EndColor", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("StartAlpha", 1)
|
||||
BUILDER:GetSet("EndAlpha", 1)
|
||||
BUILDER:PropertyOrder("Translucent")
|
||||
BUILDER:GetSet("Stretch", false)
|
||||
BUILDER:SetPropertyGroup("other")
|
||||
BUILDER:PropertyOrder("DrawOrder")
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/" .. self:GetTrailPath())
|
||||
local matched = str and str:match(".+/(.+)")
|
||||
return matched and matched:gsub("%..+", "") or "error"
|
||||
end
|
||||
|
||||
PART.LastAdd = 0
|
||||
|
||||
function PART:Initialize()
|
||||
self:SetTrailPath(self.TrailPath)
|
||||
|
||||
self.StartColorC = Color(255, 255, 255, 255)
|
||||
self.EndColorC = Color(255, 255, 255, 255)
|
||||
end
|
||||
|
||||
function PART:SetStartColor(v)
|
||||
self.StartColorC = self.StartColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.StartColorC.r = v.r
|
||||
self.StartColorC.g = v.g
|
||||
self.StartColorC.b = v.b
|
||||
|
||||
self.StartColor = v
|
||||
end
|
||||
|
||||
function PART:SetEndColor(v)
|
||||
self.EndColorC = self.EndColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.EndColorC.r = v.r
|
||||
self.EndColorC.g = v.g
|
||||
self.EndColorC.b = v.b
|
||||
|
||||
self.EndColor = v
|
||||
end
|
||||
|
||||
function PART:SetStartAlpha(n)
|
||||
self.StartColorC = self.StartColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.StartColorC.a = n * 255
|
||||
|
||||
self.StartAlpha = n
|
||||
end
|
||||
|
||||
function PART:SetEndAlpha(n)
|
||||
self.EndColorC = self.EndColorC or Color(255, 255, 255, 255)
|
||||
|
||||
self.EndColorC.a = n * 255
|
||||
|
||||
self.EndAlpha = n
|
||||
end
|
||||
|
||||
function PART:SetTrailPath(var)
|
||||
self.TrailPath = var
|
||||
self:SetMaterial(var)
|
||||
end
|
||||
|
||||
function PART:SetMaterial(var)
|
||||
var = var or ""
|
||||
|
||||
if not pac.Handleurltex(self, var) then
|
||||
if isstring(var) then
|
||||
self.Materialm = pac.Material(var, self)
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
elseif type(var) == "IMaterial" then
|
||||
self.Materialm = var
|
||||
self:CallRecursive("OnMaterialChanged")
|
||||
end
|
||||
end
|
||||
|
||||
if self.Materialm then
|
||||
local shader = self.Materialm:GetShader()
|
||||
if shader == "VertexLitGeneric" or shader == "Cable" or shader == "LightmappedGeneric" then
|
||||
self.Materialm = pac.MakeMaterialUnlitGeneric(self.Materialm, self.Id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow()
|
||||
self.points = {}
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
self.points = {}
|
||||
end
|
||||
|
||||
local temp_color = Color(255, 255, 255)
|
||||
|
||||
function PART:OnDraw()
|
||||
local mat = self.MaterialOverride or self.Materialm
|
||||
|
||||
if mat and self.StartColorC and self.EndColorC then
|
||||
self.points = self.points or {}
|
||||
|
||||
local len = tonumber(self.Length)
|
||||
local spc = tonumber(self.Spacing)
|
||||
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
|
||||
if spc == 0 or self.LastAdd < pac.RealTime then
|
||||
table_insert(self.points, pos)
|
||||
self.LastAdd = pac.RealTime + spc / 1000
|
||||
end
|
||||
|
||||
local count = #self.points
|
||||
|
||||
if spc > 0 then
|
||||
len = math_ceil(math_abs(len - spc))
|
||||
end
|
||||
|
||||
render_SetMaterial(mat)
|
||||
|
||||
render_StartBeam(count)
|
||||
for k, v in pairs(self.points) do
|
||||
local width = k / (len / self.StartSize)
|
||||
|
||||
local coord = (1 / count) * (k - 1)
|
||||
|
||||
temp_color.r = Lerp(coord, self.EndColorC.r, self.StartColorC.r)
|
||||
temp_color.g = Lerp(coord, self.EndColorC.g, self.StartColorC.g)
|
||||
temp_color.b = Lerp(coord, self.EndColorC.b, self.StartColorC.b)
|
||||
temp_color.a = Lerp(coord, self.EndColorC.a, self.StartColorC.a)
|
||||
|
||||
render_AddBeam(k == count and pos or v, width + self.EndSize, self.Stretch and coord or width, temp_color)
|
||||
end
|
||||
render_EndBeam()
|
||||
|
||||
if count >= len then
|
||||
table_remove(self.points, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
330
lua/pac3/core/client/parts/legacy/webaudio.lua
Normal file
330
lua/pac3/core/client/parts/legacy/webaudio.lua
Normal file
@@ -0,0 +1,330 @@
|
||||
--[[
|
||||
| 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 BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
local snd_mute_losefocus = GetConVar('snd_mute_losefocus')
|
||||
|
||||
PART.FriendlyName = "legacy webaudio"
|
||||
PART.ClassName = "webaudio"
|
||||
PART.Group = 'legacy'
|
||||
PART.Icon = 'icon16/sound_add.png'
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("URL", "")
|
||||
BUILDER:GetSet("Volume", 1, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("Pitch", 1, {editor_sensitivity = 0.125})
|
||||
BUILDER:GetSet("MinimumRadius", 0)
|
||||
BUILDER:GetSet("MaximumRadius", 0)
|
||||
|
||||
BUILDER:GetSet("InnerAngle", 360)
|
||||
BUILDER:GetSet("OuterAngle", 360)
|
||||
BUILDER:GetSet("OuterVolume", 0)
|
||||
|
||||
BUILDER:GetSet("Loop", false)
|
||||
BUILDER:GetSet("StopOnHide", true)
|
||||
BUILDER:GetSet("PauseOnHide", false)
|
||||
BUILDER:GetSet("Overlapping", false)
|
||||
|
||||
BUILDER:GetSet("PlayOnFootstep", false)
|
||||
BUILDER:GetSet("RandomPitch", 0, {editor_sensitivity = 0.125})
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:Initialize()
|
||||
self.streams = {}
|
||||
self.stream_count = 0
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local str = pac.PrettifyName("/" .. self:GetURL())
|
||||
return str and str:match(".+/(.-)%.") or "no sound"
|
||||
end
|
||||
|
||||
function PART:OnThink()
|
||||
if self.last_playonfootstep ~= self.PlayOnFootstep then
|
||||
local ent = self:GetOwner()
|
||||
if ent:IsValid() and ent:IsPlayer() then
|
||||
ent.pac_footstep_override = ent.pac_footstep_override or {}
|
||||
|
||||
if self.PlayOnFootstep then
|
||||
ent.pac_footstep_override[self.UniqueID] = self
|
||||
else
|
||||
ent.pac_footstep_override[self.UniqueID] = nil
|
||||
end
|
||||
|
||||
if table.Count(ent.pac_footstep_override) == 0 then
|
||||
ent.pac_footstep_override = nil
|
||||
end
|
||||
|
||||
self.last_playonfootstep = self.PlayOnFootstep
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnDraw()
|
||||
if not self.streams then return end
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
local forward = ang:Forward()
|
||||
|
||||
local shouldMute = snd_mute_losefocus:GetBool()
|
||||
local focus = system.HasFocus()
|
||||
local volume = shouldMute and not focus and 0 or self:GetVolume()
|
||||
|
||||
for url, streamdata in pairs(self.streams) do
|
||||
local stream = streamdata.stream
|
||||
if streamdata.Loading then goto CONTINUE end
|
||||
|
||||
if not stream:IsValid() then
|
||||
self.streams[url] = nil
|
||||
self.stream_count = self.stream_count - 1
|
||||
-- TODO: Notify the user somehow or reload streams
|
||||
goto CONTINUE
|
||||
end
|
||||
|
||||
stream:SetPos(pos, forward)
|
||||
|
||||
if not self.random_pitch then self:SetRandomPitch(self.RandomPitch) end
|
||||
|
||||
stream:Set3DFadeDistance(self.MinimumRadius, self.MaximumRadius)
|
||||
stream:Set3DCone(self.InnerAngle, self.OuterAngle, self.OuterVolume)
|
||||
stream:SetVolume(volume)
|
||||
stream:SetPlaybackRate(self:GetPitch() + self.random_pitch)
|
||||
|
||||
if streamdata.StartPlaying then
|
||||
stream:Play()
|
||||
streamdata.StartPlaying = false
|
||||
end
|
||||
|
||||
::CONTINUE::
|
||||
end
|
||||
end
|
||||
|
||||
function PART:SetRandomPitch(num)
|
||||
self.RandomPitch = num
|
||||
self.random_pitch = math.Rand(-num, num)
|
||||
end
|
||||
|
||||
function PART:SetLoop(b)
|
||||
self.Loop = b
|
||||
self:SetURL(self:GetURL())
|
||||
end
|
||||
|
||||
function PART:SetURL(URL)
|
||||
self.InSetup = true
|
||||
|
||||
timer.Create("pac3_webaudio_seturl_" .. tostring(self), 0.5, 1, function()
|
||||
if not self:IsValid() then return end
|
||||
|
||||
self.InSetup = false
|
||||
self:SetupURLStreamsNow(URL)
|
||||
|
||||
if self.PlayAfterSetup then
|
||||
self:PlaySound()
|
||||
self.PlayAfterSetup = false
|
||||
end
|
||||
end)
|
||||
|
||||
self.URL = URL
|
||||
end
|
||||
|
||||
function PART:SetupURLStreamsNow(URL)
|
||||
local urls = {}
|
||||
|
||||
for _, url in ipairs(URL:Split(";")) do
|
||||
local min, max = url:match(".+%[(.-),(.-)%]")
|
||||
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
|
||||
if min and max then
|
||||
for i = min, max do
|
||||
table.insert(urls, (url:gsub("%[.-%]", i)))
|
||||
end
|
||||
else
|
||||
table.insert(urls, url)
|
||||
end
|
||||
end
|
||||
|
||||
if #urls >= 150 then
|
||||
local cp = {}
|
||||
|
||||
for i = 1, 150 do
|
||||
table.insert(cp, urls[i])
|
||||
end
|
||||
|
||||
urls = cp
|
||||
end
|
||||
|
||||
for url, streamdata in pairs(self.streams) do
|
||||
if IsValid(streamdata.stream) then
|
||||
streamdata.stream:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
self.streams = {}
|
||||
self.stream_count = 0
|
||||
|
||||
local inPace = pace and pace.IsActive() and pace.current_part == self and self:GetPlayerOwner() == pac.LocalPlayer
|
||||
|
||||
for _, url in ipairs(urls) do
|
||||
local flags = "3d noplay noblock"
|
||||
local function callback(channel, errorCode, errorString)
|
||||
local streamdata = self.streams[url]
|
||||
if not streamdata then
|
||||
if IsValid(channel) then channel:Stop() end
|
||||
return
|
||||
end
|
||||
|
||||
if not channel or not channel:IsValid() then
|
||||
pac.Message("Failed to load ", url, " (" .. flags .. ") - " .. (errorString or errorCode or "UNKNOWN"))
|
||||
self:SetError("Failed to load " .. url .. " (" .. flags .. ") - " .. (errorString or errorCode or "UNKNOWN"))
|
||||
|
||||
if errorCode == -1 then
|
||||
local msg = 'GMOD BUG: WAVe and Vorbis files are known to be not working with 3D flag, recode file into MPEG-3 format!'
|
||||
pac.Message(msg)
|
||||
self:SetError(msg)
|
||||
end
|
||||
|
||||
self.streams[url] = nil
|
||||
self.stream_count = self.stream_count - 1
|
||||
return
|
||||
end
|
||||
|
||||
streamdata.Loading = false
|
||||
|
||||
if streamdata.valid then
|
||||
if streamdata.PlayAfterLoad or inPace then
|
||||
channel:EnableLooping(self.Loop and channel:GetLength() > 0)
|
||||
streamdata.PlayAfterLoad = false
|
||||
streamdata.StartPlaying = true
|
||||
end
|
||||
|
||||
streamdata.stream = channel
|
||||
|
||||
if self.NeedsToPlayAfterLoad then
|
||||
self.NeedsToPlayAfterLoad = false
|
||||
self:PlaySound()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
channel:Stop()
|
||||
end
|
||||
|
||||
self.streams[url] = {Loading = true, valid = true}
|
||||
self.stream_count = self.stream_count + 1
|
||||
|
||||
sound.PlayURL(url, flags, callback)
|
||||
end
|
||||
end
|
||||
|
||||
function PART:PlaySound()
|
||||
if self.InSetup then
|
||||
self.PlayAfterSetup = true
|
||||
return
|
||||
end
|
||||
|
||||
if self.stream_count == 0 then return end
|
||||
|
||||
local i, streamdata, atLeastSome = 0
|
||||
|
||||
while i < 20 and i < self.stream_count do
|
||||
streamdata = table.Random(self.streams)
|
||||
|
||||
if IsValid(streamdata.stream) then
|
||||
if not atLeastSome and streamdata.Loading then
|
||||
atLeastSome = true
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
local stream = streamdata.stream
|
||||
|
||||
if not IsValid(stream) then
|
||||
if atLeastSome then
|
||||
self.NeedsToPlayAfterLoad = true
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:SetRandomPitch(self.RandomPitch)
|
||||
|
||||
if IsValid(self.last_stream) and not self.Overlapping and self.last_stream ~= stream then
|
||||
pcall(function()
|
||||
-- this is erroring with noblock flag not being set, but we are doing that
|
||||
-- maybe the stream could be partially invalid
|
||||
self.last_stream:SetTime(0)
|
||||
self.last_stream:Pause()
|
||||
end)
|
||||
end
|
||||
|
||||
streamdata.StartPlaying = true
|
||||
self.last_stream = stream
|
||||
end
|
||||
|
||||
function PART:StopSound()
|
||||
local toremove
|
||||
|
||||
for key, streamdata in pairs(self.streams) do
|
||||
streamdata.PlayAfterLoad = false
|
||||
streamdata.StartPlaying = false
|
||||
|
||||
local stream = streamdata.stream
|
||||
|
||||
if IsValid(stream) then
|
||||
if self.PauseOnHide then
|
||||
stream:Pause()
|
||||
else
|
||||
pcall(function() stream:SetTime(0) end)
|
||||
stream:Pause()
|
||||
end
|
||||
elseif stream then
|
||||
toremove = toremove or {}
|
||||
table.insert(toremove, key)
|
||||
end
|
||||
end
|
||||
|
||||
if toremove then
|
||||
for i, index in ipairs(toremove) do
|
||||
self.streams[index] = nil
|
||||
end
|
||||
|
||||
self.stream_count = self.stream_count - #toremove
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnShow(from_rendering)
|
||||
if not from_rendering then
|
||||
self:PlaySound()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
if self.StopOnHide then
|
||||
self:StopSound()
|
||||
end
|
||||
end
|
||||
|
||||
function PART:OnRemove()
|
||||
for key, streamdata in pairs(self.streams) do
|
||||
streamdata.valid = false
|
||||
|
||||
if IsValid(streamdata.stream) then
|
||||
streamdata.stream:Stop()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
BUILDER:Register()
|
||||
Reference in New Issue
Block a user