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