Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Events
- addEvent( "onCharacterLogin", false )
- addEvent( "onCharacterLogout", false )
- --
- local team = createTeam( "SGC" ) -- this is used as a dummy team. We need this for faction chat to work.
- p = { }
- -- Import Groups
- local groups = {
- { groupName = "MTA Moderators", groupID = false, aclGroup = "Moderator", displayName = "Moderator", nametagColor = { 255, 255, 127 }, priority = 5 },
- { groupName = "MTA Administrators", groupID = false, aclGroup = "Admin", displayName = "Administrator", nametagColor = { 255, 255, 0 }, priority = 10, defaultForFirstUser = true },
- { groupName = "Developers", groupID = false, aclGroup = "Developer", displayName = "Developer", nametagColor = { 127, 255, 127 }, priority = 20, defaultForFirstUser = true },
- }
- local function updateNametagColor( player )
- local nametagColor = { 127, 127, 127, priority = 0 }
- if p[ player ] and isLoggedIn( player ) then
- nametagColor = { 255, 255, 255, priority = 0 }
- if getOption( player, "staffduty" ) then
- for key, value in ipairs( groups ) do
- if isObjectInACLGroup( "user." .. p[ player ].username, aclGetGroup( value.aclGroup ) ) and value.nametagColor then
- if value.priority > nametagColor.priority then
- nametagColor = value.nametagColor
- nametagColor.priority = value.priority
- end
- end
- end
- end
- end
- setPlayerNametagColor( player, unpack( nametagColor ) )
- end
- function getGroups( player )
- local g = { }
- if p[ player ] then
- for key, value in ipairs( groups ) do
- if isObjectInACLGroup( "user." .. p[ player ].username, aclGetGroup( value.aclGroup ) ) then
- table.insert( g, value )
- end
- end
- table.sort( g, function( a, b ) return a.priority > b.priority end )
- end
- return g
- end
- local function aclUpdate( player, saveAclIfChanged )
- local saveAcl = false
- if player then
- local info = p[ player ]
- if info and info.username then
- local shouldHaveAccount = false
- local account = getAccount( info.username )
- local groupinfo = exports.sql:query_assoc( "SELECT groupID FROM wcf1_user_to_groups WHERE userID = " .. info.userID )
- if groupinfo then
- -- loop through all retrieved groups
- for key, group in ipairs( groupinfo ) do
- for key2, group2 in ipairs( groups ) do
- -- we have a acl group of interest
- if group.groupID == group2.groupID then
- -- mark as person to have an account
- shouldHaveAccount = true
- -- add an account if it doesn't exist
- if not account then
- outputServerLog( tostring( info.username ) .. " " .. tostring( info.mtasalt ) )
- account = addAccount( info.username, info.mtasalt ) -- due to MTA's limitations, the password can't be longer than 30 chars
- if not account then
- outputDebugString( "Account Error for " .. info.username .. " - addAccount failed.", 1 )
- else
- outputDebugString( "Added account " .. info.username, 3 )
- end
- end
- if account then
- -- if the player has a different account password, change it
- if not getAccount( info.username, info.mtasalt ) then
- setAccountPassword( account, info.mtasalt )
- end
- if isGuestAccount( getPlayerAccount( player ) ) and not logIn( player, account, info.mtasalt ) then
- -- something went wrong here
- outputDebugString( "Account Error for " .. info.username .. " - login failed.", 1 )
- else
- -- show him a message
- outputChatBox( "You are now logged in as " .. group2.displayName .. ".", player, 0, 255, 0 )
- if aclGroupAddObject( aclGetGroup( group2.aclGroup ), "user." .. info.username ) then
- saveAcl = true
- outputDebugString( "Added account " .. info.username .. " to " .. group2.aclGroup .. " ACL", 3 )
- end
- end
- end
- end
- end
- end
- end
- if not shouldHaveAccount and account then
- -- remove account from all ACL groups we use
- for key, value in ipairs( groups ) do
- if aclGroupRemoveObject( aclGetGroup( value.aclGroup ), "user." .. info.username ) then
- saveAcl = true
- outputDebugString( "Removed account " .. info.username .. " from " .. value.aclGroup .. " ACL", 3 )
- outputChatBox( "You are no longer logged in as " .. group.displayName .. ".", player, 255, 0, 0 )
- end
- end
- -- remove the account
- removeAccount( account )
- outputDebugString( "Removed account " .. info.username, 3 )
- end
- if saveAcl then
- updateNametagColor( player )
- end
- end
- else
- -- verify all accounts and remove invalid ones
- local checkedPlayers = { }
- local accounts = getAccounts( )
- for key, account in ipairs( accounts ) do
- local accountName = getAccountName( account )
- local player = getAccountPlayer( account )
- if player then
- checkedPlayers[ player ] = true
- end
- if accountName ~= "Console" then -- console may exist untouched
- local user = exports.sql:query_assoc_single( "SELECT userID FROM wcf1_user WHERE username = '%s'", accountName )
- if user then
- -- account should be deleted if no group is found
- local shouldBeDeleted = true
- local userChanged = false
- if user.userID then -- if this doesn't exist, the user does not exist in the db
- -- fetch all of his groups groups
- local groupinfo = exports.sql:query_assoc( "SELECT groupID FROM wcf1_user_to_groups WHERE userID = " .. user.userID )
- if groupinfo then
- -- look through all of our pre-defined groups
- for key, group in ipairs( groups ) do
- -- user does not have this group
- local hasGroup = false
- -- check if he does have it
- for key2, group2 in ipairs( groupinfo ) do
- if group.groupID == group2.groupID then
- -- has the group
- hasGroup = true
- -- shouldn't delete his account
- shouldBeDeleted = false
- -- make sure acl rights are set correctly
- if aclGroupAddObject( aclGetGroup( group.aclGroup ), "user." .. accountName ) then
- outputDebugString( "Added account " .. accountName .. " to ACL " .. group.aclGroup, 3 )
- saveAcl = true
- userChanged = true
- if player then
- outputChatBox( "You are now logged in as " .. group.displayName .. ".", player, 0, 255, 0 )
- end
- end
- end
- end
- -- doesn't have it
- if not hasGroup then
- -- make sure acl rights are removed
- if aclGroupRemoveObject( aclGetGroup( group.aclGroup ), "user." .. accountName ) then
- outputDebugString( "Removed account " .. accountName .. " from ACL " .. group.aclGroup, 3 )
- saveAcl = true
- userChanged = true
- if player then
- outputChatBox( "You are no longer logged in as " .. group.displayName .. ".", player, 255, 0, 0 )
- end
- end
- end
- end
- end
- end
- -- has no relevant group, thus we don't need the MTA account
- if shouldBeDeleted then
- if player then
- logOut( player )
- end
- outputDebugString( "Removed account " .. accountName, 3 )
- removeAccount( account )
- elseif player and isGuestAccount( getPlayerAccount( player ) ) and not logIn( player, account, p[ player ].mtasalt ) then
- -- something went wrong here
- outputDebugString( "Account Error for " .. accountName .. " - login failed.", 1 )
- end
- -- update the color since we have none
- if player and ( shouldBeDeleted or userChanged ) then
- updateNametagColor( player )
- end
- else
- -- Invalid user
- -- remove account from all ACL groups we use
- for key, value in ipairs( groups ) do
- if aclGroupRemoveObject( aclGetGroup( value.aclGroup ), "user." .. accountName ) then
- saveAcl = true
- outputDebugString( "Removed account " .. accountName .. " from " .. value.aclGroup .. " ACL", 3 )
- if player then
- outputChatBox( "You are no longer logged in as " .. group.displayName .. ".", player, 255, 0, 0 )
- end
- end
- end
- -- remove the account
- if player then
- logOut( player )
- end
- removeAccount( account )
- outputDebugString( "Removed account " .. accountName, 3 )
- end
- end
- end
- -- check all players not found by this for whetever they now have an account
- for key, value in ipairs( getElementsByType( "player" ) ) do
- if not checkedPlayers[ value ] then
- local success, needsAclUpdate = aclUpdate( value, false )
- if needsAclUpdate then
- saveAcl = true
- end
- end
- end
- end
- -- if we should save the acl, do it (permissions changed)
- if saveAclIfChanged and saveAcl then
- aclSave( )
- end
- return true, saveAcl
- end
- addCommandHandler( "reloadpermissions",
- function( player )
- if aclUpdate( nil, true ) then
- outputServerLog( "Permissions have been reloaded. (Requested by " .. ( not player and "Console" or getAccountName( getPlayerAccount( player ) ) or getPlayerName(player) ) .. ")" )
- if player then
- outputChatBox( "Permissions have been reloaded.", player, 0, 255, 0 )
- end
- else
- outputServerLog( "Permissions reload failed. (Requested by " .. ( not player and "Console" or getAccountName( getPlayerAccount( player ) ) or getPlayerName(player) ) .. ")" )
- if player then
- outputChatBox( "Permissions reload failed.", player, 255, 0, 0 )
- end
- end
- end,
- true
- )
- addEventHandler( "onResourceStart", resourceRoot,
- function( )
- -- create all mysql tables
- if not exports.sql:create_table( 'characters',
- {
- { name = 'characterID', type = 'int(10) unsigned', auto_increment = true, primary_key = true },
- { name = 'characterName', type = 'varchar(22)' },
- { name = 'userID', type = 'int(10) unsigned' },
- { name = 'x', type = 'float' },
- { name = 'y', type = 'float' },
- { name = 'z', type = 'float' },
- { name = 'interior', type = 'tinyint(3) unsigned' },
- { name = 'dimension', type = 'int(10) unsigned' },
- { name = 'skin', type = 'int(10) unsigned' },
- { name = 'rotation', type = 'float' },
- { name = 'health', type = 'tinyint(3) unsigned', default = 100 },
- { name = 'armor', type = 'tinyint(3) unsigned', default = 0 },
- { name = 'money', type = 'bigint(20) unsigned', default = 100 },
- { name = 'created', type = 'timestamp', default = 'CURRENT_TIMESTAMP' },
- { name = 'lastLogin', type = 'timestamp', default = '0000-00-00 00:00:00' },
- { name = 'weapons', type = 'varchar(255)', null = true },
- { name = 'job', type = 'varchar(20)', null = true },
- { name = 'languages', type = 'text', null = true },
- } ) then cancelEvent( ) return end
- if not exports.sql:create_table( 'wcf1_user',
- {
- { name = 'userID', type = 'int(10) unsigned', auto_increment = true, primary_key = true },
- { name = 'username', type = 'varchar(255)' },
- { name = 'password', type = 'varchar(40)' },
- { name = 'salt', type = 'varchar(40)' },
- { name = 'banned', type = 'tinyint(1) unsigned', default = 0 },
- { name = 'activationCode', type = 'int(10) unsigned', default = 0 },
- { name = 'banReason', type = 'mediumtext', null = true },
- { name = 'banUser', type = 'int(10) unsigned', null = true },
- { name = 'lastIP', type = 'varchar(15)', null = true },
- { name = 'lastSerial', type = 'varchar(32)', null = true },
- { name = 'userOptions', type = 'text', null = true },
- } ) then cancelEvent( ) return end
- local success, didCreateTable = exports.sql:create_table( 'wcf1_group',
- {
- { name = 'groupID', type = 'int(10) unsigned', auto_increment = true, primary_key = true },
- { name = 'groupName', type = 'varchar(255)', default = '' },
- { name = 'canBeFactioned', type = 'tinyint(1) unsigned', default = 1 }, -- if this is set to 0, you can't make a faction from this group.
- } )
- if not success then cancelEvent( ) return end
- if didCreateTable then
- -- add default groups
- for key, value in ipairs( groups ) do
- value.groupID = exports.sql:query_insertid( "INSERT INTO wcf1_group (groupName, canBeFactioned) VALUES ('%s', 0)", value.groupName )
- end
- else
- -- import all groups
- local data = exports.sql:query_assoc( "SELECT groupID, groupName FROM wcf1_group" )
- if data then
- for key, value in ipairs( data ) do
- for key2, value2 in ipairs( groups ) do
- if value.groupName == value2.groupName then
- value2.groupID = value.groupID
- end
- end
- end
- end
- end
- local success, didCreateTable = exports.sql:create_table( 'wcf1_user_to_groups',
- {
- { name = 'userID', type = 'int(10) unsigned', default = 0, primary_key = true },
- { name = 'groupID', type = 'int(10) unsigned', default = 0, primary_key = true },
- } )
- if not success then cancelEvent( ) return end
- if didCreateTable then
- for key, value in ipairs( groups ) do
- if value.defaultForFirstUser then
- exports.sql:query_free( "INSERT INTO wcf1_user_to_groups (userID, groupID) VALUES (1, " .. value.groupID .. ")" )
- end
- end
- end
- aclUpdate( nil, true )
- end
- )
- --
- local function showLoginScreen( player, screenX, screenY, token, ip )
- -- we need at least 800x600 for proper display of all GUI
- if screenX and screenY then
- if screenX < 800 or screenY < 600 then
- kickPlayer( player, "Use 800x600 or a larger resolution." )
- return
- end
- end
- -- remove the player from his vehicle if any
- if isPedInVehicle( player ) then
- removePedFromVehicle( player )
- end
- -- hide the current view (will be faded in client-side)
- fadeCamera( player, false, 0 )
- toggleAllControls( player, false, true, false )
- -- spawn the player etc.
- spawnPlayer( source, -1504, 1376, 3.75, 315, 0, 0, 1 )
- setPedFrozen( source, true )
- setElementAlpha( source, 0 )
- setCameraInterior( source, 0 )
- setCameraMatrix( source, 2270.16, 801.89, 64.81,2069.7, 1058.37, 17.03 ) -- background position
- setPlayerNametagColor( source, 127, 127, 127 )
- -- check for ip/serial bans
- if exports.sql:query_assoc_single( "SELECT * FROM wcf1_user WHERE banned = 1 AND ( lastIP = '%s' OR lastSerial = '%s' )", getPlayerIP( player ), getPlayerSerial( player ) ) then
- showChat( player, false )
- setTimer( triggerClientEvent, 300, 1, player, getResourceName( resource ) .. ":loginResult", player, 2 ) -- Banned
- return false
- end
- triggerClientEvent( player, getResourceName( resource ) .. ":spawnscreen", player )
- if token and #token > 0 then
- performLogin( source, token, false, ip )
- end
- end
- addEvent( getResourceName( resource ) .. ":ready", true )
- addEventHandler( getResourceName( resource ) .. ":ready", root,
- function( ... )
- if source == client then
- showLoginScreen( source, ... )
- end
- end
- )
- --
- -- tweak to allow multiple servers running paradise without interfering login files.
- -- this is also used to calculate an individual player's hash so even players with same ip/serial/username/password on two servers won't get the same hash to login with.
- -- If it's ever stolen/abused - if that's even possible? -, simply delete the token.xml file and restart this resource, this is going to prompt each player to login again.
- --
- local serverToken = nil
- addEventHandler( "onResourceStart", resourceRoot,
- function( )
- local xml = xmlLoadFile( "token.xml" )
- if xml then
- serverToken = xmlNodeGetValue( xml )
- xmlUnloadFile( xml )
- end
- if not serverToken then
- -- this should ideally be unique
- serverToken = md5( getServerName( ) .. math.random( 1, 2^30 ) .. getServerPort( ) .. "~paradise" ):lower( )
- local xml = xmlCreateFile( "token.xml", "token" )
- if xml then
- if xmlNodeSetValue( xml, serverToken ) then
- xmlSaveFile( xml )
- setTimer( outputConsole, 100, 1, "Created Server Token: " .. serverToken )
- else
- serverToken = nil
- end
- xmlUnloadFile( xml )
- else
- serverToken = nil
- end
- end
- addEvent( getResourceName( resource ) .. ":requestServerToken", true )
- addEventHandler( getResourceName( resource ) .. ":requestServerToken", root,
- function( ... )
- if source == client then
- triggerClientEvent( source, getResourceName( resource ) .. ":receiveServerToken", source, serverToken and md5( serverToken ):lower( ) )
- end
- end
- )
- end
- )
- --
- local loginAttempts = { }
- local triedTokenAuth = { }
- local function getPlayerHash( player, remoteIP )
- local ip = getPlayerIP( player ) or "255.255.255.0"
- if ip == "127.0.0.1" and remoteIP then -- we don't really care about a provided ip unless we want to connect from localhost
- ip = exports.sql:escape_string( remoteIP )
- end
- return ip:sub(ip:find("%d+%.%d+%.")) .. ( getPlayerSerial( player ) or "R0FLR0FLR0FLR0FLR0FLR0FLR0FLR0FL" ) .. tostring( serverToken )
- end
- addEvent( getResourceName( resource ) .. ":login", true )
- addEventHandler( getResourceName( resource ) .. ":login", root,
- function( username, password )
- if source == client then
- triedTokenAuth[ source ] = true
- if username and password and #username > 0 and #password > 0 then
- local info = exports.sql:query_assoc_single( "SELECT CONCAT(SHA1(CONCAT(username, '%s')),SHA1(CONCAT(salt, SHA1(CONCAT('%s',SHA1(CONCAT(salt, SHA1(CONCAT(username, SHA1(password)))))))))) AS token FROM wcf1_user WHERE `username` = '%s' AND password = SHA1(CONCAT(salt, SHA1(CONCAT(salt, '" .. sha1(password) .. "'))))", getPlayerHash( source ), getPlayerHash( source ), username )
- p[ source ] = nil
- if not info then
- triggerClientEvent( source, getResourceName( resource ) .. ":loginResult", source, 1 ) -- Wrong username/password
- loginAttempts[ source ] = ( loginAttempts[ source ] or 0 ) + 1
- if loginAttempts[ source ] >= 5 then
- -- ban for 15 minutes
- local serial = getPlayerSerial( source )
- banPlayer( source, true, false, false, root, "Too many login attempts.", 900 )
- if serial then
- addBan( nil, nil, serial, root, "Too many login attempts.", 900 )
- end
- end
- else
- loginAttempts[ source ] = nil
- performLogin( source, info.token, true )
- end
- end
- end
- end
- )
- function performLogin( source, token, isPasswordAuth, ip )
- if source and ( isPasswordAuth or not triedTokenAuth[ source ] ) then
- triedTokenAuth[ source ] = true
- if token then
- if #token == 80 then
- local info = exports.sql:query_assoc_single( "SELECT userID, username, banned, activationCode, SUBSTRING(LOWER(SHA1(CONCAT(userName,SHA1(CONCAT(password,salt))))),1,30) AS salts, userOptions FROM wcf1_user WHERE CONCAT(SHA1(CONCAT(username, '%s')),SHA1(CONCAT(salt, SHA1(CONCAT('%s',SHA1(CONCAT(salt, SHA1(CONCAT(username, SHA1(password)))))))))) = '%s' LIMIT 1", getPlayerHash( source, ip ), getPlayerHash( source, ip ), token )
- p[ source ] = nil
- if not info then
- if isPasswordAuth then
- triggerClientEvent( source, getResourceName( resource ) .. ":loginResult", source, 1 ) -- Wrong username/password
- end
- return false
- else
- if info.banned == 1 then
- triggerClientEvent( source, getResourceName( resource ) .. ":loginResult", source, 2 ) -- Banned
- return false
- elseif info.activationCode > 0 then
- triggerClientEvent( source, getResourceName( resource ) .. ":loginResult", source, 3 ) -- Requires activation
- return false
- else
- -- check if another user is logged in on that account
- for player, data in pairs( p ) do
- if data.userID == info.userID then
- triggerClientEvent( source, getResourceName( resource ) .. ":loginResult", source, 5 ) -- another player with that account found
- return false
- end
- end
- local username = info.username
- p[ source ] = { userID = info.userID, username = username, mtasalt = info.salts, options = info.userOptions and fromJSON( info.userOptions ) or { } }
- -- check for admin rights
- aclUpdate( source, true )
- -- show characters
- local chars = exports.sql:query_assoc( "SELECT characterID, characterName, skin FROM characters WHERE userID = " .. info.userID .. " ORDER BY lastLogin DESC" )
- if isPasswordAuth then
- triggerClientEvent( source, getResourceName( resource ) .. ":characters", source, chars, true, token, getPlayerIP( source ) ~= "127.0.0.1" and getPlayerIP( source ) )
- else
- triggerClientEvent( source, getResourceName( resource ) .. ":characters", source, chars, true )
- end
- outputServerLog( "PARADISE LOGIN: " .. getPlayerName( source ) .. " logged in as " .. info.username .. " (IP: " .. getPlayerIP( source ) .. ", Serial: " .. getPlayerSerial( source ) .. ")" )
- exports.server:message( "%C04[" .. getID( source ) .. "]%C %B" .. info.username .. "%B logged in (Nick: %B" .. getPlayerName( source ):gsub( "_", " " ) .. "%B)." )
- exports.sql:query_free( "UPDATE wcf1_user SET lastIP = '%s', lastSerial = '%s' WHERE userID = " .. tonumber( info.userID ), getPlayerIP( source ), getPlayerSerial( source ) )
- return true
- end
- end
- end
- end
- end
- return false
- end
- local function getWeaponString( player )
- local weapons = { }
- local hasAnyWeapons = false
- for slot = 0, 12 do
- local weapon = getPedWeapon( player, slot )
- if weapon > 0 then
- local ammo = getPedTotalAmmo( player, slot )
- if ammo > 0 then
- weapons[weapon] = ammo
- hasAnyWeapons = true
- end
- end
- end
- if hasAnyWeapons then
- return "'" .. exports.sql:escape_string( toJSON( weapons ):gsub( " ", "" ) ) .. "'"
- else
- return "NULL"
- end
- end
- local function savePlayer( player )
- if not player then
- for key, value in ipairs( getElementsByType( "player" ) ) do
- savePlayer( value )
- end
- else
- if isLoggedIn( player ) then
- -- save character since it's logged in
- local x, y, z = getElementPosition( player )
- local dimension = getElementDimension( player )
- local interior = getElementInterior( player )
- if hasObjectPermissionTo( player, "command.spectate", false ) and type( getElementData( player, "collisionless" ) ) == "table" then
- -- spectating
- x, y, z, dimension, interior = unpack( getElementData( player, "collisionless" ) )
- end
- exports.sql:query_free( "UPDATE characters SET x = " .. x .. ", y = " .. y .. ", z = " .. z .. ", dimension = " .. dimension .. ", interior = " .. interior .. ", rotation = " .. getPedRotation( player ) .. ", health = " .. math.floor( getElementHealth( player ) ) .. ", armor = " .. math.floor( getPedArmor( player ) ) .. ", weapons = " .. getWeaponString( player ) .. ", lastLogin = NOW() WHERE characterID = " .. tonumber( getCharacterID( player ) ) )
- end
- end
- end
- setTimer( savePlayer, 300000, 0 ) -- Auto-Save every five minutes
- addEventHandler( "onResourceStop", resourceRoot,
- function( )
- -- logout all players
- for key, value in ipairs( getElementsByType( "player" ) ) do
- savePlayer( value )
- if p[ value ] and p[ value ].charID then
- triggerEvent( "onCharacterLogout", value )
- setPlayerTeam( value, nil )
- takeAllWeapons( value )
- end
- if not isGuestAccount( getPlayerAccount( value ) ) then
- logOut( value )
- end
- end
- end
- )
- addEvent( getResourceName( resource ) .. ":logout", true )
- addEventHandler( getResourceName( resource ) .. ":logout", root,
- function( )
- if source == client then
- savePlayer( source )
- if p[ source ].charID then
- triggerEvent( "onCharacterLogout", source )
- setPlayerTeam( source, nil )
- takeAllWeapons( source )
- end
- p[ source ] = nil
- showLoginScreen( source )
- if not isGuestAccount( getPlayerAccount( source ) ) then
- logOut( source )
- end
- end
- end
- )
- addEventHandler( "onPlayerJoin", root,
- function( )
- setPlayerNametagColor( source, 127, 127, 127 )
- end
- )
- addEventHandler( "onPlayerQuit", root,
- function( )
- if p[ source ] then
- savePlayer( source )
- if p[ source ].charID then
- triggerEvent( "onCharacterLogout", source )
- end
- p[ source ] = nil
- loginAttempts[ source ] = nil
- triedTokenAuth[ source ] = nil
- end
- end
- )
- addEvent( getResourceName( resource ) .. ":spawn", true )
- addEventHandler( getResourceName( resource ) .. ":spawn", root,
- function( charID )
- if source == client and ( not isPedDead( source ) or not isLoggedIn( source ) ) then
- local userID = p[ source ] and p[ source ].userID
- if tonumber( userID ) and tonumber( charID ) then
- -- if the player is logged in, save him
- savePlayer( source )
- if p[ source ].charID then
- triggerEvent( "onCharacterLogout", source )
- setPlayerTeam( source, nil )
- takeAllWeapons( source )
- p[ source ].charID = nil
- p[ source ].money = nil
- p[ source ].job = nil
- end
- --
- local char = exports.sql:query_assoc_single( "SELECT * FROM characters WHERE userID = " .. tonumber( userID ) .. " AND characterID = " .. tonumber( charID ) )
- if char then
- local mtaCharName = char.characterName:gsub( " ", "_" )
- local otherPlayer = getPlayerFromName( mtaCharName )
- if otherPlayer and otherPlayer ~= source then
- kickPlayer( otherPlayer )
- end
- setPlayerName( source, mtaCharName )
- -- spawn the player, as it's a valid char
- spawnPlayer( source, char.x, char.y, char.z, char.rotation, char.skin, char.interior, char.dimension )
- fadeCamera( source, true )
- setCameraTarget( source, source )
- setCameraInterior( source, char.interior )
- toggleAllControls( source, true, true, false )
- setPedFrozen( source, false )
- setElementAlpha( source, 255 )
- setElementHealth( source, char.health )
- setPedArmor( source, char.armor )
- p[ source ].money = char.money
- setPlayerMoney( source, char.money )
- p[ source ].charID = tonumber( charID )
- p[ source ].characterName = char.characterName
- updateNametag( source )
- -- restore weapons
- if char.weapons then
- local weapons = fromJSON( char.weapons )
- if weapons then
- for weapon, ammo in pairs( weapons ) do
- giveWeapon( source, weapon, ammo )
- end
- end
- end
- p[ source ].job = char.job
- -- restore the player's languages, remove invalid ones
- p[ source ].languages = fromJSON( char.languages )
- if not p[ source ].languages then
- -- default is English with full skill
- p[ source ].languages = { en = { skill = 1000, current = true } }
- saveLanguages( source, p[ source ].languages )
- else
- local changed = false
- local languages = 0
- for key, value in pairs( p[ source ].languages ) do
- if isValidLanguage( "en" ) then
- changed = true
- languages = languages + 1
- if not isValidLanguage( key ) then
- p[ source ].languages[ key ] = nil
- languages = languages - 1
- elseif type( value.skill ) ~= 'number' then
- value.skill = 0
- elseif value.skill < 0 then
- value.skill = 0
- elseif value.skill > 1000 then
- value.skill = 1000
- else
- changed = false
- end
- else
- languages = languages + 1
- end
- end
- if languages == 0 then
- -- player has no language at all
- p[ source ].languages = { en = { skill = 1000, current = true } }
- changed = true
- end
- if changed then
- saveLanguages( source, p[ source ].languages )
- end
- end
- setPlayerTeam( source, team )
- triggerClientEvent( source, getResourceName( resource ) .. ":onSpawn", source, p[ source ].languages )
- triggerEvent( "onCharacterLogin", source )
- showCursor( source, false )
- -- set last login to now
- exports.sql:query_free( "UPDATE characters SET lastLogin = NOW() WHERE characterID = " .. tonumber( charID ) )
- outputServerLog( "PARADISE CHARACTER: " .. p[ source ].username .. " is now playing as " .. char.characterName )
- exports.server:message( "%C04[" .. getID( source ) .. "]%C %B" .. p[ source ].username .. "%B is now playing in as %B" .. char.characterName .. "%B." )
- end
- end
- end
- end
- )
- addEventHandler( "onPlayerChangeNick", root,
- function( )
- if isLoggedIn( source ) then
- cancelEvent( )
- end
- end
- )
- -- exports
- function getCharacterID( player )
- return player and p[ player ] and p[ player ].charID or false
- end
- function isLoggedIn( player )
- return getCharacterID( player ) and true or false
- end
- function getUserID( player )
- return player and p[ player ] and p[ player ].userID or false
- end
- function getUserName( player )
- return player and p[ player ] and p[ player ].username or false
- end
- -- retrieves a character name from the database id
- function getCharacterName( characterID )
- if type( characterID ) == "number" then
- -- check if the player is online, if so we don't need to query
- for player, data in pairs( p ) do
- if data.charID == characterID then
- local name = getPlayerName( player ):gsub( "_", " " )
- return name
- end
- end
- local data = exports.sql:query_assoc_single( "SELECT characterName FROM characters WHERE characterID = " .. characterID )
- if data then
- return data.characterName
- end
- end
- return false
- end
- -- money functions
- function setMoney( player, amount )
- amount = tonumber( amount )
- if amount >= 0 and isLoggedIn( player ) then
- if exports.sql:query_free( "UPDATE characters SET money = " .. amount .. " WHERE characterID = " .. p[ player ].charID ) then
- p[ player ].money = amount
- setPlayerMoney( player, amount )
- return true
- end
- end
- return false
- end
- function giveMoney( player, amount )
- return amount >= 0 and setMoney( player, getMoney( player ) + amount )
- end
- function takeMoney( player, amount )
- return amount >= 0 and setMoney( player, getMoney( player ) - amount )
- end
- function getMoney( player, amount )
- return isLoggedIn( player ) and p[ player ].money or 0
- end
- --
- function updateCharacters( player )
- if player and p[ player ].userID then
- local chars = exports.sql:query_assoc( "SELECT characterID, characterName, skin FROM characters WHERE userID = " .. p[ player ].userID .. " ORDER BY lastLogin DESC" )
- triggerClientEvent( player, getResourceName( resource ) .. ":characters", player, chars, false )
- return true
- end
- return false
- end
- function createCharacter( player, name, skin )
- if player and p[ player ].userID then
- if exports.sql:query_assoc_single( "SELECT characterID FROM characters WHERE characterName = '%s'", name ) then
- triggerClientEvent( player, "players:characterCreationResult", player, 1 )
- elseif exports.sql:query_free( "INSERT INTO characters (characterName, userID, x, y, z, interior, dimension, skin, rotation) VALUES ('%s', " .. p[ player ].userID .. ", -1984.5, 138, 27.7, 0, 0, " .. tonumber( skin ) .. ", 270)", name ) then
- updateCharacters( player )
- triggerClientEvent( player, "players:characterCreationResult", player, 0 )
- exports.server:message( "%C04[" .. getID( player ) .. "]%C %B" .. p[ player ].username .. "%B created character %B" .. name .. "%B." )
- return true
- end
- end
- return false
- end
- --
- function updateNametag( player )
- if player then
- local text = "[" .. getID( player ) .. "] "
- local vehicle = getPedOccupiedVehicle( player )
- if vehicle and exports.vehicles:hasTintedWindows( vehicle ) then
- text = text .. "? (Tinted Windows)"
- else
- text = text .. ( p[ player ] and p[ player ].characterName or getPlayerName( player ):gsub( "_", " " ) )
- end
- if getPlayerNametagText( player ) ~= tostring( text ) then
- setPlayerNametagText( player, tostring( text ) )
- end
- updateNametagColor( player )
- return true
- end
- return false
- end
- addEventHandler( "onPlayerSpawn", root,
- function( )
- updateNametag( source )
- end
- )
- setTimer(
- function( )
- for player in pairs( p ) do
- updateNametag( player )
- end
- end,
- 15000,
- 0
- )
- --
- function getJob( player )
- return isLoggedIn( player ) and p[ player ].job or nil
- end
- function setJob( player, job )
- local charID = getCharacterID( player )
- if charID and exports.sql:query_free( "UPDATE characters SET job = '%s' WHERE characterID = " .. charID, job ) then
- p[ player ].job = job
- return true
- end
- return false
- end
- --
- function getOption( player, key )
- return player and p[ player ] and p[ player ].options and key and p[ player ].options[ key ] or nil
- end
- function setOption( player, key, value )
- if player and p[ player ] and p[ player ].options and type( key ) == 'string' then
- -- update the option
- local oldValue = p[ player ].options[ key ]
- p[ player ].options[ key ] = value
- local str = toJSON( p[ player ].options )
- if str then
- if str == toJSON( { } ) then
- local success = exports.sql:query_free( "UPDATE wcf1_user SET userOptions = NULL WHERE userID = " .. getUserID( player ) )
- return success
- elseif exports.sql:query_free( "UPDATE wcf1_user SET userOptions = '%s' WHERE userID = " .. getUserID( player ), str ) then
- return true
- end
- end
- -- if it failed, restore the old value
- p[ player ].options[ key ] = oldValue
- end
- return false
- end
Add Comment
Please, Sign In to add comment