-- Client & Server Variables. local accounts = {} -- Server only variable. local spawned = false -- Client only variable. -- When spawned in tell the player in chat to type !help to get a list of commands. local function welcomeMessage(player) if(spawned == false) then chatprintf(player, "Account System Loaded!") chatprintf(player, "In chat type !help to get this list of commands in your console.") 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 stringBuilder = stringBuilder + accounts[userId]["username"] .. "," .. accounts[userId]["password"] .. "," .. accounts[userId]["score"] .. "," .. accounts[userId]["rings"] .. "," .. accounts[userId]["lives"] .. "\n" 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 !resetdata - Resets everything except for password.") print("sayto 0 !savedata - Saves your data on request.") 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, " ") -- 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 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") 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 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)