Spawning multiple props on an angle and translucent preview

I have a STOOL that spawns some blocks, sort of like Legos. However, it always faces the blocks towards one axis of the map, not towards the player. It fits together perfectly this way, but turning the blocks and keeping them together is a pain in the ass. I want to face the three blocks towards the player, with block 2 on top of block 1, which is beside block 3. However, the only way I can find to do this is to turn each block individually towards the player, but still having them line up along one of the map’s axis, which puts the bottom two inside each other and makes the whole thing break apart. The two blocks vertically would work great, but the side one screws things up.

Here’s the code (re-created from memory and the GMod wiki, as I’m on a different computer):

[lua]–Get the eyetrace
local ClickPos = trace.HitPos

–I forget the exact numbers and do not have
–access to them now (I’m on a different computer)
local VerticalSpacing = Vector( 0, 0, 0 )
local HorizontalSpacing = Vector( 0, 0, 0 )

–Model filename is irrelevant
local BlockModelFilename = “[irrelevant]”

–Create three blocks
local block1 = ents.Create(“prop_physics”)
local block2 = ents.Create(“prop_physics”)
local block3 = ents.Create(“prop_physics”)

–Set the block models as the same
block1:SetModel(BlockModelFilename)
block2:SetModel(BlockModelFilename)
block3:SetModel(BlockModelFilename)

–Set the positions so that the second block is on top of the first block, which is beside the third block
block1:SetPos(ClickPos)
block2:SetPos(ClickPos + VerticalSpacing)
block3:SetPos(ClickPos + HorizonalSpacing)

–Spawn the blocks
block1:Spawn()
block2:Spawn()
block3:Spawn()[/lua] I saw some methods that convert local angles/positions to world angles/positions and vice versa, but I’m not sure if that’s what I need or not. So, how exactly would I go about doing this?

Also, I want to sort of re-create the effect you get with the thruster STOOL, where you can see a translucent version of the thruster before you actually place it, rotated and positioned properly. I took a look at the GMod LUA code for the thruster, and I can’t seem to find where it is. I also saw “self:DrawEntityOutline()” somewhere in my research, but I’m not sure if it does what I’m thinking of. Is this even possible using LUA, or is it an internal thing for GMod?

Thanks for any help in advance! :smile:

Edit:
I think I may have found the answer to my first question. Basically, I set the position of the first block, then set it as the parent of the other two blocks. Then, I grab the angle of a normalized vector of where the player’s looking, and cancel out any rotation not along the vertical axis, and set the first block’s angle to that. Then I set the two children blocks’ positions relative to the first block using a local to world vector conversion, and set the angles as local to world angle conversions of 0,0,0 (so they face the same direction). Then I spawn the three, and remove the child-parent relationship of all blocks. Here’s the code:

[lua]ClickPos = Vector( 0, 0, 0 )
BlockWidthSpacing = Vector( 0, 0, 0 ) --Actual numbers are irrelevant
BlockHeightSpacing = Vector( 0, 0, 0 ) --Actual numbers are irrelevant
BlockModelFilename = “[irrelevant]” --Actual filename is irrelevant

function SpawnBlocks(trace)
–Store where the user is aiming (may be used after this function ends)
ClickPos = trace.HitPos

–“Load” the blocks in variables
local block1 = ents.Create(“prop_physics”)
local block2 = ents.Create(“prop_physics”)
local block3 = ents.Create(“prop_physics”)

–Set the correct model
block1:SetModel(BlockModelFilename)
block2:SetModel(BlockModelFilename)
block3:SetModel(BlockModelFilename)

–Set the original block’s position
block1:SetPos(ClickPos)

–Sets the parents of the outer two blocks to the original block
block2:SetParent(block1)
block3:SetParent(block1)

–Create a temporary angle variable
local origBlockAngle = player.GetByID(1):GetForward():Normalize():Angle()

–Set the roll and pitch to zero, respectively (this orients the target towards the player along nothing but the vertical axis).
origBlockAngle.r = 0
origBlockAngle.p = 0

–Rotate the original block
block1:SetAngles(origBlockAngle)

