Best way to attach an 'entity' to player?

Hello,

I’m trying to add a ‘model attachment system’ in my gamemode, and everything’s good, except I want to do one thing.

I want the entity’s pos and ang to be set on the server every frame, but i don’t think that’s going to happen. This is my current code:

All clientside:



function AttachModels()
	local BoneIndx = LocalPlayer():LookupBone("ValveBiped.Bip01_Spine2")
	local BonePos, BoneAng = LocalPlayer():GetBonePosition( BoneIndx )
	BoneAng:RotateAroundAxis(BoneAng:Right(), 0)
	BoneAng:RotateAroundAxis(BoneAng:Up(), 180)
	BoneAng:RotateAroundAxis(BoneAng:Forward(), 90)
	globalang = BoneAng
	globalpos = BonePos + globalang:Up() * -5.2 + globalang:Forward() * 0
end

hook.Add("PrePlayerDraw", "Attach Models", AttachModels)

function ENT:Draw()
	self:SetRenderOrigin( globalpos )
	self:SetRenderAngles( globalang )
	self:SetupBones()
	self:DrawModel()
end


which results in this when ‘item_attachment’ entity was spawned:

http://vxservers.net/person.png

The reason I want the entity to set position to player every frame is so that if a bullet is shot at the entity, it will pass to the player as half the bullet damage, but I figured i guess I could just set a player variable, and on PlayerHurt, check if the player has it on, if so, do half damage, if not, do normal damage. Would that work?

Well, yeah, if you want it not to look so messy and update whenever player moves (so it doesn’t really teleport) then you have to do it clientside.

and I am not sure what is the best way, but a lot of people use :SetParent().

Well, what you could do is have an invisible entity that is serverside, and draw it clientside.

I’ve seen people who use SetParent, but the issue with that, and I’ll use an example with vehicles: The issue is they don’t update pvs, and what happens which it being improperly done is props floating around the map / becoming detached from the parent.

The way I do it is 100% client-side and have had no issues. There’s no need to create an entity. Simply send a net-message that x entity has y attachment, let the client render it from there. Sync that when new players join.

Sorry to hijack,
Would this method resolve issues with hitboxes in prop hunt?
It is a bit too advanced for me to grasp how to code though :confused:

The method of drawing clientsidemodels wouldn’t block hit-boxes if that’s what you’re asking. It’s essentially the client rendering an object in a certain location; the server knows nothing about it, aside from the data of it saying attachment x, or y, or whatever.

I’m doing that right now, only problem is the model only draws when the actual serverside entity is visible on the client :confused:

Download and look at my addon, as far as attachments go i’d consider this method pretty good, it’s not the best, but i’ve stress tested it with 1,000 attachments with 20 players with none-to-5 fps loss on few clients.

http://forum.facepunch.com/showthread.php?t=1323107

In other words, utilize DTVars on a custom entity, although it is more efficient to render a bunch of models than to have several entities, obviously. The get around to this is use DTVars on the player entity, which can be limiting, or use a shared table stored on the player object( my most updated version kind of uses a combination of both but my pc got all fucked up and i had to wipe so a few versions were lost)

Your method seems really efficient, but I think I’m gonna go with entities drawn client side for multiple reasons. I also want to know if the entity’s model isn’t drawing because the server side entity must be visible by the player (even though the server entity is invisible and no physics and stuff on it), is that really why it sometimes doesn’t draw??

this isn’t the “tech-lingo” for explaining this, but in order for me to get flawless updating i need to make sure it’s being updated on the server, and on the client. I’ve actually never seen it done any other way, nobody ends up sticking with parenting( i’d assume it just has to do with how maintaining a position in parenting works). I’d assume the server just can’t update the position as fast as it can on the client( considering the send time ), so it lags behind.

And yes, PVS is definitely a concern for things like this.

[editline]25th March 2014[/editline]

entity
[lua]
AddCSLuaFile()

ENT.Type = “anim”
ENT.PrintName = “WAE Attachment”
ENT.Category = “WAE Attachment”
ENT.Author = “LauScript”

