Automatically freeze anything welded to the ground
9 replies, posted
Hi, I'm making a gamemode deriving from sandbox and trying to make it so that any time a player welds something to the ground, the prop gets automatically frozen (i.e. like you right-clicked the physgun while holding it). The players in this gamemode will not receive the physgun so I have to do it in code.
I tried using the hook GM:OnEntityCreated and GetConstrainedEntities on the phys_constraint entity that gets created, but it always seems to return two nils. I'm thinking this may just be because the hook is called before the entity is properly defined - am I right? And if so, how do I overcome that?
Thanks in advance!
P.S. I tried using GetConstrainedPhysObjects as well with the same result, for the record...
I think the most straightforward way would be to override the creation of weld constraints.
[code]
local oldconstraintweld = constraint.Weld
function constraint.Weld(ent1,ent2,a,b,c,d,e)
if !ent1:IsWorld() && ent1:GetPhysicsObject() then ent1:GetPhysicsObject():EnableMotion(false) end
if !ent2:IsWorld() && ent2:GetPhysicsObject() then ent2:GetPhysicsObject():EnableMotion(false) end
return oldconstraintweld(ent1,ent2,a,b,c,d,e)
end
[/code]
With this, all items being welded should immediately freeze.
[editline]17th January 2015[/editline]
Or did you want only things welded to the ground to freeze, and not simply any welded object?
[code]
local oldconstraintweld = constraint.Weld
function constraint.Weld(ent1,ent2,a,b,c,d,e)
if ent1:IsWorld() && !ent2:IsWorld() && ent2:GetPhysicsObject() then ent2:GetPhysicsObject():EnableMotion(false) end
if ent2:IsWorld() && !ent1:IsWorld() && ent1:GetPhysicsObject() then ent1:GetPhysicsObject():EnableMotion(false) end
return oldconstraintweld(ent1,ent2,a,b,c,d,e)
end
[/code]
edit: forgot to return the result, fixed (thanks kogitsune)
Ooh, I didn't know you could do that. Now, is it possible to unfreeze them when the weld is removed?
Thanks for your help :)
Edit: actually I think I can figure this one out for myself using GM:EntityRemoved. I'll bump this if I get stuck (or solve it!)
Edit: Aww :(
[code]
local oldconstraintweld = constraint.Weld
function constraint.Weld(ent1,ent2,a,b,c,d,e)
if ent1:IsWorld() && !ent2:IsWorld() && ent2:GetPhysicsObject() then ent2:GetPhysicsObject():EnableMotion(false) end
if ent2:IsWorld() && !ent1:IsWorld() && ent1:GetPhysicsObject() then ent1:GetPhysicsObject():EnableMotion(false) end
return oldconstraintweld(ent1,ent2,a,b,c,d,e)
end
...
weld = constraint.Weld( left, right, ... )
if IsValid( weld ) then
local v
if ent1:IsWorld( ) then
v = ent2:GetPhysicsObject( )
else
v = ent1:GetPhysicsObject( )
end
weld:CallOnRemove( "ReleaseOnBreak", function( this ) if IsValid( v ) then v:EnableMotion( true ) v:Wake( ) end end )
end[/code]
Something like that would probably be what you want - could definitely use a little cleaning though.
Kogitsune is saying to edit the weld tool, but here's a better way:
[code]
local oldconstraintweld = constraint.Weld
function constraint.Weld(ent1,ent2,a,b,c,d,e)
local ent
if ent1:IsWorld() && !ent2:IsWorld() && ent2:GetPhysicsObject() then ent = ent2 end
if ent2:IsWorld() && !ent1:IsWorld() && ent1:GetPhysicsObject() then ent = ent1 end
local weld = oldconstraintweld(ent1,ent2,a,b,c,d,e)
if IsValid(ent) then
ent:GetPhysicsObject():EnableMotion(false)
weld:CallOnRemove("ReleaseOnBreak",function() if IsValid(ent) then ent:EnableMotion(true) ent:Wake() end end)
end
return weld
end
[/code]
If the entity doesn't start moving after the weld is removed, try waking the ent's physics object.
Awesome, thanks, uhh... bitches.... :S
This freezes the prop when welding, but unfortunately, when undoing the weld I get this error:
[img]http://gyazo.com/3525e047902f30a02895da4ea9573d42.png[/img]
I've made an attempt to fix this by adding a parameter to the function inside CallOnRemove, which sadly didn't work. My code currently looks like this:
[lua]local oldweld = constraint.Weld
function constraint.Weld( ent1 , ent2 , a , b , force , c , d )
local ent
if !ent1:IsWorld() && ent2:IsWorld() && ent2:GetPhysicsObject() then ent = ent1 end
if !ent2:IsWorld() && ent1:IsWorld() && ent1:GetPhysicsObject() then ent = ent2 end
local weld = oldweld( ent1 , ent2 , a , b , force, c , d )
if IsValid(ent) && force == 0 then
ent:GetPhysicsObject():EnableMotion(false)
weld:CallOnRemove( "ReleaseOnBreak" , function( x ) if IsValid(x) then x:EnableMotion(true) x:Wake() end end , ent) -- This is line 39
end
return weld
end[/lua]
What I THINK is happening is that we're using ent in the function, but ent was a local function to our new constraint.Weld so it was garbage-collected. That's why I tried passing it as a parameter.
I'm out of ideas. You got any?
Either way, thanks immensely for your help!
[b]Edit:[/b] wait a sec...
[b]Edit:[/b] Okay! I got it working!
First of all: obviously you were right, the local ent wasn't the problem. To quote myself from another thread:
[QUOTE=Neat-Nit;46955686]Still very new to lua, so I don't have the whole 'scope' thing [i]quite[/i] figured out yet...[/QUOTE]
Now, as for the actual problem: seems the only problem in the original code you gave me was a missing :GetPhysObject() - entities don't have EnableMotion(). However, this didn't solve the problem for me, since I introduced a new one when I tried to use args! Apparently, the first parameter of the function is the weld entity, and the ent ended up being the SECOND parameter! Which was being ignored, since x was set as the first parameter.
Long story short, both of these work:
[lua]local oldweld = constraint.Weld
function constraint.Weld( ent1 , ent2 , a , b , force , c , d )
local ent
if !ent1:IsWorld() && ent2:IsWorld() && ent1:GetPhysicsObject() then ent = ent1 end
if !ent2:IsWorld() && ent1:IsWorld() && ent2:GetPhysicsObject() then ent = ent2 end
local weld = oldweld( ent1 , ent2 , a , b , force, c , d )
if IsValid(ent) && force == 0 then
ent:GetPhysicsObject():EnableMotion(false)
weld:CallOnRemove( "ReleaseOnBreak" , function( _ , x ) if IsValid(x) then x:GetPhysicsObject():EnableMotion(true) x:PhysWake() end end , ent)
end
return weld
end[/lua]
[lua]local oldweld = constraint.Weld
function constraint.Weld( ent1 , ent2 , a , b , force , c , d )
local ent
if !ent1:IsWorld() && ent2:IsWorld() && ent1:GetPhysicsObject() then ent = ent1 end
if !ent2:IsWorld() && ent1:IsWorld() && ent2:GetPhysicsObject() then ent = ent2 end
local weld = oldweld( ent1 , ent2 , a , b , force, c , d )
if IsValid(ent) && force == 0 then
ent:GetPhysicsObject():EnableMotion(false)
weld:CallOnRemove( "ReleaseOnBreak" , function() if IsValid(ent) then ent:GetPhysicsObject():EnableMotion(true) ent:PhysWake() end end)
end
return weld
end[/lua]
Thank you for the help!!
[b]Edit:[/b] I added this information to the [url=http://wiki.garrysmod.com/page/Entity/CallOnRemove]wiki[/url] ([url=http://wiki.garrysmod.com/index.php?title=Entity%2FCallOnRemove&action=historysubmit&diff=19169&oldid=8232]my additions[/url]) in case anyone in the future runs into the same confusion...
Here's how I do it:
[code] // Prevent object from moving, and weld object to world - prevents invisible props from moving.
local _weld = _options.weld;
local _phys = _ent:GetPhysicsObject( );
if( _weld && IsValid( _phys ) ) then
_ent:GetPhysicsObject( ):EnableMotion( false );
constraint.Weld( _ent, game.GetWorld( ) );
end
[/code]
As part of a larger function but everything is here to make it work.
[QUOTE=Acecool;46967938]Here's how I do it:
[code] // Prevent object from moving, and weld object to world - prevents invisible props from moving.
local _weld = _options.weld;
local _phys = _ent:GetPhysicsObject( );
if( _weld && IsValid( _phys ) ) then
_ent:GetPhysicsObject( ):EnableMotion( false );
constraint.Weld( _ent, game.GetWorld( ) );
end
[/code]
As part of a larger function but everything is here to make it work.[/QUOTE]
Sorry to be blunt, but that is completely unrelated to what I asked... Check out foxcock's code above, he understood me! :)
[quote]Automatically freeze anything welded to the ground[/quote]
My snippet provides the means to freeze, you only need to check if the weld is between an object and the world and then apply it.
[QUOTE=Acecool;46968202]My snippet provides the means to freeze, you only need to check if the weld is between an object and the world and then apply it.[/QUOTE]
Your snippet provides both the means to freeze, and the means to weld; But it does not explain how to have code run when a player welds using the toolgun.
Sorry, you need to Log In to post a reply to this thread.