Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f4e7d98
Don't throw errors inside meshlab
Astralcircle Nov 13, 2025
04bd73f
Less diff
Astralcircle Nov 13, 2025
9076390
Do it another way
Astralcircle Nov 14, 2025
ea10445
Less diff
Astralcircle Nov 14, 2025
5c47da4
Add clientside variants to applicable starfall functions
legokidlogan Feb 26, 2026
85c9aae
Don't replicate UV/Bump, they could desync uniqueID improperly
legokidlogan Feb 26, 2026
8eb750c
Improve docstring
legokidlogan Feb 26, 2026
249abaf
Add e2 and sf getters for pos and ang
legokidlogan Feb 26, 2026
539e3b9
Add controller limit + fix cleanup
thecraftianman Jun 30, 2026
d541211
Fix "remove selected props when done" option
LengthenedGradient Jul 16, 2026
ea4feec
Add vertex count and file size to profiler
LengthenedGradient Jul 17, 2026
9ec6a83
Add controller merging
LengthenedGradient Jul 17, 2026
3756e88
Fix lua error
Astralcircle Jul 21, 2026
c22e155
Merge pull request #78 from Astralcircle/patch-2
LengthenedGradient Jul 22, 2026
c5e6992
Add entity merging
LengthenedGradient Jul 22, 2026
20989c0
Add CPPIGetOwner check for entity merging
LengthenedGradient Jul 22, 2026
936a417
Merge pull request #76 from ACF-Team/controller-merging
marchc1 Jul 22, 2026
b69b9c3
Fix lua error
Astralcircle Jul 22, 2026
b910227
Fix CPPI check
thecraftianman Jul 22, 2026
48b789a
Merge branch 'master' into patch-2
thecraftianman Jul 22, 2026
b67b6b1
Merge pull request #79 from Astralcircle/patch-2
thecraftianman Jul 22, 2026
e4eff61
Port over recent primitive shapes
LengthenedGradient Jul 20, 2026
0c6d620
Remove redundant copy of primitives
LengthenedGradient Jul 22, 2026
c5d7533
Add Improved Clipping Support
LengthenedGradient Aug 15, 2026
d3d38e7
Simplify
LengthenedGradient Aug 16, 2026
e438f68
Safely import primitive's library
LengthenedGradient Aug 16, 2026
c453cdd
Merge pull request #80 from ACF-Team/improved-clipping-retry
LengthenedGradient Aug 16, 2026
2e7317c
Merge pull request #70 from Astralcircle/patch-1
LengthenedGradient Aug 25, 2026
55c74a3
Fix bug where primitives is not installed
LengthenedGradient Sep 1, 2026
a6d0d5e
Don't clear prop2mesh modifier on copy
thecraftianman Sep 2, 2026
cf76b2d
Fix improved clipping support
LengthenedGradient Sep 2, 2026
45eadbe
Add clientside variants to applicable starfall functions
legokidlogan Feb 26, 2026
e646e28
Don't replicate UV/Bump, they could desync uniqueID improperly
legokidlogan Feb 26, 2026
648dac6
Improve docstring
legokidlogan Feb 26, 2026
0890afa
Add e2 and sf getters for pos and ang
legokidlogan Feb 26, 2026
931ef69
Pass ent correctly
legokidlogan Sep 26, 2026
2e04121
Fix E2 returns
legokidlogan Sep 26, 2026
a58b1e2
Don't return by reference
legokidlogan Sep 26, 2026
a5b7be7
Merge
legokidlogan Sep 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/workshop-upload.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Deploy to Workshop

on:
push:
branches:
- master
workflow_dispatch:

jobs:
deploy:
if: github.repository == 'ACF-Team/Prop2Mesh'
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
path: project

- name: Upload to Workshop
uses: CFC-Servers/gmod-upload@master
with:
id: 2458909924
changelog: "${{ github.event.head_commit.message }}"
title: "Prop2Mesh"
type: "tool"
tag1: "build"
tag2: "fun"
env:
STEAM_USERNAME: ${{ secrets.ACF_STEAM_ACCOUNT }}
STEAM_PASSWORD: ${{ secrets.ACF_STEAM_PASSWORD }}
38 changes: 17 additions & 21 deletions lua/autorun/prop2mesh.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
--[[

]]
if not prop2mesh then prop2mesh = {} end


--[[

]]
prop2mesh.defaultmat = "hunter/myplastic"

prop2mesh.enablelog = false
Expand All @@ -32,14 +25,11 @@ function prop2mesh.getBodygroupMask(ent)
return mask
end


--[[

]]
if SERVER then
resource.AddWorkshop("2458909924")

CreateConVar("prop2mesh_disable_allowed", 0, {FCVAR_NOTIFY, FCVAR_ARCHIVE}, "prevents prop2mesh data from networking")
CreateConVar("sbox_maxprop2mesh", 50, {FCVAR_NOTIFY, FCVAR_ARCHIVE})

