spacebuild/spacebuild

View on GitHub
lua/caf/addons/client/resourcedistribution.lua

Summary

Maintainability
Test Coverage
local RD = {}
--local nettable = {};
--local ent_table = {};
local resourcenames = {}
local resources = {}
local status = false

local rd_cache = cache.create(1, false) --Store data for 1 second
--[[

]]

--local functions

RD_OverLay_Distance = CreateClientConVar("rd_overlay_distance", "512", false, false)
RD_OverLay_Mode = CreateClientConVar("rd_overlay_mode", "-1", false, false)
local client_chosen_number = CreateClientConVar("number_to_send", "1", false, false)
local client_chosen_hold = CreateClientConVar("number_to_hold", "0", false, false)

----------NetTable functions

local function CreateNetTable(netid)
    nettable[netid] = {}
    local index = nettable[netid]
    index.resources = {}
    index.cons = {}
end
--[[
umsg.Start("RD_AddNet")
        umsg.Short(netid)
    umsg.End()
]]
--[[local function AddNet( um )
    local netid = um:ReadShort()
    if netid > 0 then
        CreateNetTable(netid)
    end
end
usermessage.Hook("RD_AddNet", AddNet)]]

--[[
umsg.Start("RD_AddResoureToNet")
        umsg.Short(netid)
        umsg.String(resource)
        umsg.Long(maxvalue)
        umsg.Long(value)
    umsg.End()
]]

--[[local function AddResoureToNet( um )
    local netid = um:ReadShort()
    local resource = um:ReadString()
    local maxvalue = um:ReadLong()
    local value = um:ReadLong()
    if not table.HasValue(resources, resource) then
        table.insert(resources, resource)
    end
    if netid > 0 then
        if not nettable[netid] then
            CreateNetTable(netid)
        end
        nettable[netid].resources[resource] = {}
        nettable[netid].resources[resource].maxvalue = maxvalue
        nettable[netid].resources[resource].value = value
    end
end
usermessage.Hook("RD_AddResoureToNet", AddResoureToNet)]]

--[[

--Needed?
umsg.Start("RD_AddConToNet")
        umsg.Short(netid)
        umsg.Short(entid)
    umsg.End()
]]

--[[local function AddConToNet(um)
    local netid = um:ReadShort()
    local conid = um:ReadShort()
    if netid > 0 then
        if not nettable[netid] then
            CreateNetTable(netid)
        end
        table.insert(nettable[netid].cons, conid)
    end
end
usermessage.Hook("RD_AddConToNet", AddConToNet)]]

--[[
umsg.Start("RD_RemoveNetCons")
        umsg.Short(netid)
    umsg.End()
]]

--[[local function RemoveConsFromNet( um)
    local netid = um:ReadShort()
    if netid > 0 then
        if not nettable[netid] then
            CreateNetTable(netid)
        end
        nettable[netid].cons = {}
    end
end
usermessage.Hook("RD_RemoveNetCons", RemoveConsFromNet)]]
--[[
umsg.Start("RD_RemoveNet")
        umsg.Short(netid)
    umsg.End()
]]

--[[local function RemoveNet( um)
    local netid = um:ReadShort()
    if netid > 0 then
        nettable[netid] = nil
    end
end
usermessage.Hook("RD_RemoveNet", RemoveNet)]]

---------ent_table functions
--[[
umsg.Start("RD_AddEnt")
        umsg.Short(entid)
    umsg.End()
]]

--[[local function CreateEntTable(entid)
    ent_table[entid] = {}
    ent_table[entid].network = 0
    ent_table[entid].resources = {}
end

local function AddEnt( um )
    local entid = um:ReadShort()
    CreateEntTable(entid)
end
usermessage.Hook("RD_AddEnt", AddEnt)]]


--[[
umsg.Start("RD_AddResoureToEnt")
        umsg.Short(entid)
        umsg.String(resource)
        umsg.Long(maxvalue)
        umsg.Long(value)
    umsg.End()
]]

--[[local function AddResourceToEnt( um )
    local entid = um:ReadShort()
    local resource = um:ReadString()
    local maxvalue = um:ReadLong()
    local value = um:ReadLong()
    if not ent_table[entid] then
        CreateEntTable(entid)
    end
    ent_table[entid].resources[resource] = {}
    ent_table[entid].resources[resource].maxvalue = maxvalue
    ent_table[entid].resources[resource].value = value
end
usermessage.Hook("RD_AddResoureToEnt", AddResourceToEnt)]]

