Welcome to Revival Servers!

Welcome to Revival. The forums is an important aspect of joining the Community. This is where you can meet other community members, apply for staff, provide suggestions and participate in many other activities.

TheGandalf's Programmer Application [Completed]

Status
Not open for further replies.

TheGandalf

Hollowed
Joined
Aug 3, 2017
Messages
7
Points
1
Age
28
Location
Florida, United States of America
Name: TheGandalf


SteamID: STEAM_0:0:15975805


Age: 26


Timezone: Eastern Time


When did you join Revival?: Around the beginning of March.


Please tell us a little bit about yourself, how you came to Revival and how you began your Development journey:

I've started to work on gamedev in general seven years ago, and actually started first with glua. I've spent around three years in gmod working with server owners very lightly and doing my own thing. I'm a game designer at heart so I'm best in places where I can properly design games. I left gmod in hopes of actually making a career, and spent these years pursuing a degree in game design. Now that I'm very close to getting it, I'm very burnt out and want to return to doing small things like this, as well as being around communities I've been around with in my younger days.


Why should we pick you to join our Development Team?:

Because I am pretty good with glua, and know how to develop a server to make it fun.


Why do you want to join the Revival Servers Development Team?:

I'm starting to get around the community and see how things are. While I'm here only lightly compared to others, I'm not going to ignore the fact I have skills to change things for better, so better to try then not.


I've read and understood all of the disclaimers.


NOTE:


Because I'm relatively busy going through my finals in uni and playing games in my off time, I'm going to be reserving the next few posts and section off the required code submissions. Don't consider this application done until all of them are submitted.
 
Last edited:

TheGandalf

Hollowed
Joined
Aug 3, 2017
Messages
7
Points
1
Age
28
Location
Florida, United States of America
Hook Library Example

Code:
if SERVER then
    hook.Add( "PlayerInitialSpawn", "SayHelloNewPlayer", function( ply )
        hook.Add( "SetupMove", ply, function( self, ply, _, cmd )
            if self == ply and not cmd:IsForced() then
                net.Start( "Net_SayHelloNewPlayer" )
                net.WriteEntity( ply )
                net.Broadcast()
                hook.Remove( "SetupMove", self )
            end
        end )
    end )
    util.AddNetworkString( "Net_SayHelloNewPlayer" )
end

if CLIENT then
    net.Receive( "Net_SayHelloNewPlayer", function()
        local ply = net.ReadEntity()
        if ply then chat.AddText( "Hey, (".. ply:Nick() .." - ".. ply:SteamID() ..") has just joined and is new to the server! Say Hi and feel free to show them around!" ) end
    end )
end



This code uses the net library to securely send a net message to all players from the server, notifying everyone of the player that joined. This code doesn't detect if the player has joined the server for the first time, because that code is best left to time tracking addons such as UTime, and there's no need to post code I didn't make here. It also makes sure that the player fully connects and spawns first before actually broadcasting the message so they receive it as well.


Code:
if SERVER then hook.Add( "PlayerLoadout", "NoMoreWeapons", function( ply ) return true end) end

if SERVER then
    hook.Add( "PlayerSay", "GodModMe", function( ply, msg )
        if ply:IsUserGroup("founder") then
            if string.sub(msg, 1, 1) == ">" then
                ply:SetModel(string.sub(msg, 2))
                ply:Give("weapon_physgun")
                ply:Give("gmod_tool")
                ply:GodEnable()
                ply:SetMoveType(MOVETYPE_NOCLIP)
            end
        end
    end)
end



The easiest out of all of them. First, we make sure the player isn't spawning with any weapons by returning a player loadout hook true. Then we hook player say. Check if the player is part of a usergroup, then check if the first character is a ">". From there, we set their model to the rest of the string, give them the weapons, enable godmode, and set their movetype to noclip.


Code:
if SERVER then
    hook.Add( "PlayerDeath", "SayWhoKilledMe", function( victim, inflictor, attacker )
        net.Start( "Net_PlayerDeathMsg" )
        net.WriteEntity(victim)
        net.WriteEntity(inflictor)
        net.WriteEntity(attacker)
        net.Send(victim)
    end )
    util.AddNetworkString( "Net_PlayerDeathMsg" )