–Positions the two outer blocks in the right location
block2:SetPos( block2:LocalToWorldVector( BlockWidthSpacing ) )
block3:SetPos( block3:LocalToWorldVector( BlockHeightSpacing ) )

–Adjusts the angles of the two outer blocks
block2:SetAngles( block2:LocalToWorldAngles( Angle(0,0,0) ) )
block3:SetAngles( block3:LocalToWorldAngles( Angle(0,0,0) ) )

–Spawn the blocks
block1:Spawn()
block2:Spawn()
block3:Spawn()

–Remove the child-parent relationship
block2:SetParent( nil )
block3:SetParent( nil )

end
[/lua]

I’m also looking at the LUA code for the “Stacker” STOOL for the answer to my second question, which shows a translucent duplicate of the model you’re aiming at above it. Looks promising so far, and I see some methods in that code that I haven’t seen elsewhere. I’ll edit this post as it progresses.

edit 2:
The previous code works in concept, but the specifics are off. Here’s what I have so far (part of it’s modified and untested, but I’ll note where):
[lua]–Store where the user is aiming
ClickPos = trace.HitPos

–Check to see if the blocks’ spawn location is on the ground
if trace.HitNonWorld then
–It is not, so display an error message in the console, then return
player.GetByID(1):PrintMessage(HUD_PRINTCENTER, “Invalid spawn location – blocks can only be created on the ground”)
return
end

–“Load” the blocks in variables
local block1 = ents.Create(“prop_physics”)
local block2 = ents.Create(“prop_physics”)
local block3 = ents.Create(“prop_physics”)

–Set the correct model
block1:SetModel(BlockModelFilename)
block2:SetModel(BlockModelFilename)
block3:SetModel(BlockModelFilename)

–Set the original block’s position
block1:SetPos(ClickPos)

–Sets the parents of the outer two blocks to the original block
block2:SetParent(block1)
block3:SetParent(block1)

–Create a temporary angle variable
local origBlockAngle = player.GetByID(1):GetForward():Normalize():Angle()

–Set the roll and pitch to zero, respectively (this orients the target towards the player).
origBlockAngle.r = 0
origBlockAngle.p = 0

–Positions the two outer blocks in the right location (UNTESTED)
block2:SetPos(ClickPos + BlockWidthSpacing)
block3:SetPos(ClickPos + BlockHeightSpacing)

–Rotate the original block after setting the positions of the first blocks, moving them where necessary
block1:SetAngles(origBlockAngle)

–Adjusts the angles of the two outer blocks (POSSIBLY UNTESTED)
block2:SetAngles( block2:LocalToWorldAngles( Angle(0,0,0) ) )
block3:SetAngles( block3:LocalToWorldAngles( Angle(0,0,0) ) )

–Spawn the blocks
block1:Spawn()
block2:Spawn()
block3:Spawn()

–Remove the child-parent relationship
block2:SetParent( nil )
block3:SetParent( nil )[/lua]Logically the untested parts should work.

As for ghosting, somehow the “Stacker” STOOL runs on client-side, while mine runs server-side. This gives me a “command not recognized” error when I try and run it. I’m going to try putting the ghosting code in cl_init.lua to see if I can get it to run TOOL:Think() on the client instead. Here’s the code anyways (errors where noted):
[lua]local player1 = player.GetByID(1)
local trace = player1:GetEyeTrace()

–Check to see if the blocks’ spawn location is on the ground
if trace.HitNonWorld then
–Errors out here
self:ReleaseGhostEntity()
return
else
local ghost = ents.Create(“prop_physics”)
ghost:SetModel(BlockModelFilename)
ghost:SetPos(trace.HitPos)

–Create a temporary angle variable
local origBlockAngle = player1:GetForward():Normalize():Angle()

–Set the roll and pitch to zero, respectively (this orients the target towards the player).
origBlockAngle.r = 0
origBlockAngle.p = 0

–Rotate the original block
ghost:SetAngles(origBlockAngle)

–Errors out here
self:MakeGhostEntity(ghost:GetModel(), ghost:GetPos(), ghost:GetAngles())
–self:MakeGhostEntity(ghost:GetModel(), Vector(0, 0, 0), Vector(0, 0, 0))
end[/lua]

I’ll update this again when I get to test it more.