mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
910 lines
22 KiB
Lua
910 lines
22 KiB
Lua
--[[
|
|
| 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/
|
|
--]]
|
|
|
|
CreateConVar( "pac_model_max_scales", "10000", FCVAR_ARCHIVE, "Maximum scales model can have")
|
|
|
|
|
|
|
|
|
|
local pac = pac
|
|
|
|
local render_SetColorModulation = render.SetColorModulation
|
|
local render_SetBlend = render.SetBlend
|
|
local render_CullMode = render.CullMode
|
|
local MATERIAL_CULLMODE_CW = MATERIAL_CULLMODE_CW
|
|
local MATERIAL_CULLMODE_CCW = MATERIAL_CULLMODE_CCW
|
|
local render_MaterialOverride = render.ModelMaterialOverride
|
|
local cam_PushModelMatrix = cam.PushModelMatrix
|
|
local cam_PopModelMatrix = cam.PopModelMatrix
|
|
local Vector = Vector
|
|
local EF_BONEMERGE = EF_BONEMERGE
|
|
local NULL = NULL
|
|
local Color = Color
|
|
local Matrix = Matrix
|
|
local vector_origin = vector_origin
|
|
local render = render
|
|
local cam = cam
|
|
local surface = surface
|
|
local render_MaterialOverrideByIndex = render.MaterialOverrideByIndex
|
|
local render_SuppressEngineLighting = render.SuppressEngineLighting
|
|
|
|
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
|
|
|
PART.FriendlyName = "model"
|
|
PART.ClassName = "model2"
|
|
PART.Category = "model"
|
|
PART.ManualDraw = true
|
|
PART.HandleModifiersManually = true
|
|
PART.Icon = 'icon16/shape_square.png'
|
|
PART.is_model_part = true
|
|
PART.ProperColorRange = true
|
|
PART.Group = 'model'
|
|
|
|
BUILDER:StartStorableVars()
|
|
:SetPropertyGroup("generic")
|
|
:PropertyOrder("Name")
|
|
:PropertyOrder("Hide")
|
|
:PropertyOrder("ParentName")
|
|
:GetSet("Model", "", {editor_panel = "model"})
|
|
:GetSet("ForceObjUrl", false)
|
|
|
|
:SetPropertyGroup("orientation")
|
|
:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
|
:GetSet("Scale", Vector(1,1,1))
|
|
:GetSet("BoneMerge", false)
|
|
:GetSet("LegacyTransform", false)
|
|
|
|
:SetPropertyGroup("appearance")
|
|
:GetSet("Color", Vector(1, 1, 1), {editor_panel = "color2"})
|
|
:GetSet("Brightness", 1)
|
|
:GetSet("NoLighting", false)
|
|
:GetSet("NoCulling", false)
|
|
:GetSet("Invert", false)
|
|
:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
|
:GetSet("ModelModifiers", "", {hidden = true})
|
|
:GetSet("Material", "", {editor_panel = "material"})
|
|
:GetSet("Materials", "", {hidden = true})
|
|
:GetSet("Skin", 0, {editor_onchange = function(self, num) return math.Round(math.Clamp(tonumber(num), 0, pace.current_part:GetOwner():SkinCount())) end})
|
|
:GetSet("LevelOfDetail", 0, {editor_clamp = {-1, 8}, editor_round = true})
|
|
:GetSetPart("EyeTarget")
|
|
|
|
:EndStorableVars()
|
|
|
|
PART.Owner = NULL
|
|
|
|
function PART:GetNiceName()
|
|
local str = pac.PrettifyName(("/" .. self:GetModel()):match(".+/(.-)%."))
|
|
|
|
return str and str:gsub("%d", "") or "error"
|
|
end
|
|
|
|
function PART:GetDynamicProperties()
|
|
local ent = self:GetOwner()
|
|
if not ent:IsValid() or not ent:GetBodyGroups() then return end
|
|
|
|
local tbl = {}
|
|
|
|
if ent:SkinCount() and ent:SkinCount() > 1 then
|
|
tbl.skin = {
|
|
key = "skin",
|
|
set = function(val)
|
|
local tbl = self:ModelModifiersToTable(self:GetModelModifiers())
|
|
tbl.skin = val
|
|
self:SetModelModifiers(self:ModelModifiersToString(tbl))
|
|
end,
|
|
get = function()
|
|
return self:ModelModifiersToTable(self:GetModelModifiers()).skin
|
|
end,
|
|
udata = {editor_onchange = function(self, num) return math.Clamp(math.Round(num), 0, ent:SkinCount() - 1) end},
|
|
}
|
|
end
|
|
|
|
for _, info in ipairs(ent:GetBodyGroups()) do
|
|
if info.num > 1 then
|
|
tbl[info.name] = {
|
|
key = info.name,
|
|
set = function(val)
|
|
local tbl = self:ModelModifiersToTable(self:GetModelModifiers())
|
|
tbl[info.name] = val
|
|
self:SetModelModifiers(self:ModelModifiersToString(tbl))
|
|
end,
|
|
get = function()
|
|
return self:ModelModifiersToTable(self:GetModelModifiers())[info.name] or 0
|
|
end,
|
|
udata = {editor_onchange = function(self, num) return math.Clamp(math.Round(num), 0, info.num - 1) end, group = "bodygroups"},
|
|
}
|
|
end
|
|
end
|
|
|
|
if ent:GetMaterials() and #ent:GetMaterials() > 1 then
|
|
for i, name in ipairs(ent:GetMaterials()) do
|
|
name = name:match(".+/(.+)") or name
|
|
tbl[name] = {
|
|
key = name,
|
|
get = function()
|
|
local tbl = self.Materials:Split(";")
|
|
return tbl[i] or ""
|
|
end,
|
|
set = function(val)
|
|
local tbl = self.Materials:Split(";")
|
|
tbl[i] = val
|
|
|
|
for i, name in ipairs(ent:GetMaterials()) do
|
|
tbl[i] = tbl[i] or ""
|
|
end
|
|
|
|
self:SetMaterials(table.concat(tbl, ";"))
|
|
end,
|
|
udata = {editor_panel = "material", editor_friendly = name, group = "sub materials"},
|
|
}
|
|
end
|
|
end
|
|
|
|
return tbl
|
|
end
|
|
|
|
function PART:SetLevelOfDetail(val)
|
|
self.LevelOfDetail = val
|
|
local ent = self:GetOwner()
|
|
if ent:IsValid() then
|
|
ent:SetLOD(val)
|
|
end
|
|
end
|
|
|
|
function PART:SetSkin(var)
|
|
self.Skin = var
|
|
local owner = self:GetOwner()
|
|
|
|
if owner:IsValid() then
|
|
owner:SetSkin(var)
|
|
end
|
|
end
|
|
|
|
function PART:ModelModifiersToTable(str)
|
|
if str == "" or (not str:find(";", nil, true) and not str:find("=", nil, true)) then return {} end
|
|
|
|
local tbl = {}
|
|
for _, data in ipairs(str:Split(";")) do
|
|
local key, val = data:match("(.+)=(.+)")
|
|
if key then
|
|
key = key:Trim()
|
|
val = tonumber(val:Trim())
|
|
|
|
tbl[key] = val
|
|
end
|
|
end
|
|
|
|
return tbl
|
|
end
|
|
|
|
function PART:ModelModifiersToString(tbl)
|
|
local str = ""
|
|
for k,v in pairs(tbl) do
|
|
str = str .. k .. "=" .. v .. ";"
|
|
end
|
|
return str
|
|
end
|
|
|
|
function PART:SetModelModifiers(str)
|
|
self.ModelModifiers = str
|
|
local owner = self:GetOwner()
|
|
|
|
if not owner:IsValid() then return end
|
|
|
|
local tbl = self:ModelModifiersToTable(str)
|
|
|
|
if tbl.skin then
|
|
self:SetSkin(tbl.skin)
|
|
tbl.skin = nil
|
|
end
|
|
|
|
if not owner:GetBodyGroups() then return end
|
|
|
|
self.draw_bodygroups = {}
|
|
|
|
for i, info in ipairs(owner:GetBodyGroups()) do
|
|
local val = tbl[info.name]
|
|
if val then
|
|
table.insert(self.draw_bodygroups, {info.id, val})
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:SetMaterial(str)
|
|
self.Material = str
|
|
|
|
if str == "" then
|
|
if self.material_override_self then
|
|
self.material_override_self[0] = nil
|
|
end
|
|
else
|
|
self.material_override_self = self.material_override_self or {}
|
|
|
|
if not pac.Handleurltex(self, str, function(mat)
|
|
self.material_override_self = self.material_override_self or {}
|
|
self.material_override_self[0] = mat
|
|
end) then
|
|
self.material_override_self[0] = pac.Material(str, self)
|
|
end
|
|
end
|
|
|
|
if self.material_override_self and not next(self.material_override_self) then
|
|
self.material_override_self = nil
|
|
end
|
|
end
|
|
|
|
function PART:SetMaterials(str)
|
|
self.Materials = str
|
|
|
|
local materials = self:GetOwner():IsValid() and self:GetOwner():GetMaterials()
|
|
|
|
if not materials then return end
|
|
|
|
self.material_count = #materials
|
|
|
|
self.material_override_self = self.material_override_self or {}
|
|
|
|
local tbl = str:Split(";")
|
|
|
|
for i = 1, #materials do
|
|
local path = tbl[i]
|
|
|
|
if path and path ~= "" then
|
|
if not pac.Handleurltex(self, path, function(mat)
|
|
self.material_override_self = self.material_override_self or {}
|
|
self.material_override_self[i] = mat
|
|
end) then
|
|
self.material_override_self[i] = pac.Material(path, self)
|
|
end
|
|
else
|
|
self.material_override_self[i] = nil
|
|
end
|
|
end
|
|
|
|
if not next(self.material_override_self) then
|
|
self.material_override_self = nil
|
|
end
|
|
end
|
|
|
|
function PART:Reset()
|
|
self:Initialize()
|
|
for _, key in pairs(self:GetStorableVars()) do
|
|
if PART[key] then
|
|
self["Set" .. key](self, self["Get" .. key](self))
|
|
end
|
|
end
|
|
self.cached_dynamic_props = nil
|
|
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:Initialize()
|
|
self.Owner = pac.CreateEntity(self:GetModel())
|
|
self.Owner:SetNoDraw(true)
|
|
self.Owner.PACPart = self
|
|
self.material_count = 0
|
|
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())
|
|
ent:SetLegacyTransform(self.LegacyTransform)
|
|
self:SetBone(self:GetBone())
|
|
end
|
|
end
|
|
|
|
function PART:OnRemove()
|
|
if not self.loading then
|
|
SafeRemoveEntityDelayed(self.Owner,0.1)
|
|
end
|
|
end
|
|
|
|
function PART:OnThink()
|
|
self:CheckBoneMerge()
|
|
end
|
|
|
|
function PART:BindMaterials(ent)
|
|
local materials = self.material_override_self or self.material_override
|
|
local material_bound = false
|
|
|
|
if self.material_override_self then
|
|
if materials[0] then
|
|
render_MaterialOverride(materials[0])
|
|
material_bound = true
|
|
end
|
|
|
|
for i = 1, self.material_count do
|
|
local mat = materials[i]
|
|
|
|
if mat then
|
|
render_MaterialOverrideByIndex(i-1, mat)
|
|
else
|
|
render_MaterialOverrideByIndex(i-1, nil)
|
|
end
|
|
end
|
|
elseif self.material_override then
|
|
if materials[0] and materials[0][1] then
|
|
render_MaterialOverride(materials[0][1]:GetRawMaterial())
|
|
material_bound = true
|
|
end
|
|
|
|
for i = 1, self.material_count do
|
|
local stack = materials[i]
|
|
if stack then
|
|
local mat = stack[1]
|
|
|
|
if mat then
|
|
render_MaterialOverrideByIndex(i-1, mat:GetRawMaterial())
|
|
else
|
|
render_MaterialOverrideByIndex(i-1, nil)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.BoneMerge and not material_bound then
|
|
render_MaterialOverride()
|
|
end
|
|
|
|
return material_bound
|
|
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")
|
|
|
|
local r, g, b = self.Color.r, self.Color.g, self.Color.b
|
|
local brightness = self.Brightness
|
|
|
|
-- render.SetColorModulation and render.SetAlpha set the material $color and $alpha.
|
|
render_SetColorModulation(r*brightness, g*brightness, b*brightness)
|
|
if not pac.drawing_motionblur_alpha then
|
|
render_SetBlend(self.Alpha)
|
|
end
|
|
|
|
if self.NoLighting then
|
|
render_SuppressEngineLighting(true)
|
|
end
|
|
end
|
|
|
|
if self.draw_bodygroups then
|
|
for _, v in ipairs(self.draw_bodygroups) do
|
|
ent:SetBodygroup(v[1], v[2])
|
|
end
|
|
end
|
|
|
|
if self.EyeTarget:IsValid() and self.EyeTarget.GetWorldPosition then
|
|
ent:SetEyeTarget(self.EyeTarget:GetWorldPosition())
|
|
ent.pac_modified_eyetarget = true
|
|
elseif ent.pac_modified_eyetarget then
|
|
ent:SetEyeTarget(vector_origin)
|
|
ent.pac_modified_eyetarget = nil
|
|
end
|
|
end
|
|
|
|
function PART:PostEntityDraw(ent, pos, ang)
|
|
if self.Alpha ~= 0 and self.Size ~= 0 then
|
|
self:ModifiersPostEvent("OnDraw")
|
|
|
|
if self.NoLighting then
|
|
render_SuppressEngineLighting(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
function PART:OnDraw()
|
|
local ent = self:GetOwner()
|
|
|
|
if not ent:IsValid() then
|
|
self:Reset()
|
|
ent = self:GetOwner()
|
|
end
|
|
|
|
local pos, ang = self:GetDrawPosition()
|
|
|
|
if self.loading then
|
|
self:DrawLoadingText(ent, pos)
|
|
return
|
|
end
|
|
|
|
|
|
self:PreEntityDraw(ent, pos, ang)
|
|
self:DrawModel(ent, pos, ang)
|
|
self:PostEntityDraw(ent, pos, ang)
|
|
|
|
pac.ResetBones(ent)
|
|
end
|
|
|
|
|
|
local matrix = Matrix()
|
|
local IDENT_SCALE = Vector(1,1,1)
|
|
local _self, _ent, _pos, _ang
|
|
|
|
local function ent_draw_model(self, ent, pos, ang)
|
|
if self.obj_mesh then
|
|
ent:SetModelScale(0,0)
|
|
ent:DrawModel()
|
|
|
|
matrix:Identity()
|
|
matrix:SetAngles(ang)
|
|
matrix:SetTranslation(pos)
|
|
matrix:SetScale(self.Scale * self.Size)
|
|
|
|
cam_PushModelMatrix(matrix)
|
|
self.obj_mesh:Draw()
|
|
cam_PopModelMatrix()
|
|
else
|
|
if ent.needs_setupbones_from_legacy_bone_parts then
|
|
pac.SetupBones(ent)
|
|
ent.needs_setupbones_from_legacy_bone_parts = nil
|
|
end
|
|
ent:DrawModel()
|
|
end
|
|
end
|
|
|
|
local function protected_ent_draw_model()
|
|
ent_draw_model(_self, _ent, _pos, _ang)
|
|
end
|
|
|
|
function PART:DrawModel(ent, pos, ang)
|
|
if self.loading then
|
|
self:DrawLoadingText(ent, pos)
|
|
end
|
|
|
|
if self.Alpha == 0 or self.Size == 0 then return end
|
|
if self.loading and not self.obj_mesh then return end
|
|
|
|
if self.NoCulling or self.Invert then
|
|
render_CullMode(MATERIAL_CULLMODE_CW)
|
|
end
|
|
|
|
local material_bound = false
|
|
|
|
material_bound = self:BindMaterials(ent) or material_bound
|
|
|
|
ent.pac_drawing_model = true
|
|
ent_draw_model(self, ent, pos, ang)
|
|
ent.pac_drawing_model = false
|
|
|
|
_self, _ent, _pos, _ang = self, ent, pos, ang
|
|
|
|
if self.ClassName ~= "entity2" then
|
|
render.PushFlashlightMode(true)
|
|
|
|
material_bound = self:BindMaterials(ent) or material_bound
|
|
ent.pac_drawing_model = true
|
|
ProtectedCall(protected_ent_draw_model)
|
|
ent.pac_drawing_model = false
|
|
|
|
render.PopFlashlightMode()
|
|
end
|
|
|
|
if self.NoCulling then
|
|
render_CullMode(MATERIAL_CULLMODE_CCW)
|
|
material_bound = self:BindMaterials(ent) or material_bound
|
|
ProtectedCall(protected_ent_draw_model)
|
|
elseif self.Invert then
|
|
render_CullMode(MATERIAL_CULLMODE_CCW)
|
|
end
|
|
|
|
-- need to unbind mateiral
|
|
if material_bound then
|
|
render_MaterialOverride()
|
|
end
|
|
end
|
|
|
|
function PART:DrawLoadingText(ent, pos)
|
|
cam.Start2D()
|
|
cam.IgnoreZ(true)
|
|
local pos2d = pos:ToScreen()
|
|
|
|
surface.SetFont("DermaDefault")
|
|
|
|
if self.errored then
|
|
surface.SetTextColor(255, 0, 0, 255)
|
|
local str = self.loading:match("^(.-):\n") or self.loading:match("^(.-)\n") or self.loading:sub(1, 100)
|
|
local w, h = surface.GetTextSize(str)
|
|
surface.SetTextPos(pos2d.x - w / 2, pos2d.y - h / 2)
|
|
surface.DrawText(str)
|
|
self:SetError(str)
|
|
else
|
|
surface.SetTextColor(255, 255, 255, 255)
|
|
local str = self.loading .. string.rep(".", pac.RealTime * 3 % 3)
|
|
local w, h = surface.GetTextSize(self.loading .. "...")
|
|
|
|
surface.SetTextPos(pos2d.x - w / 2, pos2d.y - h / 2)
|
|
surface.DrawText(str)
|
|
self:SetError()
|
|
end
|
|
cam.IgnoreZ(false)
|
|
cam.End2D()
|
|
end
|
|
|
|
local ALLOW_TO_MDL = CreateConVar('pac_allow_mdl', '1', CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, 'Allow to use custom MDLs')
|
|
|
|
function PART:RefreshModel()
|
|
if self.refreshing_model then return end
|
|
|
|
self.refreshing_model = true
|
|
|
|
local ent = self:GetOwner()
|
|
|
|
if ent:IsValid() then
|
|
pac.ResetBoneCache(ent)
|
|
end
|
|
|
|
self.cached_dynamic_props = nil
|
|
|
|
self:SetModelModifiers(self:GetModelModifiers())
|
|
self:SetMaterials(self:GetMaterials())
|
|
self:SetSize(self:GetSize())
|
|
self:SetScale(self:GetScale())
|
|
self:SetSkin(self:GetSkin())
|
|
self:SetLevelOfDetail(self:GetLevelOfDetail())
|
|
|
|
if not self:IsHidden() and not self:IsDrawHidden() then
|
|
-- notify children about model change
|
|
self:ShowFromRendering()
|
|
end
|
|
|
|
self.refreshing_model = false
|
|
end
|
|
|
|
function PART:RealSetModel(path)
|
|
self:GetOwner():SetModel(path)
|
|
self:RefreshModel()
|
|
end
|
|
|
|
function PART:SetForceObjUrl(value)
|
|
self.ForceObjUrl = value
|
|
self:ProcessModelChange()
|
|
end
|
|
|
|
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
|
|
|
|
function PART:ProcessModelChange()
|
|
local owner = self:GetOwner()
|
|
if not owner:IsValid() then return end
|
|
local path = self.Model
|
|
|
|
if path:find("://", nil, true) then
|
|
if path:StartWith("objhttp") or path:StartWith("obj:http") or path:match("%.obj%p?") or self.ForceObjUrl then
|
|
path = path:gsub("^objhttp","http"):gsub("^obj:http","http")
|
|
self.loading = "downloading obj"
|
|
|
|
pac.urlobj.GetObjFromURL(path, false, false,
|
|
function(meshes, err)
|
|
|
|
local function set_mesh(part, mesh)
|
|
local owner = part:GetOwner()
|
|
part.obj_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
|
|
|
|
owner:SetRenderBounds(Vector(1, 1, 1) * -300, Vector(1, 1, 1) * 300)
|
|
end
|
|
|
|
if not self:IsValid() then return end
|
|
|
|
self.loading = false
|
|
|
|
if not meshes and err then
|
|
owner:SetModel("models/error.mdl")
|
|
self.obj_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:GetOwnerName())
|
|
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 = nil
|
|
else
|
|
self.loading = statusMessage
|
|
end
|
|
end
|
|
)
|
|
else
|
|
local status, reason = hook.Run('PAC3AllowMDLDownload', self:GetPlayerOwner(), self, path)
|
|
|
|
if ALLOW_TO_MDL:GetBool() and status ~= false then
|
|
self.loading = "downloading mdl zip"
|
|
pac.DownloadMDL(path, function(mdl_path)
|
|
self.loading = nil
|
|
self.errored = nil
|
|
|
|
if self.ClassName == "entity2" then
|
|
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", self:GetOwner(), path)
|
|
end
|
|
|
|
self:RealSetModel(mdl_path)
|
|
|
|
end, function(err)
|
|
|
|
if pace and pace.current_part == self and not IsValid(pace.BusyWithProperties) then
|
|
pace.MessagePrompt(err, "HTTP Request Failed for " .. path, "OK")
|
|
else
|
|
pac.Message(Color(0, 255, 0), "[model] ", Color(255, 255, 255), "HTTP Request Failed for " .. path .. " - " .. err)
|
|
end
|
|
|
|
self.loading = err
|
|
self.errored = true
|
|
self:RealSetModel("models/error.mdl")
|
|
end, self:GetPlayerOwner())
|
|
else
|
|
local msg = reason or "mdl's are not allowed"
|
|
self.loading = msg
|
|
self:SetError(msg)
|
|
self:RealSetModel("models/error.mdl")
|
|
pac.Message(self, msg)
|
|
end
|
|
end
|
|
elseif path ~= "" then
|
|
if self.ClassName == "entity2" then
|
|
pac.emut.MutateEntity(self:GetPlayerOwner(), "model", owner, path)
|
|
end
|
|
|
|
self:RealSetModel(path)
|
|
end
|
|
end
|
|
|
|
function PART:SetModel(path)
|
|
self.Model = path
|
|
|
|
local owner = self:GetOwner()
|
|
if not owner:IsValid() then return end
|
|
|
|
self.old_model = path
|
|
self:ProcessModelChange()
|
|
end
|
|
|
|
local NORMAL = Vector(1,1,1)
|
|
|
|
function PART:CheckScale()
|
|
local owner = self:GetOwner()
|
|
if not owner:IsValid() then return end
|
|
|
|
-- RenderMultiply doesn't work with this..
|
|
if self.BoneMerge and owner:GetBoneCount() and 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(vec)
|
|
local max_scale = GetConVar("pac_model_max_scales"):GetFloat()
|
|
local largest_scale = math.max(math.abs(vec.x), math.abs(vec.y), math.abs(vec.z))
|
|
|
|
if vec and max_scale > 0 and (LocalPlayer() ~= self:GetPlayerOwner()) then --clamp for other players if they have pac_model_max_scales convar more than 0
|
|
vec = Vector(math.Clamp(vec.x, -max_scale, max_scale), math.Clamp(vec.y, -max_scale, max_scale), math.Clamp(vec.z, -max_scale, max_scale))
|
|
end
|
|
if largest_scale > 10000 then --warn about the default max scale
|
|
self:SetError("Scale is being limited due to having an excessive component. Default maximum values are 10000")
|
|
else self:SetError() end --if ok, clear the warning
|
|
vec = vec or Vector(1,1,1)
|
|
|
|
self.Scale = vec
|
|
|
|
if not self:CheckScale() then
|
|
self:ApplyMatrix()
|
|
end
|
|
end
|
|
|
|
local vec_one = Vector(1,1,1)
|
|
|
|
function PART:ApplyMatrix()
|
|
local ent = self:GetOwner()
|
|
if not ent:IsValid() then return end
|
|
|
|
local mat = Matrix()
|
|
|
|
if self.ClassName ~= "model2" then
|
|
mat:Translate(self.Position + self.PositionOffset)
|
|
mat:Rotate(self.Angles + self.AngleOffset)
|
|
end
|
|
|
|
if ent:IsPlayer() or ent:IsNPC() then
|
|
pac.emut.MutateEntity(self:GetPlayerOwner(), "size", ent, self.Size, {
|
|
StandingHullHeight = self.StandingHullHeight,
|
|
CrouchingHullHeight = self.CrouchingHullHeight,
|
|
HullWidth = self.HullWidth,
|
|
})
|
|
|
|
if self.Size == 1 and self.Scale == vec_one then
|
|
if self.InverseKinematics then
|
|
if ent:GetModelScale() ~= 1 then
|
|
ent:SetModelScale(1, 0)
|
|
end
|
|
ent:SetIK(true)
|
|
else
|
|
ent:SetModelScale(1.000001, 0)
|
|
ent:SetIK(false)
|
|
end
|
|
end
|
|
|
|
mat:Scale(self.Scale)
|
|
else
|
|
mat:Scale(self.Scale * self.Size)
|
|
end
|
|
|
|
ent.pac_model_scale = mat:GetScale()
|
|
|
|
if mat:IsIdentity() then
|
|
ent:DisableMatrix("RenderMultiply")
|
|
else
|
|
ent:EnableMatrix("RenderMultiply", mat)
|
|
end
|
|
end
|
|
|
|
function PART:SetSize(var)
|
|
var = var or 1
|
|
|
|
self.Size = var
|
|
|
|
if not self:CheckScale() then
|
|
self:ApplyMatrix()
|
|
end
|
|
end
|
|
|
|
function PART:CheckBoneMerge()
|
|
local ent = self:GetOwner()
|
|
|
|
if ent == pac.LocalHands or ent == pac.LocalViewModel then return end
|
|
|
|
if self.skip_orient then return end
|
|
|
|
if ent:IsValid() and not ent:IsPlayer() and ent:GetModel() 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)
|
|
owner.pac_bonemerged = owner.pac_bonemerged or {}
|
|
table.insert(owner.pac_bonemerged, ent)
|
|
ent.RenderOverride = function()
|
|
ent.pac_drawing_model = true
|
|
ent:DrawModel()
|
|
ent.pac_drawing_model = false
|
|
end
|
|
end
|
|
end
|
|
else
|
|
if ent:GetParent():IsValid() then
|
|
local owner = ent:GetParent()
|
|
ent:SetParent(NULL)
|
|
|
|
if ent:IsEffectActive(EF_BONEMERGE) then
|
|
ent:RemoveEffects(EF_BONEMERGE)
|
|
ent.RenderOverride = nil
|
|
|
|
if owner:IsValid() then
|
|
owner.pac_bonemerged = owner.pac_bonemerged or {}
|
|
for i, v in ipairs(owner.pac_bonemerged) do
|
|
if v == ent then
|
|
table.remove(owner.pac_bonemerged, i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
self.requires_bone_model_scale = false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
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()
|
|
include("model/entity.lua")
|
|
include("model/weapon.lua")
|