How to use function identifiers properly

So, I am having some trouble with running a derma button in cl_init.lua to run a function in init.lua. I can get it to call it, but the content in my function does not work.
**
Originally** in the init.lua it was:


function poppygrow(self)
	growtime = 2
	-- Timers
	self:SetModel("models/pot/pot_06.mdl")
	if !IsValid(self) then return end
	timer.Create( "timer1", growtime, 1, function()
		if !IsValid(self) then return end
		self:SetModel("models/pot/pot_07.mdl")
		timer.Create( "timer2", growtime, 1, function()
			if !IsValid(self) then return end
			self:SetModel("models/pot/pot_08.mdl")	
			timer.Create( "timer3", growtime, 1, function()
				if !IsValid(self) then return end
				self:SetModel("models/pot/pot_09.mdl")
				timer.Create( "timer4", growtime, 1, function()
					if !IsValid(self) then return end
					self:SetModel("models/pot/pot_10.mdl")
					self.isUsable = true
				end)
			end)
		end)
	end)
end

This worked fine, I could call it using:


function ENT:Use(activator)
    poppygrow(self)
end	

This was fine, then I created a derma button which inside the press function (so when you press it down it does):


net.Start("start_pop_grow")
		net.SendToServer()

This is the problem is when calling the poppygrow(self) function it does not work. I have this:


net.Receive( "start_pop_grow", function ( self )
	growtime = 2
	-- Timers
	self:SetModel("models/pot/pot_06.mdl")
	if !IsValid(self) then return end
	timer.Create( "timer1", growtime, 1, function()
		if !IsValid(self) then return end
		self:SetModel("models/pot/pot_07.mdl")
		timer.Create( "timer2", growtime, 1, function()
			if !IsValid(self) then return end
			self:SetModel("models/pot/pot_08.mdl")	
			timer.Create( "timer3", growtime, 1, function()
				if !IsValid(self) then return end
				self:SetModel("models/pot/pot_09.mdl")
				timer.Create( "timer4", growtime, 1, function()
					if !IsValid(self) then return end
					self:SetModel("models/pot/pot_10.mdl")
					self.isUsable = true
				end)
			end)
		end)
	end)
end)

It is saying that “self” is the error. Does someone mind explaining how this works? I am not looking for an answer (if you can that is great) but I want to understand how this works and what to do instead of the “self”?

Thanks guys

With

net.Receive you take the parameters:



(number) length - Length of the message, in bits
(Player) ply - The player that sent the message, works only serverside

For example:

net.Receive( "my_message", function( len, pl )
    print( ply:Nick() .. " sent me a net message" )
end


Self refers to the object itself, like when you’re inside the function you wrote:



function ENT:Use(activator)
    poppygrow(self)
end


This self just refers to the ‘ENT’ part. Since you’re inside the code of the entity. When you send a net message, you’re not inside the entity so it doesn’t know what you’re referring to.

Remember that anyone can just craft and send a net message to the server, so make sure you do some sort of server-side check such as distance of the plant to the player to make sure they’re not upgrading plants from across the map, I’m not sure what you’re trying to fully create so it’s hard to give specifics.

EDIT: Thinking about it actually that code that I snipped was an excessive way to do it, let me quickly test something and get back to you

Thank you for that, it really helped! :smile:

So what if I already have the entity name (which is “poppy_plant”). And I take it because I sent a message I cannot “get inside the entity” to do the self?

You said about needing more code but I would like to see if I can solve it (I just need directions).

What are some other “alternatives”? Could I use a conCommand to start the function?

Ignore that part that I snipped, I wasn’t thinking properly, if you throw your



net.Receive( "start_pop_grow", function ( len, ply )
	growtime = 2
	-- Timers
	self:SetModel("models/pot/pot_06.mdl")
	if !IsValid(self) then return end
	timer.Create( "timer1", growtime, 1, function()
		if !IsValid(self) then return end
		self:SetModel("models/pot/pot_07.mdl")
		timer.Create( "timer2", growtime, 1, function()
			if !IsValid(self) then return end
			self:SetModel("models/pot/pot_08.mdl")	
			timer.Create( "timer3", growtime, 1, function()
				if !IsValid(self) then return end
				self:SetModel("models/pot/pot_09.mdl")
				timer.Create( "timer4", growtime, 1, function()
					if !IsValid(self) then return end
					self:SetModel("models/pot/pot_10.mdl")
					self.isUsable = true
				end)
			end)
		end)
	end)
end)


inside of your ENT:Initialize() then your net message is running ‘inside’ of the entity, you still need the correct parameters if you want to use them however.

But I wouldn’t use this way of doing things, that above is just to explain the ‘self’. If you use the above code it should work, but only for the last plant spawned. Since every time you spawn one it’ll override the net receive from the previous one. The way I’d do it depends on what you’re actually creating, I’m assuming you want it so that the player can press E on the plant and it’ll grow? I’m having trouble understanding the derma part, pressing E on the plant opens a menu which the player can press a button to grow the plant?

If that’s the case I’d have the client send to the server the entity that needs to be changed using net.WriteEntity. Then verify on the server that the player is actually near to the plant to stop people growing plants from across the map, perhaps even a check to see if they own it (not sure on specifics). Then you’d run your timer code but using the entity sent to the server (net.ReadEntity()) instead of ‘self’.