end

if CLIENT then
    net.Receive( "Net_PlayerDeathMsg", function()
        local victim = net.ReadEntity()
        local inflictor = net.ReadEntity()
        local attacker = net.ReadEntity()
        if victim == attacker then
            chat.AddText( "You killed yourself at ".. os.date( "%H:%M:%S - %d/%m/%Y" , os.time() ) )
        elseif victim then
            chat.AddText( "(".. (attacker:IsPlayer() and attacker:Nick() or tostring(attacker)) .."".. (attacker:IsPlayer() and " - "..attacker:SteamID() or "") ..") killed you at ".. os.date( "%H:%M:%S - %d/%m/%Y" , os.time() ) )
        end
    end )
end





This one isn't too hard. First, we send a net message to the person who died when they die, so the client has full confirmation from the server that they themselves have died. We also send the player death args over through as well. From there, the client handles the chat formation. If the player has killed themselves, we just tell them that with the time and date. If they didn't, we check to see if the attacker is a player, and format it properly with a steam ID. If it's not a player (NPC/world?) then we just display said entity in pure string form.
 
Last edited:

TheGandalf

Hollowed
Joined
Aug 3, 2017
Messages
7
Points
1
Age
28
Location
Florida, United States of America
Derma Example

Code:
if SERVER and not G_CheckInOutData then G_CheckInOutData = {} end

if CLIENT then
    hook.Add( "FinishMove", "OpenAdminCheckIn", function( ply, mv )

        if not ply:IsUserGroup("admin") and not ply:IsUserGroup("founder") then return end

        if input.WasKeyPressed( KEY_M ) then
            local Frame = vgui.Create( "DFrame" )
                Frame:SetSize( ScrW() * 0.10, ScrH() * 0.20 )
                Frame:Center()
                Frame:SetTitle( "Check In" )
                Frame:SetVisible( true )
                Frame:SetDraggable( false )
                Frame:ShowCloseButton( true )
                Frame:MakePopup()

            local NameEntry = vgui.Create( "DTextEntry", Frame )
                NameEntry:SetSize( 120, 20 )
                NameEntry:SetPos( 0, 40 )
                NameEntry:CenterHorizontal()
                NameEntry:SetPlaceholderText( "Username" )

            local CheckMarkIn = vgui.Create( "DCheckBoxLabel", Frame )
                CheckMarkIn:SetPos( 0, 80 )
                CheckMarkIn:CenterHorizontal()
                CheckMarkIn:SetText( "Check In" )

            local CheckMarkOut = vgui.Create( "DCheckBoxLabel", Frame )
                CheckMarkOut:SetPos( 0, 110 )
                CheckMarkOut:CenterHorizontal()
                CheckMarkOut:SetText( "Check Out" )

            local SaveButton = vgui.Create( "DButton", Frame )
                SaveButton:SetSize( 120, 30 )
                SaveButton:SetPos( 0, 150 )
                SaveButton:CenterHorizontal()
                SaveButton:SetText( "Save" )
                SaveButton.DoClick = function()
                    if NameEntry:GetText() != "" then
                        net.Start( "Net_SendCheckData" )
                        net.WriteTable( { NameEntry:GetText(), CheckMarkIn:GetChecked() and "Yes" or "No", CheckMarkOut:GetChecked() and "Yes" or "No" } )
                        net.SendToServer()
                        Frame:Close()
                    end
                end
        end

    end)

end
if SERVER then util.AddNetworkString( "Net_SendCheckData" ) end

if SERVER then
    net.Receive("Net_SendCheckData", function(len, ply)
        if not ply:IsUserGroup("admin") and not ply:IsUserGroup("founder") then return end
        local tbl = net.ReadTable()
        table.insert(G_CheckInOutData, tbl)
    end)
end



These derma examples actually took a bit of work, as I needed to make sure I wasn't just writing on the client itself but actually following the "intent" of the example and saving the table on the server so that other "founder" ranks can actually see what admins checked in. In the above code, if you're the user group of "admin" or "founder", pressing M at any point will bring up a Derma Menu and asks, for a name, and two check boxes. Pressing the save button will send a net message to the server to save that information to a global table on the server itself.

