mirror of
https://github.com/CapsAdmin/pac3.git
synced 2025-03-04 03:03:01 -05:00
Merge pull request #1315 from CapsAdmin/develop
update master branch to latest develop
This commit is contained in:
commit
44a8e67222
10
.github/workflows/lua_linter.yaml
vendored
Normal file
10
.github/workflows/lua_linter.yaml
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
name: lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
lua-lint:
|
||||
uses: FPtje/GLuaFixer/.github/workflows/glualint.yml@master
|
30
.github/workflows/update_workshop.yaml
vendored
Normal file
30
.github/workflows/update_workshop.yaml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: update_workshop
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
linter:
|
||||
uses: CapsAdmin/pac3/.github/workflows/lua_linter.yaml@develop
|
||||
|
||||
update-workshop:
|
||||
if: github.repository == 'CapsAdmin/pac3'
|
||||
# needs: linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Publish to Steam Workshop
|
||||
uses: vurv78/gmod-upload@v0.1.3
|
||||
env:
|
||||
STEAM_USERNAME: ${{ secrets.STEAM_NAME }}
|
||||
STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }}
|
||||
with:
|
||||
id: ${{ github.ref == 'refs/heads/master' && '104691717' || '3038093543' }}
|
||||
changelog: ${{ github.event.head_commit.message }}
|
||||
config: ${{ github.ref == 'refs/heads/master' && 'addon.json' || 'addon_develop.json' }}
|
8
.glualint.json
Normal file
8
.glualint.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"lint_maxScopeDepth": 0,
|
||||
"lint_shadowing": false,
|
||||
"lint_spaceAfterComma": true,
|
||||
"lint_ignoreFiles": [
|
||||
"lua/entities/gmod_wire_expression2/*"
|
||||
]
|
||||
}
|
22
.travis.yml
22
.travis.yml
@ -1,22 +0,0 @@
|
||||
sudo: false
|
||||
|
||||
language: c
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libc6:i386
|
||||
- libstdc++6:i386
|
||||
|
||||
before_install:
|
||||
# Download the lua
|
||||
- wget https://github.com/Metastruct/gtravis/releases/download/travisbins/gluac.tar.xz
|
||||
- tar -xf gluac.tar.xz
|
||||
- export LD_LIBRARY_PATH=`pwd`/gluac${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH:-}
|
||||
|
||||
# Set the $PATH so gluac can be executed
|
||||
- export PATH=$PATH:`pwd`/gluac
|
||||
|
||||
- echo $PWD
|
||||
|
||||
script: find lua/ -iname '*.lua' -not -path 'lua/entities/gmod_wire_expression2/core/custom/*' -print0 | xargs -0 -- gluac -p --
|
@ -10,11 +10,10 @@ You can wear your outfit on any server with PAC3 and everyone should be able to
|
||||
|
||||
<img width="650" alt="Screenshot 2023-09-02 at 06 54 28" src="https://github.com/CapsAdmin/pac3/assets/204157/276c7bfc-f5a9-422a-bfb6-683a26981539">
|
||||
|
||||
The Wiki for PAC3 can be found [here](https://wiki.pac3.info/start "PAC3 Wiki")
|
||||
|
||||
This addon is also on the [workshop](http://steamcommunity.com/sharedfiles/filedetails/?id=104691717 "Workshop Version")
|
||||
|
||||
You can join the official pac3 discord server [here](https://discord.gg/utpR3gJ "Join PAC3 Discord Server")
|
||||
Some links to check out:
|
||||
* [wiki](https://wiki.pac3.info/start "PAC3 Wiki")
|
||||
* [steam workshop](http://steamcommunity.com/sharedfiles/filedetails/?id=104691717 "Workshop Version")
|
||||
* [discord server](https://discord.gg/utpR3gJ "Join PAC3 Discord Server")
|
||||
|
||||
---
|
||||
|
||||
|
15
addon.json
15
addon.json
@ -4,18 +4,19 @@
|
||||
"tags" : [ "fun", "roleplay" ],
|
||||
"ignore" :
|
||||
[
|
||||
".gitignore",
|
||||
".editorconfig",
|
||||
".git*",
|
||||
".gitignore",
|
||||
".glualint.json",
|
||||
".vscode/*",
|
||||
"*.txt",
|
||||
"*.md",
|
||||
"*.bat",
|
||||
"*.sh",
|
||||
"icon.jpg",
|
||||
"*.7z",
|
||||
"*.bat",
|
||||
"*.md",
|
||||
"*.md",
|
||||
"*.sh",
|
||||
"*.txt",
|
||||
"*.yml",
|
||||
"COPYING"
|
||||
"COPYING",
|
||||
"icon.jpg"
|
||||
]
|
||||
}
|
||||
|
22
addon_develop.json
Normal file
22
addon_develop.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"title" : "PAC3 [develop version]",
|
||||
"type" : "tool",
|
||||
"tags" : [ "fun", "roleplay" ],
|
||||
"ignore" :
|
||||
[
|
||||
".editorconfig",
|
||||
".git*",
|
||||
".gitignore",
|
||||
".glualint.json",
|
||||
".vscode/*",
|
||||
"*.7z",
|
||||
"*.bat",
|
||||
"*.md",
|
||||
"*.md",
|
||||
"*.sh",
|
||||
"*.txt",
|
||||
"*.yml",
|
||||
"COPYING",
|
||||
"icon.jpg"
|
||||
]
|
||||
}
|
@ -16,7 +16,7 @@ AnimStack = {
|
||||
local top = self:getTop()
|
||||
if top ~= part then
|
||||
if top then top:OnStackStop() end
|
||||
|
||||
|
||||
-- Remove self from stack to move to end and also prevent things from breaking because table.RemoveByValue() only removes the first instance
|
||||
table.RemoveByValue(stack, part)
|
||||
table.insert(stack, part)
|
||||
@ -28,7 +28,7 @@ AnimStack = {
|
||||
pop = function(self, part)
|
||||
part:OnStackStop()
|
||||
local stack = self.stack
|
||||
|
||||
|
||||
-- Remove self from animation stack
|
||||
if table.RemoveByValue(stack, part) == #stack + 1 then
|
||||
-- This was the current animation so play the next in the stack
|
||||
|
@ -200,7 +200,7 @@ end
|
||||
|
||||
function PART:OnDraw()
|
||||
local part = self.EndPoint
|
||||
|
||||
|
||||
if self.Materialm and self.StartColorC and self.EndColorC and part:IsValid() and part.GetWorldPosition then
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
render.SetMaterial(self.Materialm)
|
||||
|
@ -35,12 +35,12 @@ BUILDER:StartStorableVars()
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:SetEvent(event)
|
||||
local reset = (self.Arguments == "") or
|
||||
local reset = (self.Arguments == "") or
|
||||
(self.Arguments ~= "" and self.Event ~= "" and self.Event ~= event)
|
||||
|
||||
self.Event = event
|
||||
self:SetWarning()
|
||||
self:GetDynamicProperties(reset)
|
||||
self:GetDynamicProperties(reset)
|
||||
end
|
||||
|
||||
local function get_default(typ)
|
||||
@ -95,8 +95,8 @@ function PART:GetDynamicProperties(reset_to_default)
|
||||
}
|
||||
|
||||
local arg = tbl[key]
|
||||
if arg.get() == nil or reset_to_default then
|
||||
if udata.default then
|
||||
if arg.get() == nil or reset_to_default then
|
||||
if udata.default then
|
||||
arg.set(udata.default)
|
||||
else
|
||||
arg.set(nil)
|
||||
@ -824,8 +824,8 @@ PART.OldEvents = {
|
||||
command = {
|
||||
arguments = {{find = "string"}, {time = "number"}, {hide_in_eventwheel = "boolean"}},
|
||||
userdata = {
|
||||
{default = "change_me", editor_friendly = "CommandName"},
|
||||
{default = 0.1, editor_friendly = "EventDuration"},
|
||||
{default = "change_me", editor_friendly = "CommandName"},
|
||||
{default = 0.1, editor_friendly = "EventDuration"},
|
||||
{default = false, group = "event wheel", editor_friendly = "HideInEventWheel"}
|
||||
},
|
||||
nice = function(self, ent, find, time)
|
||||
|
@ -180,17 +180,19 @@ function PART:PlaySound(osnd, ovol)
|
||||
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
|
||||
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
|
||||
@ -210,7 +212,7 @@ function PART:PlaySound(osnd, ovol)
|
||||
"(%[%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
|
||||
|
@ -1,3 +1,5 @@
|
||||
local DynamicLight = DynamicLight
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
PART.FriendlyName = "light"
|
||||
@ -20,7 +22,7 @@ BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetLight()
|
||||
if not self.light then
|
||||
self.light = DynamicLight(tonumber(self.UniqueID))
|
||||
self.light = DynamicLight(tonumber(self:GetPrintUniqueID(), 16))
|
||||
end
|
||||
self.light.decay = 0
|
||||
self.light.dietime = math.huge
|
||||
@ -33,14 +35,15 @@ function PART:RemoveLight()
|
||||
local light = self.light
|
||||
self.light = nil
|
||||
-- this prevents fade out when removing the light
|
||||
light.pos = Vector(9999,9999,9999)
|
||||
light.pos = Vector(9999, 9999, 9999)
|
||||
timer.Simple(0, function()
|
||||
light.dietime = 0
|
||||
end)
|
||||
end
|
||||
|
||||
function PART:GetNiceName()
|
||||
local hue = pac.ColorToNames(self:GetColor())
|
||||
local color = self:GetColor()
|
||||
local hue = pac.ColorToNames({r = color[1] * 255, g = color[2] * 255, b = color[3] * 255})
|
||||
return hue .. " light"
|
||||
end
|
||||
|
||||
@ -60,8 +63,6 @@ function PART:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
local DynamicLight = DynamicLight
|
||||
|
||||
function PART:OnDraw()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
self:GetLight().pos = pos
|
||||
@ -75,9 +76,9 @@ end
|
||||
|
||||
function PART:SetColor(val)
|
||||
self.Color = val
|
||||
self:GetLight().r = math.Clamp(val.r*255, 0, 255)
|
||||
self:GetLight().g = math.Clamp(val.g*255, 0, 255)
|
||||
self:GetLight().b = math.Clamp(val.b*255, 0, 255)
|
||||
self:GetLight().r = math.Clamp(val.r * 255, 0, 255)
|
||||
self:GetLight().g = math.Clamp(val.g * 255, 0, 255)
|
||||
self:GetLight().b = math.Clamp(val.b * 255, 0, 255)
|
||||
end
|
||||
|
||||
function PART:SetBrightness(val)
|
||||
|
@ -606,7 +606,7 @@ function PART:ProcessModelChange()
|
||||
local path = self.Model
|
||||
|
||||
if path:find("://", nil, true) then
|
||||
if path:StartWith("objhttp") or path:StartWith("obj:http") or path:EndsWith(".obj") or self.ForceObjUrl 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"
|
||||
|
||||
@ -747,8 +747,9 @@ function PART:SetAlternativeScaling(b)
|
||||
end
|
||||
|
||||
function PART:SetScale(vec)
|
||||
max_scale = GetConVar("pac_model_max_scales"):GetFloat()
|
||||
largest_scale = math.max(math.abs(vec.x), math.abs(vec.y), math.abs(vec.z))
|
||||
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
|
||||
|
@ -168,11 +168,11 @@ function PART:OnShow()
|
||||
end
|
||||
end
|
||||
|
||||
if not self.real_model then
|
||||
self.real_model = ent:GetModel()
|
||||
if not self.real_model then
|
||||
self.real_model = ent:GetModel()
|
||||
end
|
||||
|
||||
if not (self.old_model == self:GetModel()) or
|
||||
if not (self.old_model == self:GetModel()) or
|
||||
(pac.LocalHands:IsValid() and ent == pac.LocalHands
|
||||
and not (self.real_model == pac.LocalHands:GetModel())) then
|
||||
self.old_model = self:GetModel()
|
||||
|
@ -356,7 +356,7 @@ function PART:EmitParticles(pos, ang, real_ang)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
self.NextShot = pac.RealTime + self.FireDelay
|
||||
end
|
||||
self.FirstShot = false
|
||||
|
@ -293,10 +293,26 @@ PART.Inputs.ftime = FrameTime
|
||||
PART.Inputs.framenumber = FrameNumber
|
||||
PART.Inputs.fnumber = FrameNumber
|
||||
|
||||
PART.Inputs.random = function(self)
|
||||
return math.random()
|
||||
PART.Inputs.random = function(self, min, max)
|
||||
min = min or 0
|
||||
max = max or 1
|
||||
return min + math.random()*(max-min)
|
||||
end
|
||||
|
||||
PART.Inputs.random_once = function(self, seed, min, max)
|
||||
min = min or 0
|
||||
max = max or 1
|
||||
|
||||
seed = seed or 0
|
||||
self.rand_id = self.rand_id or {}
|
||||
if seed then
|
||||
self.rand_id[seed] = self.rand_id[seed] or min + math.random()*(max-min)
|
||||
else
|
||||
self.rand = self.rand or min + math.random()*(max-min)
|
||||
end
|
||||
|
||||
return self.rand_id[seed] or self.rand
|
||||
end
|
||||
|
||||
PART.Inputs.lerp = function(self, m, a, b)
|
||||
m = tonumber(m) or 0
|
||||
@ -306,12 +322,71 @@ PART.Inputs.lerp = function(self, m, a, b)
|
||||
return (b - a) * m + a
|
||||
end
|
||||
|
||||
for ease,f in pairs(math.ease) do
|
||||
if string.find(ease,"In") or string.find(ease,"Out") then
|
||||
local f2 = function(self, frac, min, max)
|
||||
min = min or 0
|
||||
max = max or 1
|
||||
return min + f(frac)*(max-min)
|
||||
end
|
||||
PART.Inputs["ease"..ease] = f2
|
||||
PART.Inputs["ease_"..ease] = f2
|
||||
PART.Inputs[ease] = f2
|
||||
end
|
||||
end
|
||||
|
||||
PART.Inputs.timeex = function(s)
|
||||
s.time = s.time or pac.RealTime
|
||||
|
||||
return pac.RealTime - s.time
|
||||
end
|
||||
|
||||
PART.Inputs.part_distance = function(self, uid1, uid2)
|
||||
if not uid1 or not uid2 then return 0 end
|
||||
|
||||
local PartA = pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), uid1)
|
||||
if not PartA:IsValid() then PartA = pac.FindPartByName(pac.Hash(pac.LocalPlayer), uid1, self) end
|
||||
|
||||
local PartB = pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), uid2)
|
||||
if not PartB:IsValid() then PartB = pac.FindPartByName(pac.Hash(pac.LocalPlayer), uid2, self) end
|
||||
|
||||
if not PartA:IsValid() or not PartB:IsValid() then return 0 end
|
||||
return (PartB:GetWorldPosition() - PartA:GetWorldPosition()):Length()
|
||||
end
|
||||
|
||||
PART.Inputs.event_alternative = function(self, uid1, num1, num2)
|
||||
if not uid1 then return 0 end
|
||||
|
||||
local PartA = pac.GetPartFromUniqueID(pac.Hash(pac.LocalPlayer), uid1)
|
||||
if not PartA:IsValid() then PartA = pac.FindPartByName(pac.Hash(pac.LocalPlayer), uid1, self) end
|
||||
|
||||
if PartA.ClassName == "event" then
|
||||
if PartA.event_triggered then return num1 or 0
|
||||
else return num2 or 0 end
|
||||
else return -1 end
|
||||
return 0
|
||||
end
|
||||
|
||||
PART.Inputs.number_operator_alternative = function(self, comp1, op, comp2, num1, num2)
|
||||
if not (comp1 and op and comp2 and num1 and num2) then return -1 end
|
||||
if not (isnumber(comp1) and isnumber(comp2) and isnumber(num1) and isnumber(num2)) then return -1 end
|
||||
local b = true
|
||||
if op == "=" or op == "==" or op == "equal" then
|
||||
b = comp1 == comp2
|
||||
elseif op == ">" or op == "above" or op == "greater" or op == "greater than" then
|
||||
b = comp1 > comp2
|
||||
elseif op == ">=" or op == "above or equal" or op == "greater or equal" or op == "greater than or equal" then
|
||||
b = comp1 >= comp2
|
||||
elseif op == "<" or op == "below" or op == "less" or op == "less than" then
|
||||
b = comp1 < comp2
|
||||
elseif op == "<=" or op == "below or equal" or op == "less or equal" or op == "less than or equal" then
|
||||
b = comp1 <= comp2
|
||||
elseif op == "~=" or op == "~=" or op == "not equal" then
|
||||
b = comp1 ~= comp2
|
||||
end
|
||||
if b then return num1 or 0 else return num2 or 0 end
|
||||
end
|
||||
|
||||
do
|
||||
local function get_pos(self)
|
||||
local part = self:GetPhysicalTarget()
|
||||
@ -556,10 +631,9 @@ PART.Inputs.pose_parameter_true = function(self, name)
|
||||
if not name then return 0 end
|
||||
local owner = get_owner(self)
|
||||
if owner:IsValid() then
|
||||
min,max = owner:GetPoseParameterRange(owner:LookupPoseParameter(name))
|
||||
actual_value = min + (max - min)*(owner:GetPoseParameter(name))
|
||||
return actual_value
|
||||
else end
|
||||
local min, max = owner:GetPoseParameterRange(owner:LookupPoseParameter(name))
|
||||
return min + (max - min)*(owner:GetPoseParameter(name))
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
@ -912,6 +986,8 @@ end
|
||||
|
||||
function PART:OnHide()
|
||||
self.time = nil
|
||||
self.rand = nil
|
||||
self.rand_id = nil
|
||||
self.vec_additive = Vector()
|
||||
|
||||
if self.ResetVelocitiesOnHide then
|
||||
@ -937,6 +1013,8 @@ end
|
||||
|
||||
function PART:OnShow()
|
||||
self.time = nil
|
||||
self.rand = nil
|
||||
self.rand_id = nil
|
||||
self.vec_additive = Vector()
|
||||
end
|
||||
|
||||
|
@ -19,7 +19,7 @@ BUILDER:StartStorableVars()
|
||||
BUILDER:GetSet("MaxPitch", 0, {editor_sensitivity = 0.125})
|
||||
|
||||
BUILDER:SetPropertyGroup("playback")
|
||||
BUILDER:GetSet("PlayCount", 1,
|
||||
BUILDER:GetSet("PlayCount", 1,
|
||||
{editor_onchange =
|
||||
function(self, num)
|
||||
self.sens = 0.25
|
||||
@ -239,10 +239,8 @@ function PART:SetPath(path)
|
||||
path = info.sound
|
||||
end
|
||||
|
||||
if
|
||||
not path:StartWith("http")
|
||||
or not pac.resource.Download(path, function(path) load("data/" .. path) end)
|
||||
|
||||
if not string.StartsWith(path, "http") or not pac.resource.Download(path, function(path) load("data/" .. path) end)
|
||||
|
||||
then load("sound/" .. path)
|
||||
end
|
||||
end
|
||||
@ -259,14 +257,14 @@ function PART:PlaySound(_, additiveVolumeFraction)
|
||||
if not stream:IsValid() then return end
|
||||
|
||||
if self.Sequential then
|
||||
|
||||
|
||||
self.seq_index = self.seq_index or 1
|
||||
|
||||
|
||||
local basepath = self.paths[self.seq_index] or self.paths[1]
|
||||
local snd = "sound/".. basepath
|
||||
|
||||
|
||||
local cached_path = "data/pac3_cache/downloads/" .. pac.Hash(basepath) .. ".dat"
|
||||
|
||||
|
||||
if string.find(basepath, "^http") then
|
||||
snd = cached_path
|
||||
end
|
||||
@ -282,7 +280,7 @@ function PART:PlaySound(_, additiveVolumeFraction)
|
||||
self.seq_index = self.seq_index + #self.paths
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
stream:SetAdditiveVolumeModifier(additiveVolumeFraction)
|
||||
|
||||
if self.last_stream:IsValid() and not self.Overlapping and not self.PauseOnHide then
|
||||
|
@ -13,26 +13,99 @@ local Color = Color
|
||||
|
||||
local BUILDER, PART = pac.PartTemplate("base_drawable")
|
||||
|
||||
local default_fonts = {
|
||||
"BudgetLabel",
|
||||
"CenterPrintText",
|
||||
"ChatFont",
|
||||
"ClientTitleFont",
|
||||
"CloseCaption_Bold",
|
||||
"CloseCaption_BoldItalic",
|
||||
"CloseCaption_Italic",
|
||||
"CloseCaption_Normal",
|
||||
"CreditsLogo",
|
||||
"CreditsOutroLogos",
|
||||
"CreditsOutroText",
|
||||
"CreditsText",
|
||||
"Crosshairs",
|
||||
"DebugFixed",
|
||||
"DebugFixedSmall",
|
||||
"DebugOverlay",
|
||||
"Default",
|
||||
"DefaultFixed",
|
||||
"DefaultFixedDropShadow",
|
||||
"DefaultSmall",
|
||||
"DefaultUnderline",
|
||||
"DefaultVerySmall",
|
||||
"HDRDemoText",
|
||||
"HL2MPTypeDeath",
|
||||
"HudDefault",
|
||||
"HudHintTextLarge",
|
||||
"HudHintTextSmall",
|
||||
"HudNumbers",
|
||||
"HudNumbersGlow",
|
||||
"HudNumbersSmall",
|
||||
"HudSelectionNumbers",
|
||||
"HudSelectionText",
|
||||
"Marlett",
|
||||
"QuickInfo",
|
||||
"TargetID",
|
||||
"TargetIDSmall",
|
||||
"Trebuchet18",
|
||||
"Trebuchet24",
|
||||
"WeaponIcons",
|
||||
"WeaponIconsSelected",
|
||||
"WeaponIconsSmall",
|
||||
"DermaDefault",
|
||||
"DermaDefaultBold",
|
||||
"DermaLarge",
|
||||
"GModNotify",
|
||||
"ScoreboardDefault",
|
||||
"ScoreboardDefaultTitle",
|
||||
"GModToolName",
|
||||
"GModToolSubtitle",
|
||||
"GModToolHelp",
|
||||
"GModToolScreen",
|
||||
"ContentHeader",
|
||||
"GModWorldtip",
|
||||
"ContentHeader",
|
||||
"DefaultBold",
|
||||
"TabLarge",
|
||||
"Trebuchet22",
|
||||
"TraitorState",
|
||||
"TimeLeft",
|
||||
"HealthAmmo",
|
||||
"cool_small",
|
||||
"cool_large",
|
||||
"treb_small"
|
||||
}
|
||||
|
||||
|
||||
PART.ClassName = "text"
|
||||
PART.Group = 'effects'
|
||||
PART.Icon = 'icon16/text_align_center.png'
|
||||
PART.Group = "effects"
|
||||
PART.Icon = "icon16/text_align_center.png"
|
||||
|
||||
BUILDER:StartStorableVars()
|
||||
:SetPropertyGroup("generic")
|
||||
:PropertyOrder("Name")
|
||||
:PropertyOrder("Hide")
|
||||
:GetSet("Text", "")
|
||||
:GetSet("Font", "default")
|
||||
:GetSet("Font", "default", {enums = default_fonts})
|
||||
:GetSet("Size", 1, {editor_sensitivity = 0.25})
|
||||
|
||||
:GetSet("DrawMode", "DrawTextOutlined", {enums = {
|
||||
["draw.SimpleTextOutlined 3D2D"] = "DrawTextOutlined",
|
||||
["draw.SimpleTextOutlined 2D"] = "DrawTextOutlined2D",
|
||||
["surface.DrawText"] = "SurfaceText"
|
||||
}})
|
||||
|
||||
:SetPropertyGroup("text layout")
|
||||
:GetSet("HorizontalTextAlign", TEXT_ALIGN_CENTER, {enums = {["Left"] = "0", ["Center"] = "1", ["Right"] = "2"}})
|
||||
:GetSet("VerticalTextAlign", TEXT_ALIGN_CENTER, {enums = {["Center"] = "1", ["Top"] = "3", ["Bottom"] = "4"}})
|
||||
:GetSet("ConcatenateTextAndOverrideValue",false,{editor_friendly = "CombinedText"})
|
||||
:GetSet("TextPosition","Prefix", {enums = {["Prefix"] = "Prefix", ["Postfix"] = "Postfix"}},{editor_friendly = "ConcatenateMode"})
|
||||
|
||||
:SetPropertyGroup("data source")
|
||||
:GetSet("TextOverride", "Text", {enums = {
|
||||
["Proxy value (DynamicTextValue)"] = "Proxy",
|
||||
["Text"] = "Text",
|
||||
["Health"] = "Health",
|
||||
["Maximum Health"] = "MaxHealth",
|
||||
@ -41,13 +114,38 @@ BUILDER:StartStorableVars()
|
||||
["Timerx"] = "Timerx",
|
||||
["CurTime"] = "CurTime",
|
||||
["RealTime"] = "RealTime",
|
||||
["Velocity"] = "Velocity",
|
||||
["Velocity Vector"] = "VelocityVector",
|
||||
["Position Vector"] = "PositionVector",
|
||||
["Owner Position Vector"] = "OwnerPositionVector",
|
||||
["Clip current Ammo"] = "Ammo",
|
||||
["Clip Size"] = "ClipSize",
|
||||
["Ammo Reserve"] = "AmmoReserve",
|
||||
["Proxy value (Using DynamicTextValue)"] = "Proxy"}})
|
||||
["Sequence Name"] = "SequenceName",
|
||||
["Weapon Name"] = "Weapon",
|
||||
["Vehicle Class"] = "VehicleClass",
|
||||
["Model Name"] = "ModelName",
|
||||
["Model Path"] = "ModelPath",
|
||||
["Player Name"] = "PlayerName",
|
||||
["Player SteamID"] = "SteamID",
|
||||
["Map"] = "Map",
|
||||
["Ground Surface"] = "GroundSurface",
|
||||
["Ground Entity Class"] = "GroundEntityClass",
|
||||
["Players"] = "Players",
|
||||
["Max Players"] = "MaxPlayers",
|
||||
["Difficulty"] = "GameDifficulty"
|
||||
}})
|
||||
:GetSet("DynamicTextValue", 0)
|
||||
:GetSet("RoundingPosition", 2, {editor_onchange = function(self, num)
|
||||
return math.Round(num,0)
|
||||
end})
|
||||
|
||||
:SetPropertyGroup("orientation")
|
||||
:PropertyOrder("AimPartName")
|
||||
:PropertyOrder("Bone")
|
||||
:PropertyOrder("Position")
|
||||
:SetPropertyGroup("appearance")
|
||||
BUILDER:GetSet("ForceAdditive",false, {description = "additive rendering for the surface.DrawText mode"})
|
||||
BUILDER:GetSet("Outline", 0)
|
||||
BUILDER:GetSet("Color", Vector(255, 255, 255), {editor_panel = "color"})
|
||||
BUILDER:GetSet("Alpha", 1, {editor_sensitivity = 0.25, editor_clamp = {0, 1}})
|
||||
@ -58,6 +156,22 @@ BUILDER:StartStorableVars()
|
||||
return math.Clamp(num, 0, 1)
|
||||
end})
|
||||
BUILDER:GetSet("Translucent", true)
|
||||
:SetPropertyGroup("CustomFont")
|
||||
:GetSet("CreateCustomFont",false, {description = "Tries to create a custom font.\nHeavily throttled as creating fonts is an expensive process.\nSupport is limited because of the fonts' supported features and the limits of Lua strings.\nFont names include those stored in your operating system. for example: Comic Sans MS, Ink Free"})
|
||||
:GetSet("CustomFont", "DermaDefault")
|
||||
:GetSet("FontSize", 13)
|
||||
:GetSet("FontWeight",500)
|
||||
:GetSet("FontBlurSize",0)
|
||||
:GetSet("FontScanLines",0)
|
||||
:GetSet("FontAntialias",true)
|
||||
:GetSet("FontUnderline",false)
|
||||
:GetSet("FontItalic",false)
|
||||
:GetSet("FontStrikeout",false)
|
||||
:GetSet("FontSymbol",false)
|
||||
:GetSet("FontRotary",false)
|
||||
:GetSet("Shadow",false)
|
||||
:GetSet("FontAdditive",false)
|
||||
:GetSet("FontOutline",false)
|
||||
BUILDER:EndStorableVars()
|
||||
|
||||
function PART:GetNiceName()
|
||||
@ -101,60 +215,308 @@ function PART:SetOutlineAlpha(n)
|
||||
end
|
||||
|
||||
function PART:SetFont(str)
|
||||
if not pcall(surface_SetFont, str) then
|
||||
pac.Message(Color(255,150,0),str.." Font not found! Reverting to DermaDefault!")
|
||||
str = "DermaDefault"
|
||||
self.UsedFont = str
|
||||
if not self.CreateCustomFont then
|
||||
if not pcall(surface_SetFont, str) then
|
||||
if #self.Font > 20 then
|
||||
|
||||
self.lastwarn = self.lastwarn or CurTime()
|
||||
if self.lastwarn > CurTime() + 1 then
|
||||
pac.Message(Color(255,150,0),str.." Font not found! Could be custom font, trying again in 4 seconds!")
|
||||
self.lastwarn = CurTime()
|
||||
end
|
||||
timer.Simple(4, function()
|
||||
if not pcall(surface_SetFont, str) then
|
||||
pac.Message(Color(255,150,0),str.." Font still not found! Reverting to DermaDefault!")
|
||||
str = "DermaDefault"
|
||||
self.UsedFont = str
|
||||
end
|
||||
end)
|
||||
else
|
||||
timer.Simple(5, function()
|
||||
if not pcall(surface_SetFont, str) then
|
||||
pac.Message(Color(255,150,0),str.." Font still not found! Reverting to DermaDefault!")
|
||||
str = "DermaDefault"
|
||||
self.UsedFont = str
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.Font = str
|
||||
self.Font = self.UsedFont
|
||||
end
|
||||
|
||||
local lastfontcreationtime = 0
|
||||
function PART:OnDraw()
|
||||
local pos, ang = self:GetDrawPosition()
|
||||
self:CheckFont()
|
||||
if not pcall(surface_SetFont, self.UsedFont) then return end
|
||||
|
||||
local DisplayText = self.Text or ""
|
||||
if self.TextOverride == "Text" then goto DRAW end
|
||||
|
||||
if self.TextOverride == "Health"then DisplayText = self:GetPlayerOwner():Health()
|
||||
DisplayText = ""
|
||||
if self.TextOverride == "Health" then DisplayText = self:GetRootPart():GetOwner():Health()
|
||||
elseif self.TextOverride == "MaxHealth" then
|
||||
DisplayText = self:GetPlayerOwner():GetMaxHealth()
|
||||
DisplayText = self:GetRootPart():GetOwner():GetMaxHealth()
|
||||
elseif self.TextOverride == "Ammo" then
|
||||
DisplayText = self:GetPlayerOwner():GetActiveWeapon():Clip1()
|
||||
DisplayText = IsValid(self:GetPlayerOwner():GetActiveWeapon()) and self:GetPlayerOwner():GetActiveWeapon():Clip1() or ""
|
||||
elseif self.TextOverride == "ClipSize" then
|
||||
DisplayText = self:GetPlayerOwner():GetActiveWeapon():GetMaxClip1()
|
||||
DisplayText = IsValid(self:GetPlayerOwner():GetActiveWeapon()) and self:GetPlayerOwner():GetActiveWeapon():GetMaxClip1() or ""
|
||||
elseif self.TextOverride == "AmmoReserve" then
|
||||
DisplayText = self:GetPlayerOwner():GetAmmoCount(self:GetPlayerOwner():GetActiveWeapon():GetPrimaryAmmoType())
|
||||
DisplayText = IsValid(self:GetPlayerOwner():GetActiveWeapon()) and self:GetPlayerOwner():GetAmmoCount(self:GetPlayerOwner():GetActiveWeapon():GetPrimaryAmmoType()) or ""
|
||||
elseif self.TextOverride == "Armor" then
|
||||
DisplayText = self:GetPlayerOwner():Armor()
|
||||
elseif self.TextOverride == "MaxArmor" then
|
||||
DisplayText = self:GetPlayerOwner():GetMaxArmor()
|
||||
elseif self.TextOverride == "Timerx" then
|
||||
DisplayText = ""..math.Round(CurTime() - self.time,2)
|
||||
DisplayText = ""..math.Round(CurTime() - self.time,self.RoundingPosition)
|
||||
elseif self.TextOverride == "CurTime" then
|
||||
DisplayText = ""..math.Round(CurTime(),2)
|
||||
DisplayText = ""..math.Round(CurTime(),self.RoundingPosition)
|
||||
elseif self.TextOverride == "RealTime" then
|
||||
DisplayText = ""..math.Round(RealTime(),2)
|
||||
DisplayText = ""..math.Round(RealTime(),self.RoundingPosition)
|
||||
elseif self.TextOverride == "Velocity" then
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
DisplayText = math.Round(ent:GetVelocity():Length(),2)
|
||||
elseif self.TextOverride == "VelocityVector" then
|
||||
local ent = self:GetOwner() or self:GetRootPart():GetOwner()
|
||||
local vec = ent:GetVelocity()
|
||||
DisplayText = "("..math.Round(vec.x,self.RoundingPosition)..","..math.Round(vec.y,self.RoundingPosition)..","..math.Round(vec.z,self.RoundingPosition)..")"
|
||||
elseif self.TextOverride == "PositionVector" then
|
||||
local vec = self:GetDrawPosition()
|
||||
DisplayText = "("..math.Round(vec.x,self.RoundingPosition)..","..math.Round(vec.y,self.RoundingPosition)..","..math.Round(vec.z,self.RoundingPosition)..")"
|
||||
elseif self.TextOverride == "OwnerPositionVector" then
|
||||
local ent = self:GetRootPart():GetOwner()
|
||||
local vec = ent:GetPos()
|
||||
DisplayText = "("..math.Round(vec.x,self.RoundingPosition)..","..math.Round(vec.y,self.RoundingPosition)..","..math.Round(vec.z,self.RoundingPosition)..")"
|
||||
elseif self.TextOverride == "SequenceName" then
|
||||
DisplayText = self:GetRootPart():GetOwner():GetSequenceName(self:GetPlayerOwner():GetSequence())
|
||||
elseif self.TextOverride == "PlayerName" then
|
||||
DisplayText = self:GetPlayerOwner():GetName()
|
||||
elseif self.TextOverride == "SteamID" then
|
||||
DisplayText = self:GetPlayerOwner():SteamID()
|
||||
elseif self.TextOverride == "ModelName" then
|
||||
local path = self:GetRootPart():GetOwner():GetModel() or "null"
|
||||
path = string.Split(path, "/")[#string.Split(path, "/")]
|
||||
path = string.gsub(path,".mdl","")
|
||||
DisplayText = path
|
||||
elseif self.TextOverride == "ModelPath" then
|
||||
DisplayText = self:GetPlayerOwner():GetModel()
|
||||
elseif self.TextOverride == "Map" then
|
||||
DisplayText = game.GetMap()
|
||||
elseif self.TextOverride == "GroundSurface" then
|
||||
local trace = util.TraceLine( {
|
||||
start = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, 30),
|
||||
endpos = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, -60 ),
|
||||
filter = function(ent)
|
||||
if ent == self:GetRootPart():GetOwner() or ent == self:GetPlayerOwner() then return false else return true end
|
||||
end
|
||||
})
|
||||
if trace.Hit then
|
||||
if trace.MatType == MAT_ANTLION then DisplayText = "Antlion"
|
||||
elseif trace.MatType == MAT_BLOODYFLESH then DisplayText = "Bloody Flesh"
|
||||
elseif trace.MatType == MAT_CONCRETE then DisplayText = "Concrete"
|
||||
elseif trace.MatType == MAT_DIRT then DisplayText = "Dirt"
|
||||
elseif trace.MatType == MAT_EGGSHELL then DisplayText = "Egg Shell"
|
||||
elseif trace.MatType == MAT_FLESH then DisplayText = "Flesh"
|
||||
elseif trace.MatType == MAT_GRATE then DisplayText = "Grate"
|
||||
elseif trace.MatType == MAT_ALIENFLESH then DisplayText = "Alien Flesh"
|
||||
elseif trace.MatType == MAT_CLIP then DisplayText = "Clip"
|
||||
elseif trace.MatType == MAT_SNOW then DisplayText = "Snow"
|
||||
elseif trace.MatType == MAT_PLASTIC then DisplayText = "Plastic"
|
||||
elseif trace.MatType == MAT_METAL then DisplayText = "Metal"
|
||||
elseif trace.MatType == MAT_SAND then DisplayText = "Sand"
|
||||
elseif trace.MatType == MAT_FOLIAGE then DisplayText = "Foliage"
|
||||
elseif trace.MatType == MAT_COMPUTER then DisplayText = "Computer"
|
||||
elseif trace.MatType == MAT_SLOSH then DisplayText = "Slime"
|
||||
elseif trace.MatType == MAT_TILE then DisplayText = "Tile"
|
||||
elseif trace.MatType == MAT_GRASS then DisplayText = "Grass"
|
||||
elseif trace.MatType == MAT_VENT then DisplayText = "Grass"
|
||||
elseif trace.MatType == MAT_WOOD then DisplayText = "Wood"
|
||||
elseif trace.MatType == MAT_DEFAULT then DisplayText = "Default"
|
||||
elseif trace.MatType == MAT_GLASS then DisplayText = "Glass"
|
||||
elseif trace.MatType == MAT_WARPSHIELD then DisplayText = "Warp Shield"
|
||||
else DisplayText = "Other Surface" end
|
||||
else DisplayText = "Air" end
|
||||
elseif self.TextOverride == "GroundEntityClass" then
|
||||
local trace = util.TraceLine( {
|
||||
start = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, 30),
|
||||
endpos = self:GetRootPart():GetOwner():GetPos() + Vector( 0, 0, -60 ),
|
||||
filter = function(ent)
|
||||
if ent == self:GetRootPart():GetOwner() or ent == self:GetPlayerOwner() then return false else return true end
|
||||
end
|
||||
})
|
||||
if trace.Hit then
|
||||
DisplayText = trace.Entity:GetClass()
|
||||
end
|
||||
elseif self.TextOverride == "GameDifficulty" then
|
||||
local diff = game.GetSkillLevel()
|
||||
if diff == 1 then DisplayText = "Easy"
|
||||
elseif diff == 2 then DisplayText = "Normal"
|
||||
elseif diff == 3 then DisplayText = "Hard" end
|
||||
elseif self.TextOverride == "Players" then
|
||||
DisplayText = #player.GetAll()
|
||||
elseif self.TextOverride == "MaxPlayers" then
|
||||
DisplayText = game.MaxPlayers()
|
||||
elseif self.TextOverride == "Weapon" then
|
||||
if IsValid(self:GetPlayerOwner():GetActiveWeapon()) then
|
||||
DisplayText = self:GetPlayerOwner():GetActiveWeapon():GetClass()
|
||||
else DisplayText = "unarmed" end
|
||||
elseif self.TextOverride == "VehicleClass" then
|
||||
if IsValid(self:GetPlayerOwner():GetVehicle()) then
|
||||
DisplayText = self:GetPlayerOwner():GetVehicle():GetClass()
|
||||
else DisplayText = "not driving" end
|
||||
elseif self.TextOverride == "Proxy" then
|
||||
--print(type(self.DynamicTextValue))
|
||||
DisplayText = ""..math.Round(self.DynamicTextValue,2)
|
||||
DisplayText = ""..math.Round(self.DynamicTextValue,self.RoundingPosition)
|
||||
end
|
||||
|
||||
if self.ConcatenateTextAndOverrideValue then DisplayText = ""..self.Text..DisplayText end
|
||||
if self.ConcatenateTextAndOverrideValue then
|
||||
if self.TextPosition == "Prefix" then
|
||||
DisplayText = ""..self.Text..DisplayText
|
||||
elseif self.TextPosition == "Postfix" then
|
||||
DisplayText = ""..DisplayText..self.Text
|
||||
end
|
||||
end
|
||||
|
||||
::DRAW::
|
||||
|
||||
if DisplayText ~= "" then
|
||||
cam_Start3D(EyePos(), EyeAngles())
|
||||
cam_Start3D2D(pos, ang, self.Size)
|
||||
local oldState = DisableClipping(true)
|
||||
if self.DrawMode == "DrawTextOutlined" then
|
||||
cam_Start3D(EyePos(), EyeAngles())
|
||||
cam_Start3D2D(pos, ang, self.Size)
|
||||
local oldState = DisableClipping(true)
|
||||
|
||||
draw_SimpleTextOutlined(DisplayText, self.Font, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(1) -- MATERIAL_CULLMODE_CW
|
||||
draw_SimpleTextOutlined(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(1) -- MATERIAL_CULLMODE_CW
|
||||
|
||||
draw_SimpleTextOutlined(DisplayText, self.Font, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(0) -- MATERIAL_CULLMODE_CCW
|
||||
draw_SimpleTextOutlined(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(0) -- MATERIAL_CULLMODE_CCW
|
||||
|
||||
DisableClipping(oldState)
|
||||
cam_End3D2D()
|
||||
cam_End3D()
|
||||
DisableClipping(oldState)
|
||||
cam_End3D2D()
|
||||
cam_End3D()
|
||||
cam_Start3D(EyePos(), EyeAngles())
|
||||
cam_Start3D2D(pos, ang, self.Size)
|
||||
local oldState = DisableClipping(true)
|
||||
|
||||
draw.SimpleText(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(1) -- MATERIAL_CULLMODE_CW
|
||||
|
||||
draw.SimpleText(DisplayText, self.UsedFont, 0,0, self.ColorC, self.HorizontalTextAlign,self.VerticalTextAlign, self.Outline, self.OutlineColorC)
|
||||
render_CullMode(0) -- MATERIAL_CULLMODE_CCW
|
||||
|
||||
DisableClipping(oldState)
|
||||
cam_End3D2D()
|
||||
cam_End3D()
|
||||
elseif self.DrawMode == "SurfaceText" or self.DrawMode == "DrawTextOutlined2D" then
|
||||
hook.Add("HUDPaint", "pac.DrawText"..self.UniqueID, function()
|
||||
if not pcall(surface_SetFont, self.UsedFont) then return end
|
||||
self:SetFont(self.UsedFont)
|
||||
|
||||
surface.SetTextColor(self.Color.r, self.Color.g, self.Color.b, 255*self.Alpha)
|
||||
|
||||
surface.SetFont(self.UsedFont)
|
||||
local pos2d = self:GetDrawPosition():ToScreen()
|
||||
local w, h = surface.GetTextSize(DisplayText)
|
||||
|
||||
if self.HorizontalTextAlign == 0 then --left
|
||||
pos2d.x = pos2d.x
|
||||
elseif self.HorizontalTextAlign == 1 then --center
|
||||
pos2d.x = pos2d.x - w/2
|
||||
elseif self.HorizontalTextAlign == 2 then --right
|
||||
pos2d.x = pos2d.x - w
|
||||
end
|
||||
|
||||
if self.VerticalTextAlign == 1 then --center
|
||||
pos2d.y = pos2d.y - h/2
|
||||
elseif self.VerticalTextAlign == 3 then --top
|
||||
pos2d.y = pos2d.y
|
||||
elseif self.VerticalTextAlign == 4 then --bottom
|
||||
pos2d.y = pos2d.y - h
|
||||
end
|
||||
|
||||
surface.SetTextPos(pos2d.x, pos2d.y)
|
||||
local dist = (EyePos() - self:GetWorldPosition()):Length()
|
||||
local fadestartdist = 200
|
||||
local fadeenddist = 1000
|
||||
if fadestartdist == 0 then fadestartdist = 0.1 end
|
||||
if fadeenddist == 0 then fadeenddist = 0.1 end
|
||||
|
||||
if fadestartdist > fadeenddist then
|
||||
local temp = fadestartdist
|
||||
fadestartdist = fadeenddist
|
||||
fadeenddist = temp
|
||||
end
|
||||
|
||||
if dist < fadeenddist then
|
||||
if dist < fadestartdist then
|
||||
if self.DrawMode == "DrawTextOutlined2D" then
|
||||
draw.SimpleTextOutlined(DisplayText, self.UsedFont, pos2d.x, pos2d.y, Color(self.Color.r,self.Color.g,self.Color.b,255*self.Alpha), TEXT_ALIGN_TOP, TEXT_ALIGN_LEFT, self.Outline, Color(self.OutlineColor.r,self.OutlineColor.g,self.OutlineColor.b, 255*self.OutlineAlpha))
|
||||
elseif self.DrawMode == "SurfaceText" then
|
||||
surface.DrawText(DisplayText, self.ForceAdditive)
|
||||
end
|
||||
|
||||
else
|
||||
local fade = math.pow(math.Clamp(1 - (dist-fadestartdist)/fadeenddist,0,1),3)
|
||||
|
||||
if self.DrawMode == "DrawTextOutlined2D" then
|
||||
draw.SimpleTextOutlined(DisplayText, self.UsedFont, pos2d.x, pos2d.y, Color(self.Color.r,self.Color.g,self.Color.b,255*self.Alpha*fade), TEXT_ALIGN_TOP, TEXT_ALIGN_LEFT, self.Outline, Color(self.OutlineColor.r,self.OutlineColor.g,self.OutlineColor.b, 255*self.OutlineAlpha*fade))
|
||||
elseif self.DrawMode == "SurfaceText" then
|
||||
surface.SetTextColor(self.Color.r * fade, self.Color.g * fade, self.Color.b * fade)
|
||||
surface.DrawText(DisplayText, true)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
if self.DrawMode == "DrawTextOutlined" then
|
||||
hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID)
|
||||
end
|
||||
else hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID) end
|
||||
end
|
||||
|
||||
function PART:Initialize()
|
||||
self:TryCreateFont()
|
||||
end
|
||||
|
||||
function PART:CheckFont()
|
||||
if self.CreateCustomFont then
|
||||
lastfontcreationtime = lastfontcreationtime or 0
|
||||
if lastfontcreationtime + 3 <= CurTime() then
|
||||
self:TryCreateFont()
|
||||
end
|
||||
else
|
||||
self:SetFont(self.Font)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function PART:TryCreateFont()
|
||||
if "Font_"..self.CustomFont.."_"..math.Round(self.FontSize,3).."_"..self.UniqueID == self.lastcustomfont then
|
||||
self.UsedFont = "Font_"..self.CustomFont.."_"..math.Round(self.FontSize,3).."_"..self.UniqueID
|
||||
return
|
||||
end
|
||||
if self.CreateCustomFont then
|
||||
local newfont = "Font_"..self.CustomFont.."_"..math.Round(self.FontSize,3).."_"..self.UniqueID
|
||||
surface.CreateFont( newfont, {
|
||||
font = self.CustomFont, -- Use the font-name which is shown to you by your operating system Font Viewer, not the file name
|
||||
extended = self.Extended,
|
||||
size = self.FontSize,
|
||||
weight = self.Weight,
|
||||
blursize = self.BlurSize,
|
||||
scanlines = self.ScanLines,
|
||||
antialias = self.Antialias,
|
||||
underline = self.Underline,
|
||||
italic = self.Italic,
|
||||
strikeout = self.Strikeout,
|
||||
symbol = self.Symbol,
|
||||
rotary = self.Rotary,
|
||||
shadow = self.Shadow,
|
||||
additive = self.Additive,
|
||||
outline = self.Outline,
|
||||
} )
|
||||
self:SetFont(newfont)
|
||||
self.lastcustomfont = newfont
|
||||
lastfontcreationtime = CurTime()
|
||||
end
|
||||
end
|
||||
|
||||
@ -162,6 +524,12 @@ function PART:OnShow()
|
||||
self.time = CurTime()
|
||||
end
|
||||
|
||||
function PART:OnHide()
|
||||
hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID)
|
||||
end
|
||||
function PART:OnRemove()
|
||||
hook.Remove("HUDPaint", "pac.DrawText"..self.UniqueID)
|
||||
end
|
||||
function PART:SetText(str)
|
||||
self.Text = str
|
||||
end
|
||||
|
@ -8,7 +8,7 @@ util.AddNetworkString("pac3_test_suite_backdoor")
|
||||
net.Receive("pac3_test_suite_backdoor", function(len, ply)
|
||||
-- needs to be enabled through lua first, eg lua_run pac.test_suite_backdoor_enabled = true
|
||||
if not pac.test_suite_backdoor_enabled then return end
|
||||
|
||||
|
||||
-- need to be at least super admin
|
||||
if not ply:IsSuperAdmin() then return end
|
||||
|
||||
|
@ -4,11 +4,11 @@ if game.SinglePlayer() then
|
||||
util.AddNetworkString('pac_footstep')
|
||||
util.AddNetworkString('pac_footstep_request_state_update')
|
||||
util.AddNetworkString('pac_signal_mute_footstep')
|
||||
|
||||
|
||||
hook.Add("PlayerFootstep", "footstep_fix", function(ply, pos, _, snd, vol)
|
||||
net.Start("pac_footstep_request_state_update")
|
||||
net.Send(ply)
|
||||
|
||||
|
||||
net.Start("pac_footstep")
|
||||
net.WriteEntity(ply)
|
||||
net.WriteVector(pos)
|
||||
@ -16,7 +16,7 @@ if game.SinglePlayer() then
|
||||
net.WriteFloat(vol)
|
||||
net.Broadcast()
|
||||
end)
|
||||
|
||||
|
||||
net.Receive("pac_signal_mute_footstep", function(len,ply)
|
||||
local b = net.ReadBool()
|
||||
ply.pac_mute_footsteps = b
|
||||
@ -26,8 +26,8 @@ if game.SinglePlayer() then
|
||||
end)
|
||||
else hook.Remove("PlayerFootstep", "pac_footstep_silence") end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
|
@ -2,12 +2,12 @@
|
||||
local CL_LIMIT, CL_LIMIT_OVERRIDE, CL_NO_CLENGTH
|
||||
|
||||
if CLIENT then
|
||||
CL_LIMIT = CreateConVar("pac_webcontent_limit", "-1", {FCVAR_ARCHIVE}, "webcontent limit in mb, -1 = unlimited")
|
||||
CL_LIMIT = CreateConVar("pac_webcontent_limit", "-1", {FCVAR_ARCHIVE}, "webcontent limit in kb, -1 = unlimited")
|
||||
CL_NO_CLENGTH = CreateConVar("pac_webcontent_allow_no_content_length", "0", {FCVAR_ARCHIVE}, "allow downloads with no content length")
|
||||
CL_LIMIT_OVERRIDE = CreateConVar("pac_webcontent_limit_force", "0", {FCVAR_ARCHIVE}, "Override serverside setting")
|
||||
end
|
||||
|
||||
local SV_LIMIT = CreateConVar("sv_pac_webcontent_limit", "-1", CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "webcontent limit in mb, -1 = unlimited")
|
||||
local SV_LIMIT = CreateConVar("sv_pac_webcontent_limit", "-1", CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "webcontent limit in kb, -1 = unlimited")
|
||||
local SV_NO_CLENGTH = CreateConVar("sv_pac_webcontent_allow_no_content_length", "-1", CLIENT and {FCVAR_REPLICATED} or {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "allow downloads with no content length")
|
||||
|
||||
function pac.FixGMODUrl(url)
|
||||
|
@ -421,7 +421,7 @@ function pac.DownloadMDL(url, callback, onfail, ply)
|
||||
if not found then
|
||||
for i, v in pairs(files) do
|
||||
if string.find(v.file_path, material_name, 1, true) or string.find(material_name, v.file_name, 1, true) then
|
||||
v.file_name = material_name
|
||||
table.insert(files, {file_name = material_name, buffer = v.buffer, crc = v.crc, file_path = v.file_path})
|
||||
found = v.file_path
|
||||
break
|
||||
end
|
||||
@ -597,8 +597,13 @@ function pac.DownloadMDL(url, callback, onfail, ply)
|
||||
|
||||
for i, data in ipairs(files) do
|
||||
if data.file_name:EndsWith(".vmt") then
|
||||
local proxies = data.buffer:match('("?%f[%w_]P?p?roxies%f[^%w_]"?%s*%b{})')
|
||||
data.buffer = data.buffer:lower():gsub("\\", "/")
|
||||
|
||||
if proxies then
|
||||
data.buffer = data.buffer:gsub('("?%f[%w_]proxies%f[^%w_]"?%s*%b{})', proxies)
|
||||
end
|
||||
|
||||
if DEBUG_MDL or VERBOSE then
|
||||
print(data.file_name .. ":")
|
||||
end
|
||||
|
@ -632,7 +632,7 @@ do
|
||||
surface.DrawTexturedRect(1+x,mat:Height() - 5,mat:Width(), mat:Height())
|
||||
|
||||
end
|
||||
|
||||
|
||||
if esmat then
|
||||
local ps = v:GetSize()
|
||||
local x = v:GetPos() + (ps * 0.5)
|
||||
@ -826,7 +826,7 @@ do
|
||||
function KEYFRAME:GetRestart()
|
||||
return self.restart
|
||||
end
|
||||
|
||||
|
||||
function KEYFRAME:GetData()
|
||||
return self.DataTable
|
||||
end
|
||||
@ -1048,10 +1048,12 @@ do
|
||||
timeline.frame.keyframe_scroll:InvalidateLayout()
|
||||
|
||||
self:Remove()
|
||||
|
||||
timeline.SelectKeyframe(timeline.frame.keyframe_scroll:GetCanvas():GetChildren()[#timeline.frame.keyframe_scroll:GetCanvas():GetChildren()])
|
||||
-- * even if it was removed from the table it still exists for some reason
|
||||
local count = #timeline.frame.keyframe_scroll:GetCanvas():GetChildren()
|
||||
local offset = frameNum == count and count - 1 or count
|
||||
timeline.SelectKeyframe(timeline.frame.keyframe_scroll:GetCanvas():GetChildren()[offset])
|
||||
end):SetImage("icon16/application_delete.png")
|
||||
|
||||
|
||||
menu:AddOption(L"set easing style", function()
|
||||
if timeline.data.Interpolation != "linear" then
|
||||
local frame = vgui.Create("DFrame")
|
||||
@ -1059,7 +1061,7 @@ do
|
||||
frame:Center()
|
||||
frame:SetTitle("Easing styles work only with the linear interpolation type!")
|
||||
frame:ShowCloseButton(false)
|
||||
|
||||
|
||||
local button = vgui.Create("DButton", frame)
|
||||
button:SetText("Okay")
|
||||
button:Dock(FILL)
|
||||
@ -1069,31 +1071,31 @@ do
|
||||
frame:MakePopup()
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local frameNum = self:GetAnimationIndex()
|
||||
|
||||
|
||||
local frame = vgui.Create( "DFrame" )
|
||||
frame:SetSize( 200, 100 )
|
||||
frame:Center()
|
||||
frame:SetTitle("Select easing type")
|
||||
frame:MakePopup()
|
||||
|
||||
|
||||
local combo = vgui.Create( "DComboBox", frame )
|
||||
|
||||
|
||||
combo:SetPos( 5, 30 )
|
||||
combo:Dock(FILL)
|
||||
combo:SetValue("None")
|
||||
|
||||
|
||||
for easeName, _ in pairs(eases) do
|
||||
combo:AddChoice(easeName)
|
||||
end
|
||||
|
||||
|
||||
combo.OnSelect = function(sf, index, val)
|
||||
self:SetEaseStyle(val)
|
||||
frame:Close()
|
||||
end
|
||||
end):SetImage("icon16/arrow_turn_right.png")
|
||||
|
||||
|
||||
if self:GetEaseStyle() then
|
||||
menu:AddOption(L"unset easing style", function()
|
||||
self:RemoveEaseStyle()
|
||||
@ -1110,17 +1112,17 @@ do
|
||||
self:GetParent():GetParent():InvalidateLayout() --rebuild the timeline
|
||||
self:GetData().FrameRate = 1/math.max(int, 0.001) --set animation frame rate
|
||||
end
|
||||
|
||||
|
||||
function KEYFRAME:GetEaseStyle()
|
||||
return self.estyle
|
||||
end
|
||||
|
||||
|
||||
function KEYFRAME:SetEaseStyle(style)
|
||||
if not style then return end
|
||||
self:GetData().EaseStyle = style
|
||||
self.estyle = style
|
||||
end
|
||||
|
||||
|
||||
function KEYFRAME:RemoveEaseStyle()
|
||||
self:GetData().EaseStyle = nil
|
||||
self.estyle = nil
|
||||
|
@ -2555,7 +2555,7 @@ pace.example_outfits["southpark"] = {
|
||||
["Duplicate"] = false,
|
||||
["ClassName"] = "group",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
@ -353,7 +353,7 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
if showInEditor:GetInt() == 1 then
|
||||
if showInEditor:GetInt() == 1 then
|
||||
local pos_3d = ply:NearestPoint(ply:EyePos() + up) + Vector(0,0,5)
|
||||
local alpha = math.Clamp(pos_3d:Distance(EyePos()) * -1 + 500, 0, 500)/500
|
||||
if alpha > 0 then
|
||||
|
@ -746,7 +746,7 @@ do -- event is_touching
|
||||
mins = mins,
|
||||
filter = ent
|
||||
} )
|
||||
|
||||
|
||||
if self.udata then
|
||||
render.DrawWireframeBox( startpos, Angle( 0, 0, 0 ), mins, maxs, tr.Hit and Color(255,0,0) or Color(255,255,255), true )
|
||||
end
|
||||
|
@ -119,7 +119,9 @@ function pace.OnPartSelected(part, is_selecting)
|
||||
|
||||
pace.SetViewPart(part)
|
||||
|
||||
pace.Editor:InvalidateLayout()
|
||||
if pace.Editor:IsValid() then
|
||||
pace.Editor:InvalidateLayout()
|
||||
end
|
||||
|
||||
pace.SafeRemoveSpecialPanel()
|
||||
|
||||
|
@ -240,7 +240,7 @@ end)
|
||||
function pace.Notify(allowed, reason, name)
|
||||
name = name or "???"
|
||||
|
||||
if allowed == true then
|
||||
if allowed == true then
|
||||
pac.Message(string.format('Your part %q has been applied', name))
|
||||
else
|
||||
chat.AddText(Color(255, 255, 0), "[PAC3] ", Color(255, 0, 0), string.format('The server rejected applying your part (%q) - %s', name, reason))
|
||||
@ -258,9 +258,18 @@ do
|
||||
elseif pace.IsActive() then
|
||||
pac.Message("not wearing autoload outfit, editor is open")
|
||||
else
|
||||
pac.Message("Wearing autoload...")
|
||||
pace.LoadParts("autoload")
|
||||
pace.WearParts()
|
||||
local autoload_file = "autoload"
|
||||
local autoload_result = hook.Run("PAC3Autoload", autoload_file)
|
||||
|
||||
if autoload_result ~= false then
|
||||
if isstring(autoload_result) then
|
||||
autoload_file = autoload_result
|
||||
end
|
||||
|
||||
pac.Message("Wearing " .. autoload_file .. "...")
|
||||
pace.LoadParts(autoload_file)
|
||||
pace.WearParts()
|
||||
end
|
||||
end
|
||||
|
||||
pac.RemoveHook("Think", "pac_request_outfits")
|
||||
|
@ -1,20 +1,38 @@
|
||||
local next = next
|
||||
local type = type
|
||||
local istable = istable
|
||||
local IsValid = IsValid
|
||||
local tostring = tostring
|
||||
local isfunction = isfunction
|
||||
local ProtectedCall = ProtectedCall
|
||||
|
||||
pace.StreamQueue = pace.StreamQueue or {}
|
||||
|
||||
local frame_number = 0
|
||||
local last_frame
|
||||
local ERROR_COLOR = Color(228, 37, 37)
|
||||
|
||||
local function catchError(err)
|
||||
pac.Message(ERROR_COLOR, 'Error: ', err)
|
||||
pac.Message(debug.traceback())
|
||||
end
|
||||
|
||||
timer.Create("pac_check_stream_queue", 0.1, 0, function()
|
||||
if not pace.BusyStreaming and #pace.StreamQueue ~= 0 then
|
||||
xpcall(pace.SubmitPart, catchError, unpack(table.remove(pace.StreamQueue)))
|
||||
local item = table.remove(pace.StreamQueue)
|
||||
if not item then return end
|
||||
|
||||
local data = item.data
|
||||
local filter = item.filter
|
||||
local callback = item.callback
|
||||
|
||||
local allowed, reason
|
||||
local function submitPart()
|
||||
allowed, reason = pace.SubmitPartNow(data, filter)
|
||||
end
|
||||
|
||||
frame_number = frame_number + 1
|
||||
local success = ProtectedCall(submitPart)
|
||||
|
||||
if not isfunction(callback) then return end
|
||||
|
||||
if not success then
|
||||
allowed = false
|
||||
reason = "Unexpected Error"
|
||||
end
|
||||
|
||||
ProtectedCall(function()
|
||||
callback(allowed, reason)
|
||||
end)
|
||||
end)
|
||||
|
||||
local function make_copy(tbl, input)
|
||||
@ -22,7 +40,7 @@ local function make_copy(tbl, input)
|
||||
tbl.self.UniqueID = pac.Hash(tbl.self.UniqueID .. input)
|
||||
end
|
||||
|
||||
for key, val in pairs(tbl.children) do
|
||||
for _, val in pairs(tbl.children) do
|
||||
make_copy(val, input)
|
||||
end
|
||||
end
|
||||
@ -45,7 +63,7 @@ end
|
||||
|
||||
pace.dupe_ents = pace.dupe_ents or {}
|
||||
|
||||
local uid2key = include("legacy_network_dictionary_translate.lua")
|
||||
local uid2key = include("pac3/editor/server/legacy_network_dictionary_translate.lua")
|
||||
|
||||
local function translate_old_dupe(tableIn, target)
|
||||
for key, value2 in pairs(tableIn) do
|
||||
@ -85,7 +103,7 @@ duplicator.RegisterEntityModifier("pac_config", function(ply, ent, parts)
|
||||
|
||||
-- give source engine time
|
||||
timer.Simple(0, function()
|
||||
for uid, data in pairs(parts) do
|
||||
for _, data in pairs(parts) do
|
||||
if istable(data.part) then
|
||||
make_copy(data.part, id)
|
||||
|
||||
@ -108,44 +126,47 @@ duplicator.RegisterEntityModifier("pac_config", function(ply, ent, parts)
|
||||
end)
|
||||
end)
|
||||
|
||||
function pace.SubmitPart(data, filter)
|
||||
if istable(data.part) then
|
||||
if last_frame == frame_number then
|
||||
table.insert(pace.StreamQueue, {data, filter})
|
||||
pace.dprint("queuing part %q from %s", data.part.self.Name, tostring(data.owner))
|
||||
return "queue"
|
||||
end
|
||||
function pace.SubmitPartNow(data, filter)
|
||||
local part = data.part
|
||||
local owner = data.owner
|
||||
|
||||
-- last arg "true" is pac3 only in case you need to do your checking differently from pac2
|
||||
local allowed, reason = hook.Run("PrePACConfigApply", owner, data, true)
|
||||
if allowed == false then return allowed, reason end
|
||||
|
||||
local uid = data.uid
|
||||
if uid ~= false and pace.IsBanned(owner) then
|
||||
return false, "you are banned from using pac"
|
||||
end
|
||||
|
||||
-- last arg "true" is pac3 only in case you need to do your checking differnetly from pac2
|
||||
local allowed, reason = hook.Run("PrePACConfigApply", data.owner, data, true)
|
||||
if istable(part) then
|
||||
local ent = Entity(tonumber(part.self.OwnerName) or -1)
|
||||
|
||||
if istable(data.part) then
|
||||
local ent = Entity(tonumber(data.part.self.OwnerName) or -1)
|
||||
if ent:IsValid() then
|
||||
if not pace.CanPlayerModify(data.owner, ent) then
|
||||
allowed = false
|
||||
reason = "you are not allowed to modify this entity: " .. tostring(ent) .. " owned by: " .. tostring(ent.CPPIGetOwner and ent:CPPIGetOwner() or "world")
|
||||
if not pace.CanPlayerModify(owner, ent) then
|
||||
local entOwner = ent.CPPIGetOwner and ent:CPPIGetOwner()
|
||||
entOwner = tostring(entOwner or "world")
|
||||
|
||||
return false, "you are not allowed to modify this entity: " .. tostring(ent) .. " owned by: " .. entOwner
|
||||
else
|
||||
if not data.is_dupe then
|
||||
ent.pac_parts = ent.pac_parts or {}
|
||||
ent.pac_parts[pac.Hash(data.owner)] = data
|
||||
ent.pac_parts[pac.Hash(owner)] = data
|
||||
|
||||
pace.dupe_ents[ent:EntIndex()] = {owner = data.owner, ent = ent}
|
||||
pace.dupe_ents[ent:EntIndex()] = {owner = owner, ent = ent}
|
||||
|
||||
duplicator.ClearEntityModifier(ent, "pac_config")
|
||||
--duplicator.StoreEntityModifier(ent, "pac_config", ent.pac_parts)
|
||||
--duplicator.StoreEntityModifier(ent, "pac_config", {json = util.TableToJSON(ent.pac_parts)})
|
||||
-- fresh table copy
|
||||
duplicator.StoreEntityModifier(ent, "pac_config", {json = util.TableToJSON(table.Copy(ent.pac_parts))})
|
||||
end
|
||||
ent:CallOnRemove("pac_config", function(ent)
|
||||
if ent.pac_parts then
|
||||
for _, data in pairs(ent.pac_parts) do
|
||||
if istable(data.part) then
|
||||
data.part = data.part.self.UniqueID
|
||||
|
||||
ent:CallOnRemove("pac_config", function(e)
|
||||
if e.pac_parts then
|
||||
for _, eData in pairs(e.pac_parts) do
|
||||
if istable(eData.part) then
|
||||
eData.part = eData.part.self.UniqueID
|
||||
end
|
||||
pace.RemovePart(data)
|
||||
pace.RemovePart(eData)
|
||||
end
|
||||
end
|
||||
end)
|
||||
@ -153,23 +174,17 @@ function pace.SubmitPart(data, filter)
|
||||
end
|
||||
end
|
||||
|
||||
if data.uid ~= false then
|
||||
if allowed == false then return allowed, reason end
|
||||
if pace.IsBanned(data.owner) then return false, "you are banned from using pac" end
|
||||
end
|
||||
|
||||
local uid = data.uid
|
||||
pace.Parts[uid] = pace.Parts[uid] or {}
|
||||
|
||||
if istable(data.part) then
|
||||
pace.Parts[uid][data.part.self.UniqueID] = data
|
||||
if istable(part) then
|
||||
pace.Parts[uid][part.self.UniqueID] = data
|
||||
else
|
||||
if data.part == "__ALL__" then
|
||||
if part == "__ALL__" then
|
||||
pace.Parts[uid] = {}
|
||||
filter = true
|
||||
|
||||
for key, v in pairs(pace.dupe_ents) do
|
||||
if v.owner:IsValid() and v.owner == data.owner then
|
||||
if v.owner:IsValid() and v.owner == owner then
|
||||
if v.ent:IsValid() and v.ent.pac_parts then
|
||||
v.ent.pac_parts = nil
|
||||
duplicator.ClearEntityModifier(v.ent, "pac_config")
|
||||
@ -178,26 +193,8 @@ function pace.SubmitPart(data, filter)
|
||||
|
||||
pace.dupe_ents[key] = nil
|
||||
end
|
||||
elseif data.part then
|
||||
pace.Parts[uid][data.part] = nil
|
||||
|
||||
-- this doesn't work because the unique id is different for some reason
|
||||
-- use clear for now if you wanna clear a dupes outfit
|
||||
--[[for key, v in pairs(pace.dupe_ents) do
|
||||
if v.owner:IsValid() and v.owner == data.owner then
|
||||
if v.ent:IsValid() and v.ent.pac_parts then
|
||||
local id = pac.Hash(data.part .. v.ent:EntIndex())
|
||||
v.ent.pac_parts[id] = nil
|
||||
duplicator.ClearEntityModifier(v.ent, "pac_config")
|
||||
duplicator.StoreEntityModifier(v.ent, "pac_config", v.ent.pac_parts)
|
||||
return
|
||||
else
|
||||
pace.dupe_ents[key] = nil
|
||||
end
|
||||
else
|
||||
pace.dupe_ents[key] = nil
|
||||
end
|
||||
end]]
|
||||
elseif part then
|
||||
pace.Parts[uid][part] = nil
|
||||
end
|
||||
end
|
||||
|
||||
@ -218,12 +215,12 @@ function pace.SubmitPart(data, filter)
|
||||
end
|
||||
|
||||
if filter == false then
|
||||
filter = data.owner
|
||||
filter = owner
|
||||
elseif filter == true then
|
||||
local tbl = {}
|
||||
|
||||
for k, v in pairs(players) do
|
||||
if v ~= data.owner then
|
||||
for _, v in pairs(players) do
|
||||
if v ~= owner then
|
||||
table.insert(tbl, v)
|
||||
end
|
||||
end
|
||||
@ -232,26 +229,28 @@ function pace.SubmitPart(data, filter)
|
||||
end
|
||||
|
||||
if not data.server_only then
|
||||
if data.owner:IsValid() then
|
||||
data.player_uid = pac.Hash(data.owner)
|
||||
if owner:IsValid() then
|
||||
data.player_uid = pac.Hash(owner)
|
||||
end
|
||||
|
||||
local players = filter or players
|
||||
players = filter or players
|
||||
|
||||
if istable(players) then
|
||||
for key = #players, 1, -1 do
|
||||
local ply = players[key]
|
||||
if not ply.pac_requested_outfits and ply ~= data.owner then
|
||||
if not ply.pac_requested_outfits and ply ~= owner then
|
||||
table.remove(players, key)
|
||||
end
|
||||
end
|
||||
|
||||
if pace.GlobalBans and data.owner:IsValid() then
|
||||
local owner_steamid = data.owner:SteamID()
|
||||
if pace.GlobalBans and owner:IsValid() then
|
||||
local owner_steamid = owner:SteamID()
|
||||
|
||||
for key, ply in pairs(players) do
|
||||
local steamid = ply:SteamID()
|
||||
for var, reason in pairs(pace.GlobalBans) do
|
||||
if var == steamid or istable(var) and (table.HasValue(var, steamid) or table.HasValue(var, util.CRC(ply:IPAddress():match("(.+):") or ""))) then
|
||||
|
||||
for var in pairs(pace.GlobalBans) do
|
||||
if var == steamid or istable(var) and (table.HasValue(var, steamid) or table.HasValue(var, util.CRC(ply:IPAddress():match("(.+):") or ""))) then
|
||||
table.remove(players, key)
|
||||
|
||||
if owner_steamid == steamid then
|
||||
@ -262,7 +261,7 @@ function pace.SubmitPart(data, filter)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif type(players) == "Player" and (not players.pac_requested_outfits and players ~= data.owner) then
|
||||
elseif type(players) == "Player" and (not players.pac_requested_outfits and players ~= owner) then
|
||||
data.transmissionID = nil
|
||||
return true
|
||||
end
|
||||
@ -276,19 +275,19 @@ function pace.SubmitPart(data, filter)
|
||||
local bytes, err = net_write_table(data)
|
||||
|
||||
if not bytes then
|
||||
ErrorNoHalt("[PAC3] Outfit broadcast failed for " .. tostring(data.owner) .. ": " .. tostring(err) .. '\n')
|
||||
local errStr = tostring(err)
|
||||
ErrorNoHalt("[PAC3] Outfit broadcast failed for " .. tostring(owner) .. ": " .. errStr .. '\n')
|
||||
|
||||
if data.owner and data.owner:IsValid() then
|
||||
data.owner:ChatPrint('[PAC3] ERROR: Could not broadcast your outfit: ' .. tostring(err))
|
||||
if owner and owner:IsValid() then
|
||||
owner:ChatPrint('[PAC3] ERROR: Could not broadcast your outfit: ' .. errStr)
|
||||
end
|
||||
else
|
||||
net.Send(players)
|
||||
end
|
||||
end
|
||||
|
||||
if istable(data.part) then
|
||||
last_frame = frame_number
|
||||
pace.CallHook("OnWoreOutfit", data.owner, data.part)
|
||||
if istable(part) then
|
||||
pace.CallHook("OnWoreOutfit", owner, part)
|
||||
end
|
||||
end
|
||||
|
||||
@ -298,33 +297,58 @@ function pace.SubmitPart(data, filter)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Inserts the given part into the StreamQueue
|
||||
function pace.SubmitPart(data, filter, callback)
|
||||
if istable(data.part) then
|
||||
pac.dprint("queuing part %q from %s", data.part.self.Name, tostring(data.owner))
|
||||
table.insert(pace.StreamQueue, {
|
||||
data = data,
|
||||
filter = filter,
|
||||
callback = callback
|
||||
})
|
||||
|
||||
return "queue"
|
||||
end
|
||||
|
||||
return pace.SubmitPartNow(data, filter)
|
||||
end
|
||||
|
||||
-- Inserts the given part into the StreamQueue, and notifies when it completes
|
||||
function pace.SubmitPartNotify(data)
|
||||
pace.dprint("submitted outfit %q from %s with %i number of children to set on %s", data.part.self.Name or "", data.owner:GetName(), table.Count(data.part.children), data.part.self.OwnerName or "")
|
||||
local part = data.part
|
||||
local partName = part.self.Name or "no name"
|
||||
|
||||
local allowed, reason = pace.SubmitPart(data)
|
||||
pac.dprint("submitted outfit %q from %s with %i children to set on %s", partName, data.owner:GetName(), table.Count(part.children), part.self.OwnerName or "")
|
||||
|
||||
if data.owner:IsPlayer() then
|
||||
local function callback(allowed, reason)
|
||||
if allowed == "queue" then return end
|
||||
if not data.owner:IsPlayer() then return end
|
||||
|
||||
if not reason and allowed and istable(data.part) then
|
||||
reason = string.format('Your part %q has been applied', data.part.self.Name or '<unknown>')
|
||||
reason = reason or ""
|
||||
|
||||
if not reason and allowed and istable(part) then
|
||||
reason = string.format("Your part %q has been applied", partName or "<unknown>")
|
||||
end
|
||||
|
||||
net.Start("pac_submit_acknowledged")
|
||||
net.WriteBool(allowed)
|
||||
net.WriteString(reason or "")
|
||||
net.WriteString(data.part.self.Name or "no name")
|
||||
net.WriteString(reason)
|
||||
net.WriteString(partName)
|
||||
net.Send(data.owner)
|
||||
|
||||
hook.Run("PACSubmitAcknowledged", data.owner, util.tobool(allowed), reason or "", data.part.self.Name or "no name", data)
|
||||
hook.Run("PACSubmitAcknowledged", data.owner, not not allowed, reason, partName, data)
|
||||
end
|
||||
|
||||
pace.SubmitPart(data, nil, callback)
|
||||
end
|
||||
|
||||
function pace.RemovePart(data)
|
||||
pace.dprint("%s is removed %q", data.owner and data.owner:IsValid() and data.owner:GetName(), data.part)
|
||||
local part = data.part
|
||||
local owner = data.owner
|
||||
pac.dprint("%s is removed %q", owner and owner:IsValid() and owner:GetName(), part)
|
||||
|
||||
if data.part == "__ALL__" then
|
||||
pace.CallHook("RemoveOutfit", data.owner)
|
||||
if part == "__ALL__" then
|
||||
pace.CallHook("RemoveOutfit", owner)
|
||||
end
|
||||
|
||||
pace.SubmitPart(data, data.filter)
|
||||
|
@ -27,6 +27,10 @@ function pacx.PartToContraptionData(part, tbl)
|
||||
data.mat = part:GetMaterial()
|
||||
data.mdl = part:GetModel()
|
||||
data.skn = part:GetSkin()
|
||||
|
||||
local size = part:GetSize()
|
||||
data.scale = part:GetScale()*size
|
||||
|
||||
data.id = part.UniqueID
|
||||
|
||||
table.insert(tbl, data)
|
||||
@ -39,4 +43,4 @@ function pacx.PartToContraptionData(part, tbl)
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
end
|
||||
|
@ -1,5 +1,4 @@
|
||||
local bones =
|
||||
{
|
||||
local bones = {
|
||||
["pelvis"] = "valvebiped.bip01_pelvis",
|
||||
["spine"] = "valvebiped.bip01_spine",
|
||||
["spine 2"] = "valvebiped.bip01_spine1",
|
||||
@ -326,6 +325,22 @@ end
|
||||
local glon = {}
|
||||
|
||||
do
|
||||
local function Read(reader, rtabs)
|
||||
local t, pos = reader:Peek()
|
||||
if not t then
|
||||
error(string.format("Expected type ID at %s! (Got EOF)",
|
||||
pos))
|
||||
else
|
||||
local dt = decode_types[string.byte(t)]
|
||||
if not dt then
|
||||
error(string.format("Unknown type ID, %s!",
|
||||
string.byte(t)))
|
||||
else
|
||||
return dt(reader, rtabs or {0})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local decode_types
|
||||
decode_types = {
|
||||
-- \2\6omg\1\6omgavalue\1\1
|
||||
@ -462,21 +477,6 @@ do
|
||||
return rtabs[decode_types[6](reader) - 1]
|
||||
end,
|
||||
}
|
||||
function Read(reader, rtabs)
|
||||
local t, pos = reader:Peek()
|
||||
if not t then
|
||||
error(string.format("Expected type ID at %s! (Got EOF)",
|
||||
pos))
|
||||
else
|
||||
local dt = decode_types[string.byte(t)]
|
||||
if not dt then
|
||||
error(string.format("Unknown type ID, %s!",
|
||||
string.byte(t)))
|
||||
else
|
||||
return dt(reader, rtabs or {0})
|
||||
end
|
||||
end
|
||||
end
|
||||
local reader_meta = {}
|
||||
reader_meta.__index = reader_meta
|
||||
function reader_meta:Next()
|
||||
|
@ -43,6 +43,16 @@ local function spawn(val,ply)
|
||||
if phys:IsValid() then
|
||||
phys:EnableMotion(false)
|
||||
|
||||
local maxabs = 150
|
||||
|
||||
val.scale.X = math.Clamp(val.scale.X,-maxabs,maxabs)
|
||||
val.scale.Y = math.Clamp(val.scale.Y,-maxabs,maxabs)
|
||||
val.scale.Z = math.Clamp(val.scale.Z,-maxabs,maxabs)
|
||||
|
||||
for i=0, ent:GetBoneCount()-1 do
|
||||
ent:ManipulateBoneScale( i, val.scale )
|
||||
end
|
||||
|
||||
undo.Create("Prop")
|
||||
undo.SetPlayer(ply)
|
||||
undo.AddEntity(ent)
|
||||
|
@ -29,7 +29,7 @@ pac.AddHook("RenderScene", "webaudio_3d", function(position, angle)
|
||||
end)
|
||||
|
||||
webaudio.Streams.STREAM = {}
|
||||
STREAM = webaudio.Streams.STREAM
|
||||
local STREAM = webaudio.Streams.STREAM
|
||||
STREAM.__index = STREAM
|
||||
|
||||
-- Identity
|
||||
|
Loading…
Reference in New Issue
Block a user