mirror of
https://github.com/CFC-Servers/cfc_chip_lister.git
synced 2025-03-04 03:03:14 -05:00
Initial setup
This commit is contained in:
parent
a0d79288cb
commit
583dba9b20
18
README.md
18
README.md
@ -1,2 +1,18 @@
|
||||
# cfc_chip_lister
|
||||
Doritos, Lays, Pringles - a list of our favorite potato or corn-based snacks
|
||||
Adds a board to track the owners, names, and processing time of Expression 2 and Starfall chips in GMod.
|
||||
|
||||
## Server Convars
|
||||
|
||||
| Convar | Description | Default |
|
||||
| :---: | :---: | :---: |
|
||||
| cfc_chiplister_interval | How often (in seconds) the chip lister will update and send info to players. | 1 |
|
||||
|
||||
## Client Convars
|
||||
|
||||
| Convar | Description | Default |
|
||||
| :---: | :---: | :---: |
|
||||
| cfc_chiplister_enabled | Enables the Expression2/Starfall chip lister. | 1 |
|
||||
| cfc_chiplister_hud_enabled | Whether or not to display the chip lister on your screen at all times. | 0 |
|
||||
| cfc_chiplister_hud_scale | The size of the chip lister on your HUD, scaled by your screen width. | 0.2 |
|
||||
| cfc_chiplister_hud_pos_x | The x-position of the chip lister on your HUD, scaled by your screen width. | 0.8 |
|
||||
| cfc_chiplister_hud_pos_y | The y-position of the chip lister on your HUD, scaled by your screen height. | 0.2 |
|
||||
|
321
lua/autorun/client/cl_chip_lister.lua
Normal file
321
lua/autorun/client/cl_chip_lister.lua
Normal file
@ -0,0 +1,321 @@
|
||||
include( "cfc_chip_lister/shared/sh_chip_lister.lua" )
|
||||
|
||||
local ID_WORLD = "[WORLD]"
|
||||
local CPUS_FORMAT = "%05d"
|
||||
local STR_GLOBAL = "Overall Total CPUs: "
|
||||
local STR_TOTAL = "Total: "
|
||||
local STR_CPUS = " CPUs: "
|
||||
local STR_MICROSECONDS = utf8.char( 181 ) .. "s"
|
||||
local STR_TITLE = "-----E2/SF Lister-----"
|
||||
local STR_TOGGLE = "(Press " .. string.upper( input.LookupBinding( "+use" ) or "e" ) .. "/use to toggle)"
|
||||
local STR_ENABLE = "Press " .. string.upper( input.LookupBinding( "+use" ) or "e" ) .. "/use to turn on"
|
||||
local STR_WAITING = "Waiting for next update from the server..."
|
||||
local RENDER_TARGET_NAME = "cfc_chiplister_rt"
|
||||
local MATERIAL_NAME = "cfc_chiplister_screen"
|
||||
local FONT_NAME = "CFC_ChipLister_Font"
|
||||
local FONT_SIZE = 30
|
||||
local MAX_ELEMENTS = 30
|
||||
local SCREEN_SIZE = 1024
|
||||
local SCREEN_SIZE_HALF = SCREEN_SIZE / 2
|
||||
local TOGGLE_DIST = 1500
|
||||
local COLOR_BACKGROUND = Color( 0, 0, 0, 255 )
|
||||
local COLOR_DIVIDER = Color( 255, 255, 255, 255 )
|
||||
local COLOR_TEXT = Color( 255, 255, 255, 255 )
|
||||
local COLOR_TEXT_FADED
|
||||
local COLOR_MICROS
|
||||
local COLOR_WORLD = Color( 150, 120, 120, 255 )
|
||||
local COLOR_FADE_OFFSET = Color( 0, 0, -0.65 )
|
||||
local COLOR_FADE_MICROS_OFFSET = Color( 0, 0, -0.25 )
|
||||
local CHIP_COLORS = {
|
||||
E2 = Color( 216, 34, 45, 255 ),
|
||||
SF = Color( 55, 100, 252, 255 ),
|
||||
}
|
||||
|
||||
local rtChipLister = GetRenderTarget( RENDER_TARGET_NAME, SCREEN_SIZE, SCREEN_SIZE )
|
||||
local INFO_OFFSET_OWNER = 0
|
||||
local INFO_OFFSET_CHIP = 0
|
||||
local TOGGLE_DIST_SQR = TOGGLE_DIST ^ 2
|
||||
|
||||
local matChipLister = CreateMaterial( MATERIAL_NAME, "UnlitGeneric", {
|
||||
["$basetexture"] = RENDER_TARGET_NAME,
|
||||
["$model"] = 1,
|
||||
} )
|
||||
|
||||
local isValid = IsValid
|
||||
local rawset = rawset
|
||||
local rawget = rawget
|
||||
local _colorToHSV = ColorToHSV
|
||||
local _hsvToColor = HSVToColor
|
||||
local stringLen = string.len
|
||||
local stringSub = string.sub
|
||||
local stringFormat = string.format
|
||||
local teamGetColor = team.GetColor
|
||||
local getClass
|
||||
local getTeam
|
||||
|
||||
local FONT_DATA = {
|
||||
font = "Roboto Mono",
|
||||
extended = false,
|
||||
size = FONT_SIZE,
|
||||
weight = 500,
|
||||
blursize = 0,
|
||||
scanlines = 0,
|
||||
antialias = true,
|
||||
underline = false,
|
||||
italic = false,
|
||||
strikeout = false,
|
||||
symbol = false,
|
||||
rotary = false,
|
||||
shadow = false,
|
||||
Additive = false,
|
||||
outline = false,
|
||||
}
|
||||
|
||||
do
|
||||
local entityMeta = FindMetaTable( "Entity" )
|
||||
|
||||
getClass = entityMeta.GetClass
|
||||
|
||||
|
||||
local playerMeta = FindMetaTable( "Player" )
|
||||
|
||||
getTeam = playerMeta.Team
|
||||
|
||||
|
||||
if not file.Exists( "resource/fonts/RobotoMono.ttf", "MOD" ) then
|
||||
local files, folders = file.Find( "resource/fonts/*", "THIRDPARTY" )
|
||||
local robotoExists = false
|
||||
|
||||
for _, v in ipairs( files ) do
|
||||
if v == "RobotoMono.ttf" then
|
||||
robotoExists = true
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not robotoExists then
|
||||
FONT_DATA.font = "Arial"
|
||||
end
|
||||
end
|
||||
|
||||
surface.CreateFont( FONT_NAME, FONT_DATA )
|
||||
|
||||
surface.SetFont( FONT_NAME )
|
||||
INFO_OFFSET_OWNER = -surface.GetTextSize( STR_TOTAL .. stringFormat( CPUS_FORMAT, 0 ) .. STR_MICROSECONDS )
|
||||
INFO_OFFSET_CHIP = -surface.GetTextSize( table.GetKeys( CHIP_COLORS )[1] .. " " .. stringFormat( CPUS_FORMAT, 0 ) .. STR_MICROSECONDS )
|
||||
end
|
||||
|
||||
local LISTER_ENABLED = CreateClientConVar( "cfc_chiplister_enabled", 1, true, false, "Enables the Expression2/Starfall chip lister." )
|
||||
|
||||
local listerEnabled = LISTER_ENABLED:GetBool()
|
||||
|
||||
|
||||
include( "cfc_chip_lister/client/cl_hud.lua" )
|
||||
|
||||
|
||||
local function colorToHSV( color )
|
||||
return Color( _colorToHSV( color ) )
|
||||
end
|
||||
|
||||
local function hsvToColor( color )
|
||||
return _hsvToColor( color.r, color.g, color.b )
|
||||
end
|
||||
|
||||
local function formatCPUs( num )
|
||||
local usageStr = stringFormat( CPUS_FORMAT, num or 0 )
|
||||
local leadStr = ""
|
||||
local numStr = ""
|
||||
local leadCount = 0
|
||||
|
||||
for i = 1, stringLen( usageStr ) do
|
||||
if stringSub( usageStr, i, i ) == "0" then
|
||||
leadStr = leadStr .. "0"
|
||||
leadCount = leadCount + 1
|
||||
else
|
||||
return leadStr, stringSub( usageStr, leadCount + 1 )
|
||||
end
|
||||
end
|
||||
|
||||
return leadStr, ""
|
||||
end
|
||||
|
||||
local function getTeamColor( ply )
|
||||
if ply == ID_WOLRD or not isValid( ply ) then
|
||||
return COLOR_WORLD
|
||||
end
|
||||
|
||||
return teamGetColor( getTeam( ply ) )
|
||||
end
|
||||
|
||||
local function fadeColor( color, fadeOverride )
|
||||
local hsv = colorToHSV( color )
|
||||
local off = fadeOverride or COLOR_FADE_OFFSET
|
||||
|
||||
return _hsvToColor( hsv.r + off.r, hsv.g + off.g, hsv.b + off.b )
|
||||
end
|
||||
|
||||
COLOR_TEXT_FADED = fadeColor( COLOR_TEXT )
|
||||
COLOR_MICROS = fadeColor( COLOR_TEXT, COLOR_FADE_MICROS_OFFSET )
|
||||
|
||||
|
||||
cvars.AddChangeCallback( "cfc_chiplister_enabled", function( _, old, new )
|
||||
local state = new ~= "0"
|
||||
|
||||
if state == listerEnabled then return end
|
||||
|
||||
listerEnabled = state
|
||||
|
||||
net.Start( "CFC_ChipLister_SetEnabled" )
|
||||
net.WriteBool( listerEnabled )
|
||||
net.SendToServer()
|
||||
|
||||
if listerEnabled then
|
||||
render.PushRenderTarget( rtChipLister )
|
||||
cam.Start2D()
|
||||
|
||||
surface.SetDrawColor( COLOR_BACKGROUND )
|
||||
surface.DrawRect( 0, 0, SCREEN_SIZE, SCREEN_SIZE )
|
||||
|
||||
draw.SimpleText( STR_WAITING, FONT_NAME, SCREEN_SIZE_HALF, SCREEN_SIZE_HALF, COLOR_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
else
|
||||
render.PushRenderTarget( rtChipLister )
|
||||
cam.Start2D()
|
||||
|
||||
surface.SetDrawColor( COLOR_BACKGROUND )
|
||||
surface.DrawRect( 0, 0, SCREEN_SIZE, SCREEN_SIZE )
|
||||
|
||||
draw.SimpleText( STR_ENABLE, FONT_NAME, SCREEN_SIZE_HALF, SCREEN_SIZE_HALF, COLOR_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
|
||||
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
end
|
||||
end )
|
||||
|
||||
|
||||
hook.Add( "InitPostEntity", "CFC_ChipLister_InformServerOfPlayerChoice", function()
|
||||
timer.Simple( 10, function()
|
||||
net.Start( "CFC_ChipLister_SetEnabled" )
|
||||
net.WriteBool( LISTER_ENABLED:GetBool() )
|
||||
net.SendToServer()
|
||||
end )
|
||||
end )
|
||||
|
||||
hook.Add( "KeyPress", "CFC_ChipLister_ToggleScreen", function( ply, key ) -- ply i always LocalPlayer() on client
|
||||
if key ~= IN_USE then return end
|
||||
|
||||
local tr = ply:GetEyeTrace()
|
||||
local ent = tr.Entity
|
||||
|
||||
if not isValid( ent ) or getClass( ent ) ~= "cfc_chip_lister" then return end
|
||||
if tr.StartPos:DistToSqr( tr.HitPos ) > TOGGLE_DIST_SQR then return end
|
||||
|
||||
ply:ConCommand( "cfc_chiplister_enabled " .. ( listerEnabled and "0" or "1" ) )
|
||||
end )
|
||||
|
||||
|
||||
net.Receive( "CFC_ChipLister_UpdateListData", function()
|
||||
if not listerEnabled then return end
|
||||
|
||||
local perPlyData = net.ReadTable()
|
||||
local globalUsage = net.ReadUInt( 20 )
|
||||
local plyCount = rawget( perPlyData, "Count" )
|
||||
local elemCount = 0
|
||||
local x = 0
|
||||
local xEnd = SCREEN_SIZE_HALF
|
||||
local y = 0
|
||||
|
||||
globalUsageStrLead, globalUsageStr = formatCPUs( globalUsage )
|
||||
|
||||
render.PushRenderTarget( rtChipLister )
|
||||
cam.Start2D()
|
||||
|
||||
surface.SetDrawColor( COLOR_BACKGROUND )
|
||||
surface.SetFont( FONT_NAME )
|
||||
surface.SetTextColor( COLOR_TEXT )
|
||||
surface.DrawRect( 0, 0, SCREEN_SIZE, SCREEN_SIZE )
|
||||
|
||||
draw.SimpleText( STR_TITLE, FONT_NAME, SCREEN_SIZE_HALF, 0, COLOR_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP )
|
||||
y = y + FONT_SIZE
|
||||
draw.SimpleText( STR_TOGGLE, FONT_NAME, SCREEN_SIZE_HALF, y, COLOR_TEXT, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP )
|
||||
y = y + FONT_SIZE * 2
|
||||
|
||||
surface.SetTextPos( x, y )
|
||||
surface.DrawText( STR_GLOBAL )
|
||||
surface.SetTextColor( COLOR_TEXT_FADED )
|
||||
surface.DrawText( globalUsageStrLead )
|
||||
surface.SetTextColor( COLOR_TEXT )
|
||||
surface.DrawText( globalUsageStr )
|
||||
surface.SetTextColor( COLOR_MICROS )
|
||||
surface.DrawText( STR_MICROSECONDS )
|
||||
y = y + FONT_SIZE
|
||||
|
||||
for i = 1, plyCount do
|
||||
local data = rawget( perPlyData, i )
|
||||
local dataCount = rawget( data, "Count" )
|
||||
local owner = rawget( data, "Owner" )
|
||||
local ownerUsage = rawget( data, "OwnerUsage" )
|
||||
|
||||
local ownerColor = getTeamColor( owner)
|
||||
local ownerColorFaded = fadeColor( ownerColor )
|
||||
local ownerUsageStrLead, ownerUsageStr = formatCPUs( ownerUsage )
|
||||
|
||||
surface.SetTextPos( x, y )
|
||||
surface.SetTextColor( ownerColor )
|
||||
surface.DrawText( rawget( data, "OwnerName" ) )
|
||||
|
||||
surface.SetTextPos( xEnd + INFO_OFFSET_OWNER, y )
|
||||
surface.DrawText( STR_TOTAL )
|
||||
surface.SetTextColor( ownerColorFaded )
|
||||
surface.DrawText( ownerUsageStrLead )
|
||||
surface.SetTextColor( ownerColor )
|
||||
surface.DrawText( ownerUsageStr )
|
||||
surface.SetTextColor( COLOR_MICROS )
|
||||
surface.DrawText( STR_MICROSECONDS )
|
||||
y = y + FONT_SIZE
|
||||
elemCount = elemCount + 1
|
||||
|
||||
if elemCount == MAX_ELEMENTS then
|
||||
x = SCREEN_SIZE_HALF
|
||||
xEnd = xEnd + SCREEN_SIZE_HALF
|
||||
y = FONT_SIZE * 4
|
||||
end
|
||||
|
||||
for i2 = 1, dataCount / 3 do
|
||||
local baseInd = i2 * 3 - 2
|
||||
local chipShorthand = rawget( data, baseInd + 1 )
|
||||
local chipUsageStrLead, chipUsageStr = formatCPUs( rawget( data, baseInd + 2 ) )
|
||||
|
||||
surface.SetTextPos( x, y )
|
||||
surface.SetTextColor( ownerColor )
|
||||
surface.DrawText( rawget( data, baseInd ) ) -- chipName
|
||||
|
||||
surface.SetTextPos( xEnd + INFO_OFFSET_CHIP, y )
|
||||
surface.SetTextColor( rawget( CHIP_COLORS, chipShorthand ) )
|
||||
surface.DrawText( chipShorthand .. " " )
|
||||
surface.SetTextColor( COLOR_TEXT_FADED )
|
||||
surface.DrawText( chipUsageStrLead )
|
||||
surface.SetTextColor( COLOR_TEXT )
|
||||
surface.DrawText( chipUsageStr )
|
||||
surface.SetTextColor( COLOR_MICROS )
|
||||
surface.DrawText( STR_MICROSECONDS )
|
||||
y = y + FONT_SIZE
|
||||
elemCount = elemCount + 1
|
||||
|
||||
if elemCount == MAX_ELEMENTS then
|
||||
x = SCREEN_SIZE_HALF
|
||||
xEnd = xEnd + SCREEN_SIZE_HALF
|
||||
y = FONT_SIZE * 4
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
surface.SetDrawColor( COLOR_DIVIDER )
|
||||
surface.DrawLine( SCREEN_SIZE_HALF, FONT_SIZE * 3, SCREEN_SIZE_HALF, SCREEN_SIZE )
|
||||
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
end )
|
240
lua/autorun/server/sv_chip_lister.lua
Normal file
240
lua/autorun/server/sv_chip_lister.lua
Normal file
@ -0,0 +1,240 @@
|
||||
AddCSLuaFile( "cfc_chip_lister/shared/sh_chip_lister.lua" )
|
||||
AddCSLuaFile( "cfc_chip_lister/client/cl_hud.lua" )
|
||||
include( "cfc_chip_lister/shared/sh_chip_lister.lua" )
|
||||
|
||||
local CPU_MULT = 1000000
|
||||
local PLAYER_LENGTH_MAX = 20
|
||||
local CHIP_LENGTH_MAX = 25
|
||||
local ID_WORLD = "[WORLD]"
|
||||
local TIMER_NAME = "CFC_ChipLister_UpdateListData"
|
||||
local CHIP_SHORTHANDS = { -- Must all be unique two-character strings
|
||||
gmod_wire_expression2 = "E2",
|
||||
starfall_processor = "SF",
|
||||
}
|
||||
|
||||
local listUsers = {}
|
||||
local chips = {}
|
||||
local listUserCount = 0
|
||||
local chipCount = 0
|
||||
local convarFlags = { FCVAR_ARCHIVE, FCVAR_REPLICATED }
|
||||
|
||||
local isValid = IsValid
|
||||
local rawset = rawset
|
||||
local rawget = rawget
|
||||
local mRound = math.Round
|
||||
local tableInsert = table.insert
|
||||
local tableRemove = table.remove
|
||||
local tableKeyFromValue = table.KeyFromValue
|
||||
local tableRemoveByValue = table.RemoveByValue
|
||||
local stringLen = string.len
|
||||
local stringSub = string.sub
|
||||
local stringReplace = string.Replace
|
||||
local stringTrim = string.Trim
|
||||
local getClass
|
||||
local getOwner
|
||||
local getNick
|
||||
|
||||
do
|
||||
local entityMeta = FindMetaTable( "Entity" )
|
||||
|
||||
getClass = entityMeta.GetClass
|
||||
|
||||
local _getOwner = entityMeta.GetOwner
|
||||
local cppiGetOwner = entityMeta.CPPIGetOwner
|
||||
|
||||
getOwner = function( ent )
|
||||
local owner = cppiGetOwner and cppiGetOwner( ent )
|
||||
|
||||
if not isValid( owner ) then
|
||||
owner = _getOwner( ent )
|
||||
end
|
||||
|
||||
return owner
|
||||
end
|
||||
|
||||
|
||||
local playerMeta = FindMetaTable( "Player" )
|
||||
|
||||
getNick = playerMeta.Nick
|
||||
end
|
||||
|
||||
local LISTER_INTERVAL = CreateConVar( "cfc_chiplister_interval", 1, convarFlags, "How often (in seconds) the chip lister will update and send info to players.", 0.05, 10 )
|
||||
|
||||
util.AddNetworkString( "CFC_ChipLister_SetEnabled" )
|
||||
util.AddNetworkString( "CFC_ChipLister_UpdateListData" )
|
||||
|
||||
|
||||
local function getChipName( ent )
|
||||
return ent.GetGateName and ent:GetGateName() or "[UNKNOWN]"
|
||||
end
|
||||
|
||||
local function getCPUs( ent, class )
|
||||
if ent.Starfall then
|
||||
local instance = ent.instance
|
||||
|
||||
return instance and instance:movingCPUAverage() or 0
|
||||
end
|
||||
|
||||
if ( class or getClass( ent ) ) == "gmod_wire_expression2" then
|
||||
local context = ent.context
|
||||
|
||||
return context and context.timebench or 0
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
local function normalizeCPUs( cpus )
|
||||
return mRound( ( cpus or 0 ) * CPU_MULT )
|
||||
end
|
||||
|
||||
local function prepareName( str, maxLength )
|
||||
str = stringTrim( stringReplace( str or "", "\n", " " ) )
|
||||
|
||||
if stringLen( str ) > maxLength then
|
||||
str = stringSub( str, 1, maxLength - 3 ) .. "..."
|
||||
end
|
||||
|
||||
return str
|
||||
end
|
||||
|
||||
local function preparePlyName( str )
|
||||
return prepareName( str, PLAYER_LENGTH_MAX )
|
||||
end
|
||||
|
||||
local function prepareChipName( str )
|
||||
return prepareName( str, CHIP_LENGTH_MAX )
|
||||
end
|
||||
|
||||
local function updateChipLister()
|
||||
if listUserCount == 0 then return end
|
||||
|
||||
local perPlyData = {}
|
||||
local idLookup = {}
|
||||
local globalUsage = 0
|
||||
local idCount = 0
|
||||
|
||||
for i = 1, chipCount do
|
||||
local chip = rawget( chips, i )
|
||||
|
||||
if isValid( chip ) then
|
||||
local chipName = prepareChipName( " -" .. getChipName( chip ) )
|
||||
local chipClass = getClass( chip )
|
||||
local chipUsage = normalizeCPUs( getCPUs( chip, chipClass ) )
|
||||
local owner = getOwner( chip )
|
||||
local ownerName
|
||||
|
||||
globalUsage = globalUsage + chipUsage
|
||||
|
||||
-- For some reason, :IsPlayer() always returns false if obtained locally from entityMeta, it HAS to be called this way
|
||||
if isValid( owner ) and owner:IsPlayer() then
|
||||
ownerName = preparePlyName( getNick( owner ) )
|
||||
else
|
||||
owner = ID_WORLD
|
||||
ownerName = ID_WORLD
|
||||
end
|
||||
|
||||
local id = rawget( idLookup, owner )
|
||||
|
||||
if not id then
|
||||
idCount = idCount + 1
|
||||
id = idCount
|
||||
rawset( idLookup, owner, id )
|
||||
end
|
||||
|
||||
local data = rawget( perPlyData, id )
|
||||
local dataCount
|
||||
|
||||
if data then
|
||||
dataCount = rawget( data, "Count" )
|
||||
rawset( data, "OwnerUsage", rawget( data, "OwnerUsage" ) + chipUsage )
|
||||
else
|
||||
data = {
|
||||
Count = 0,
|
||||
Owner = owner,
|
||||
OwnerName = ownerName,
|
||||
OwnerUsage = chipUsage,
|
||||
}
|
||||
|
||||
rawset( perPlyData, id, data )
|
||||
dataCount = 0
|
||||
end
|
||||
|
||||
dataCount = dataCount + 1
|
||||
rawset( data, dataCount, chipName )
|
||||
dataCount = dataCount + 1
|
||||
rawset( data, dataCount, CHIP_SHORTHANDS[chipClass] )
|
||||
dataCount = dataCount + 1
|
||||
rawset( data, dataCount, chipUsage )
|
||||
|
||||
rawset( data, "Count", dataCount )
|
||||
end
|
||||
end
|
||||
|
||||
rawset( perPlyData, "Count", idCount )
|
||||
|
||||
net.Start( "CFC_ChipLister_UpdateListData" )
|
||||
net.WriteTable( perPlyData ) -- I would use TableToJSON, Compress, and WriteData, but player and chip names could easily break the formatting
|
||||
net.WriteUInt( globalUsage, 20 )
|
||||
net.Send( listUsers )
|
||||
end
|
||||
|
||||
cvars.AddChangeCallback( "cfc_chiplister_interval", function( _, old, new )
|
||||
timer.Create( TIMER_NAME, tonumber( new ) or 1, 0, updateChipLister )
|
||||
end )
|
||||
|
||||
|
||||
hook.Add( "OnEntityCreated", "CFC_ChipLister_ChipCreated", function( ent )
|
||||
if not isValid( ent ) then return end
|
||||
|
||||
local class = getClass( ent )
|
||||
|
||||
if not CHIP_SHORTHANDS[class] then return end
|
||||
|
||||
chipCount = chipCount + 1
|
||||
chips[chipCount] = ent
|
||||
end )
|
||||
|
||||
hook.Add( "OnEntityRemoved", "CFC_ChipLister_ChipRemoved", function( ent )
|
||||
if not isValid( ent ) then return end
|
||||
|
||||
local class = getClass( ent )
|
||||
|
||||
if not CHIP_SHORTHANDS[class] then return end
|
||||
|
||||
chipCount = chipCount - 1
|
||||
tableRemoveByValue( chips, ent )
|
||||
end )
|
||||
|
||||
hook.Add( "PlayerDisconnected", "CFC_ChipLister_UpdateListUserCount", function( ply )
|
||||
if not ( ply or {} ).cfcChipLister_usesLister then return end
|
||||
|
||||
local ind = tableKeyFromValue( listUsers, ply )
|
||||
|
||||
if ind then
|
||||
tableRemove( listUsers, ind )
|
||||
listUserCount = listUserCount - 1
|
||||
ply.cfcChipLister_usesLister = nil
|
||||
end
|
||||
end )
|
||||
|
||||
|
||||
net.Receive( "CFC_ChipLister_SetEnabled", function( _, ply )
|
||||
local state = net.ReadBool()
|
||||
|
||||
if state then
|
||||
tableInsert( listUsers, ply )
|
||||
listUserCount = listUserCount + 1
|
||||
ply.cfcChipLister_usesLister = true
|
||||
else
|
||||
local ind = tableKeyFromValue( listUsers, ply )
|
||||
|
||||
if ind then
|
||||
tableRemove( listUsers, ind )
|
||||
listUserCount = listUserCount - 1
|
||||
ply.cfcChipLister_usesLister = nil
|
||||
end
|
||||
end
|
||||
end )
|
||||
|
||||
timer.Create( TIMER_NAME, LISTER_INTERVAL:GetFloat(), 0, updateChipLister )
|
82
lua/cfc_chip_lister/client/cl_hud.lua
Normal file
82
lua/cfc_chip_lister/client/cl_hud.lua
Normal file
@ -0,0 +1,82 @@
|
||||
local clConVars = {}
|
||||
|
||||
local function createChipListerClientConVar( name, default, save, userinfo, text, min, max )
|
||||
local convar = CreateClientConVar( name, default, save, userinfo, text, min, max )
|
||||
clConVars[name] = convar
|
||||
|
||||
return convar
|
||||
end
|
||||
|
||||
local matChipLister = Material( "!cfc_chiplister_screen" )
|
||||
|
||||
local HUD_ENABLED = createChipListerClientConVar( "cfc_chiplister_hud_enabled", 0, true, false, "Whether or not to display the chip lister on your screen at all times.", 0, 1 )
|
||||
local HUD_SCALE = createChipListerClientConVar( "cfc_chiplister_hud_scale", 0.2, true, false, "The size of the chip lister on your HUD, scaled by your screen width.", 0, 1 )
|
||||
local HUD_POS_X = createChipListerClientConVar( "cfc_chiplister_hud_pos_x", 0.8, true, false, "The x-position of the chip lister on your HUD, scaled by your screen width.", 0, 1 )
|
||||
local HUD_POS_Y = createChipListerClientConVar( "cfc_chiplister_hud_pos_y", 0.2, true, false, "The y-position of the chip lister on your HUD, scaled by your screen height.", 0, 1 )
|
||||
|
||||
clConVars.cfc_chiplister_enabled = GetConVar( "cfc_chiplister_enabled" )
|
||||
|
||||
local hudEnabled = HUD_ENABLED:GetBool()
|
||||
local hudScale = HUD_SCALE:GetFloat()
|
||||
local hudPosX = HUD_POS_X:GetFloat()
|
||||
local hudPosY = HUD_POS_Y:GetFloat()
|
||||
|
||||
|
||||
hook.Add( "AddToolMenuCategories", "CFC_ChipLister_AddToolMenuCategories", function()
|
||||
spawnmenu.AddToolCategory( "Options", "CFC", "#CFC" )
|
||||
end )
|
||||
|
||||
hook.Add( "PopulateToolMenu", "CFC_ChipLister_PopulateToolMenu", function()
|
||||
spawnmenu.AddToolMenuOption( "Options", "CFC", "cfc_chiplister", "#Chip Lister", "", "", function( panel )
|
||||
pcall( function() -- ControlPresets only exists in certain gamemodes
|
||||
local presetControl = vgui.Create( "ControlPresets", panel )
|
||||
local defaults = {}
|
||||
|
||||
for cvName, cv in pairs( clConVars ) do
|
||||
presetControl:AddConVar( cvName )
|
||||
defaults[cvName] = cv:GetDefault()
|
||||
end
|
||||
|
||||
presets.Add( "cfc_chiplister", "Default", defaults )
|
||||
presetControl:SetPreset( "cfc_chiplister" )
|
||||
|
||||
panel:AddItem( presetControl )
|
||||
end )
|
||||
|
||||
panel:CheckBox( "Enable E2/SF Lister", "cfc_chiplister_enabled" )
|
||||
panel:CheckBox( "Enable Chip Lister on HUD", "cfc_chiplister_hud_enabled" )
|
||||
|
||||
panel:NumSlider( "Lister HUD Size", "cfc_chiplister_hud_scale", 0, 1, 2 )
|
||||
panel:NumSlider( "Lister HUD x-pos", "cfc_chiplister_hud_pos_x", 0, 1, 2 )
|
||||
panel:NumSlider( "Lister HUD y-pos", "cfc_chiplister_hud_pos_y", 0, 1, 2 )
|
||||
end )
|
||||
end )
|
||||
|
||||
|
||||
cvars.AddChangeCallback( "cfc_chiplister_hud_enabled", function( _, old, new )
|
||||
hudEnabled = new ~= "0"
|
||||
end )
|
||||
|
||||
cvars.AddChangeCallback( "cfc_chiplister_hud_scale", function( _, old, new )
|
||||
hudScale = tonumber( new ) or 0.2
|
||||
end )
|
||||
|
||||
cvars.AddChangeCallback( "cfc_chiplister_hud_pos_x", function( _, old, new )
|
||||
hudPosX = tonumber( new ) or 0.8
|
||||
end )
|
||||
|
||||
cvars.AddChangeCallback( "cfc_chiplister_hud_pos_y", function( _, old, new )
|
||||
hudPosY = tonumber( new ) or 0.1
|
||||
end )
|
||||
|
||||
hook.Add( "HUDPaint", "CFC_ChipLister_DrawHUD", function()
|
||||
if not hudEnabled then return end
|
||||
|
||||
local scrW = ScrW()
|
||||
local scrH = ScrH()
|
||||
local size = hudScale * scrW
|
||||
|
||||
surface.SetMaterial( matChipLister )
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.DrawTexturedRect( hudPosX * scrW, hudPosY * scrH, size, size )
|
||||
end )
|
34
lua/cfc_chip_lister/shared/sh_chip_lister.lua
Normal file
34
lua/cfc_chip_lister/shared/sh_chip_lister.lua
Normal file
@ -0,0 +1,34 @@
|
||||
local function addChipListerModel( spawnName, name, model )
|
||||
list.Set( "SpawnableEntities", spawnName, {
|
||||
PrintName = name,
|
||||
ClassName = "cfc_chip_lister",
|
||||
Category = "Chip Lister",
|
||||
KeyValues = {
|
||||
model = model
|
||||
}
|
||||
} )
|
||||
end
|
||||
|
||||
addChipListerModel(
|
||||
"cfc_chip_lister_tiny",
|
||||
"Tiny Chip Lister",
|
||||
"models/hunter/plates/plate1x1.mdl"
|
||||
)
|
||||
|
||||
addChipListerModel(
|
||||
"cfc_chip_lister_small",
|
||||
"Small Chip Lister",
|
||||
"models/hunter/plates/plate2x2.mdl"
|
||||
)
|
||||
|
||||
addChipListerModel(
|
||||
"cfc_chip_lister_medium",
|
||||
"Medium Chip Lister",
|
||||
"models/hunter/plates/plate4x4.mdl"
|
||||
)
|
||||
|
||||
addChipListerModel(
|
||||
"cfc_chip_lister_large",
|
||||
"Large Chip Lister",
|
||||
"models/hunter/plates/plate8x8.mdl"
|
||||
)
|
182
lua/entities/cfc_chip_lister/cl_init.lua
Normal file
182
lua/entities/cfc_chip_lister/cl_init.lua
Normal file
@ -0,0 +1,182 @@
|
||||
include( "shared.lua" )
|
||||
|
||||
ENT.RenderGroup = RENDERGROUP_BOTH
|
||||
|
||||
local render = render
|
||||
local matChipLister = Material( "!cfc_chiplister_screen" )
|
||||
|
||||
function ENT:Initialize()
|
||||
self.BaseClass.Initialize( self )
|
||||
|
||||
local info = self.Monitor_Offsets[self:GetModel()]
|
||||
if not info then
|
||||
local mins = self:OBBMins()
|
||||
local maxs = self:OBBMaxs()
|
||||
local size = maxs-mins
|
||||
info = {
|
||||
Name = "",
|
||||
RS = (size.y-1)/512,
|
||||
RatioX = size.y/size.x,
|
||||
offset = self:OBBCenter()+Vector(0,0,maxs.z-0.24),
|
||||
rot = Angle(0, 0, 180),
|
||||
x1 = 0,
|
||||
x2 = 0,
|
||||
y1 = 0,
|
||||
y2 = 0,
|
||||
z = 0,
|
||||
}
|
||||
end
|
||||
|
||||
self.ScreenInfo = info
|
||||
self:SetScreenMatrix(info)
|
||||
end
|
||||
|
||||
function ENT:SetScreenMatrix(info)
|
||||
local rotation, translation, translation2, scale = Matrix(), Matrix(), Matrix(), Matrix()
|
||||
rotation:SetAngles(info.rot)
|
||||
translation:SetTranslation(info.offset)
|
||||
translation2:SetTranslation(Vector(-256 / info.RatioX, -256, 0))
|
||||
scale:SetScale(Vector(info.RS, info.RS, info.RS))
|
||||
|
||||
self.ScreenMatrix = translation * rotation * scale * translation2
|
||||
self.Aspect = info.RatioX
|
||||
self.Scale = info.RS
|
||||
self.Origin = info.offset
|
||||
self.Transform = self:GetWorldTransformMatrix() * self.ScreenMatrix
|
||||
|
||||
local w, h = 512 / self.Aspect, 512
|
||||
self.ScreenQuad = {Vector(0,0,0), Vector(w,0,0), Vector(w,h,0), Vector(0,h,0), Color(0, 0, 0, 255)}
|
||||
end
|
||||
|
||||
function ENT:RenderScreen()
|
||||
if not matChipLister or matChipLister:IsError() then
|
||||
matChipLister = Material( "!cfc_chiplister_screen" )
|
||||
end
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetMaterial( matChipLister )
|
||||
surface.DrawTexturedRect( 0, 0, 512, 512 )
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
end
|
||||
|
||||
function ENT:SetBackgroundColor(r, g, b, a)
|
||||
self.ScreenQuad[5] = Color(r, g, b, math.max(a, 1))
|
||||
end
|
||||
|
||||
local writez = Material("engine/writez")
|
||||
function ENT:DrawTranslucent() -- Code taken from Starfall screen rendering. Most likely could be improved.
|
||||
self:DrawModel()
|
||||
|
||||
if halo.RenderedEntity() == self then return end
|
||||
|
||||
local entityMatrix = self:GetWorldTransformMatrix()
|
||||
|
||||
-- Draw screen here
|
||||
local transform = entityMatrix * self.ScreenMatrix
|
||||
self.Transform = transform
|
||||
cam.PushModelMatrix(transform)
|
||||
render.ClearStencil()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilFailOperation(STENCILOPERATION_KEEP)
|
||||
render.SetStencilZFailOperation(STENCILOPERATION_KEEP)
|
||||
render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
|
||||
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_ALWAYS)
|
||||
render.SetStencilWriteMask(1)
|
||||
render.SetStencilReferenceValue(1)
|
||||
|
||||
--First draw a quad that defines the visible area
|
||||
render.SetColorMaterial()
|
||||
render.DrawQuad(unpack(self.ScreenQuad))
|
||||
|
||||
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL)
|
||||
render.SetStencilTestMask(1)
|
||||
|
||||
--Clear it to the clear color and clear depth as well
|
||||
local color = self.ScreenQuad[5]
|
||||
if color.a == 255 then
|
||||
render.ClearBuffersObeyStencil(color.r, color.g, color.b, color.a, true)
|
||||
end
|
||||
|
||||
--Render the starfall stuff
|
||||
render.PushFilterMag(TEXFILTER.ANISOTROPIC)
|
||||
render.PushFilterMin(TEXFILTER.ANISOTROPIC)
|
||||
|
||||
self:RenderScreen()
|
||||
|
||||
render.PopFilterMag()
|
||||
render.PopFilterMin()
|
||||
|
||||
render.SetStencilEnable(false)
|
||||
|
||||
--Give the screen back its depth
|
||||
render.SetMaterial(writez)
|
||||
render.DrawQuad(unpack(self.ScreenQuad))
|
||||
|
||||
cam.PopModelMatrix()
|
||||
end
|
||||
|
||||
ENT.Monitor_Offsets = {
|
||||
["models/hunter/plates/plate1x1.mdl"] = {
|
||||
Name = "Panel 1x1",
|
||||
RS = 0.09,
|
||||
RatioX = 1,
|
||||
offset = Vector(0, 0, 2),
|
||||
rot = Angle(0, 90, 180),
|
||||
x1 = -48,
|
||||
x2 = 48,
|
||||
y1 = -48,
|
||||
y2 = 48,
|
||||
z = 0,
|
||||
},
|
||||
["models/hunter/plates/plate2x2.mdl"] = {
|
||||
Name = "Panel 2x2",
|
||||
RS = 0.182,
|
||||
RatioX = 1,
|
||||
offset = Vector(0, 0, 2),
|
||||
rot = Angle(0, 90, 180),
|
||||
x1 = -48,
|
||||
x2 = 48,
|
||||
y1 = -48,
|
||||
y2 = 48,
|
||||
z = 0,
|
||||
},
|
||||
["models/hunter/plates/plate4x4.mdl"] = {
|
||||
Name = "plate4x4.mdl",
|
||||
RS = 0.3707,
|
||||
RatioX = 1,
|
||||
offset = Vector(0, 0, 2),
|
||||
rot = Angle(0, 90, 180),
|
||||
x1 = -94.9,
|
||||
x2 = 94.9,
|
||||
y1 = -94.9,
|
||||
y2 = 94.9,
|
||||
z = 1.7,
|
||||
},
|
||||
["models/hunter/plates/plate8x8.mdl"] = {
|
||||
Name = "plate8x8.mdl",
|
||||
RS = 0.741,
|
||||
RatioX = 1,
|
||||
offset = Vector(0, 0, 2),
|
||||
rot = Angle(0, 90, 180),
|
||||
x1 = -189.8,
|
||||
x2 = 189.8,
|
||||
y1 = -189.8,
|
||||
y2 = 189.8,
|
||||
z = 1.7,
|
||||
},
|
||||
["models/hunter/plates/plate16x16.mdl"] = {
|
||||
Name = "plate16x16.mdl",
|
||||
RS = 1.482,
|
||||
RatioX = 1,
|
||||
offset = Vector(0, 0, 2),
|
||||
rot = Angle(0, 90, 180),
|
||||
x1 = -379.6,
|
||||
x2 = 379.6,
|
||||
y1 = -379.6,
|
||||
y2 = 379.6,
|
||||
z = 1.7,
|
||||
},
|
||||
}
|
32
lua/entities/cfc_chip_lister/init.lua
Normal file
32
lua/entities/cfc_chip_lister/init.lua
Normal file
@ -0,0 +1,32 @@
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
include( "shared.lua" )
|
||||
|
||||
|
||||
local ErrorModel = "models/error.mdl"
|
||||
|
||||
function ENT:KeyValue( key, value )
|
||||
if key == "model" then
|
||||
self.Model = value
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self.BaseClass.Initialize( self )
|
||||
|
||||
if self:GetModel() == ErrorModel then
|
||||
self:SetModel( self.Model )
|
||||
end
|
||||
|
||||
--self:SetModel( "models/hunter/plates/plate16x16.mdl" )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
|
||||
self:AddEFlags( EFL_FORCE_CHECK_TRANSMIT )
|
||||
end
|
||||
|
||||
function ENT:UpdateTransmitState()
|
||||
return TRANSMIT_ALWAYS
|
||||
end
|
12
lua/entities/cfc_chip_lister/shared.lua
Normal file
12
lua/entities/cfc_chip_lister/shared.lua
Normal file
@ -0,0 +1,12 @@
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_gmodentity"
|
||||
|
||||
ENT.PrintName = "Huge Chip Lister"
|
||||
ENT.Author = "legokidlogan"
|
||||
ENT.Contact = "https://cfcservers.org/discord"
|
||||
ENT.Purpose = "Displays E2 and Starfall chips"
|
||||
ENT.Instructions = ""
|
||||
ENT.Category = "Chip Lister"
|
||||
|
||||
ENT.Spawnable = true
|
||||
ENT.Model = "models/hunter/plates/plate16x16.mdl"
|
Loading…
Reference in New Issue
Block a user