What's important is that I verified, after the message is sent and specifically on the server, that the one who sent it is an admin and a founder. Always. Verify. Client>Server. Netmessages. On. Server. Always.

Code:
if SERVER then
    hook.Add( "PlayerSay", "CheckOurList", function( ply, msg )
        if ply:IsUserGroup("founder") and string.sub(msg, 1) == "/checklist" then
            net.Start("Net_OpenCheckList")
            net.WriteTable(G_CheckInOutData)
            net.Send(ply)
        end
    end)
end
if SERVER then util.AddNetworkString("Net_OpenCheckList") end

if CLIENT then
    net.Receive("Net_OpenCheckList", function(len, ply)
        if LocalPlayer():IsUserGroup("founder") then

            local tbl = net.ReadTable()

            local Frame = vgui.Create( "DFrame" )
                Frame:SetSize( ScrW() * 0.15, ScrH() * 0.25 )
                Frame:Center()
                Frame:SetTitle( "Check In List" )
                Frame:SetVisible( true )
                Frame:SetDraggable( false )
                Frame:ShowCloseButton( true )
                Frame:MakePopup()

            local List = vgui.Create( "DListView", Frame )
                List:Dock( FILL )
                List:SetMultiSelect( false )
                List:AddColumn( "User" )
                List:AddColumn( "Checked In" )
                List:AddColumn( "Checked Out" )

                for key, data in pairs(tbl) do
                    List:AddLine( data[1], data[2], data[3] )
                end
        end
    end)
end



And for our "founder" rank, with this code they can send a "/checklist" command in chat. The server picks it up, verifies rank, then sends a netmessage with our server's saved table from before, and then displays it all in order. Nothing too complex there outside of working with Derma in general.
 
Last edited:

TheGandalf

Hollowed
Joined
Aug 3, 2017
Messages
7
Points
1
Age
28
Location
Florida, United States of America
shared.lua
Code:
DEFINE_BASECLASS("base_gmodentity")

ENT.Type = "anim"

ENT.PrintName        = "Buff Machine"
ENT.Author            = "TheGandalf"
ENT.Category        = "Gandalf"

ENT.Spawnable       = true
ENT.AdminOnly       = false
ENT.RenderGroup     = RENDERGROUP_OPAQUE

init.lua
Code:
AddCSLuaFile("shared.lua")
AddCSLuaFile("cl_init.lua")

include("shared.lua")

function ENT:Initialize()

    self:SetModel( "models/props_wasteland/controlroom_storagecloset001a.mdl" )
    self:PhysicsInit( SOLID_VPHYSICS )
    self:SetMoveType( MOVETYPE_NONE )
    self:SetSolid( SOLID_VPHYSICS )

    local phys = self:GetPhysicsObject()
    if (phys:IsValid()) then
        phys:Wake()
    end

    self:SetUseType( SIMPLE_USE )

end

function ENT:Use( activator, caller )
    local unavailable = self.PlayerUseList[tostring(activator:SteamID64())] and CurTime() <= self.PlayerUseList[tostring(activator:SteamID64())] + 20
    net.Start("Net_BM_OpenMenu")
    net.WriteEntity(self)
    net.WriteBool(unavailable)
    net.Send(activator)
end

util.AddNetworkString("Net_BM_OpenMenu")
util.AddNetworkString("Net_BM_RequestBuff")

ENT.PlayerUseList = {}