AddCSLuaFile("prop2mesh/cl_meshlab.lua")
AddCSLuaFile("prop2mesh/cl_modelfixer.lua")
Expand All @@ -63,20 +53,23 @@ if SERVER then
}
end

local function makeEntity(class, pl, dupedata) -- limits would go here?
local self = ents.Create(class)
if not (self and self:IsValid()) then
return false
end
local function makeEntity(class, ply, dupedata)
if not ply:CheckLimit("prop2mesh") then return false end

local ent = ents.Create(class)
if not IsValid(ent) then return false end

if dupedata then
duplicator.DoGeneric(self, dupedata)
duplicator.DoGeneric(ent, dupedata)
end
self:Spawn()
self:Activate()
self:SetPlayer(pl)
ent:Spawn()
ent:Activate()
ent:SetPlayer(ply)

if ply.AddCleanup then ply:AddCleanup(class, ent) end
if ply.AddCount then ply:AddCount("prop2mesh", ent) end

return self
return ent
end
prop2mesh.makeEntity = makeEntity

Expand Down Expand Up @@ -132,6 +125,9 @@ elseif CLIENT then
E2Helper.Descriptions["p2mSetMaterial(e:s)"] = backcompat
E2Helper.Descriptions["p2mSetMeshScale(e:n)"] = backcompat
end)

language.Add("Cleanup_sent_prop2mesh", "Prop2Mesh Controllers")
language.Add("Cleanup_sent_prop2mesh_legacy", "Prop2Mesh Legacy Controllers")
end