--[[
umsg.Start("RD_ChangeNetOnEnt")
        umsg.Short(entid)
        umsg.Short(netid)
    umsg.End()
]]
--[[local function ChangeNetOnEnt( um )
    local entid = um:ReadShort()
    local netid = um:ReadShort()
    if not ent_table[entid] then
        CreateEntTable(entid)
    end
    ent_table[entid].network = netid
end
usermessage.Hook("RD_ChangeNetOnEnt", ChangeNetOnEnt)]]

--[[
umsg.Start("RD_RemoveEnt")
        umsg.Short(entid)
    umsg.End()
]]
--[[local function RemoveEnt( um )
    local entid = um:ReadShort()
    ent_table[entid] = nil
end
usermessage.Hook("RD_RemoveEnt", RemoveEnt)]]

------ nettable and ent_table
--[[
umsg.Start("RD_ClearNets")
    umsg.End()
]]
local function ClearNets( um )
    --nettable = {}
    --ent_table = {}
    rd_cache:clear();
end
usermessage.Hook("RD_ClearNets", ClearNets)

--[[
umsg.Start("RD_Entity_Data", ply)
    umsg.Short(entid) --send key to update
    umsg.Short(rddata.network) --send network used in entity
    
    local nr_of_resources = table.Count(rddata.resources);
    umsg.Short(nr_of_resources) --How many resources are going to be send?
    if nr_of_resources > 0 then
        for l, w in pairs(rddata.resources) do
            umsg.String(l)
            umsg.Long(w.maxvalue)
            umsg.Long(w.value)
        end
    end
    
umsg.End()
]]

local function ReadBool()
   return net.ReadBit() == 1
end

local function ReadShort()
   return net.ReadInt(16);
end

local function ReadLong()
    return net.ReadInt(32);
end

local dev = GetConVar("developer")
local function AddEntityToCache( nrofbytes )
    if dev:GetBool() then print("RD_Entity_Data #", nrofbytes, " bytes received") end
    local data = {}

    data.entid = ReadShort() --Key
    local up_to_date = ReadBool();
    if up_to_date then
        rd_cache:update("entity_"..tostring(data.entid))
    end
    data.network = ReadShort() --network key
    
    data.resources = {}
    local i = 0;
    local nr_of_resources = ReadShort();
    if (nr_of_resources > 0) then
        --print("nr_of_sources", nr_of_resources)
        local resource 
        local maxvalue 
        local value
        for i = 1, nr_of_resources do
            --print(i)
            resource = net.ReadString()
            maxvalue = ReadLong()
            value = ReadLong()
            
            data.resources[resource] = {value = value, maxvalue = maxvalue}
        end
    end
    
    rd_cache:add("entity_"..tostring(data.entid), data)
end
net.Receive("RD_Entity_Data", AddEntityToCache)

--[[
umsg.Start("RD_Network_Data", ply)
        umsg.Short(netid) --send key to update
        
        local nr_of_resources = table.Count(rddata.resources);
        umsg.Short(nr_of_resources) --How many resources are going to be send?
        if nr_of_resources > 0 then
            for l, w in pairs(rddata.resources) do
                umsg.String(l)
                umsg.Long(w.maxvalue)
                umsg.Long(w.value)
            end
        end
        
        local nr_of_cons = table.Count(rddata.cons);
        umsg.Short(nr_of_cons) --How many connections are going to be send?
        if nr_of_cons > 0 then
            for l, w in pairs(rddata.cons) do
                umsg.Short(w)
            end
        end
        
    umsg.End()

]]

local function AddNetworkToCache( nrofbytes )
    if dev:GetBool() then print("RD_Network_Data #", nrofbytes, " bytes received") end
    local data = {}
    
    data.netid = ReadShort() --network key
    local up_to_date = ReadBool();
    if up_to_date then
        rd_cache:update("network_"..tostring(data.netid))
    end
    
    data.resources = {}
    local i = 0;
    local nr_of_resources = ReadShort();
    if (nr_of_resources > 0) then
        --print("nr_of_sources", nr_of_resources)
        local resource 
        local maxvalue 
        local value
        local localmaxvalue
        local localvalue
        for i = 1, nr_of_resources do
            --print(i)
            resource = net.ReadString()
            maxvalue = ReadLong()
            value = ReadLong()
            localmaxvalue = ReadLong()
            localvalue = ReadLong()
            
            data.resources[resource] = {value = value, maxvalue = maxvalue, localvalue = localvalue, localmaxvalue = localmaxvalue}
        end
    end
    
    data.cons = {}
    local nr_of_cons = ReadShort();
    if (nr_of_cons > 0) then
        --print("nr_of_cons", nr_of_cons)
        for i = 1, nr_of_cons do
            --print(i)
            con = ReadShort()
            table.insert(data.cons, con);
        end
    end
    
    rd_cache:add("network_"..tostring(data.netid), data)
