Add New Entities to Menu

šŸ› ļø Modifying & ContributingUpdated 5 days ago•5 views2 revisions
Learn how to add entities to ACE menu. Covers coding aspect of it

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

Was this article helpful?

See More

Discussion(0)

No comments yet. Be the first to ask a question!

Have a question? Sign in to join the discussion.