--[[
Expand Down
31 changes: 27 additions & 4 deletions lua/entities/gmod_wire_expression2/core/custom/prop2mesh.lua
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ local function p2mCreate(context, count, pos, ang, uvs, scale, bump)
error("controller limit is 64 per entity")
end

local ply = context.player
if not ply:CheckLimit("prop2mesh") then return end

local self = ents.Create("sent_prop2mesh")

self:SetNoDraw(true)
Expand All @@ -130,10 +133,13 @@ local function p2mCreate(context, count, pos, ang, uvs, scale, bump)
end

if CPPI then
self:CPPISetOwner(context.player)
self:CPPISetOwner(ply)
end

self:SetPlayer(context.player)
if ply.AddCleanup then ply:AddCleanup("sent_prop2mesh", self) end
if ply.AddCount then ply:AddCount("prop2mesh", self) end

self:SetPlayer(ply)
self:SetSolid(SOLID_NONE)
self:SetMoveType(MOVETYPE_NONE)
self:DrawShadow(false)
Expand Down Expand Up @@ -447,13 +453,30 @@ e2function vector4 entity:p2mGetColor(index)
return {255,255,255,255}
end
local info = this.prop2mesh_controllers[index]
return {info.col.r, info.col.g, info.col.b, info.col.a}
local col = info.col or color_white
return {col.r, col.g, col.b, col.a}
end
e2function vector entity:p2mGetPos(index)
if not checkvalid(self, this, nil, index, nil) then
return Vector(0,0,0)
end
local linkpos = this.prop2mesh_controllers[index].linkpos
if not linkpos then return Vector(0,0,0) end
return Vector(linkpos.x, linkpos.y, linkpos.z)
end
e2function angle entity:p2mGetAng(index)
if not checkvalid(self, this, nil, index, nil) then
return Angle(0,0,0)
end
local linkang = this.prop2mesh_controllers[index].linkang
if not linkang then return Angle(0,0,0) end
return Angle(linkang.p, linkang.y, linkang.r)
end
e2function string entity:p2mGetMaterial(index)
if not checkvalid(self, this, nil, index, nil) then
return ""
end
return this.prop2mesh_controllers[index].mat
return this.prop2mesh_controllers[index].mat or ""
end
e2function string entity:p2mGetName(index)
if not checkvalid(self, this, nil, index, nil) then
Expand Down
128 changes: 102 additions & 26 deletions lua/entities/sent_prop2mesh/cl_init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ local Ent_SetColor = entMeta.SetColor
local Ent_GetTable = entMeta.GetTable
local Ent_DrawModel = entMeta.DrawModel
local Ent_GetAngles = entMeta.GetAngles
local Ent_GetParent = entMeta.GetParent
local Ent_SetParent = entMeta.SetParent
local Ent_SetAngles = entMeta.SetAngles
local Ent_SetMaterial = entMeta.SetMaterial
Expand Down Expand Up @@ -396,6 +397,39 @@ local function drawMesh(self)
return meshes and meshes.basic or empty
end

local function refreshSetColor(infoEnt, col)
local isOpaque = col.a == 255

Ent_SetColor(infoEnt, col)
Ent_SetRenderMode(infoEnt, isOpaque and RENDERMODE_NORMAL or RENDERMODE_TRANSCOLOR)
infoEnt.RenderGroup = isOpaque and RENDERGROUP_OPAQUE or RENDERGROUP_BOTH
end

local function refreshSetScale(infoEnt, scale)
if scale.x ~= 1 or scale.y ~= 1 or scale.z ~= 1 then
local matrix = Matrix()
matrix:SetScale(scale)
Ent_EnableMatrix(infoEnt, "RenderMultiply", matrix)
infoEnt.scale = scale
else
Ent_DisableMatrix(infoEnt, "RenderMultiply")
infoEnt.scale = nil
end
end

local function refreshSetPosAng(infoEnt, info, p2mEnt)
local linkEnt = info.linkent
local parent = IsValid(linkEnt) and linkEnt or p2mEnt
local pos, ang = LocalToWorld(info.linkpos or vecZero, info.linkang or angZero, Ent_GetPos(parent), Ent_GetAngles(parent))

if parent ~= Ent_GetParent(infoEnt) then
Ent_SetParent(infoEnt, parent)
end

Ent_SetPos(infoEnt, pos)
Ent_SetAngles(infoEnt, ang)
end

local function refresh(self, info)
local infoEnt = info.ent

Expand All @@ -411,33 +445,12 @@ local function refresh(self, info)
info.ent = infoEnt
end

local linkEnt = info.linkent
local parent = IsValid(linkEnt) and linkEnt or self
local pos, ang = LocalToWorld(info.linkpos or vecZero, info.linkang or angZero, Ent_GetPos(parent), Ent_GetAngles(parent))

Ent_SetParent(infoEnt, parent)
Ent_SetAngles(infoEnt, ang)
Ent_SetPos(infoEnt, pos)

local infoEntTable = Ent_GetTable(infoEnt)
local infoCol = info.col
local isOpaque = infoCol.a == 255

Ent_SetMaterial(infoEnt, info.mat)
Ent_SetColor(infoEnt, infoCol)
Ent_SetRenderMode(infoEnt, isOpaque and RENDERMODE_NORMAL or RENDERMODE_TRANSCOLOR)
infoEntTable.RenderGroup = isOpaque and RENDERGROUP_OPAQUE or RENDERGROUP_BOTH

local infoScale = info.scale
if infoScale.x ~= 1 or infoScale.y ~= 1 or infoScale.z ~= 1 then
local matrix = Matrix()
matrix:SetScale(infoScale)
Ent_EnableMatrix(infoEnt, "RenderMultiply", matrix)
infoEnt.scale = info.scale
else
Ent_DisableMatrix(infoEnt, "RenderMultiply")
infoEnt.scale = nil
end
refreshSetColor(infoEnt, info.col)
refreshSetScale(infoEnt, info.scale)
refreshSetPosAng(infoEnt, info, self)

local infoCrc = info.crc
local infoUniqueID = info.uniqueID
Expand Down Expand Up @@ -583,10 +596,72 @@ function ENT:GetDownloadProgress()
end


local kvpass = {}
local function applyPropertyWithKVPass(ent, index, key, val)
local info = ent.prop2mesh_controllers[index]
if not info then return end

local pass = kvpass[key]

if pass then
pass(ent, info, val)
val = info[key] -- Get the modified result
else
info[key] = val
end

return val, info.ent
end

function ENT:SetControllerCol(index, col)
local infoEnt
col, infoEnt = applyPropertyWithKVPass(self, index, "col", col)
if col == nil then return end
if not IsValid(infoEnt) then return end

refreshSetColor(infoEnt, col)
end

function ENT:SetControllerPos(index, linkpos)
local infoEnt
linkpos, infoEnt = applyPropertyWithKVPass(self, index, "linkpos", linkpos)
if linkpos == nil then return end
if not IsValid(infoEnt) then return end

refreshSetPosAng(infoEnt, self.prop2mesh_controllers[index], self)
end

function ENT:SetControllerAng(index, linkang)
local infoEnt
linkang, infoEnt = applyPropertyWithKVPass(self, index, "linkang", linkang)
if linkang == nil then return end
if not IsValid(infoEnt) then return end

refreshSetPosAng(infoEnt, self.prop2mesh_controllers[index], self)
end

function ENT:SetControllerMat(index, mat)
local infoEnt
mat, infoEnt = applyPropertyWithKVPass(self, index, "mat", mat)
if mat == nil then return end
if not IsValid(infoEnt) then return end

Ent_SetMaterial(infoEnt, mat)
end

function ENT:SetControllerScale(index, scale)
local infoEnt
scale, infoEnt = applyPropertyWithKVPass(self, index, "scale", scale)
if scale == nil then return end
if not IsValid(infoEnt) then return end

refreshSetScale(infoEnt, scale)
end


--[[

]]
local kvpass = {}
kvpass.crc = function(self, info, val)
local crc = info.crc
info.crc = val
Expand Down Expand Up @@ -667,7 +742,8 @@ kvpass.mat = function(self, info, val)
end

kvpass.scale = function(self, info, val)
info.scale = Vector(unpack(val))
if type(val) == "table" then val = Vector(unpack(val)) end
info.scale = val
end

kvpass.clips = function(self, info, val)
Expand Down
Loading