function ENT:SetupDataTables()
self:NetworkVar(“Vector”, 0, “AttachOffset”);
self:NetworkVar(“Angle”, 0, “AttachAngles”);
self:NetworkVar(“Entity”, 0, “AttachParent”);
self:NetworkVar(“Int”, 0, “AttachBoneIndex” );
self:NetworkVar( “String”, 0, “AttachClass” );
end

if (SERVER) then
function ENT:Initialize()
self:SetModel(“models/props_junk/watermelon01.mdl”);
self:SetSolid(SOLID_NONE);
self:PhysicsInit(SOLID_NONE);
self:SetMoveType(MOVETYPE_NONE);

	local physicsObject = self:GetPhysicsObject();

	if (IsValid(physicsObject)) then
		physicsObject:EnableMotion(true);
		physicsObject:Wake();
	end
end;

end;

function ENT:Think()
if ( CLIENT ) then
local pos,ang = self:GetAttachmentPosition();

	self:SetPos( pos );
	self:SetAngles( ang );
end;

end;

function ENT:GetAttachmentPosition()
local pos,ang = self:GetAttachOffset(), self:GetAttachAngles();
local parent,bone = self:GetAttachParent(), self:GetAttachBoneIndex();

if ( pos and ang and parent and bone ) then
	local bonepos,boneang = parent:GetBonePosition(bone);
	local x,y,z = boneang:Up() * pos.x, boneang:Right() * pos.y, boneang:Forward() * pos.z;
	
	boneang:RotateAroundAxis(boneang:Forward(), ang.p);
	boneang:RotateAroundAxis(boneang:Right(), ang.y);
	boneang:RotateAroundAxis(boneang:Up(), ang.r);
	
	return bonepos + x + y + z, boneang;
end;

end;

if ( CLIENT ) then

function ENT:Draw()
local ap = self:GetAttachParent();
local active = ap:GetActiveWeapon();

if ( active and active != NULL ) then
	if ( active:GetClass() == self:GetAttachClass() or not ap:Alive() ) then
		return;
	else
		self:DrawModel();
	end;
end;

end

end;
[/lua]

update func

[lua]
function _PLAYER:UpdateWeaponAttachments()
if ( not self.WeaponAttachments ) then
self.WeaponAttachments = {};
end;

for _,weapon in pairs( self:GetWeapons() ) do
	local class = weapon:GetClass();
	if ( not self.WeaponAttachments[class] and not table.HasValue(WAE.blacklist, class)) then
		local attachment = ents.Create("wae_attachment");
		local offsetpos, offsetang, bone = Vector(-3.96, 4.95, -2.97), Angle(0,0,0), "ValveBiped.Bip01_Spine";
		local ht = weapon:GetHoldType();
		local model = weapon:GetModel();
		
		if ( WAE.modelreg[model] ) then
			offsetpos = WAE.modelreg[model][2];
			offsetang = WAE.modelreg[model][3];
			bone = WAE.modelreg[model][1];
		elseif ( WAE.htreg[ht] ) then
			offsetpos = WAE.htreg[ht][2];
			offsetang = WAE.htreg[ht][3];
			bone = WAE.htreg[ht][1];
		end;
		
		attachment:SetModel(model);
		attachment:SetAttachParent(self);
		attachment:SetAttachOffset(offsetpos);
		attachment:SetAttachAngles(offsetang);
		attachment:SetAttachBoneIndex( self:LookupBone(bone) );
		attachment:SetAttachClass(weapon:GetClass() );
		attachment:SetParent(self);
		
		self.WeaponAttachments[weapon:GetClass()] = attachment;
	end;
end;

for k,v in pairs( self.WeaponAttachments ) do
	local gw = self:GetWeapon(k);
	if ( not gw or gw == NULL ) then
		v:Remove();
		self.WeaponAttachments[k] = nil;
	end;
end;

end;
[/lua]

they’re outdated but good refs