end
net.Receive("RD_Network_Data", AddNetworkToCache)

--end local functions

--The Class
--[[
    The Constructor for this Custom Addon Class
]]
function RD.__Construct()
    status = true
    return true
    --return false , "No Implementation yet"
end

--[[
    The Destructor for this Custom Addon Class
]]
function RD.__Destruct()
    status = false
    return true
    --return false , "No Implementation yet"
end

--[[
    Get the required Addons for this Addon Class
]]
function RD.GetRequiredAddons()
    return {}
end

--[[
    Get the Boolean Status from this Addon Class
]]
function RD.GetStatus()
    return status
end

--[[
    Get the Version of this Custom Addon Class
]]
function RD.GetVersion()
    return 3.1, "Alpha"
end

local isuptodatecheck;
--[[
    Update check
]]
function RD.IsUpToDate(callBackfn)
    if not CAF.HasInternet then
        return
    end
    if isuptodatecheck ~= nil then
        callBackfn(isuptodatecheck);
        return
    end
    --[[http.Get("http://www.snakesvx.net/versions/rd.txt","",
        function(html,size)
            local version = tonumber(html);
            if(version) then
                local latest = version;
                if(latest > RD.GetVersion()) then
                    isuptodatecheck = false;
                    callBackfn(false)
                else
                    isuptodatecheck = true;
                    callBackfn(true)
                end
            end
        end
    ); ]]
end

--[[
    Get any custom options this Custom Addon Class might have
]]
function RD.GetExtraOptions()
    return {}
end

--[[
    Gets a menu from this Custom Addon Class
]]
function RD.GetMenu(menutype, menuname) --Name is nil for main menu, String for others
    local data = {}
    return data
end

--[[
    Get the Custom String Status from this Addon Class
]]
function RD.GetCustomStatus()
    return ; --CAF.GetLangVar("Not Implemented Yet")
end

--[[
    Returns a table containing the Description of this addon
]]
function RD.GetDescription()
    return {
                "Resource Distribution",
                "",
                ""
            }
end
CAF.RegisterAddon("Resource Distribution", RD, "1")

--[[ Shared stuff ]]

--TODO UPDATE FROM HERE

--RD.GetEntityTable(ent)
--RD.GetNetTable(netid)

--[[function RD.getConnectedNets(netid) -- NEEDED ANYWHERE?
    local contable = {}
    local tmpcons = { netid}
    while(table.Count(tmpcons) > 0) do
        for k, v in pairs(tmpcons) do
            if not table.HasValue(contable, v) then
                table.insert(contable, v)
                if nettable[v] and nettable[v].cons then
                    if table.Count(nettable[v].cons) > 0 then
                        for l, w in pairs(nettable[v].cons) do
                            table.insert(tmpcons, w)
                        end
                    end
                end
            end
            table.remove(tmpcons, k)
        end
    end
    return contable
end]]

function RD.GetNetResourceAmount(netid, resource)
    if not resource then return 0, "No resource given" end
    local data = RD.GetNetTable(netid);
    if not data then return 0, "Not a valid network" end
    if not data.resources or (data.resources and table.Count(data.resources)==0) then return 0, "No resources available" end
    if not data.resources[resource] then return 0, "Resource not available" end

    local amount = 0;
    amount = data.resources[resource].value
    return amount
end

function RD.GetResourceAmount(ent, resource)
    if not IsValid( ent ) then return 0, "Not a valid entity" end
    if not resource then return 0, "No resource given" end
    local data=RD.GetEntityTable(ent)
    if not data.resources or (data.resources and table.Count(data.resources)==0) then return 0, "No resources available" end
    if not data.resources[resource] then return 0, "Resource not available" end

    local amount = 0
    amount = data.resources[resource].value
    return amount
