Структура проекта для директории: c:\Program Files (x86)\Steam\steamapps\common\GarrysMod\garrysmod\addons\gmod-industrialization

[Файл] addon.txt
    "AddonInfo"
    {
        "name"          "Industrialization System"
        "version"       "1.0"
        "up_date"       "2024-04-27"
        "author_name"   "YourName"
        "author_email"  "youremail@example.com"
        "info"          "Simulates a robust production and automation environment within GMod."
        "url"           "https://youraddonwebsite.com"
    }
[Папка] lua/
    [Папка] autorun/
        [Файл] industrialization_init.lua
            -- lua/autorun/industrialization_init.lua
            
            if SERVER then
                -- Include all server-side entity scripts
                AddCSLuaFile("entities/basic_factory/cl_init.lua")
                AddCSLuaFile("entities/basic_factory/shared.lua")
                AddCSLuaFile("entities/resource_node/cl_init.lua")
                AddCSLuaFile("entities/resource_node/shared.lua")
                AddCSLuaFile("entities/automated_harvester/cl_init.lua")
                AddCSLuaFile("entities/automated_harvester/shared.lua")
                AddCSLuaFile("entities/smelter/cl_init.lua")
                AddCSLuaFile("entities/smelter/shared.lua")
                AddCSLuaFile("entities/assembly_machine/cl_init.lua")
                AddCSLuaFile("entities/assembly_machine/shared.lua")
                AddCSLuaFile("entities/warehouse/cl_init.lua")
                AddCSLuaFile("entities/warehouse/shared.lua")
                AddCSLuaFile("entities/generator/cl_init.lua")
                AddCSLuaFile("entities/generator/shared.lua")
                AddCSLuaFile("entities/power_distribution_unit/cl_init.lua")
                AddCSLuaFile("entities/power_distribution_unit/shared.lua")
                AddCSLuaFile("entities/plc/cl_init.lua")
                AddCSLuaFile("entities/plc/shared.lua")
            
                -- Include server-side modules
                include("shared/resource_types.lua")
                include("modules/resource_management.lua")
                include("modules/power_system.lua")
                include("modules/utility.lua")
            
                -- Spawn initial resource nodes on server startup
                hook.Add("InitPostEntity", "Industrialization_SpawnResourceNodes", function()
                    SpawnInitialResourceNodes()
                end)
            else
                -- Client-side includes
                include("entities/basic_factory/cl_init.lua")
                include("entities/resource_node/cl_init.lua")
                include("entities/automated_harvester/cl_init.lua")
                include("entities/smelter/cl_init.lua")
                include("entities/assembly_machine/cl_init.lua")
                include("entities/warehouse/cl_init.lua")
                include("entities/generator/cl_init.lua")
                include("entities/power_distribution_unit/cl_init.lua")
                include("entities/plc/cl_init.lua")
            
                -- Include client-side modules
                include("modules/ui_elements.lua")
            end
    [Папка] entities/
        [Папка] assembly_machine/
            [Файл] cl_init.lua
                -- lua/entities/assembly_machine/cl_init.lua
                
                include("shared.lua")
                
                -- Function to open assembly machine control panel
                function OpenAssemblyMachineControlPanel(assemblyMachine)
                    if not IsValid(assemblyMachine) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_AssemblyMachineControlFrame")) then return end
                
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Assembly Machine Control Panel")
                    frame:SetSize(300, 200)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_AssemblyMachineControlFrame")
                
                    local startButton = vgui.Create("DButton", frame)
                    startButton:SetText("Start Assembling")
                    startButton:SetPos(50, 50)
                    startButton:SetSize(200, 30)
                    startButton.DoClick = function()
                        assemblyMachine:StartAssembling()
                        frame:Close()
                    end
                
                    local stopButton = vgui.Create("DButton", frame)
                    stopButton:SetText("Stop Assembling")
                    stopButton:SetPos(50, 100)
                    stopButton:SetSize(200, 30)
                    stopButton.DoClick = function()
                        assemblyMachine:StopAssembling()
                        frame:Close()
                    end
                end
                
                -- Example: Receive assembly machine updates
                net.Receive("Industrialization_UpdateAssemblyMachine", function()
                    local assemblyMachine = net.ReadEntity()
                    local isAssembling = net.ReadBool()
                    local inputRefinedMetal = net.ReadInt(32)
                    local inputElectronics = net.ReadInt(32)
                    local outputAdvancedGadget = net.ReadInt(32)
                
                    if not IsValid(assemblyMachine) then return end
                
                    -- Optional: Display information above the assembly machine
                    hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawAssemblyMachineInfo", function()
                        if not IsValid(assemblyMachine) then return end
                        cam.Start3D2D(assemblyMachine:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText("Assembly Machine", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Assembling: " .. (isAssembling and "Yes" or "No"), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Refined Metal: " .. inputRefinedMetal, "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Electronics: " .. inputElectronics, "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Advanced Gadget: " .. outputAdvancedGadget, "DermaDefault", 0, 80, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        cam.End3D2D()
                    end)
                end)
            [Файл] init.lua
                -- lua/entities/assembly_machine/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_combine/breenglobe.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetAssembling(false)
                    self:SetInputRefinedMetal(0)
                    self:SetInputElectronics(0)
                    self:SetOutputAdvancedGadget(0)
                
                    -- Register as a power consumer
                    RegisterConsumer(self, 15) -- Example: needs 15 power units
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open assembly machine control panel (handled client-side)
                    if SERVER then
                        activator:SendLua("OpenAssemblyMachineControlPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to start assembling
                function ENT:StartAssembling()
                    if self:GetAssembling() then return end
                    if self:GetInputRefinedMetal() < 2 or self:GetInputElectronics() < 1 then
                        NotifyPlayer(nil, "Not enough resources to start assembling.")
                        return
                    end
                
                    self:SetAssembling(true)
                    timer.Simple(10, function()
                        if not IsValid(self) then return end
                        if self:GetInputRefinedMetal() >= 2 and self:GetInputElectronics() >= 1 then
                            self:SetInputRefinedMetal(self:GetInputRefinedMetal() - 2)
                            self:SetInputElectronics(self:GetInputElectronics() - 1)
                            self:SetOutputAdvancedGadget(self:GetOutputAdvancedGadget() + 1)
                            NotifyAll("An Assembly Machine has produced 1 Advanced Gadget.")
                        end
                        self:SetAssembling(false)
                    end)
                end
                
                -- Function to stop assembling (if applicable)
                function ENT:StopAssembling()
                    if not self:GetAssembling() then return end
                    self:SetAssembling(false)
                    NotifyAll("An Assembly Machine has stopped assembling.")
                end
                
                function ENT:Think()
                    -- Continuous logic can be added here if needed
                    self:NextThink(CurTime() + 1)
                    return true
                end
            [Файл] shared.lua
                -- lua/entities/assembly_machine/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Assembly Machine"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("Bool", 0, "Assembling")
                    self:NetworkVar("Int", 1, "InputRefinedMetal")
                    self:NetworkVar("Int", 2, "InputElectronics")
                    self:NetworkVar("Int", 3, "OutputAdvancedGadget")
                end
        [Папка] automated_harvester/
            [Файл] cl_init.lua
                -- lua/entities/automated_harvester/cl_init.lua
                
                include("shared.lua")
                
                -- Function to open harvester configuration panel
                function OpenHarvesterConfigPanel(harvester)
                    if not IsValid(harvester) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_HarvesterConfigFrame")) then return end
                
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Harvester Configuration")
                    frame:SetSize(300, 200)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_HarvesterConfigFrame")
                
                    local resourceLabel = vgui.Create("DLabel", frame)
                    resourceLabel:SetText("Resource Type:")
                    resourceLabel:SetPos(50, 50)
                    resourceLabel:SizeToContents()
                
                    local resourceCombo = vgui.Create("DComboBox", frame)
                    resourceCombo:SetPos(150, 45)
                    resourceCombo:SetSize(100, 20)
                    for key, res in pairs(ResourceTypes) do
                        resourceCombo:AddChoice(res.name, key)
                    end
                    resourceCombo.OnSelect = function(panel, index, value, data)
                        harvester:SetResourceType(data)
                        frame:Close()
                    end
                
                    local intervalLabel = vgui.Create("DLabel", frame)
                    intervalLabel:SetText("Harvest Interval (s):")
                    intervalLabel:SetPos(50, 100)
                    intervalLabel:SizeToContents()
                
                    local intervalSlider = vgui.Create("DNumSlider", frame)
                    intervalSlider:SetPos(50, 120)
                    intervalSlider:SetSize(200, 20)
                    intervalSlider:SetText("")
                    intervalSlider:SetMin(5)
                    intervalSlider:SetMax(60)
                    intervalSlider:SetDecimals(0)
                    intervalSlider:SetValue(harvester:GetHarvestInterval())
                    intervalSlider.OnValueChanged = function(panel, value)
                        harvester:SetHarvestInterval(math.Round(value))
                    end
                end
                
                -- Optional: Display information above the harvester
                hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawHarvesterInfo", function()
                    for _, harvester in ipairs(ents.FindByClass("automated_harvester")) do
                        if not IsValid(harvester) then return end
                        cam.Start3D2D(harvester:GetPos() + Vector(0, 0, 60), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText("Automated Harvester", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Resource: " .. ResourceTypes[harvester:GetResourceType()].name, "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Interval: " .. harvester:GetHarvestInterval() .. "s", "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        cam.End3D2D()
                    end
                end)
            [Файл] init.lua
                -- lua/entities/automated_harvester/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_c17/oildrum001.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetResourceType("metal") -- Default resource type
                    self:SetHarvestInterval(10) -- Harvest every 10 seconds
                
                    self.NextHarvest = CurTime() + self:GetHarvestInterval()
                
                    -- Register as a power consumer
                    RegisterConsumer(self, 5) -- Example: needs 5 power units
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open a configuration UI (handled client-side)
                    if SERVER then
                        activator:SendLua("OpenHarvesterConfigPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to harvest resources
                function ENT:HarvestResource()
                    local resourceType = self:GetResourceType()
                    if not ResourceTypes[resourceType] then return end
                
                    local storage = GetNearestStorage(self:GetPos())
                    if not IsValid(storage) then
                        NotifyPlayer(nil, "No available storage nearby for Automated Harvesters.")
                        return
                    end
                
                    storage:AddResource(resourceType, 1)
                    NotifyAll("An Automated Harvester has collected 1 " .. ResourceTypes[resourceType].name)
                end
                
                function ENT:Think()
                    -- Check if the harvester has power
                    if not self:HasPower() then
                        self:NextThink(CurTime() + 1)
                        return true
                    end
                
                    if CurTime() >= self.NextHarvest then
                        self:HarvestResource()
                        self.NextHarvest = CurTime() + self:GetHarvestInterval()
                    end
                
                    self:NextThink(CurTime() + 1)
                    return true
                end
                
                -- Function to receive power status
                function ENT:ReceivePower(status)
                    self.HasPower = status
                    if not status then
                        NotifyAll("An Automated Harvester has lost power and has stopped harvesting.")
                    end
                end
                
                -- Placeholder function to check power status (can be expanded)
                function ENT:HasPower()
                    return self.HasPower == true
                end
            [Файл] shared.lua
                -- lua/entities/automated_harvester/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Automated Harvester"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("String", 0, "ResourceType")
                    self:NetworkVar("Int", 1, "HarvestInterval") -- in seconds
                end
        [Папка] basic_factory/
            [Файл] cl_init.lua
                -- lua/entities/basic_factory/cl_init.lua
                
                include("shared.lua")
                
                net.Receive("Industrialization_UpdateFactory", function()
                    local factory = net.ReadEntity()
                    local isProcessing = net.ReadBool()
                    local inputMetal = net.ReadInt(32)
                    local outputRefinedMetal = net.ReadInt(32)
                
                    if not IsValid(factory) then return end
                
                    -- Optional: Display information above the factory
                    hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawFactoryInfo", function()
                        if not IsValid(factory) then return end
                        cam.Start3D2D(factory:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText("Basic Factory", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Processing: " .. (isProcessing and "Yes" or "No"), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Input Metal: " .. inputMetal, "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Refined Metal: " .. outputRefinedMetal, "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        cam.End3D2D()
                    end)
                end)
            [Файл] init.lua
                -- lua/entities/basic_factory/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_borealis/bluebarrel001a.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_VPHYSICS)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetProcessing(false)
                    self:SetInputMetal(0)
                    self:SetOutputRefinedMetal(0)
                
                    -- Register as a power consumer
                    RegisterConsumer(self, 5) -- Example: needs 5 power units
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open a control panel UI (handled client-side)
                    if SERVER then
                        activator:SendLua("CreateFactoryControlPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to start processing
                function ENT:StartProcessing()
                    if self:GetProcessing() then return end
                    if self:GetInputMetal() < 1 then
                        NotifyPlayer(nil, "Not enough Metal to start processing.")
                        return
                    end
                
                    self:SetProcessing(true)
                    timer.Simple(5, function()
                        if not IsValid(self) then return end
                        if self:GetInputMetal() >= 1 then
                            self:SetInputMetal(self:GetInputMetal() - 1)
                            self:SetOutputRefinedMetal(self:GetOutputRefinedMetal() + 1)
                            NotifyAll("A factory has processed 1 Metal into Refined Metal.")
                        end
                        self:SetProcessing(false)
                    end)
                end
                
                -- Function to stop processing (if applicable)
                function ENT:StopProcessing()
                    if not self:GetProcessing() then return end
                    self:SetProcessing(false)
                    NotifyAll("A factory has stopped processing.")
                end
                
                function ENT:Think()
                    -- Continuous logic can be added here if needed
                    self:NextThink(CurTime() + 1)
                    return true
                end
            [Файл] shared.lua
                -- lua/entities/basic_factory/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Basic Factory"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("Bool", 0, "Processing")
                    self:NetworkVar("Int", 1, "InputMetal")
                    self:NetworkVar("Int", 2, "OutputRefinedMetal")
                end
        [Папка] generator/
            [Файл] cl_init.lua
                -- lua/entities/generator/cl_init.lua
                
                include("shared.lua")
                
                -- Function to open generator refuel panel
                function OpenGeneratorRefuelPanel(generator)
                    if not IsValid(generator) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_GeneratorRefuelFrame")) then return end
                
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Generator Refuel Panel")
                    frame:SetSize(300, 150)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_GeneratorRefuelFrame")
                
                    local fuelLabel = vgui.Create("DLabel", frame)
                    fuelLabel:SetText("Fuel to Add:")
                    fuelLabel:SetPos(50, 50)
                    fuelLabel:SizeToContents()
                
                    local fuelSlider = vgui.Create("DNumSlider", frame)
                    fuelSlider:SetPos(50, 70)
                    fuelSlider:SetSize(200, 20)
                    fuelSlider:SetText("")
                    fuelSlider:SetMin(10)
                    fuelSlider:SetMax(100)
                    fuelSlider:SetDecimals(0)
                    fuelSlider:SetValue(50)
                
                    local refuelButton = vgui.Create("DButton", frame)
                    refuelButton:SetText("Refuel")
                    refuelButton:SetPos(100, 100)
                    refuelButton:SetSize(100, 30)
                    refuelButton.DoClick = function()
                        local fuelAmount = math.Round(fuelSlider:GetValue())
                        RunConsoleCommand("industrial_refuel_generator", generator:EntIndex(), fuelAmount)
                        frame:Close()
                    end
                end
                
                -- Optional: Display fuel status above the generator
                hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawGeneratorInfo", function()
                    for _, generator in ipairs(ents.FindByClass("generator")) do
                        if not IsValid(generator) then return end
                        cam.Start3D2D(generator:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText("Generator", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Fuel: " .. generator:GetFuel(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Power Output: " .. generator:GetPowerOutput(), "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        cam.End3D2D()
                    end
                end)
            [Файл] init.lua
                -- lua/entities/generator/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_c17/oildrum001.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetFuel(100) -- Initial fuel
                    self:SetPowerOutput(10) -- Power units per second
                
                    -- Register as a power generator
                    RegisterGenerator(self)
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open a refuel panel (handled client-side)
                    if SERVER then
                        activator:SendLua("OpenGeneratorRefuelPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to handle refueling
                concommand.Add("industrial_refuel_generator", function(player, cmd, args)
                    local entIndex = tonumber(args[1])
                    local generator = ents.GetByIndex(entIndex)
                    if not IsValid(generator) or generator:GetClass() ~= "generator" then return end
                
                    local fuelToAdd = 50 -- Example value
                    generator:SetFuel(generator:GetFuel() + fuelToAdd)
                    player:ChatPrint("Refueled Generator by " .. fuelToAdd .. " units.")
                end)
            [Файл] shared.lua
                -- lua/entities/generator/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Generator"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("Int", 0, "Fuel")
                    self:NetworkVar("Int", 1, "PowerOutput")
                end
        [Папка] plc/
            [Файл] cl_init.lua
                -- lua/entities/plc/cl_init.lua
                
                include("shared.lua")
                
                -- Function to open PLC script input panel
                function OpenPLCPanel(plc)
                    if not IsValid(plc) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_PLCPanelFrame")) then return end
                
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("PLC Script Panel")
                    frame:SetSize(500, 400)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_PLCPanelFrame")
                
                    local scriptLabel = vgui.Create("DLabel", frame)
                    scriptLabel:SetText("Enter PLC Script:")
                    scriptLabel:SetPos(10, 30)
                    scriptLabel:SizeToContents()
                
                    local scriptBox = vgui.Create("DTextEntry", frame)
                    scriptBox:SetPos(10, 50)
                    scriptBox:SetSize(480, 300)
                    scriptBox:SetMultiline(true)
                    scriptBox:SetValue(plc:GetScript())
                
                    local saveButton = vgui.Create("DButton", frame)
                    saveButton:SetText("Save Script")
                    saveButton:SetPos(200, 360)
                    saveButton:SetSize(100, 30)
                    saveButton.DoClick = function()
                        local script = scriptBox:GetValue()
                        RunConsoleCommand("industrial_set_plc_script", plc:EntIndex(), script)
                        frame:Close()
                    end
                end
                
                -- Function to handle PLC script saving (client-side, sends to server)
                net.Receive("Industrialization_PLC_Update", function()
                    -- Handle updates if necessary
                end)
            [Файл] init.lua
                -- lua/entities/plc/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_lab/reciever01a.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetScript("") -- Initialize with no script
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open PLC script input panel (handled client-side)
                    if SERVER then
                        activator:SendLua("OpenPLCPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to execute the script
                function ENT:ExecuteScript()
                    local script = self:GetScript()
                    if script == "" then return end
                
                    local func, err = loadstring(script)
                    if func then
                        local success, execErr = pcall(func, self)
                        if not success then
                            NotifyAll("PLC Execution Error: " .. execErr)
                        end
                    else
                        NotifyAll("PLC Script Error: " .. err)
                    end
                end
                
                function ENT:Think()
                    if self:GetScript() ~= "" then
                        self:ExecuteScript()
                    end
                    self:NextThink(CurTime() + 5) -- Execute script every 5 seconds
                    return true
                end
            [Файл] shared.lua
                -- lua/entities/plc/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Programmable Logic Controller (PLC)"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("String", 0, "Script")
                end
        [Папка] power_distribution_unit/
            [Файл] cl_init.lua
                -- lua/entities/power_distribution_unit/cl_init.lua
                
                include("shared.lua")
                
                -- Function to open power distribution panel
                function OpenPowerDistributionPanel(distributionUnit)
                    if not IsValid(distributionUnit) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_PowerDistributionFrame")) then return end
                
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Power Distribution Panel")
                    frame:SetSize(300, 200)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_PowerDistributionFrame")
                
                    local capacityLabel = vgui.Create("DLabel", frame)
                    capacityLabel:SetText("Power Capacity: " .. distributionUnit:GetPowerCapacity())
                    capacityLabel:SetPos(50, 50)
                    capacityLabel:SizeToContents()
                
                    local currentPowerLabel = vgui.Create("DLabel", frame)
                    currentPowerLabel:SetText("Current Power: " .. distributionUnit:GetCurrentPower())
                    currentPowerLabel:SetPos(50, 80)
                    currentPowerLabel:SizeToContents()
                
                    -- Add more controls if needed
                end
                
                -- Optional: Display information above the power distribution unit
                hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawPowerDistributionUnitInfo", function()
                    for _, unit in ipairs(ents.FindByClass("power_distribution_unit")) do
                        if not IsValid(unit) then return end
                        cam.Start3D2D(unit:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText("Power Distribution Unit", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Capacity: " .. unit:GetPowerCapacity(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Current Power: " .. unit:GetCurrentPower(), "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        cam.End3D2D()
                    end
                end)
            [Файл] init.lua
                -- lua/entities/power_distribution_unit/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_combine/breenglobe.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_NONE)
                
                    self:SetPowerCapacity(100)
                    self:SetCurrentPower(0)
                
                    -- Register as a power consumer (optional)
                    RegisterConsumer(self, 0) -- Does not consume power itself
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open power distribution panel (handled client-side)
                    if SERVER then
                        activator:SendLua("OpenPowerDistributionPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to distribute power to consumers
                function ENT:DistributePower()
                    local totalPowerNeeded = 0
                    for consumer, powerNeeded in pairs(PowerConsumers) do
                        if IsValid(consumer) then
                            totalPowerNeeded = totalPowerNeeded + powerNeeded
                        end
                    end
                
                    if totalPowerNeeded <= self:GetPowerCapacity() then
                        for consumer, powerNeeded in pairs(PowerConsumers) do
                            if IsValid(consumer) then
                                consumer:ReceivePower(true)
                            end
                        end
                        self:SetCurrentPower(totalPowerNeeded)
                    else
                        -- Distribute power based on priority or other logic
                        local powerLeft = self:GetPowerCapacity()
                        for consumer, powerNeeded in pairs(PowerConsumers) do
                            if IsValid(consumer) then
                                if powerLeft >= powerNeeded then
                                    consumer:ReceivePower(true)
                                    powerLeft = powerLeft - powerNeeded
                                else
                                    consumer:ReceivePower(false)
                                end
                            end
                        end
                        self:SetCurrentPower(self:GetPowerCapacity() - powerLeft)
                    end
                end
                
                function ENT:Think()
                    self:DistributePower()
                    self:NextThink(CurTime() + 1)
                    return true
                end
            [Файл] shared.lua
                -- lua/entities/power_distribution_unit/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Power Distribution Unit"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("Int", 0, "PowerCapacity")
                    self:NetworkVar("Int", 1, "CurrentPower")
                end
        [Папка] resource_node/
            [Файл] cl_init.lua
                -- lua/entities/resource_node/cl_init.lua
                
                include("shared.lua")
                
                function ENT:Draw()
                    self:DrawModel()
                
                    -- Draw resource information above the node for administrators
                    if LocalPlayer():IsAdmin() then
                        cam.Start3D2D(self:GetPos() + Vector(0, 0, 20), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText(self:GetResourceType():upper(), "DermaDefaultBold", 0, 0, Color(255, 215, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Qty: " .. self:GetResourceQuantity(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        cam.End3D2D()
                    end
                end
            [Файл] init.lua
                -- lua/entities/resource_node/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    local resourceType = self:GetResourceType()
                    self:SetModel(ResourceTypes[resourceType] and ResourceTypes[resourceType].model or "models/props_debris/concrete_chunk05a.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetResourceQuantity(self.ResourceQuantity)
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    local resourceType = self:GetResourceType()
                    local available = self:GetResourceQuantity()
                
                    if available <= 0 then
                        activator:ChatPrint("This resource node is depleted.")
                        return
                    end
                
                    -- Example extraction: 1 unit per use
                    local extracted = 1
                    if available < extracted then extracted = available end
                
                    if SERVER then
                        local success = AddPlayerResource(activator, resourceType, extracted)
                        if success then
                            self:SetResourceQuantity(available - extracted)
                            if self:GetResourceQuantity() <= 0 then
                                self:Remove()
                            end
                        end
                    end
                end
                
                function ENT:Think()
                    -- Optional: Regenerate resources over time
                    if SERVER and AddPlayerResource(activator, resourceType, extracted) then
                        self:SetResourceQuantity(available - extracted)
                        if self:GetResourceQuantity() <= 0 then
                            self:Remove()
                        end
                    end
                
                    self:NextThink(CurTime() + 60) -- Regenerate every 60 seconds
                    return true
                end
            [Файл] shared.lua
                -- lua/entities/resource_node/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Resource Node"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = false
                ENT.AdminOnly = false
                
                ENT.ResourceType = "wood" -- Default, can be set when spawned
                ENT.ResourceQuantity = 10 -- Amount of resource available
                
                function ENT:SetupDataTables()
                    self:NetworkVar("String", 0, "ResourceType")
                    self:NetworkVar("Int", 1, "ResourceQuantity")
                end
        [Папка] smelter/
            [Файл] cl_init.lua
                -- lua/entities/smelter/cl_init.lua
                
                include("shared.lua")
                
                -- Function to open smelter control panel
                function OpenSmelterControlPanel(smelter)
                    if not IsValid(smelter) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_SmelterControlFrame")) then return end
                
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Smelter Control Panel")
                    frame:SetSize(300, 200)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_SmelterControlFrame")
                
                    local startButton = vgui.Create("DButton", frame)
                    startButton:SetText("Start Smelting")
                    startButton:SetPos(50, 50)
                    startButton:SetSize(200, 30)
                    startButton.DoClick = function()
                        smelter:StartSmelting()
                        frame:Close()
                    end
                
                    local stopButton = vgui.Create("DButton", frame)
                    stopButton:SetText("Stop Smelting")
                    stopButton:SetPos(50, 100)
                    stopButton:SetSize(200, 30)
                    stopButton.DoClick = function()
                        smelter:StopSmelting()
                        frame:Close()
                    end
                end
                
                -- Example: Receive smelter updates
                net.Receive("Industrialization_UpdateSmelter", function()
                    local smelter = net.ReadEntity()
                    local isSmelting = net.ReadBool()
                    local inputIronOre = net.ReadInt(32)
                    local outputIronIngot = net.ReadInt(32)
                
                    if not IsValid(smelter) then return end
                
                    -- Optional: Display information above the smelter
                    hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawSmelterInfo", function()
                        if not IsValid(smelter) then return end
                        cam.Start3D2D(smelter:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText("Smelter", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Smelting: " .. (isSmelting and "Yes" or "No"), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Iron Ore: " .. inputIronOre, "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Iron Ingot: " .. outputIronIngot, "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                        cam.End3D2D()
                    end)
                end)
            [Файл] init.lua
                -- lua/entities/smelter/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_c17/oildrum001.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetSmelting(false)
                    self:SetInputIronOre(0)
                    self:SetOutputIronIngot(0)
                
                    -- Register as a power consumer
                    RegisterConsumer(self, 10) -- Example: needs 10 power units
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open a smelter control panel (handled client-side)
                    if SERVER then
                        activator:SendLua("OpenSmelterControlPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to start smelting
                function ENT:StartSmelting()
                    if self:GetSmelting() then return end
                    if self:GetInputIronOre() < 1 then
                        NotifyPlayer(nil, "Not enough Iron Ore to start smelting.")
                        return
                    end
                
                    self:SetSmelting(true)
                    timer.Simple(7, function()
                        if not IsValid(self) then return end
                        if self:GetInputIronOre() >= 1 then
                            self:SetInputIronOre(self:GetInputIronOre() - 1)
                            self:SetOutputIronIngot(self:GetOutputIronIngot() + 1)
                            NotifyAll("A Smelter has processed 1 Iron Ore into an Iron Ingot.")
                        end
                        self:SetSmelting(false)
                    end)
                end
                
                -- Function to stop smelting (if applicable)
                function ENT:StopSmelting()
                    if not self:GetSmelting() then return end
                    self:SetSmelting(false)
                    NotifyAll("A Smelter has stopped smelting.")
                end
                
                function ENT:Think()
                    -- Continuous logic can be added here if needed
                    self:NextThink(CurTime() + 1)
                    return true
                end
            [Файл] shared.lua
                -- lua/entities/smelter/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Smelter"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("Bool", 0, "Smelting")
                    self:NetworkVar("Int", 1, "InputIronOre")
                    self:NetworkVar("Int", 2, "OutputIronIngot")
                end
        [Папка] warehouse/
            [Файл] cl_init.lua
                -- lua/entities/warehouse/cl_init.lua
                
                include("shared.lua")
                
                -- Function to open warehouse inventory
                function OpenWarehouseInventory(warehouse)
                    if not IsValid(warehouse) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_WarehouseInventoryFrame")) then return end
                
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Warehouse Inventory")
                    frame:SetSize(500, 600)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_WarehouseInventoryFrame")
                
                    local list = vgui.Create("DListView", frame)
                    list:Dock(FILL)
                    list:AddColumn("Resource")
                    list:AddColumn("Quantity")
                    list:SetMultiSelect(false)
                
                    -- Populate the list with stored resources
                    local resources = {
                        "wood",
                        "metal",
                        "oil",
                        "minerals",
                        "refined_metal",
                        "electronics",
                        "advanced_gadget"
                    }
                
                    for _, resource in ipairs(resources) do
                        local qty = warehouse:GetStoredResource(resource)
                        if qty and qty > 0 then
                            list:AddLine(ResourceTypes[resource].name or resource, qty)
                        end
                    end
                
                    -- Optionally, add buttons to interact with resources
                end
                
                -- Optional: Display information above the warehouse
                hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawWarehouseInfo", function()
                    for _, warehouse in ipairs(ents.FindByClass("warehouse")) do
                        if not IsValid(warehouse) then return end
                        cam.Start3D2D(warehouse:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                            draw.SimpleText("Warehouse", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Wood: " .. warehouse:GetStoredWood(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Metal: " .. warehouse:GetStoredMetal(), "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            draw.SimpleText("Oil: " .. warehouse:GetStoredOil(), "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            -- Add more resources as needed
                        cam.End3D2D()
                    end
                end)
            [Файл] init.lua
                -- lua/entities/warehouse/init.lua
                
                AddCSLuaFile("cl_init.lua")
                AddCSLuaFile("shared.lua")
                
                include("shared.lua")
                
                function ENT:Initialize()
                    self:SetModel("models/props_c17/FurnitureShelf001a.mdl")
                    self:PhysicsInit(SOLID_VPHYSICS)
                    self:SetMoveType(MOVETYPE_NONE)
                    self:SetSolid(SOLID_VPHYSICS)
                
                    self:SetStoredWood(0)
                    self:SetStoredMetal(0)
                    self:SetStoredOil(0)
                    self:SetStoredMinerals(0)
                    self:SetStoredRefinedMetal(0)
                    self:SetStoredElectronics(0)
                    self:SetStoredAdvancedGadget(0)
                
                    -- Register as a power consumer (optional)
                    RegisterConsumer(self, 20) -- Example: needs 20 power units
                end
                
                function ENT:Use(activator, caller)
                    if not IsValid(activator) or not activator:IsPlayer() then return end
                
                    -- Open warehouse inventory UI (handled client-side)
                    if SERVER then
                        activator:SendLua("OpenWarehouseInventory(ents.GetByIndex(" .. self:EntIndex() .. "))")
                    end
                end
                
                -- Function to add resources to the warehouse
                function ENT:AddResource(resource, qty)
                    if not ResourceTypes[resource] then return end
                    local currentQty = self:GetStoredResource(resource)
                
                    self:SetStoredResource(resource, currentQty + qty)
                    NotifyAll("A Warehouse has stored " .. qty .. " " .. ResourceTypes[resource].name)
                end
                
                -- Function to remove resources from the warehouse
                function ENT:RemoveResource(resource, qty)
                    if not ResourceTypes[resource] then return false end
                    local currentQty = self:GetStoredResource(resource)
                
                    if currentQty >= qty then
                        self:SetStoredResource(resource, currentQty - qty)
                        NotifyAll("A Warehouse has removed " .. qty .. " " .. ResourceTypes[resource].name)
                        return true
                    else
                        return false
                    end
                end
                
                -- Helper function to get stored resource based on resource type
                function ENT:GetStoredResource(resource)
                    if resource == "wood" then return self:GetStoredWood()
                    elseif resource == "metal" then return self:GetStoredMetal()
                    elseif resource == "oil" then return self:GetStoredOil()
                    elseif resource == "minerals" then return self:GetStoredMinerals()
                    elseif resource == "refined_metal" then return self:GetStoredRefinedMetal()
                    elseif resource == "electronics" then return self:GetStoredElectronics()
                    elseif resource == "advanced_gadget" then return self:GetStoredAdvancedGadget()
                    else return 0 end
                end
                
                -- Helper function to set stored resource based on resource type
                function ENT:SetStoredResource(resource, qty)
                    if resource == "wood" then self:SetStoredWood(qty)
                    elseif resource == "metal" then self:SetStoredMetal(qty)
                    elseif resource == "oil" then self:SetStoredOil(qty)
                    elseif resource == "minerals" then self:SetStoredMinerals(qty)
                    elseif resource == "refined_metal" then self:SetStoredRefinedMetal(qty)
                    elseif resource == "electronics" then self:SetStoredElectronics(qty)
                    elseif resource == "advanced_gadget" then self:SetStoredAdvancedGadget(qty)
                    end
                end
                
                function ENT:Think()
                    -- Optional: Implement periodic resource checks or other logic
                    self:NextThink(CurTime() + 60)
                    return true
                end
            [Файл] shared.lua
                -- lua/entities/warehouse/shared.lua
                ENT = ENT or {}
                ENT.Type = "anim"
                ENT.Base = "base_anim"
                ENT.PrintName = "Warehouse"
                ENT.Author = "YourName"
                ENT.Category = "Industrialization"
                ENT.Spawnable = true
                ENT.AdminOnly = false
                
                function ENT:SetupDataTables()
                    self:NetworkVar("Int", 0, "StoredWood")
                    self:NetworkVar("Int", 1, "StoredMetal")
                    self:NetworkVar("Int", 2, "StoredOil")
                    self:NetworkVar("Int", 3, "StoredMinerals")
                    self:NetworkVar("Int", 4, "StoredRefinedMetal")
                    self:NetworkVar("Int", 5, "StoredElectronics")
                    self:NetworkVar("Int", 6, "StoredAdvancedGadget")
                end
    [Папка] modules/
        [Файл] power_system.lua
            -- lua/modules/power_system.lua
            
            if SERVER then
                util.AddNetworkString("Industrialization_UpdatePowerStatus")
                util.AddNetworkString("Industrialization_Notify")
            
                PowerGenerators = PowerGenerators or {}
                PowerConsumers = PowerConsumers or {}
            
                -- Function to register a generator
                function RegisterGenerator(generator)
                    table.insert(PowerGenerators, generator)
                end
            
                -- Function to register a consumer
                function RegisterConsumer(consumer, powerNeeded)
                    PowerConsumers[consumer] = powerNeeded
                end
            
                -- Function to distribute power every second
                timer.Create("Industrialization_PowerDistribution", 1, 0, function()
                    local totalPower = 0
                    for _, gen in ipairs(PowerGenerators) do
                        if IsValid(gen) and gen:GetFuel() > 0 then
                            totalPower = totalPower + gen:GetPowerOutput()
                            gen:SetFuel(gen:GetFuel() - 1) -- Consume fuel
                            if gen:GetFuel() <= 0 then
                                -- Generator ran out of fuel
                                net.Start("Industrialization_Notify")
                                    net.WriteString("A generator has run out of fuel and stopped producing power.")
                                net.Broadcast()
                            end
                        end
                    end
            
                    -- Distribute power to consumers based on totalPower
                    for consumer, powerNeeded in pairs(PowerConsumers) do
                        if IsValid(consumer) then
                            if totalPower >= powerNeeded then
                                consumer:ReceivePower(true)
                            else
                                consumer:ReceivePower(false)
                            end
                        end
                    end
            
                    -- Send power status to clients
                    net.Start("Industrialization_UpdatePowerStatus")
                        net.WriteInt(totalPower, 32)
                    net.Broadcast()
                end)
            end
            
            if CLIENT then
                -- Handle power status updates on client-side
                net.Receive("Industrialization_UpdatePowerStatus", function()
                    local totalPower = net.ReadInt(32)
                    -- Update UI or display power status as needed
                    -- Example: Print to chat
                    print("Total Power Available: " .. totalPower)
                end)
            
                net.Receive("Industrialization_Notify", function()
                    local message = net.ReadString()
                    chat.AddText(Color(255, 0, 0), "[Industrialization] ", Color(255, 255, 255), message)
                end)
            end
        [Файл] resource_management.lua
            -- lua/modules/resource_management.lua
            
            if SERVER then
                util.AddNetworkString("Industrialization_UpdateInventory")
                util.AddNetworkString("Industrialization_Notify")
            
                PlayerInventory = PlayerInventory or {}
                AvailableResources = AvailableResources or {
                    wood = 500,
                    metal = 300,
                    oil = 200,
                    minerals = 100,
                }
            
                -- Initialize player inventory on spawn
                hook.Add("PlayerInitialSpawn", "Industrialization_InitInventory", function(player)
                    PlayerInventory[player:SteamID()] = {
                        wood = 0,
                        metal = 0,
                        oil = 0,
                        minerals = 0,
                        refined_metal = 0,
                        electronics = 0,
                        -- Initialize other resources
                    }
                end)
            
                -- Function to add resources to player inventory
                function AddPlayerResource(player, resource, qty)
                    if not PlayerInventory[player:SteamID()] then return false end
                    if not ResourceTypes[resource] then return false end
            
                    if (PlayerInventory[player:SteamID()][resource] or 0) + qty <= 1000 then -- Max limit
                        PlayerInventory[player:SteamID()][resource] = PlayerInventory[player:SteamID()][resource] + qty
                        AvailableResources[resource] = (AvailableResources[resource] or 0) - qty
                        -- Notify player
                        player:ChatPrint("You have gained " .. qty .. " " .. ResourceTypes[resource].name)
                        -- Update UI
                        net.Start("Industrialization_UpdateInventory")
                            net.WriteTable(PlayerInventory[player:SteamID()])
                        net.Send(player)
                        return true
                    else
                        player:ChatPrint("Cannot carry more " .. ResourceTypes[resource].name)
                        return false
                    end
                end
            
                -- Function to remove resources from player inventory
                function RemovePlayerResource(player, resource, qty)
                    if not PlayerInventory[player:SteamID()] then return false end
                    if not ResourceTypes[resource] then return false end
            
                    if PlayerInventory[player:SteamID()][resource] and PlayerInventory[player:SteamID()][resource] >= qty then
                        PlayerInventory[player:SteamID()][resource] = PlayerInventory[player:SteamID()][resource] - qty
                        AvailableResources[resource] = (AvailableResources[resource] or 0) + qty
                        -- Notify player
                        player:ChatPrint("You have used " .. qty .. " " .. ResourceTypes[resource].name)
                        -- Update UI
                        net.Start("Industrialization_UpdateInventory")
                            net.WriteTable(PlayerInventory[player:SteamID()])
                        net.Send(player)
                        return true
                    else
                        player:ChatPrint("Not enough " .. ResourceTypes[resource].name)
                        return false
                    end
                end
            
                -- Function to spawn initial resource nodes
                function SpawnInitialResourceNodes()
                    local positions = {
                        Vector(100, 100, 10),
                        Vector(200, 200, 10),
                        Vector(300, 300, 10),
                        -- Add more positions as needed
                    }
            
                    for _, pos in ipairs(positions) do
                        local resourceType = table.Random({"wood", "metal", "oil", "minerals"})
                        SpawnResourceNode(resourceType, pos)
                    end
                end
            
                -- Function to spawn a resource node
                function SpawnResourceNode(resourceType, position)
                    if not ResourceTypes[resourceType] then return end
            
                    local node = ents.Create("resource_node")
                    node:SetModel(ResourceTypes[resourceType].model)
                    node:SetPos(position)
                    node:SetNWString("ResourceType", resourceType)
                    node:SetNWInt("ResourceQuantity", 10) -- Initial quantity
                    node:Spawn()
                end
            
                -- Recycling system
                function RecycleWaste(player, wasteType, qty)
                    if ResourceTypes[wasteType] and wasteType == "scrap_metal" then
                        if RemovePlayerResource(player, "scrap_metal", qty) then
                            AddPlayerResource(player, "refined_metal", qty)
                            player:ChatPrint("Recycled " .. qty .. " Scrap Metal into Refined Metal")
                        end
                    else
                        player:ChatPrint("Invalid waste type for recycling.")
                    end
                end
            
                -- Handle player commands or interactions
                -- Example: Using a recycling facility
                concommand.Add("industrial_recycle", function(player, cmd, args)
                    local wasteType = args[1]
                    local qty = tonumber(args[2]) or 1
                    RecycleWaste(player, wasteType, qty)
                end)
            end
        [Файл] ui_elements.lua
            -- lua/modules/ui_elements.lua
            
            if SERVER then
                -- Register network strings on the server
                util.AddNetworkString("Industrialization_UpdateInventory")
                util.AddNetworkString("Industrialization_UpdateFactory")
                util.AddNetworkString("Industrialization_UpdateSmelter")
                util.AddNetworkString("Industrialization_UpdateAssemblyMachine")
                util.AddNetworkString("Industrialization_UpdateHarvester")
                util.AddNetworkString("Industrialization_UpdatePowerStatus")
            
                -- Optionally, you can handle server-side networking here
                -- For example:
                -- net.Send or net.Broadcast logic
            end
            
            if CLIENT then
                -- Table to store player inventory
                local PlayerInventoryUI = {}
            
                -- Receive inventory updates from the server
                net.Receive("Industrialization_UpdateInventory", function()
                    local inventory = net.ReadTable()
                    PlayerInventoryUI = inventory -- Utilize the 'inventory' variable
                    -- Refresh the inventory UI if it's open
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_InventoryFrame")) then
                        local frame = vgui.GetControl("DFrame", "Industrialization_InventoryFrame")
                        local list = frame:GetChildren()[1] -- Assuming the DListView is the first child
                        list:Clear()
                        for resource, qty in pairs(PlayerInventoryUI) do
                            if qty > 0 then
                                list:AddLine(ResourceTypes[resource].name or resource, qty)
                            end
                        end
                    end
                end)
            
                -- Function to create and display the inventory UI
                function CreateInventoryUI()
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_InventoryFrame")) then return end
            
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Inventory")
                    frame:SetSize(400, 600)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_InventoryFrame")
            
                    local list = vgui.Create("DListView", frame)
                    list:Dock(FILL)
                    list:AddColumn("Resource")
                    list:AddColumn("Quantity")
            
                    for resource, qty in pairs(PlayerInventoryUI) do
                        if qty > 0 then
                            list:AddLine(ResourceTypes[resource].name or resource, qty)
                        end
                    end
                end
            
                -- Bind a key to open the inventory (e.g., F1)
                hook.Add("PlayerButtonDown", "Industrialization_OpenInventory", function(ply, button)
                    if ply ~= LocalPlayer() then return end
                    if button == KEY_F1 then
                        CreateInventoryUI()
                    end
                end)
            
                -- Factory Control Panel (example)
                function CreateFactoryControlPanel(factory)
                    if not IsValid(factory) then return end
                    if IsValid(vgui.GetControl("DFrame", "Industrialization_ControlPanelFrame")) then return end
            
                    local frame = vgui.Create("DFrame")
                    frame:SetTitle("Factory Control Panel")
                    frame:SetSize(300, 200)
                    frame:Center()
                    frame:MakePopup()
                    frame:SetName("Industrialization_ControlPanelFrame")
            
                    local startButton = vgui.Create("DButton", frame)
                    startButton:SetText("Start Processing")
                    startButton:SetPos(50, 50)
                    startButton:SetSize(200, 30)
                    startButton.DoClick = function()
                        factory:StartProcessing()
                        frame:Close()
                    end
            
                    local stopButton = vgui.Create("DButton", frame)
                    stopButton:SetText("Stop Processing")
                    stopButton:SetPos(50, 100)
                    stopButton:SetSize(200, 30)
                    stopButton.DoClick = function()
                        factory:StopProcessing()
                        frame:Close()
                    end
                end
            
                -- Similar functions can be created for Smelter, Assembly Machine, etc.
            end
        [Файл] utility.lua
            -- lua/modules/utility.lua
            
            if SERVER then
                -- Function to find the nearest warehouse to a position
                function GetNearestStorage(pos)
                    local warehouses = ents.FindByClass("warehouse")
                    local nearest = nil
                    local minDist = math.huge
            
                    for _, warehouse in ipairs(warehouses) do
                        local dist = pos:Distance(warehouse:GetPos())
                        if dist < minDist then
                            minDist = dist
                            nearest = warehouse
                        end
                    end
            
                    return nearest
                end
            
                -- Function to notify a specific player
                function NotifyPlayer(player, message)
                    if IsValid(player) then
                        player:ChatPrint(message)
                    end
                end
            
                -- Function to send a chat message to all players
                function NotifyAll(message)
                    for _, ply in ipairs(player.GetAll()) do
                        ply:ChatPrint("[Industrialization] " .. message)
                    end
                end
            end
    [Папка] shared/
        [Файл] resource_types.lua
            -- lua/shared/resource_types.lua
            
            ResourceTypes = {
                wood = {
                    name = "Wood",
                    model = "models/props_foliage/forest_fern01a.mdl",
                    icon = "materials/icons/wood.vmt",
                },
                metal = {
                    name = "Metal",
                    model = "models/props_c17/oildrum001.mdl",
                    icon = "materials/icons/metal.vmt",
                },
                oil = {
                    name = "Oil",
                    model = "models/props_junk/metal_paintcan001a.mdl",
                    icon = "materials/icons/oil.vmt",
                },
                minerals = {
                    name = "Minerals",
                    model = "models/props_debris/concrete_chunk05a.mdl",
                    icon = "materials/icons/minerals.vmt",
                },
                refined_metal = {
                    name = "Refined Metal",
                    model = "models/props_combine/breenglobe.mdl",
                    icon = "materials/icons/refined_metal.vmt",
                },
                electronics = {
                    name = "Electronics",
                    model = "models/props_lab/reciever01a.mdl",
                    icon = "materials/icons/electronics.vmt",
                },
                -- Add more resource types as needed
            }
[Папка] materials/
    [Папка] icons/
    [Папка] models/
        [Папка] industrialization/
[Папка] models/
    [Папка] industrialization/
[Файл] project_structure.txt
    Структура проекта для директории: c:\Program Files (x86)\Steam\steamapps\common\GarrysMod\garrysmod\addons\gmod-industrialization
    
    [Файл] addon.txt
        "AddonInfo"
        {
            "name"          "Industrialization System"
            "version"       "1.0"
            "up_date"       "2024-04-27"
            "author_name"   "YourName"
            "author_email"  "youremail@example.com"
            "info"          "Simulates a robust production and automation environment within GMod."
            "url"           "https://youraddonwebsite.com"
        }
    [Папка] lua/
        [Папка] autorun/
            [Файл] industrialization_init.lua
                -- lua/autorun/industrialization_init.lua
                
                if SERVER then
                    -- Include all server-side entity scripts
                    AddCSLuaFile("entities/basic_factory/cl_init.lua")
                    AddCSLuaFile("entities/basic_factory/shared.lua")
                    AddCSLuaFile("entities/resource_node/cl_init.lua")
                    AddCSLuaFile("entities/resource_node/shared.lua")
                    AddCSLuaFile("entities/automated_harvester/cl_init.lua")
                    AddCSLuaFile("entities/automated_harvester/shared.lua")
                    AddCSLuaFile("entities/smelter/cl_init.lua")
                    AddCSLuaFile("entities/smelter/shared.lua")
                    AddCSLuaFile("entities/assembly_machine/cl_init.lua")
                    AddCSLuaFile("entities/assembly_machine/shared.lua")
                    AddCSLuaFile("entities/warehouse/cl_init.lua")
                    AddCSLuaFile("entities/warehouse/shared.lua")
                    AddCSLuaFile("entities/generator/cl_init.lua")
                    AddCSLuaFile("entities/generator/shared.lua")
                    AddCSLuaFile("entities/power_distribution_unit/cl_init.lua")
                    AddCSLuaFile("entities/power_distribution_unit/shared.lua")
                    AddCSLuaFile("entities/plc/cl_init.lua")
                    AddCSLuaFile("entities/plc/shared.lua")
                
                    -- Include server-side modules
                    include("shared/resource_types.lua")
                    include("modules/resource_management.lua")
                    include("modules/power_system.lua")
                    include("modules/utility.lua")
                
                    -- Spawn initial resource nodes on server startup
                    hook.Add("InitPostEntity", "Industrialization_SpawnResourceNodes", function()
                        SpawnInitialResourceNodes()
                    end)
                else
                    -- Client-side includes
                    include("entities/basic_factory/cl_init.lua")
                    include("entities/resource_node/cl_init.lua")
                    include("entities/automated_harvester/cl_init.lua")
                    include("entities/smelter/cl_init.lua")
                    include("entities/assembly_machine/cl_init.lua")
                    include("entities/warehouse/cl_init.lua")
                    include("entities/generator/cl_init.lua")
                    include("entities/power_distribution_unit/cl_init.lua")
                    include("entities/plc/cl_init.lua")
                
                    -- Include client-side modules
                    include("modules/ui_elements.lua")
                end
        [Папка] entities/
            [Папка] assembly_machine/
                [Файл] cl_init.lua
                    -- lua/entities/assembly_machine/cl_init.lua
                    
                    include("shared.lua")
                    
                    -- Function to open assembly machine control panel
                    function OpenAssemblyMachineControlPanel(assemblyMachine)
                        if not IsValid(assemblyMachine) then return end
                        if IsValid(vgui.GetControl("DFrame", "Industrialization_AssemblyMachineControlFrame")) then return end
                    
                        local frame = vgui.Create("DFrame")
                        frame:SetTitle("Assembly Machine Control Panel")
                        frame:SetSize(300, 200)
                        frame:Center()
                        frame:MakePopup()
                        frame:SetName("Industrialization_AssemblyMachineControlFrame")
                    
                        local startButton = vgui.Create("DButton", frame)
                        startButton:SetText("Start Assembling")
                        startButton:SetPos(50, 50)
                        startButton:SetSize(200, 30)
                        startButton.DoClick = function()
                            assemblyMachine:StartAssembling()
                            frame:Close()
                        end
                    
                        local stopButton = vgui.Create("DButton", frame)
                        stopButton:SetText("Stop Assembling")
                        stopButton:SetPos(50, 100)
                        stopButton:SetSize(200, 30)
                        stopButton.DoClick = function()
                            assemblyMachine:StopAssembling()
                            frame:Close()
                        end
                    end
                    
                    -- Example: Receive assembly machine updates
                    net.Receive("Industrialization_UpdateAssemblyMachine", function()
                        local assemblyMachine = net.ReadEntity()
                        local isAssembling = net.ReadBool()
                        local inputRefinedMetal = net.ReadInt(32)
                        local inputElectronics = net.ReadInt(32)
                        local outputAdvancedGadget = net.ReadInt(32)
                    
                        if not IsValid(assemblyMachine) then return end
                    
                        -- Optional: Display information above the assembly machine
                        hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawAssemblyMachineInfo", function()
                            if not IsValid(assemblyMachine) then return end
                            cam.Start3D2D(assemblyMachine:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText("Assembly Machine", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Assembling: " .. (isAssembling and "Yes" or "No"), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Refined Metal: " .. inputRefinedMetal, "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Electronics: " .. inputElectronics, "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Advanced Gadget: " .. outputAdvancedGadget, "DermaDefault", 0, 80, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            cam.End3D2D()
                        end)
                    end)
                [Файл] init.lua
                    -- lua/entities/assembly_machine/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_combine/breenglobe.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetAssembling(false)
                        self:SetInputRefinedMetal(0)
                        self:SetInputElectronics(0)
                        self:SetOutputAdvancedGadget(0)
                    
                        -- Register as a power consumer
                        RegisterConsumer(self, 15) -- Example: needs 15 power units
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open assembly machine control panel (handled client-side)
                        if SERVER then
                            activator:SendLua("OpenAssemblyMachineControlPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to start assembling
                    function ENT:StartAssembling()
                        if self:GetAssembling() then return end
                        if self:GetInputRefinedMetal() < 2 or self:GetInputElectronics() < 1 then
                            NotifyPlayer(nil, "Not enough resources to start assembling.")
                            return
                        end
                    
                        self:SetAssembling(true)
                        timer.Simple(10, function()
                            if not IsValid(self) then return end
                            if self:GetInputRefinedMetal() >= 2 and self:GetInputElectronics() >= 1 then
                                self:SetInputRefinedMetal(self:GetInputRefinedMetal() - 2)
                                self:SetInputElectronics(self:GetInputElectronics() - 1)
                                self:SetOutputAdvancedGadget(self:GetOutputAdvancedGadget() + 1)
                                NotifyAll("An Assembly Machine has produced 1 Advanced Gadget.")
                            end
                            self:SetAssembling(false)
                        end)
                    end
                    
                    -- Function to stop assembling (if applicable)
                    function ENT:StopAssembling()
                        if not self:GetAssembling() then return end
                        self:SetAssembling(false)
                        NotifyAll("An Assembly Machine has stopped assembling.")
                    end
                    
                    function ENT:Think()
                        -- Continuous logic can be added here if needed
                        self:NextThink(CurTime() + 1)
                        return true
                    end
                [Файл] shared.lua
                    -- lua/entities/assembly_machine/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Assembly Machine"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("Bool", 0, "Assembling")
                        self:NetworkVar("Int", 1, "InputRefinedMetal")
                        self:NetworkVar("Int", 2, "InputElectronics")
                        self:NetworkVar("Int", 3, "OutputAdvancedGadget")
                    end
            [Папка] automated_harvester/
                [Файл] cl_init.lua
                    -- lua/entities/automated_harvester/cl_init.lua
                    
                    include("shared.lua")
                    
                    -- Function to open harvester configuration panel
                    function OpenHarvesterConfigPanel(harvester)
                        if not IsValid(harvester) then return end
                        if IsValid(vgui.GetControl("DFrame", "Industrialization_HarvesterConfigFrame")) then return end
                    
                        local frame = vgui.Create("DFrame")
                        frame:SetTitle("Harvester Configuration")
                        frame:SetSize(300, 200)
                        frame:Center()
                        frame:MakePopup()
                        frame:SetName("Industrialization_HarvesterConfigFrame")
                    
                        local resourceLabel = vgui.Create("DLabel", frame)
                        resourceLabel:SetText("Resource Type:")
                        resourceLabel:SetPos(50, 50)
                        resourceLabel:SizeToContents()
                    
                        local resourceCombo = vgui.Create("DComboBox", frame)
                        resourceCombo:SetPos(150, 45)
                        resourceCombo:SetSize(100, 20)
                        for key, res in pairs(ResourceTypes) do
                            resourceCombo:AddChoice(res.name, key)
                        end
                        resourceCombo.OnSelect = function(panel, index, value, data)
                            harvester:SetResourceType(data)
                            frame:Close()
                        end
                    
                        local intervalLabel = vgui.Create("DLabel", frame)
                        intervalLabel:SetText("Harvest Interval (s):")
                        intervalLabel:SetPos(50, 100)
                        intervalLabel:SizeToContents()
                    
                        local intervalSlider = vgui.Create("DNumSlider", frame)
                        intervalSlider:SetPos(50, 120)
                        intervalSlider:SetSize(200, 20)
                        intervalSlider:SetText("")
                        intervalSlider:SetMin(5)
                        intervalSlider:SetMax(60)
                        intervalSlider:SetDecimals(0)
                        intervalSlider:SetValue(harvester:GetHarvestInterval())
                        intervalSlider.OnValueChanged = function(panel, value)
                            harvester:SetHarvestInterval(math.Round(value))
                        end
                    end
                    
                    -- Optional: Display information above the harvester
                    hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawHarvesterInfo", function()
                        for _, harvester in ipairs(ents.FindByClass("automated_harvester")) do
                            if not IsValid(harvester) then return end
                            cam.Start3D2D(harvester:GetPos() + Vector(0, 0, 60), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText("Automated Harvester", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Resource: " .. ResourceTypes[harvester:GetResourceType()].name, "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Interval: " .. harvester:GetHarvestInterval() .. "s", "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            cam.End3D2D()
                        end
                    end)
                [Файл] init.lua
                    -- lua/entities/automated_harvester/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_c17/oildrum001.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetResourceType("metal") -- Default resource type
                        self:SetHarvestInterval(10) -- Harvest every 10 seconds
                    
                        self.NextHarvest = CurTime() + self:GetHarvestInterval()
                    
                        -- Register as a power consumer
                        RegisterConsumer(self, 5) -- Example: needs 5 power units
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open a configuration UI (handled client-side)
                        if SERVER then
                            activator:SendLua("OpenHarvesterConfigPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to harvest resources
                    function ENT:HarvestResource()
                        local resourceType = self:GetResourceType()
                        if not ResourceTypes[resourceType] then return end
                    
                        local storage = GetNearestStorage(self:GetPos())
                        if not IsValid(storage) then
                            NotifyPlayer(nil, "No available storage nearby for Automated Harvesters.")
                            return
                        end
                    
                        storage:AddResource(resourceType, 1)
                        NotifyAll("An Automated Harvester has collected 1 " .. ResourceTypes[resourceType].name)
                    end
                    
                    function ENT:Think()
                        -- Check if the harvester has power
                        if not self:HasPower() then
                            self:NextThink(CurTime() + 1)
                            return true
                        end
                    
                        if CurTime() >= self.NextHarvest then
                            self:HarvestResource()
                            self.NextHarvest = CurTime() + self:GetHarvestInterval()
                        end
                    
                        self:NextThink(CurTime() + 1)
                        return true
                    end
                    
                    -- Function to receive power status
                    function ENT:ReceivePower(status)
                        self.HasPower = status
                        if not status then
                            NotifyAll("An Automated Harvester has lost power and has stopped harvesting.")
                        end
                    end
                    
                    -- Placeholder function to check power status (can be expanded)
                    function ENT:HasPower()
                        return self.HasPower == true
                    end
                [Файл] shared.lua
                    -- lua/entities/automated_harvester/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Automated Harvester"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("String", 0, "ResourceType")
                        self:NetworkVar("Int", 1, "HarvestInterval") -- in seconds
                    end
            [Папка] basic_factory/
                [Файл] cl_init.lua
                    -- lua/entities/basic_factory/cl_init.lua
                    
                    include("shared.lua")
                    
                    net.Receive("Industrialization_UpdateFactory", function()
                        local factory = net.ReadEntity()
                        local isProcessing = net.ReadBool()
                        local inputMetal = net.ReadInt(32)
                        local outputRefinedMetal = net.ReadInt(32)
                    
                        if not IsValid(factory) then return end
                    
                        -- Optional: Display information above the factory
                        hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawFactoryInfo", function()
                            if not IsValid(factory) then return end
                            cam.Start3D2D(factory:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText("Basic Factory", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Processing: " .. (isProcessing and "Yes" or "No"), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Input Metal: " .. inputMetal, "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Refined Metal: " .. outputRefinedMetal, "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            cam.End3D2D()
                        end)
                    end)
                [Файл] init.lua
                    -- lua/entities/basic_factory/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_borealis/bluebarrel001a.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_VPHYSICS)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetProcessing(false)
                        self:SetInputMetal(0)
                        self:SetOutputRefinedMetal(0)
                    
                        -- Register as a power consumer
                        RegisterConsumer(self, 5) -- Example: needs 5 power units
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open a control panel UI (handled client-side)
                        if SERVER then
                            activator:SendLua("CreateFactoryControlPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to start processing
                    function ENT:StartProcessing()
                        if self:GetProcessing() then return end
                        if self:GetInputMetal() < 1 then
                            NotifyPlayer(nil, "Not enough Metal to start processing.")
                            return
                        end
                    
                        self:SetProcessing(true)
                        timer.Simple(5, function()
                            if not IsValid(self) then return end
                            if self:GetInputMetal() >= 1 then
                                self:SetInputMetal(self:GetInputMetal() - 1)
                                self:SetOutputRefinedMetal(self:GetOutputRefinedMetal() + 1)
                                NotifyAll("A factory has processed 1 Metal into Refined Metal.")
                            end
                            self:SetProcessing(false)
                        end)
                    end
                    
                    -- Function to stop processing (if applicable)
                    function ENT:StopProcessing()
                        if not self:GetProcessing() then return end
                        self:SetProcessing(false)
                        NotifyAll("A factory has stopped processing.")
                    end
                    
                    function ENT:Think()
                        -- Continuous logic can be added here if needed
                        self:NextThink(CurTime() + 1)
                        return true
                    end
                [Файл] shared.lua
                    -- lua/entities/basic_factory/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Basic Factory"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("Bool", 0, "Processing")
                        self:NetworkVar("Int", 1, "InputMetal")
                        self:NetworkVar("Int", 2, "OutputRefinedMetal")
                    end
            [Папка] generator/
                [Файл] cl_init.lua
                    -- lua/entities/generator/cl_init.lua
                    
                    include("shared.lua")
                    
                    -- Function to open generator refuel panel
                    function OpenGeneratorRefuelPanel(generator)
                        if not IsValid(generator) then return end
                        if IsValid(vgui.GetControl("DFrame", "Industrialization_GeneratorRefuelFrame")) then return end
                    
                        local frame = vgui.Create("DFrame")
                        frame:SetTitle("Generator Refuel Panel")
                        frame:SetSize(300, 150)
                        frame:Center()
                        frame:MakePopup()
                        frame:SetName("Industrialization_GeneratorRefuelFrame")
                    
                        local fuelLabel = vgui.Create("DLabel", frame)
                        fuelLabel:SetText("Fuel to Add:")
                        fuelLabel:SetPos(50, 50)
                        fuelLabel:SizeToContents()
                    
                        local fuelSlider = vgui.Create("DNumSlider", frame)
                        fuelSlider:SetPos(50, 70)
                        fuelSlider:SetSize(200, 20)
                        fuelSlider:SetText("")
                        fuelSlider:SetMin(10)
                        fuelSlider:SetMax(100)
                        fuelSlider:SetDecimals(0)
                        fuelSlider:SetValue(50)
                    
                        local refuelButton = vgui.Create("DButton", frame)
                        refuelButton:SetText("Refuel")
                        refuelButton:SetPos(100, 100)
                        refuelButton:SetSize(100, 30)
                        refuelButton.DoClick = function()
                            local fuelAmount = math.Round(fuelSlider:GetValue())
                            RunConsoleCommand("industrial_refuel_generator", generator:EntIndex(), fuelAmount)
                            frame:Close()
                        end
                    end
                    
                    -- Optional: Display fuel status above the generator
                    hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawGeneratorInfo", function()
                        for _, generator in ipairs(ents.FindByClass("generator")) do
                            if not IsValid(generator) then return end
                            cam.Start3D2D(generator:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText("Generator", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Fuel: " .. generator:GetFuel(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Power Output: " .. generator:GetPowerOutput(), "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            cam.End3D2D()
                        end
                    end)
                [Файл] init.lua
                    -- lua/entities/generator/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_c17/oildrum001.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetFuel(100) -- Initial fuel
                        self:SetPowerOutput(10) -- Power units per second
                    
                        -- Register as a power generator
                        RegisterGenerator(self)
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open a refuel panel (handled client-side)
                        if SERVER then
                            activator:SendLua("OpenGeneratorRefuelPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to handle refueling
                    concommand.Add("industrial_refuel_generator", function(player, cmd, args)
                        local entIndex = tonumber(args[1])
                        local generator = ents.GetByIndex(entIndex)
                        if not IsValid(generator) or generator:GetClass() ~= "generator" then return end
                    
                        local fuelToAdd = 50 -- Example value
                        generator:SetFuel(generator:GetFuel() + fuelToAdd)
                        player:ChatPrint("Refueled Generator by " .. fuelToAdd .. " units.")
                    end)
                [Файл] shared.lua
                    -- lua/entities/generator/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Generator"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("Int", 0, "Fuel")
                        self:NetworkVar("Int", 1, "PowerOutput")
                    end
            [Папка] plc/
                [Файл] cl_init.lua
                    -- lua/entities/plc/cl_init.lua
                    
                    include("shared.lua")
                    
                    -- Function to open PLC script input panel
                    function OpenPLCPanel(plc)
                        if not IsValid(plc) then return end
                        if IsValid(vgui.GetControl("DFrame", "Industrialization_PLCPanelFrame")) then return end
                    
                        local frame = vgui.Create("DFrame")
                        frame:SetTitle("PLC Script Panel")
                        frame:SetSize(500, 400)
                        frame:Center()
                        frame:MakePopup()
                        frame:SetName("Industrialization_PLCPanelFrame")
                    
                        local scriptLabel = vgui.Create("DLabel", frame)
                        scriptLabel:SetText("Enter PLC Script:")
                        scriptLabel:SetPos(10, 30)
                        scriptLabel:SizeToContents()
                    
                        local scriptBox = vgui.Create("DTextEntry", frame)
                        scriptBox:SetPos(10, 50)
                        scriptBox:SetSize(480, 300)
                        scriptBox:SetMultiline(true)
                        scriptBox:SetValue(plc:GetScript())
                    
                        local saveButton = vgui.Create("DButton", frame)
                        saveButton:SetText("Save Script")
                        saveButton:SetPos(200, 360)
                        saveButton:SetSize(100, 30)
                        saveButton.DoClick = function()
                            local script = scriptBox:GetValue()
                            RunConsoleCommand("industrial_set_plc_script", plc:EntIndex(), script)
                            frame:Close()
                        end
                    end
                    
                    -- Function to handle PLC script saving (client-side, sends to server)
                    net.Receive("Industrialization_PLC_Update", function()
                        -- Handle updates if necessary
                    end)
                [Файл] init.lua
                    -- lua/entities/plc/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_lab/reciever01a.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetScript("") -- Initialize with no script
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open PLC script input panel (handled client-side)
                        if SERVER then
                            activator:SendLua("OpenPLCPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to execute the script
                    function ENT:ExecuteScript()
                        local script = self:GetScript()
                        if script == "" then return end
                    
                        local func, err = loadstring(script)
                        if func then
                            local success, execErr = pcall(func, self)
                            if not success then
                                NotifyAll("PLC Execution Error: " .. execErr)
                            end
                        else
                            NotifyAll("PLC Script Error: " .. err)
                        end
                    end
                    
                    function ENT:Think()
                        if self:GetScript() ~= "" then
                            self:ExecuteScript()
                        end
                        self:NextThink(CurTime() + 5) -- Execute script every 5 seconds
                        return true
                    end
                [Файл] shared.lua
                    -- lua/entities/plc/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Programmable Logic Controller (PLC)"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("String", 0, "Script")
                    end
            [Папка] power_distribution_unit/
                [Файл] cl_init.lua
                    -- lua/entities/power_distribution_unit/cl_init.lua
                    
                    include("shared.lua")
                    
                    -- Function to open power distribution panel
                    function OpenPowerDistributionPanel(distributionUnit)
                        if not IsValid(distributionUnit) then return end
                        if IsValid(vgui.GetControl("DFrame", "Industrialization_PowerDistributionFrame")) then return end
                    
                        local frame = vgui.Create("DFrame")
                        frame:SetTitle("Power Distribution Panel")
                        frame:SetSize(300, 200)
                        frame:Center()
                        frame:MakePopup()
                        frame:SetName("Industrialization_PowerDistributionFrame")
                    
                        local capacityLabel = vgui.Create("DLabel", frame)
                        capacityLabel:SetText("Power Capacity: " .. distributionUnit:GetPowerCapacity())
                        capacityLabel:SetPos(50, 50)
                        capacityLabel:SizeToContents()
                    
                        local currentPowerLabel = vgui.Create("DLabel", frame)
                        currentPowerLabel:SetText("Current Power: " .. distributionUnit:GetCurrentPower())
                        currentPowerLabel:SetPos(50, 80)
                        currentPowerLabel:SizeToContents()
                    
                        -- Add more controls if needed
                    end
                    
                    -- Optional: Display information above the power distribution unit
                    hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawPowerDistributionUnitInfo", function()
                        for _, unit in ipairs(ents.FindByClass("power_distribution_unit")) do
                            if not IsValid(unit) then return end
                            cam.Start3D2D(unit:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText("Power Distribution Unit", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Capacity: " .. unit:GetPowerCapacity(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Current Power: " .. unit:GetCurrentPower(), "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            cam.End3D2D()
                        end
                    end)
                [Файл] init.lua
                    -- lua/entities/power_distribution_unit/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_combine/breenglobe.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_NONE)
                    
                        self:SetPowerCapacity(100)
                        self:SetCurrentPower(0)
                    
                        -- Register as a power consumer (optional)
                        RegisterConsumer(self, 0) -- Does not consume power itself
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open power distribution panel (handled client-side)
                        if SERVER then
                            activator:SendLua("OpenPowerDistributionPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to distribute power to consumers
                    function ENT:DistributePower()
                        local totalPowerNeeded = 0
                        for consumer, powerNeeded in pairs(PowerConsumers) do
                            if IsValid(consumer) then
                                totalPowerNeeded = totalPowerNeeded + powerNeeded
                            end
                        end
                    
                        if totalPowerNeeded <= self:GetPowerCapacity() then
                            for consumer, powerNeeded in pairs(PowerConsumers) do
                                if IsValid(consumer) then
                                    consumer:ReceivePower(true)
                                end
                            end
                            self:SetCurrentPower(totalPowerNeeded)
                        else
                            -- Distribute power based on priority or other logic
                            local powerLeft = self:GetPowerCapacity()
                            for consumer, powerNeeded in pairs(PowerConsumers) do
                                if IsValid(consumer) then
                                    if powerLeft >= powerNeeded then
                                        consumer:ReceivePower(true)
                                        powerLeft = powerLeft - powerNeeded
                                    else
                                        consumer:ReceivePower(false)
                                    end
                                end
                            end
                            self:SetCurrentPower(self:GetPowerCapacity() - powerLeft)
                        end
                    end
                    
                    function ENT:Think()
                        self:DistributePower()
                        self:NextThink(CurTime() + 1)
                        return true
                    end
                [Файл] shared.lua
                    -- lua/entities/power_distribution_unit/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Power Distribution Unit"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("Int", 0, "PowerCapacity")
                        self:NetworkVar("Int", 1, "CurrentPower")
                    end
            [Папка] resource_node/
                [Файл] cl_init.lua
                    -- lua/entities/resource_node/cl_init.lua
                    
                    include("shared.lua")
                    
                    function ENT:Draw()
                        self:DrawModel()
                    
                        -- Draw resource information above the node for administrators
                        if LocalPlayer():IsAdmin() then
                            cam.Start3D2D(self:GetPos() + Vector(0, 0, 20), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText(self:GetResourceType():upper(), "DermaDefaultBold", 0, 0, Color(255, 215, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Qty: " .. self:GetResourceQuantity(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            cam.End3D2D()
                        end
                    end
                [Файл] init.lua
                    -- lua/entities/resource_node/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        local resourceType = self:GetResourceType()
                        self:SetModel(ResourceTypes[resourceType] and ResourceTypes[resourceType].model or "models/props_debris/concrete_chunk05a.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetResourceQuantity(self.ResourceQuantity)
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        local resourceType = self:GetResourceType()
                        local available = self:GetResourceQuantity()
                    
                        if available <= 0 then
                            activator:ChatPrint("This resource node is depleted.")
                            return
                        end
                    
                        -- Example extraction: 1 unit per use
                        local extracted = 1
                        if available < extracted then extracted = available end
                    
                        if SERVER then
                            local success = AddPlayerResource(activator, resourceType, extracted)
                            if success then
                                self:SetResourceQuantity(available - extracted)
                                if self:GetResourceQuantity() <= 0 then
                                    self:Remove()
                                end
                            end
                        end
                    end
                    
                    function ENT:Think()
                        -- Optional: Regenerate resources over time
                        if SERVER and AddPlayerResource(activator, resourceType, extracted) then
                            self:SetResourceQuantity(available - extracted)
                            if self:GetResourceQuantity() <= 0 then
                                self:Remove()
                            end
                        end
                    
                        self:NextThink(CurTime() + 60) -- Regenerate every 60 seconds
                        return true
                    end
                [Файл] shared.lua
                    -- lua/entities/resource_node/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Resource Node"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = false
                    ENT.AdminOnly = false
                    
                    ENT.ResourceType = "wood" -- Default, can be set when spawned
                    ENT.ResourceQuantity = 10 -- Amount of resource available
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("String", 0, "ResourceType")
                        self:NetworkVar("Int", 1, "ResourceQuantity")
                    end
            [Папка] smelter/
                [Файл] cl_init.lua
                    -- lua/entities/smelter/cl_init.lua
                    
                    include("shared.lua")
                    
                    -- Function to open smelter control panel
                    function OpenSmelterControlPanel(smelter)
                        if not IsValid(smelter) then return end
                        if IsValid(vgui.GetControl("DFrame", "Industrialization_SmelterControlFrame")) then return end
                    
                        local frame = vgui.Create("DFrame")
                        frame:SetTitle("Smelter Control Panel")
                        frame:SetSize(300, 200)
                        frame:Center()
                        frame:MakePopup()
                        frame:SetName("Industrialization_SmelterControlFrame")
                    
                        local startButton = vgui.Create("DButton", frame)
                        startButton:SetText("Start Smelting")
                        startButton:SetPos(50, 50)
                        startButton:SetSize(200, 30)
                        startButton.DoClick = function()
                            smelter:StartSmelting()
                            frame:Close()
                        end
                    
                        local stopButton = vgui.Create("DButton", frame)
                        stopButton:SetText("Stop Smelting")
                        stopButton:SetPos(50, 100)
                        stopButton:SetSize(200, 30)
                        stopButton.DoClick = function()
                            smelter:StopSmelting()
                            frame:Close()
                        end
                    end
                    
                    -- Example: Receive smelter updates
                    net.Receive("Industrialization_UpdateSmelter", function()
                        local smelter = net.ReadEntity()
                        local isSmelting = net.ReadBool()
                        local inputIronOre = net.ReadInt(32)
                        local outputIronIngot = net.ReadInt(32)
                    
                        if not IsValid(smelter) then return end
                    
                        -- Optional: Display information above the smelter
                        hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawSmelterInfo", function()
                            if not IsValid(smelter) then return end
                            cam.Start3D2D(smelter:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText("Smelter", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Smelting: " .. (isSmelting and "Yes" or "No"), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Iron Ore: " .. inputIronOre, "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Iron Ingot: " .. outputIronIngot, "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                            cam.End3D2D()
                        end)
                    end)
                [Файл] init.lua
                    -- lua/entities/smelter/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_c17/oildrum001.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetSmelting(false)
                        self:SetInputIronOre(0)
                        self:SetOutputIronIngot(0)
                    
                        -- Register as a power consumer
                        RegisterConsumer(self, 10) -- Example: needs 10 power units
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open a smelter control panel (handled client-side)
                        if SERVER then
                            activator:SendLua("OpenSmelterControlPanel(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to start smelting
                    function ENT:StartSmelting()
                        if self:GetSmelting() then return end
                        if self:GetInputIronOre() < 1 then
                            NotifyPlayer(nil, "Not enough Iron Ore to start smelting.")
                            return
                        end
                    
                        self:SetSmelting(true)
                        timer.Simple(7, function()
                            if not IsValid(self) then return end
                            if self:GetInputIronOre() >= 1 then
                                self:SetInputIronOre(self:GetInputIronOre() - 1)
                                self:SetOutputIronIngot(self:GetOutputIronIngot() + 1)
                                NotifyAll("A Smelter has processed 1 Iron Ore into an Iron Ingot.")
                            end
                            self:SetSmelting(false)
                        end)
                    end
                    
                    -- Function to stop smelting (if applicable)
                    function ENT:StopSmelting()
                        if not self:GetSmelting() then return end
                        self:SetSmelting(false)
                        NotifyAll("A Smelter has stopped smelting.")
                    end
                    
                    function ENT:Think()
                        -- Continuous logic can be added here if needed
                        self:NextThink(CurTime() + 1)
                        return true
                    end
                [Файл] shared.lua
                    -- lua/entities/smelter/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Smelter"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("Bool", 0, "Smelting")
                        self:NetworkVar("Int", 1, "InputIronOre")
                        self:NetworkVar("Int", 2, "OutputIronIngot")
                    end
            [Папка] warehouse/
                [Файл] cl_init.lua
                    -- lua/entities/warehouse/cl_init.lua
                    
                    include("shared.lua")
                    
                    -- Function to open warehouse inventory
                    function OpenWarehouseInventory(warehouse)
                        if not IsValid(warehouse) then return end
                        if IsValid(vgui.GetControl("DFrame", "Industrialization_WarehouseInventoryFrame")) then return end
                    
                        local frame = vgui.Create("DFrame")
                        frame:SetTitle("Warehouse Inventory")
                        frame:SetSize(500, 600)
                        frame:Center()
                        frame:MakePopup()
                        frame:SetName("Industrialization_WarehouseInventoryFrame")
                    
                        local list = vgui.Create("DListView", frame)
                        list:Dock(FILL)
                        list:AddColumn("Resource")
                        list:AddColumn("Quantity")
                        list:SetMultiSelect(false)
                    
                        -- Populate the list with stored resources
                        local resources = {
                            "wood",
                            "metal",
                            "oil",
                            "minerals",
                            "refined_metal",
                            "electronics",
                            "advanced_gadget"
                        }
                    
                        for _, resource in ipairs(resources) do
                            local qty = warehouse:GetStoredResource(resource)
                            if qty and qty > 0 then
                                list:AddLine(ResourceTypes[resource].name or resource, qty)
                            end
                        end
                    
                        -- Optionally, add buttons to interact with resources
                    end
                    
                    -- Optional: Display information above the warehouse
                    hook.Add("PostDrawOpaqueRenderables", "Industrialization_DrawWarehouseInfo", function()
                        for _, warehouse in ipairs(ents.FindByClass("warehouse")) do
                            if not IsValid(warehouse) then return end
                            cam.Start3D2D(warehouse:GetPos() + Vector(0, 0, 80), Angle(0, LocalPlayer():GetAngles().y - 90, 90), 0.2)
                                draw.SimpleText("Warehouse", "DermaDefaultBold", 0, 0, Color(0, 255, 0, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Wood: " .. warehouse:GetStoredWood(), "DermaDefault", 0, 20, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Metal: " .. warehouse:GetStoredMetal(), "DermaDefault", 0, 40, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                draw.SimpleText("Oil: " .. warehouse:GetStoredOil(), "DermaDefault", 0, 60, Color(255, 255, 255, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
                                -- Add more resources as needed
                            cam.End3D2D()
                        end
                    end)
                [Файл] init.lua
                    -- lua/entities/warehouse/init.lua
                    
                    AddCSLuaFile("cl_init.lua")
                    AddCSLuaFile("shared.lua")
                    
                    include("shared.lua")
                    
                    function ENT:Initialize()
                        self:SetModel("models/props_c17/FurnitureShelf001a.mdl")
                        self:PhysicsInit(SOLID_VPHYSICS)
                        self:SetMoveType(MOVETYPE_NONE)
                        self:SetSolid(SOLID_VPHYSICS)
                    
                        self:SetStoredWood(0)
                        self:SetStoredMetal(0)
                        self:SetStoredOil(0)
                        self:SetStoredMinerals(0)
                        self:SetStoredRefinedMetal(0)
                        self:SetStoredElectronics(0)
                        self:SetStoredAdvancedGadget(0)
                    
                        -- Register as a power consumer (optional)
                        RegisterConsumer(self, 20) -- Example: needs 20 power units
                    end
                    
                    function ENT:Use(activator, caller)
                        if not IsValid(activator) or not activator:IsPlayer() then return end
                    
                        -- Open warehouse inventory UI (handled client-side)
                        if SERVER then
                            activator:SendLua("OpenWarehouseInventory(ents.GetByIndex(" .. self:EntIndex() .. "))")
                        end
                    end
                    
                    -- Function to add resources to the warehouse
                    function ENT:AddResource(resource, qty)
                        if not ResourceTypes[resource] then return end
                        local currentQty = self:GetStoredResource(resource)
                    
                        self:SetStoredResource(resource, currentQty + qty)
                        NotifyAll("A Warehouse has stored " .. qty .. " " .. ResourceTypes[resource].name)
                    end
                    
                    -- Function to remove resources from the warehouse
                    function ENT:RemoveResource(resource, qty)
                        if not ResourceTypes[resource] then return false end
                        local currentQty = self:GetStoredResource(resource)
                    
                        if currentQty >= qty then
                            self:SetStoredResource(resource, currentQty - qty)
                            NotifyAll("A Warehouse has removed " .. qty .. " " .. ResourceTypes[resource].name)
                            return true
                        else
                            return false
                        end
                    end
                    
                    -- Helper function to get stored resource based on resource type
                    function ENT:GetStoredResource(resource)
                        if resource == "wood" then return self:GetStoredWood()
                        elseif resource == "metal" then return self:GetStoredMetal()
                        elseif resource == "oil" then return self:GetStoredOil()
                        elseif resource == "minerals" then return self:GetStoredMinerals()
                        elseif resource == "refined_metal" then return self:GetStoredRefinedMetal()
                        elseif resource == "electronics" then return self:GetStoredElectronics()
                        elseif resource == "advanced_gadget" then return self:GetStoredAdvancedGadget()
                        else return 0 end
                    end
                    
                    -- Helper function to set stored resource based on resource type
                    function ENT:SetStoredResource(resource, qty)
                        if resource == "wood" then self:SetStoredWood(qty)
                        elseif resource == "metal" then self:SetStoredMetal(qty)
                        elseif resource == "oil" then self:SetStoredOil(qty)
                        elseif resource == "minerals" then self:SetStoredMinerals(qty)
                        elseif resource == "refined_metal" then self:SetStoredRefinedMetal(qty)
                        elseif resource == "electronics" then self:SetStoredElectronics(qty)
                        elseif resource == "advanced_gadget" then self:SetStoredAdvancedGadget(qty)
                        end
                    end
                    
                    function ENT:Think()
                        -- Optional: Implement periodic resource checks or other logic
                        self:NextThink(CurTime() + 60)
                        return true
                    end
                [Файл] shared.lua
                    -- lua/entities/warehouse/shared.lua
                    ENT = ENT or {}
                    ENT.Type = "anim"
                    ENT.Base = "base_anim"
                    ENT.PrintName = "Warehouse"
                    ENT.Author = "YourName"
                    ENT.Category = "Industrialization"
                    ENT.Spawnable = true
                    ENT.AdminOnly = false
                    
                    function ENT:SetupDataTables()
                        self:NetworkVar("Int", 0, "StoredWood")
                        self:NetworkVar("Int", 1, "StoredMetal")
                        self:NetworkVar("Int", 2, "StoredOil")
                        self:NetworkVar("Int", 3, "StoredMinerals")
                        self:NetworkVar("Int", 4, "StoredRefinedMetal")
                        self:NetworkVar("Int", 5, "StoredElectronics")
                        self:NetworkVar("Int", 6, "StoredAdvancedGadget")
                    end
        [Папка] modules/
            [Файл] power_system.lua
                -- lua/modules/power_system.lua
                
                if SERVER then
                    util.AddNetworkString("Industrialization_UpdatePowerStatus")
                    util.AddNetworkString("Industrialization_Notify")
                
                    PowerGenerators = PowerGenerators or {}
                    PowerConsumers = PowerConsumers or {}
                
                    -- Function to register a generator
                    function RegisterGenerator(generator)
                        table.insert(PowerGenerators, generator)
                    end
                
                    -- Function to register a consumer
                    function RegisterConsumer(consumer, powerNeeded)
                        PowerConsumers[consumer] = powerNeeded
                    end
                
                    -- Function to distribute power every second
                    timer.Create("Industrialization_PowerDistribution", 1, 0, function()
                        local totalPower = 0
                        for _, gen in ipairs(PowerGenerators) do
                            if IsValid(gen) and gen:GetFuel() > 0 then
                                totalPower = totalPower + gen:GetPowerOutput()
                                gen:SetFuel(gen:GetFuel() - 1) -- Consume fuel
                                if gen:GetFuel() <= 0 then
                                    -- Generator ran out of fuel
                                    net.Start("Industrialization_Notify")
                                        net.WriteString("A generator has run out of fuel and stopped producing power.")
                                    net.Broadcast()
                                end
                            end
                        end
                
                        -- Distribute power to consumers based on totalPower
                        for consumer, powerNeeded in pairs(PowerConsumers) do
                            if IsValid(consumer) then
                                if totalPower >= powerNeeded then
                                    consumer:ReceivePower(true)
                                else
                                    consumer:ReceivePower(false)
                                end
                            end
                        end
                
                        -- Send power status to clients
                        net.Start("Industrialization_UpdatePowerStatus")
                            net.WriteInt(totalPower, 32)
                        net.Broadcast()
                    end)
                end
                
                if CLIENT then
                    -- Handle power status updates on client-side
                    net.Receive("Industrialization_UpdatePowerStatus", function()
                        local totalPower = net.ReadInt(32)
                        -- Update UI or display power status as needed
                        -- Example: Print to chat
                        print("Total Power Available: " .. totalPower)
                    end)
                
                    net.Receive("Industrialization_Notify", function()
                        local message = net.ReadString()
                        chat.AddText(Color(255, 0, 0), "[Industrialization] ", Color(255, 255, 255), message)
                    end)
                end
            [Файл] resource_management.lua
                -- lua/modules/resource_management.lua
                
                if SERVER then
                    util.AddNetworkString("Industrialization_UpdateInventory")
                    util.AddNetworkString("Industrialization_Notify")
                
                    PlayerInventory = PlayerInventory or {}
                    AvailableResources = AvailableResources or {
                        wood = 500,
                        metal = 300,
                        oil = 200,
                        minerals = 100,
                    }
                
                    -- Initialize player inventory on spawn
                    hook.Add("PlayerInitialSpawn", "Industrialization_InitInventory", function(player)
                        PlayerInventory[player:SteamID()] = {
                            wood = 0,
                            metal = 0,
                            oil = 0,
                            minerals = 0,
                            refined_metal = 0,
                            electronics = 0,