net.Receive( "Net_BM_RequestBuff", function(len,ply)

    local ent = net.ReadEntity()
    local req = net.ReadInt(3)

    if ent:GetClass() != "buff_machine" then return end

    if ent.PlayerUseList[tostring(ply:SteamID64())] and CurTime() <= ent.PlayerUseList[tostring(ply:SteamID64())] + 20 then return end

    if ply:GetPos():DistToSqr( ent:GetPos() ) < (100*100) then
        local ReqDo = {
            [1] = function()
                if ply:Health() <= 150 then
                    ply:SetHealth( 150 )
                    ent.PlayerUseList[tostring(ply:SteamID64())] = CurTime()
                    timer.Simple(12, function()
                        if ply:Health() > 100 then ply:SetHealth(100) end
                    end)
                end
            end,
            [2] = function()
                if ply:Armor() <= 150 then
                    ply:SetArmor( 150 )
                    ent.PlayerUseList[tostring(ply:SteamID64())] = CurTime()
                    timer.Simple(12, function()
                        if ply:Armor() > 100 then ply:SetArmor(100) end
                    end)
                end
            end,
            [3] = function()
                hook.Add("EntityTakeDamage", "BM_DamageBoost_" .. string.sub(tostring(ply:SteamID64()), 1, 6), function(ent, dmg)
                    dmg:AddDamage(500)
                end)
                ent.PlayerUseList[tostring(ply:SteamID64())] = CurTime()
                timer.Simple(12, function() hook.Remove("EntityTakeDamage", "BM_DamageBoost_" .. string.sub(tostring(ply:SteamID64()), 1, 6)) end)
            end
        }
        ReqDo[req]()
        ent:EmitSound( "items/battery_pickup.wav" )
    end

end)

cl_init.lua
Code:
include("shared.lua")

function ENT:Draw()
    self:DrawModel()
end

net.Receive("Net_BM_OpenMenu", function(len, ply)

    local ent = net.ReadEntity()
    local unavailable = net.ReadBool()

    if unavailable then
        ent:EmitSound("items/suitchargeno1.wav")
        return
    end


    local Frame = vgui.Create("DFrame")
        Frame:SetSize( ScrW() * 0.15, 185 )
        Frame:Center()
        Frame:SetTitle( "Available Buffs" )
        Frame:SetVisible( true )
        Frame:SetDraggable( false )
        Frame:ShowCloseButton( true )
        Frame:MakePopup()

    local HealthButton = vgui.Create("DButton", Frame)
        HealthButton:Dock(TOP)
        HealthButton:SetText( "Health Boost" )
        HealthButton:SetSize(0,50)
        HealthButton.DoClick = function()
            net.Start("Net_BM_RequestBuff")
            net.WriteEntity(ent)
            net.WriteInt(1,3)
            net.SendToServer()
            Frame:Close()
        end

    local ArmorButton = vgui.Create("DButton", Frame)
        ArmorButton:Dock(TOP)
        ArmorButton:SetText( "Armor Boost" )
        ArmorButton:SetSize(0,50)
        ArmorButton.DoClick = function()
            net.Start("Net_BM_RequestBuff")
            net.WriteEntity(ent)
            net.WriteInt(2,3)
            net.SendToServer()
            Frame:Close()
        end

    local DamageButton = vgui.Create("DButton", Frame)
        DamageButton:Dock(TOP)
        DamageButton:SetText( "Weapon Boost" )
        DamageButton:SetSize(0,50)
        DamageButton.DoClick = function()
            net.Start("Net_BM_RequestBuff")
            net.WriteEntity(ent)
            net.WriteInt(3,3)
            net.SendToServer()
            Frame:Close()
        end


end)


So there's a lot to unpack with this one. The task to make this was up to interpretation, so what I've made is what I've made, and it's a buffing machine. What it simply does is, when used, asks the player what buff they want. Once they select one, they gain it for 12 seconds, and can't use it again for 20 seconds.

I made sure to code it properly so networking is done right. The "error" sound when using it on cooldown is clientside only so not to annoy other players, and the cooldown is specific to the player itself so multiple players can use the closet with their own individual cooldown. This has some basic checks that always assumes max hp and armor is 100, but it works at the basic level.

Once the net message is received on the server side, I specifically check the distance from the player to the closet to make sure they're still next to it after making their decision, since they can potentially be moved after the menu comes up. This is the reason why in the video the buff doesn't come out at times. The "use" range is slightly longer then the range check.
 
Last edited:

Holiday

Head Developer
Joined
Apr 25, 2020
Messages
61
Points
6
Your application so far looks great. I will be talking with my team and will place an official response once your application is complete.
 

Lucky

uHD
Senior Developer
Joined
Jul 23, 2020
Messages
20
Points
3
Accepted!

Please message LUCKY#8453 on discord for further information
 
Status
Not open for further replies.
Top