end

--[[function RD.GetUnitCapacity(ent, resource)
    if not IsValid( ent ) then return 0, "Not a valid entity" end
    if not resource then return 0, "No resource given" end
    local amount = 0
    if ent_table[ent:EntIndex( )] then
        local index = ent_table[ent:EntIndex( )];
        if index.resources[resource] then
            amount = index.resources[resource].maxvalue
        end
    end
    return amount
end]]

function RD.GetNetNetworkCapacity(netid, resource)
    if not resource then return 0, "No resource given" end
    local data = RD.GetNetTable(netid);
    if not data then return 0, "Not a valid network" end
    if not data.resources or (data.resources and table.Count(data.resources)==0) then return 0, "No resources available" end
    if not data.resources[resource] then return 0, "Resource not available" end

    local amount = 0;
    amount = data.resources[resource].maxvalue
    return amount
end

function RD.GetNetworkCapacity(ent, resource)
    if not IsValid( ent ) then return 0, "Not a valid entity" end
    if not resource then return 0, "No resource given" end
    local data = RD.GetEntityTable(ent)
    if not data then return 0, "Not a valid network" end
    if not data.resources or (data.resources and table.Count(data.resources)==0) then return 0, "No resources available" end
    if not data.resources[resource] then return 0, "Resource not available" end

    local amount = 0
    if data.resources[resource] then
        amount = data.resources[resource].maxvalue
    end
    return amount
end

local requests = {}
local ttl = 0.2; --Wait 0.2 second before doing a new request

function RD.GetEntityTable(ent)
    local entid = ent:EntIndex( )
    local id = "entity_"..tostring(entid)
    local data, needs_update = rd_cache:get(id);
    if not data or needs_update then
        if not requests[id] or requests[id] < CurTime() then
            --Do (new) request
            requests[id] = CurTime() + ttl;
            RunConsoleCommand("RD_REQUEST_RESOURCE_DATA", "ENT", entid, needs_update and "UPDATE");
        end
    end
    --PrintTable(data)
    return data or {}
end

function RD.GetNetTable(netid)
    local id = "network_"..tostring(netid)
    local data, needs_update = rd_cache:get(id);
    if not data or needs_update then
        if not requests[id] or requests[id] < CurTime() then
            --Do (new) request
            requests[id] = CurTime() + ttl;
            RunConsoleCommand("RD_REQUEST_RESOURCE_DATA", "NET", netid, needs_update and "UPDATE");
        end
    end
    return data or {}
end

--TODO UPDATE TO HERE

function RD.AddProperResourceName(resource, name)
    if not resource or not name then return end
    if not table.HasValue(resources, resource) then
        table.insert(resources, resource)
    end
    resourcenames[resource] = name
end

function RD.GetProperResourceName(resource)
    if not resource then return "" end
    if resourcenames[resource] then
        return resourcenames[resource]
    end
    return resource
end

function RD.GetAllRegisteredResources()
    if not resourcenames or table.Count(resourcenames) < 0 then
        return {}
    end
    return table.Copy(resourcenames)
end

function RD.GetRegisteredResources()
    return table.Copy(resources)
end

--[[function RD.GetNetworkIDs() --NEEDED FOR SOMEONE?
    local ids = {}
    if table.Count(nettable) > 0 then
        for k, v in pairs(nettable) do
            if not v.clear then
                table.insert(ids, k)
            end
        end
    end
    return ids
end]]

function RD.PrintDebug(ent)
    if ent then
        if ent.IsNode then
            local nettable = RD.GetNetTable(ent.netid)
            PrintTable(nettable)
        elseif ent.IsValve then
            --
        elseif ent.IsPump then
            --
        else
            local enttable = RD.GetEntityTable(ent)
            PrintTable(enttable)
        end
    end
end

list.Add( "BeamMaterials", "cable/rope_icon" )
list.Add( "BeamMaterials", "cable/cable2" )
list.Add( "BeamMaterials", "cable/xbeam" )
list.Add( "BeamMaterials", "cable/redlaser" )
list.Add( "BeamMaterials", "cable/blue_elec" )
list.Add( "BeamMaterials", "cable/physbeam" )
list.Add( "BeamMaterials", "cable/hydra" )

--holds the materials
beamMat = {}

for _,mat in pairs(list.Get( "BeamMaterials" )) do
    beamMat[mat] = Material(mat)
