Kick players based on their Garry's Mod playtime

This script uses the Steam API to read the number of Garry’s Mod playing hours that a connecting client has on their Steam account. If the player is below the number of hours you specify, they’ll be kicked. Likewise, they’ll also be kicked if they’re using Steam Family Sharing to play the game. I wrote this plugin for a few servers that were having various problems with new players disrupting the server and/or trolls using family sharing to get around bans.

A Steam API key is required to use this script. You can fill out a form here: To get an API key. Once you have your key, put it in the apikey="" global.

I did make a version of this script that used a public service to get player hours, but it was unreliable because it couldn’t get information from private Steam accounts and the XML format would change frequently. If you find a reliable way to get player hours without using the Steam API, you can modify the script to suit.

If you have players that you want to exempt for any reason, just add their SteamID to the ImmunePly table.

if SERVER then

	-- Minimum number of playing hours required to join server.
	-- Don't touch these values.
	-- Immune Clients List. Make sure there's a comma after every entry but the last one.
	ImmunePly = {

	function CheckPlayTime( ply )
		ply:PrintMessage( HUD_PRINTTALK, "[Hours Script] Checking your playtime.." )
		-- Doesn't work on local server.
		httpurl="" .. hoursurl .. "" .. apikey .. "&steamid=" .. ply:SteamID64() .. "&format=json"
		http.Fetch( httpurl , HoursCheck, CheckError )

	hook.Add( "PlayerInitialSpawn", "PlayTimeCheck", CheckPlayTime )
	function HoursCheck( contents, size )
		local PlyTime="0"
		local PlyTable = string.Explode( "
", contents )
		local PlyMins = { }
		local MinCnt = "0"
		for k,v in pairs (ImmunePly) do
			if (tostring(ply1:SteamID()) == tostring(v)) then
				ply1:PrintMessage( HUD_PRINTTALK, "[Hours Script] You have immunity." )
				print("Hours Script: Client " .. player.GetBySteamID( v ):Nick() .. " has immunity.")
		for k,v in pairs( PlyTable ) do
			statusgameok = string.find( v, ": 4000" )
			if ( statusgameok ) then
					for PlyExplode in string.gmatch( PlyTable[k+2], "%d") do
						table.insert( PlyMins, MinCnt , PlyExplode )
				local PlyTime = math.Round( tonumber(table.concat( PlyMins ) )/60, 0 )
				if ( Immunity == 1 ) then
				elseif (tonumber(PlyTime) < PlayerHours) then
					PrintMessage( HUD_PRINTTALK, "[Hours Script] " .. ply1:Nick() .. " Was kicked for being under the " .. PlayerHours .. " Hour limit (Has " .. PlyTime .. " Hours.)" )
					ply1:Kick( "Sorry, you need at least " .. PlayerHours .. " hours to play here. You currently have " .. PlyTime .. " Hours." )
					ply1:PrintMessage( HUD_PRINTTALK, "[Hours Script] You have " .. PlyTime .. " hours, welcome to the server!" )
					PrintMessage( HUD_PRINTTALK, "[Hours Script] " .. ply1:Nick() .. " Has joined the server with " .. PlyTime .. " Hours." )
		if ( ErrCnt < 1 ) then
				ply1:Kick( "Steam family sharing is unsupported. Please purchase Garry's Mod for your account." )
		PlyMins = { }
		MinCnt = "0"
	function CheckError()
		print( "Hours Script: Error! Something failed" )

To install this on your server, just copypasta the code to a text file you rename to “playerhours.lua” and put it in your lua/autorun/server folder. After you restart the server, you should be good to go.

This isn’t the most elegant or easy to use code out there, but it works for our purposes and should work for you as well. There are probably better ways to do this with fancy GUIs but this is what I came up with.

Don’t know why anyone would want to do that.

Kind of a selfish thing if you ask me. If people think that they’ll get a lot of players by doing this, they’ll soon find out real quick that’s not the case.

I really don’t like this idea. Why not give beginners a chance? Kind of an asshole-ish thing to do imo.

I’m not sure why you think this script is a gimmick to get more people on the server, because it’s not.

It’s been used with success on advanced build servers to keep more of the disruptive players out. 50-300 hours (2-12 days of playtime) is enough time to filter out newbie players that are far more likely to be disruptive on the server.

If you don’t like the script then just don’t use it. We server owners have the right to filter out players we don’t want on our servers.

The way I look at this, even though I disagree with it, is that it’s truly up to the sole discretion of the owner to install it.

If they don’t want said players with less playtime on their server, then they’re going to lose potential players (and even current players who want their friends on the server with them).

So in the end, you’ll maintain the same elitist group of people who will play there, with barely anyone new coming into the fold. But hey, again, up to the owner.

I personally find newer players are more to follow rules. People with a lot of hours will want to have a bit more fun and minge a bit, some people play Garry’s Mod just to minge.

OP, I took the script and made my own version of it. (I mainly just improved it.)

-- Minimum number of playing hours required to join server.
local PlayerHours = 50
local apikey = ""
local ServerKickMessage = "[Hours Script]: %s Was kicked for being under the %s Hour limit (Has %s Hours.)"
local ServerJoinMessage = "[Hours Script]: %s Has joined the server with %s Hours."
local ClientKickMessage = "[Hours Script]: Sorry, you need at least %s hours to play here. You currently have %s Hours."
local ClientJoinMessage = "[Hours Script]: Welcome to the server %s. You have %s hours"
-- Don't touch these values.
local hoursurl = ""
-- Immune Clients List. Make sure there's a comma after every entry but the last one.
local ImmunePly = {

hook.Add( "PlayerInitialSpawn", "PlayTimeCheck", function( ply )

	-- Doesn't work on local server.
	for i = 1, #ImmunePly do
		if ply:SteamID() == ImmunePly[ i ] then
			ply:PrintMessage( HUD_PRINTTALK, "[Hours Script]: You have immunity." )
			print( string.format( "[Hours Script]: Client %s has immunity.", ply:Nick() ) )
	ply:PrintMessage( HUD_PRINTTALK, "[Hours Script]: Checking your playtime." )
	local httpurl = string.format( hoursurl, apikey, ply:SteamID64() )

	http.Fetch( httpurl, function( contents, size ) --Success
		if not IsValid( ply ) then return end
		local tbl = util.JSONToTable( contents )
		if tbl and tbl[ "response" ] and tbl[ "response" ][ "games" ] then
			for i = 1, #tbl[ "response" ][ "games" ] do
				if tbl[ "response" ][ "games" ][ i ][ "appid" ] == 4000 then
					local PlayTime = tbl[ "response" ][ "games" ][ i ][ "playtime_forever" ] / 60
					local roundtime = math.Round( PlyTime, 1 )

					if PlayTime < PlayerHours then
						PrintMessage( HUD_PRINTTALK, string.format( ServerKickMessage, ply:Nick(), PlayerHours, roundtime ) )
						ply:Kick( string.format( ClientKickMessage, PlayerHours, roundtime ) )
						PrintMessage( HUD_PRINTTALK, string.format( ServerJoinMessage, ply:Nick(), roundtime ) )
						ply:PrintMessage( HUD_PRINTTALK, string.format( ClientJoinMessage, ply:Nick(), roundtime ) )
		ply:Kick( "Steam family sharing is unsupported. Please purchase Garry's Mod for your account." )
	function( err ) --Error
		print( "[Hours Script]: Error! Something failed", err )
	end )

end )

I don’t support the idea but I could not stand all the global variables and the if SERVER then.

How about I turn this reasoning right around: if you don’t like the criticism on the scripts you release on Facepunch, then don’t use Facepunch. You telling people not to use things they have a problem with is just some stupid dismissal of their criticism. People have every right to criticise your script, whether you like it or not.

The goal of your script is to catch minges’ alt accounts and steam shared games. Kicking players for playtime to do this has several problems:

  • Not every alt account is caught, because quite a few alt accounts have more than 50 hours
  • Minges can easily bypass your check by just letting gmod run for two days, or just a couple of nights. They will start doing this if scripts like this become popular.
  • Besides alt accounts it also just kicks genuinely new players

So not only does this script fail to do what it’s supposed to do, it also punishes innocent people in the process. As such, it is both worthless and damaging. The automatic punishment of innocent people by script is capital sin.

Now tell me how I shouldn’t have given this criticism because I just “shouldn’t use” it and shut the fuck up when I don’t like it.

He did specify ‘Advanced Build Servers’ which generally implies that it’s not going to be played by newer players. Although, I can’t really see much harm in allowing new players onto advanced build servers anyway, since these types of servers typically have players that are more than capable of dealing with minges on their own or the server has certain addons that make most methods of crashing a server un-usable.
A server based on the sole premise of advanced/complicated builds seems like the kind of place a newer player would enjoy for a few reasons:

  • They could experience the pinnacle of G-mod build with players making exceptionally complex or interesting contraptions. This could ignite an interest in the dying build gamemode for that player in particular.
  • The best people to learn the more obscure controls (or even the more obvious ones like shift+e while holding a prop with the phys gun) are the people most familiar with the game; builders.
  • They respect builders and are fascinated with what other players are capable of.

I sort of repeated myself, but the general premise is; if the server has a half-active admin staff (which on most build servers is practically half the server) only the most clever of minges could do even reasonable amounts of damage.
A new player might be annoying, but if you show them the ropes, they’ll start building in no time.

Not entirely sure why you’re so offended. If you don’t like the script, you’re not required to use it. Just like you’re not required to run a Spacebuild or DarkRP server.

I also never said anything about preventing you from criticizing it, you did so that’s your own problem.

And then you went to do exactly what I told you not to do. Rather than addressing my actual criticism, you’ve told me that I don’t need to run the script. I know I don’t have to run scripts I don’t like. I don’t even have a server of my own. Stop telling people that, seriously, you’re repeating yourself.

The “don’t like it, don’t use it” argument serves no purpose other than to shut people up. It’s not like you’re telling them something new. “Oh I don’t have to? Well I’ll be damned!”.

Your inability to address criticism is not my problem, it’s yours.

One of the build servers had a second smaller server and they modified the script to redirect players under x hours to the smaller server so the newbie players could hang there. This helped keep the more advanced builders in the middle of projects free from being nagged by newbies.

I don’t need permission from you to do things, sorry.

There’s also no addressing your criticism because you have issue with the base function of the script of filtering out players based on hour counts. The use case scenarios I talked about above are examples of what I know it was used for. If you have a problem with that, you need to take it up with the server owners if you want to criticise how they run their stuff.

You are responsible for the scripts you make and release. Not the server owners. Your script is both ineffective and harmful to new players, and the only way you know to address it is to shove all your responsibility to the server owners.

The criticism and your response to it will act as a warning towards server owners who might be considering installing it. Server owners now have three reasons not to install this script: it doesn’t solve the problem, it catches innocent people in the process and the author has no sense of responsibility.

Although I agree with your argument, I have to disagree with your third point. I don’t believe an author’s perceived incompetence or negligence by a single party should in any way influence the use or criticism of a work. A movie’s quality is not based on how the director handles critical responses – just the same to a script. I’m not defending this script particularly under this premise, but I am saying in general that the argument against a work should only pertain to the work itself. It’s ad hominem otherwise, honestly.

How to kill your server in one easy step

No. Scripts generally have to be maintained, bugs are to be solved, suggestions are to be at least considered. An author taking no responsibility for the scripts definitely causes the script to have less value, simply because you’re less likely to get support when you have a problem with the script. Really, with this guy you’re really likely to hear “then don’t use the script” with any problem. That’s a real downside.

It’s not an ad hominem, it’s a genuine reason not to use the script.

I’m in the boat of disagreeing how the script works; however have you considered implementing some form of ranking system that limits what a player can do to a degree? I had this issue many years ago with players just coming on to grief; so I locked it down and essentially added a system whereby the higher “ranked” you are, the different types of props / tools you can use expand.

Not only did this filter out most mingebags (blacklisted rank is essentially a ban without booting them off the server) but it allowed those that really wanted to build, to actually build. Ultimately it’s a win-win and less of a shotgun approach.

I can see this really working for community’s… Maybe they have multiple darkrp servers and if someone tries to join there “serious darkrp” server maybe it will re-direct them to there normal fun darkrp server.

I think that would be a pretty good use to this script but that’s just my views on things

I like the code, but I can’t say I like the idea

If someone minges in gmod chances are they have more than 50 hours in it. I’ve seen minges with hundreds of hours. This script is useless.