Add New Entities to Menu
Overview The ACE menu uses a tree structure defined in lua/acf/client/cl_acfmenu_gui.lua . Items are registered through definition functions in lua/acf/shared/sh_ace_loader.lua .
File Structure lua/
āāā acf/
ā āāā shared/
ā ā āāā sh_ace_loader.lua # Definition functions & loader
ā ā āāā entities/ # Entity definitions
ā ā ā āāā youritem.lua
ā ā āāā tools/ # Tool definitions
ā ā āāā yourtool.lua
ā āāā client/
ā āāā cl_acfmenu_gui.lua # Menu GUI
āāā entities/
āāā ace_yourentity/ # Entity code
āāā init.lua
āāā cl_init.lua
āāā shared.lua
Adding to an Existing Category If you want to add an item to an existing category (like Entities or Tools ), you only need to create a definition file.
Example: Adding to Entities Category Create lua/acf/shared/entities/myitem.lua :
ACF_DefineEntity("MyItemId", {
name = "My Item Name",
ent = "ace_myentity",
category = "Misc", -- Sub-folder: "Crew" or "Misc"
desc = "Description here.\n\nSupports multiple lines.",
model = "models/props_c17/oildrum001.mdl",
weight = 10,
acepoints = 0,
})
Available Categories Entities - Use ACF_DefineEntity()
- Sub-categories: Crew, Misc
Tools - Use ACF_DefineVHeatSource()
- No sub-categories
Creating a New Category Step 1: Update sh_ace_loader.lua Add at the top with other tables:
local MyCategory = {}
Add base class:
local mycategory_base = {
type = "MyCategory"
}
Add GUI binding in the if CLIENT then block:
mycategory_base.guicreate = function(_, Table) MyCategoryGUICreate(Table) end or nil
mycategory_base.guiupdate = function() return end
Add definition function:
function ACF_DefineMyCategory(id, data)
data.id = id
table.Inherit(data, mycategory_base)
MyCategory[id] = data
end
Add folder to loader:
local folders = { -- ... existing folders ... "mycategory" }
Export at bottom:
ACF.Weapons.MyCategory = MyCategory
Step 2: Add Menu Node (cl_acfmenu_gui.lua) Simple Category do
local myNode = HomeNode:AddNode("My Category", "icon16/brick.png")
for _, ItemData in pairs(FinalContainer["MyCategory"] or {}) do
local ItemNode = myNode:AddNode(ItemData.name or "No Name", ItemIcon2)
ItemNode.mytable = ItemData
function ItemNode:DoClick()
RunConsoleCommand("acfmenu_type", self.mytable.type)
acfmenupanel:UpdateDisplay(self.mytable)
end
end
end
Category with Sub-folders do
local myNode = HomeNode:AddNode("My Category", "icon16/brick.png")
local subA = myNode:AddNode("Sub A", "icon16/folder.png")
local subB = myNode:AddNode("Sub B", "icon16/folder.png")
for _, ItemData in pairs(FinalContainer["MyCategory"] or {}) do
local targetNode
if ItemData.category == "SubA" then
targetNode = subA
elseif ItemData.category == "SubB" then
targetNode = subB
else
targetNode = myNode
end
local ItemNode = targetNode:AddNode(ItemData.name or "No Name", ItemIcon2)
ItemNode.mytable = ItemData
function ItemNode:DoClick()
RunConsoleCommand("acfmenu_type", self.mytable.type)
acfmenupanel:UpdateDisplay(self.mytable)
end
end
end
Step 3: Create GUI Function (cl_acfmenu_gui.lua) Add at the end of file:
function MyCategoryGUICreate(Table)
acfmenupanel:CPanelText("Name", Table.name, "DermaDefaultBold")
if Table.model then
acfmenupanel.CData.DisplayModel = vgui.Create("DModelPanel", acfmenupanel.CustomDisplay)
acfmenupanel.CData.DisplayModel:SetModel(Table.model)
acfmenupanel.CData.DisplayModel:SetCamPos(Vector(50, 50, 40))
acfmenupanel.CData.DisplayModel:SetLookAt(Vector(0, 0, 10))
acfmenupanel.CData.DisplayModel:SetFOV(35)
acfmenupanel.CData.DisplayModel:SetSize(acfmenupanel:GetWide(), acfmenupanel:GetWide() * 0.5)
acfmenupanel.CData.DisplayModel.LayoutEntity = function() end
acfmenupanel.CustomDisplay:AddItem(acfmenupanel.CData.DisplayModel)
end
acfmenupanel:CPanelText("Desc", "\n" .. Table.desc)
if Table.weight then
acfmenupanel:CPanelText("Weight", "\nWeight: " .. Table.weight .. " kg")
end
acfmenupanel.CustomDisplay:PerformLayout()
end
Creating the Entity shared.lua ENT.Type = "anim"
ENT.Base = "base_wire_entity"
ENT.PrintName = "ACE My Entity"
ENT.WireDebugName = "ACE My Entity"
ENT.Author = "Your Name"
ENT.Category = "ACE - Entities"
ENT.Spawnable = false
ENT.AdminSpawnable = false
DEFINE_BASECLASS("base_wire_entity")
### cl_init.lua
include("shared.lua")
local ACF_InfoWhileSeated = CreateClientConVar("ACF_GunInfoWhileSeated", 0, true, false)
function ENT:Draw()
local lply = LocalPlayer()
local hideBubble = not ACF_InfoWhileSeated:GetBool() and IsValid(lply) and lply:InVehicle()
self.BaseClass.DoNormalDraw(self, false, hideBubble)
Wire_Render(self)
end
init.lua AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
DEFINE_BASECLASS("base_wire_entity")
local EntityTable = ACF.Weapons.MyCategory
function ENT:Initialize()
self.Inputs = WireLib.CreateInputs(self, {})
self.Outputs = WireLib.CreateOutputs(self, {
"MyOutput (Description)",
})
self:UpdateOverlayText()
end
function MakeACE_MyEntity(Owner, Pos, Angle, Id, EntityData)
if not Owner:CheckLimit("_ace_myentity") then return false end
Id = Id or "MyItemId"
local entData = EntityTable[Id]
if not entData then return false end
local ent = ents.Create("ace_myentity")
if not IsValid(ent) then return false end
ent:SetAngles(Angle)
ent:SetPos(Pos)
ent.Model = entData.model
ent.Weight = entData.weight
ent.ACFName = entData.name
ent.ACEPoints = entData.acepoints or 0
ent.Id = Id
ent:Spawn()
ent:CPPISetOwner(Owner)
ent:SetNWNetwork()
ent:SetModelEasy(entData.model)
Owner:AddCount("_ace_myentity", ent)
Owner:AddCleanup("acfmenu", ent)
return ent
end
list.Set("ACFCvars", "ace_myentity", {"id", "entitydata"})
duplicator.RegisterEntityClass("ace_myentity", MakeACE_MyEntity, "Pos", "Angle", "Id", "Data")
function ENT:SetNWNetwork()
self:SetNWString("WireName", self.ACFName or "My Entity")
end
function ENT:SetModelEasy(mdl)
self:SetModel(mdl)
self.Model = mdl
self:PhysicsInit(SOLID_VPHYSICS)
self:SetMoveType(MOVETYPE_VPHYSICS)
self:SetSolid(SOLID_VPHYSICS)
local phys = self:GetPhysicsObject()
if IsValid(phys) then
phys:SetMass(self.Weight or 10)
end
end
function ENT:UpdateOverlayText()
self:SetOverlayText("My Entity\n\nStatus: Active")
end
function ENT:Think()
self:UpdateOverlayText()
self:NextThink(CurTime() + 0.1)
return true
end
GUI Helper Reference Text acfmenupanel:CPanelText("Id", "Text") acfmenupanel:CPanelText("Id", "Bold", "DermaDefaultBold") Slider acfmenupanel:AmmoSlider("VarName", default, min, max, decimals, "Title", "Desc") Checkbox acfmenupanel:AmmoCheckbox("VarName", "Title", "Desc", "Tooltip") Dropdown local combo = vgui.Create("DComboBox", acfmenupanel.CustomDisplay) combo:SetSize(acfmenupanel.CustomDisplay:GetWide(), 30) combo:AddChoice("Option", "value") combo.OnSelect = function(_, _, value) RunConsoleCommand("acfmenu_data", value) end
acfmenupanel.CustomDisplay:AddItem(combo) Icon Reference
- icon16/brick.png - Generic item
- icon16/bricks.png - Category
- icon16/cog.png - Misc/settings
- icon16/user.png - Crew
- icon16/transmit.png - Sensors
- icon16/car.png - Mobility
- icon16/box.png - Ammo
- icon16/folder.png - Sub-folder
- icon16/plugin.png - Tools
Checklist When adding to existing category:
- Definition file in lua/acf/shared/category/
- Entity folder with init.lua , cl_init.lua , shared.lua
When creating new category (additional steps):
- Storage table in sh_ace_loader.lua
- Base class and GUI binding
- Definition function
- Folder in loader list
- Export table
- Menu node in cl_acfmenu_gui.lua
- GUI create function