end

-----------------------------------------
--START BEAMS BY MADDOG
-----------------------------------------

local xbeam = Material("cable/xbeam")
-- Desc: draws beams on ents
function RD.Beam_Render( ent )

    --get the number of beams to use
    local intBeams = ent:GetNWInt( "Beams" )

    --if we have beams, then create them
    if intBeams and intBeams ~= 0 then
        --make some vars we are about to use
        local i, start, scroll = 1, ent:GetNWVector( "Beam1" ), CurTime() * 0.5

        --get beam info and explode into a table
        local beamInfo = string.Explode(";", ent:GetNWString("BeamInfo"))

        --get beam info from table (1: beamMaterial 2: beamSize 3: beamR 4: beamG 5: beamB 6: beamAlpha)
        local beamMaterial, beamSize, color = (beamMat[beamInfo[1]] or xbeam), (beamInfo[2] or 2), Color( beamInfo[3] or 255, beamInfo[4] or 255, beamInfo[5] or 255, beamInfo[6] or 255 )

        -- set material
        render.SetMaterial( beamMaterial )
        render.StartBeam( intBeams )    --how many links (points) the beam has

        --loop through all beams
        for i=1,intBeams do
            --get beam data
            local beam, ent = ent:GetNWVector( "Beam" .. tostring(i) ), ent:GetNWEntity( "BeamEnt" .. tostring(i) )

            --if no beam break for statement
            if not beam or  not ent or not ent:IsValid() then
                ent:SetNWInt( "Beams", 0 )
                break
            end

            --get beam world vector
            local pos = ent:LocalToWorld(beam)

            --update scroll
            scroll = scroll - (pos-start):Length()/10

            -- add point
            render.AddBeam(pos, beamSize, scroll, color)

            --reset start postion
            start = pos
        end

        --beam done
        render.EndBeam()
    end
end
-----------------------------------------
--END BEAMS BY MADDOG
-----------------------------------------

--Alternate Use Code--

local function GenUseMenu(ent)
    local SmallFrame = vgui.Create("DFrame")
    SmallFrame:SetPos( (ScrW()/2)-110,(ScrH()/2)-100)
    SmallFrame:SetSize( 220, (#ent.Inputs*40)+90 )
    SmallFrame:SetTitle( ent.PrintName )
    
    local ypos = 30
    
    local HoldSlider = vgui.Create( "DNumSlider", SmallFrame )
        HoldSlider:SetPos( 10,ypos )
        HoldSlider:SetSize( 200, 30 )
        HoldSlider:SetText( "Time to Hold:" )
        HoldSlider:SetMin( 0 )
        HoldSlider:SetMax( 10 )
        HoldSlider:SetDecimals( 1 )
        HoldSlider:SetConVar( "number_to_hold" )
        
        ypos = ypos + 40
    for k,v in pairs(ent.Inputs) do
        local NumSliderThingy = vgui.Create( "DNumSlider", SmallFrame )
        NumSliderThingy:SetPos( 10,ypos )
        NumSliderThingy:SetSize( 120, 30 )
        NumSliderThingy:SetText( v.." :" )
        NumSliderThingy:SetMin( 0 )
        NumSliderThingy:SetMax( 10 )
        NumSliderThingy:SetDecimals( 0 )
        NumSliderThingy:SetConVar( "number_to_send" )
        
        local SendButton = vgui.Create( "DButton", SmallFrame )
        SendButton:SetPos(140,ypos)
        SendButton:SetText("Send Command")
        SendButton:SizeToContents()
        SendButton.DoClick = function()
            RunConsoleCommand("send_input_selection_to_server",ent.serverindex,v,client_chosen_number:GetInt(),client_chosen_hold:GetFloat())
        end
        
        ypos = ypos + 40
    end
    
    SmallFrame:MakePopup()
end 

local function RecieveInputs(um)
    local last = um:ReadBool()
    local input = um:ReadString()
    local index = um:ReadShort()
    local ent = ents.GetByIndex(index)
    ent.serverindex = index
    if not ent.Inputs then ent.Inputs = {} end
    if not table.HasValue(ent.Inputs,input) then table.insert(ent.Inputs,input) end
    if last and last == true then
        GenUseMenu(ent)
    end
end
usermessage.Hook("RD_AddInputToMenu", RecieveInputs)