Dynamic Global Entity List

Haven’t coded lua in awhile so I’m trying to make a mod that involves growing plants. I’m working on a derma panel that lists all the plants spawned in categories of the plant type. But I can’t really figure out how to make a global table of all the plant entities spawned. Can someone please tell me the correct way to do so?

Here is my current code, the menu opens, sees the table, and puts it’s content on the list. But the entities don’t add themselves to the table after they’re spawned.

menu.lua



function Playermenu()


local ply = LocalPlayer;

local DermaPanel = vgui.Create( "DFrame" )
DermaPanel:SetPos( 50,50 )
DermaPanel:SetSize( 500, 700 )
DermaPanel:SetTitle( "Plant List" )
DermaPanel:SetVisible( true )
DermaPanel:SetDraggable( true )
DermaPanel:ShowCloseButton( true )
DermaPanel:MakePopup()
 
local DermaListView = vgui.Create("DListView")
DermaListView:SetParent(DermaPanel)
DermaListView:SetPos(25, 50)
DermaListView:SetSize(450, 625)
DermaListView:SetMultiSelect(false)
DermaListView:AddColumn("ID") -- Add column
DermaListView:AddColumn("Location")

for k,v in pairs(spawnedPlants) do
    DermaListView:AddLine(k,string(v)) -- Add lines
end

end

concommand.Add("plants_menu", Playermenu)


Tables



spawnedPlants = {}


Entity’s init.lua




AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include( 'shared.lua' )
include( 'autorun/client/Menu_Tables.lua' )

local max_melons = 10;
local planted_melons = 0;

function ENT:Initialize()

	
	local id = math.Round(math.Rand(0,9999999));
	
	
	self.ID = id
	// self.GrowTime = math.Round(math.Rand(0,120)) // seconds, not milliseconds!
	self.GrowTime = 5;
	self.StringName = "MELON";
	self.HealthIncrease = 25;
	
	self:PhysicsInit( SOLID_VPHYSICS )
	self:SetMoveType( MOVETYPE_VPHYSICS )
	self:SetSolid( SOLID_VPHYSICS )
	
	// Use the bugbait model just for the seed shape(because it's about the same size)
	self.Entity:SetModel( "models/weapons/w_bugbait.mdl" )
	
end

function ENT:SpawnFunction( ply, tr )

	if ( !tr.Hit ) then return end
	
	local SpawnPos = tr.HitPos + tr.HitNormal * 2
	local pos = SpawnPos;
	
	if(planted_melons <= max_melons) then
	local ent = ents.Create( "sent_melon" )
	if(ent != nil) then planted_melons = planted_melons + 1; end;
		ent:SetPos( SpawnPos )
		ent:Spawn()
		ent:Activate()	
		ply:ChatPrint("Melon ID " ..ent.ID.. " has just been planted!");
		
			tempTable = {ent.ID, pos};
			print("Added " ..ent.ID.. " to table");
			table.Add(spawnedPlants, tempTable);
			
		startTimerSequence( ent, ply );
		
	
	else
		ply:EmitSound("/buttons/weapon_cant_buy.wav", 500, 200)
		ply:ChatPrint("Maxmimum plants of the type "..self.StringName.. " have been placed globally!");
	end
	
end

function startTimerSequence( ent, ply )

 if(ent.GrowTime > 0) then

 ent.GrowTime = ent.GrowTime - 1;
	timer.Simple(1, startTimerSequence, ent, ply);
else
	ent:SetModel("models/props_junk/watermelon01.mdl");
	ent:EmitSound("/ambient/creatures/pigeon_idle4.wav", 500, 200)
	ply:ChatPrint("Melon ID " ..ent.ID.. " has just grown!");
	ent.GrowTime = 0;
end
	
end


function ENT:Use( activator, caller )

if(self.GrowTime <= 0) then
	activator:SetHealth(activator:Health() + self.HealthIncrease)
	planted_melons = planted_melons - 1;
		self:Remove()
	end
	
end




They would add themselves if you re-open the window, this is because you’re just putting them in a table that is only looped through upon initialization of your derma.

What you could do is:

  • re-build the panel, you need to have a global function or panel for this
  • add a simple refresh button that :Clear()'s the list and re-does the loop through the table.

It still doesn’t seem to work.

New code:



include('Menu_Tables.lua');


function Playermenu()


local ply = LocalPlayer;

DermaPanel = vgui.Create( "DFrame" )
DermaPanel:SetPos( 50,50 )
DermaPanel:SetSize( 500, 700 )
DermaPanel:SetTitle( "Plant List" )
DermaPanel:SetVisible( true )
DermaPanel:SetDraggable( true )
DermaPanel:ShowCloseButton( true )
DermaPanel:MakePopup()
 
DermaListView = vgui.Create("DListView")
DermaListView:SetParent(DermaPanel)
DermaListView:SetPos(25, 50)
DermaListView:SetSize(450, 625)
DermaListView:SetMultiSelect(false)
DermaListView:AddColumn("ID") -- Add column
DermaListView:AddColumn("Location")

 
button = vgui.Create( "DButton", window )
	button:SetSize( 100, 30 )
	button:SetPos( 15, 15 )
	button:SetText( "Refresh" )
	button:SetParent(DermaPanel);
	button.DoClick = function( button )
	print("Scanning for new plants...");
	getNewList(DermaListView);
	print("Finished scanning for plants");
	
	end
 

end

function getNewList(DL)

DL:Clear();
for k,v in pairs(spawnedPlants) do
    DL:AddLine(k) -- Add lines
	print("Added");
	end
	
end

concommand.Add("plants_menu", Playermenu)


This is what’s wrong, other than it not being parented to the right window, the SpawnFunction is called on the server and you’re adding it to the table there. Meaning that you have to network the table everytime. Seeing how it’s an entity, you could use ents.FindByClass(“foldernameofentity”) instead of spawnedPlants

Okay thanks, I fixed it. I also have another question, how do I detect if the seed is placed on a dirt/ grass material and nothing else?

Trace down to the ground where you want to place the seed and check the ground material with HitTexture