-- Client & Server Variables. local accounts = {} -- Server only variable. -- When spawned in tell the player in chat to type !help to get a list of commands. local function welcomeMessage(player) if(player.spawned == nil) then chatprintf(player, "Account System Loaded!") chatprintf(player, "In chat type !help to get this list of commands in your console.") player.spawned = true player.loggedon = false end end -- My split string function. I could've used other methods but I like making my own functions to work with. local function splitString(str, del) local arr = {} local last_num = 0; local copy = "" for i=1,string.len(str) do local strCopy = string.sub(str, i, i) if(strCopy == del) then last_num=last_num+1 arr[last_num] = copy copy = "" else copy = copy .. strCopy end end last_num=last_num+1 arr[last_num] = copy return arr end -- Saves the account in the client/accounts.dat. Trying to save the file in the server just caused the client to crash. local function saveAccounts() local pserv = consoleplayer; if(pserv == nil) then print("Saving accounts...") local acc=io.openlocal("client/accounts.dat", "w") local stringBuilder = "" for userId,v in pairs(accounts) do -- Check to see if they are deleted accounts. If so then ignore them from the save system... if(accounts[userId] ~= nil) then stringBuilder = stringBuilder + accounts[userId]["username"] .. "," .. accounts[userId]["password"] .. "," .. accounts[userId]["score"] .. "," .. accounts[userId]["rings"] .. "," .. accounts[userId]["lives"] .. "\n" end end acc:write(stringBuilder) acc:close() print("Accounts saved!") end end -- Loads up the account data and restores them for each server restart. local function loadAccounts() print("Loading accounts...") local pserv = consoleplayer; if(pserv == nil) then local acc2 = io.openlocal("client/accounts.dat", "r") if(acc2 ~= nil) then for line in acc2:lines() do if(line ~= "") then local data = splitString(line, "\n") for l=1,#data do local data2 = splitString(data[l], ",") print("Loading "..data2[1]) accounts[data2[1]] = { rings = tonumber(data2[4]), score = tonumber(data2[3]), lives = tonumber(data2[5]), mobj = nil, password = data2[2], username = data2[1] } end end end acc2:close() end print("Accounts loaded!") end end -- TF2 Engineer be like: "Erectin' a accounts!" loadAccounts() -- PlayerMsg local function cmdSystem(source, _type, target, msg) -- pserv or in this case consoleplayer will grab the player's player_t variable. pserv serves no purpose other then to check to see if it's a server or not. -- Servers will return a nil if the player doesn't exist. If it does exists execute it on the client side only. local pserv = consoleplayer; -- Check to see if player is using say command. if(_type == 0 and pserv ~= nil) then local cmd = splitString(msg, " ") if(cmd[1] == "!help") then print("sayto 0 !login - Login") print("sayto 0 !register - Changes password") print("sayto 0 !delete_account - Deletes the account ") print("sayto 0 !resetdata - Resets everything except for password.") print("sayto 0 !savedata - Saves your data on request.") print("sayto 0 !adminhelp - Shows displayed information about the admin sayto commands.") print("In chat type !help to get this list of commands again.") end end if(pserv == nil) then if(_type == 2) then -- Checks to see if your messaging the server instead of a player. if(#target == 0) then local cmd = splitString(msg, " ") print(source.loggedon) -- Login cmd if(cmd[1] == "!login" and source.loggedon == false) then -- Checks to see if the account exists. Player won't see this but I suppose it's much secure that way. if(accounts[cmd[2]] ~= nil) then if(accounts[cmd[2]]["password"] == sha1(cmd[3])) then -- Set the userid so that the player is always logged in. source.userid = cmd[2] source.rings = accounts[cmd[2]]["rings"] source.score = accounts[cmd[2]]["score"] source.lives = accounts[cmd[2]]["lives"] accounts[cmd[2]]["mobj"] = #source source.loggedon = true print("Authenticated "..cmd[2].." successfully! Scores, Rings and Lives are now synchronized!") else print("Authenticated "..cmd[2].." failed! Please type in the right username and password.") end else print("Account "..cmd[2].." does not exists! Try typing in console \"sayto 0 !register "..cmd[2].." "..cmd[3].."\" to register an account.") end end -- Register cmd if(cmd[1] == "!register") then -- Checks to see if the acocunt doesn't exists. if(accounts[cmd[2]] == nil) then accounts[cmd[2]] = { rings = 0, score = 0, lives = 3, mobj = nil, password = sha1(cmd[3]), username = cmd[2] } -- Save the account in the database. saveAccounts() print("Account "..cmd[2].." registered successfully!") else print("Account "..cmd[2].." already with that name has registered.") end end -- New Password cmd if(cmd[1] == "!newpassword") then if(source.userid ~= nil) then -- Sets the new password. accounts[source.userid]["password"] = sha1(cmd[2]) saveAccounts() print("Password for "..source.userid.." changed!") end end -- Reset Data cmd if(cmd[1] == "!resetdata") then if(source.userid ~= nil) then -- Resets the account's data back to zero. accounts[source.userid]["rings"] = 0 accounts[source.userid]["score"] = 0 accounts[source.userid]["lives"] = 3 saveAccounts() source.rings = 0 source.score = 0 source.lives = 3 print("Account "..source.userid.." has reset everything back to zero.") end end -- Sync cmd if(cmd[1] == "!savedata") then if(source.userid ~= nil) then -- Updates the account's data from the player. accounts[source.userid]["rings"] = source.rings accounts[source.userid]["score"] = source.score accounts[source.userid]["lives"] = source.lives saveAccounts() print("Account "..source.userid.." has saved their account's data.") end end if(cmd[1] == "!delete_account") then if(source.userid ~= nil) then accounts[source.userid] = nil saveAccounts() source.rings = 0 source.score = 0 source.lives = 3 print("Account "..source.userid.." has been deleted. Logging them out now.") source.userid = nil end end if(cmd[1] == "!admin") then if(cmd[2] == "changepassword") then if(IsPlayerAdmin(source)) then if(accounts[cmd[3]] ~= nil) then accounts[cmd[3]]["password"] = sha1(cmd[4]) saveAccounts() print(source.name.." has changed account "..cmd[3].."'s password.") else print(cmd[3].."'s account does not exists...") end else print(source.name.." does not have admin privileges.") end end if(cmd[2] == "delete_user") then if(IsPlayerAdmin(source)) then if(accounts[cmd[3]] ~= nil) then accounts[cmd[3]] = nil saveAccounts() print(source.name.." has deleted account "..cmd[3].." completely.") else print(cmd[3].."'s account does not exists...") end else print(source.name.." does not have admin privileges.") end end if(cmd[2] == "edit_user") then if(IsPlayerAdmin(source)) then if(accounts[cmd[3]] ~= nil) then accounts[cmd[3]]["score"] = cmd[4] accounts[cmd[3]]["rings"] = cmd[5] accounts[cmd[3]]["lives"] = cmd[6] saveAccounts() print(source.name.." has changed account "..cmd[3].."'s rings, score and lives.") else print(cmd[3].."'s account does not exists...") end else print(source.name.." does not have admin privileges.") end end end end end end -- Client side only. if(_type == 2) then -- Remember when I said the pserv serves no purpose well it actually does. SRB2 has no way to execute things either client-side or server-side. It's important to use consoleplayer which the server would not have. if(pserv ~= nil) then local me = source.realmo local cmd = splitString(msg, " ") -- DO NOT PANIC! You are not actually dead. The client just killed you but you'll resync in either seconds or minutes depending on how the server is configured. if(cmd[1] == "!login" or cmd[1] == "!resetdata" or cmd[1] == "!delete_account") then chatprintf(source, "Just gonna kill you from the client side. Don't worry this is just to resync your game.") P_KillMobj(me, nil, nil, DMG_FIRE) end -- Anyone can execute this but they actually gotta know you have to be admin to do these actions. if(cmd[1] == "!adminhelp") then print("sayto 0 !admin changepassword - Changes the account's password.") print("sayto 0 !admin delete_user - Deletes the account permanently. This action is irreversable.") print("sayto 0 !admin edit_user - Edits user data.") end end end end -- When a player quits the game, depends on how the rejointimeout is configured. Servers may immediately time you out when you leave. local function logoutAccount(player, unused) for userId,v in pairs(accounts) do if(accounts[userId]["mobj"] == #player) then print("Logging out "..userId) accounts[userId]["mobj"] = nil end end end -- Hook events. addHook("PlayerMsg", cmdSystem) addHook("PlayerQuit", logoutAccount) addHook("PlayerSpawn", welcomeMessage)