Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Metadata #912

Merged
merged 11 commits into from
Feb 26, 2023
Merged

feat: Metadata #912

merged 11 commits into from
Feb 26, 2023

Conversation

Rav3n95
Copy link
Member

@Rav3n95 Rav3n95 commented Feb 21, 2023

No description provided.

[core]/es_extended/server/main.lua Outdated Show resolved Hide resolved
Copy link
Member

@CsokiHUN CsokiHUN left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

@Gellipapa
Copy link
Member

Really cool, but a log system would be better than using prints, and if I have metadata then how can I update the value of a given key? So I don't want the whole table just one value of it, if I saw it right it allows to add table as metadata.

@CsokiHUN
Copy link
Member

Really cool, but a log system would be better than using prints, and if I have metadata then how can I update the value of a given key? So I don't want the whole table just one value of it, if I saw it right it allows to add table as metadata.

xPlayer.setMeta('your_key', value)

So you are not updating the whole key, only the value for that key.

@Gellipapa
Copy link
Member

Gellipapa commented Feb 22, 2023

What happens if I add table as value how do I update the value?
table_data = {bread = 200, water = 300}
key: table_data
value: {bread = 200, water = 300}
i would like the water to be only 400 the correct output would be: {bread = 200, water = 400}.

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 22, 2023

Then you get the index of the data, update it yourself, then send the updated table back. That's why I posted in Dev branch, if you have a idea how to fix this issue whit out using the getter first. Go for it :D

@Gellipapa
Copy link
Member

Another feature, I want to retrieve a value from a table, how do I do that?

key: table_data
value {bread:200, water:300}

I'm only interested in the water value? How can I get it?

getMeta(table_data, "water") --> output: 300.

I think such an option could be in getter, of course it would only work for table.

@CsokiHUN
Copy link
Member

What happens if I add table as value how do I update the value? table_data = {bread = 200, water = 300} key: table_data value: {bread = 200, water = 300} i would like the water to be only 400 the correct output would be: {bread = 200, water = 400}.

I understand what you are saying, but I don't think we can do it well. Because what if someone uses a non-string key at the table..
It's not that big of a problem if the whole table needs to be updated, because we're not going to store a lot of data here.

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 22, 2023

What if the stored value it's not a table?

@CsokiHUN
Copy link
Member

If we include the option to retrieve the value of the key from the table, we are in the same place as if we had done it ourselves

@Gellipapa
Copy link
Member

Then you get the index of the data, update it yourself, then send the updated table back. That's why I posted in Dev branch, if you have a idea how to fix this issue whit out using the getter first. Go for it :D

A possible solution, with an optional parameter, is to use only a table because you can update a not a table value.
For example: setMeta(table_data,'water', 400)

@Gellipapa
Copy link
Member

If it is not a table you return the given key value.

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 22, 2023

Show me the code then :D

@Gellipapa
Copy link
Member

If we include the option to retrieve the value of the key from the table, we are in the same place as if we had done it ourselves

It is better than always having to retrieve and index everything. Of course there is also an indexing in the background but it is in the background. It is more practical to have the option to return a specific value or the whole table.

These are just the features and ideas I threw in here :)

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 22, 2023

xPlayer.setMeta('bikes', {'20', '24', '26', '27.5', '28', '29'}) How about a not indexed table value?

@CsokiHUN
Copy link
Member

xPlayer.setMeta('bikes', {'20', '24', '26', '27.5', '28', '29'}) How about a not indexed table value?

fun fact: you store the numbers as string 😂

@Gellipapa
Copy link
Member

image

This is core logic. Need nil handler etc.

local function printTable( t )
 
    local printTable_cache = {}
 
    local function sub_printTable( t, indent )
 
        if ( printTable_cache[tostring(t)] ) then
            print( indent .. "*" .. tostring(t) )
        else
            printTable_cache[tostring(t)] = true
            if ( type( t ) == "table" ) then
                for pos,val in pairs( t ) do
                    if ( type(val) == "table" ) then
                        print( indent .. "[" .. pos .. "] => " .. tostring( t ).. " {" )
                        sub_printTable( val, indent .. string.rep( " ", string.len(pos)+8 ) )
                        print( indent .. string.rep( " ", string.len(pos)+6 ) .. "}" )
                    elseif ( type(val) == "string" ) then
                        print( indent .. "[" .. pos .. '] => "' .. val .. '"' )
                    else
                        print( indent .. "[" .. pos .. "] => " .. tostring(val) )
                    end
                end
            else
                print( indent..tostring(t) )
            end
        end
    end
 
    if ( type(t) == "table" ) then
        print( tostring(t) .. " {" )
        sub_printTable( t, "  " )
        print( "}" )
    else
        sub_printTable( t, "  " )
    end
end


local metadata = {
  ["table_data"] = {bread =  200, water =  300}
}

function getMeta(key, searchedKey)
  if type(metadata[key]) == 'table' and searchedKey then
    return metadata[key][searchedKey]
  end
  return metadata[key]
end

function setMeta(key, value, newValue)
  if type(metadata[key]) == 'table' and newValue then
    metadata[key][value] = newValue
    return
  end
  metadata[key] = value
end

print("GET DEFAULT VALUES")
printTable(getMeta("table_data"))
print("SET NEW VALUE ONLY WATER TO 600")
setMeta("table_data", "water", 600)
print("GET ONLY WATER VALUE")
printTable(getMeta("table_data","water"))
print("------------------------------------")
print("DEFAULT SET VERSION WORKS {bread =  200, water =  300}")
setMeta("table_data", {bread =  200, water =  300})
print("GET DEFAULT VALUES")
printTable(getMeta("table_data"))


@Gellipapa
Copy link
Member

You can do index, but why do this or you can use default version can set all table -> backwards compatiblity. Sorry guys i should go to work.

@Gellipapa
Copy link
Member

Next level if i can search in one value, why can't we pass it a table if i only need 5 out of 20 values, same with update, it would be nice to update those 5 values in order. 👍

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 22, 2023

Also play a violin and a guitar in a same time ;)

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 22, 2023

RegisterCommand('meta', function(source)
    local xPlayer = ESX.GetPlayerFromId(source)
    print('--------------------------------------------')
    print('Clearing "shopPrices" meta')
    xPlayer.clearMeta('shopPrices')
    print('First meta getter')
    print(json.encode(xPlayer.getMeta(),{indent=true}))
    print('--------------------------------------------')
    print('Setting "shopPrices" meta')
    xPlayer.setMeta('shopPrices', {bread = 200, water = 300})
    print('--------------------------------------------')
    print('Second meta getter')
    print(json.encode(xPlayer.getMeta(),{indent=true}))
    print('--------------------------------------------')
    print('Setting "bread" value on "shopPrices" meta')
    xPlayer.setMeta('shopPrices', 'bread', 250)
    print('Third meta getter -> just getting the bread price')
    print(xPlayer.getMeta('shopPrices', 'bread'))
    print('--------------------------------------------')
    print('Forth meta getter')
    print(json.encode(xPlayer.getMeta(),{indent=true}))
end, false)

Copy link
Member

@Gellipapa Gellipapa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice good job, thank you buddy. 👍

[core]/.gitignore Outdated Show resolved Hide resolved
@mrscriptsid
Copy link

cool, its posible to direct save when set meta?

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 26, 2023

cool, its posible to direct save when set meta?

If you are using the ESX.Saveplayer() function after you set the meta 🤣

@mrscriptsid
Copy link

mrscriptsid commented Feb 26, 2023

cool, its posible to direct save when set meta?

If you are using the ESX.Saveplayer() function after you set the meta 🤣

i just set player detail (first lastname, bod, sex, height, etc) as a meta, but i have issue when get the meta, give me nil value

GetCharacters = function(source,data,slots)
	local characters = {}
	local license = ESX.GetIdentifier(source)
	local id = Config.Prefix..'%:'..license
	local data = MySQL.query.await('SELECT * FROM users WHERE identifier LIKE ?', {'%'..id..'%'})
	if data then
		for k,v in pairs(data) do
			local job, grade = v.job or 'imigran', tostring(v.job_grade)
			local accounts = json.decode(v.accounts)
			local id = tonumber(string.sub(v.identifier, #Config.Prefix+1, string.find(v.identifier, ':')-1))
			local xPlayer = ESX.GetPlayerFromId(source)
			print(xPlayer.getMeta('detail','firstname'))
		end
	end
	return {characters = characters , slots = slots}
end

@Gellipapa
Copy link
Member

cool, its posible to direct save when set meta?

If you are using the ESX.Saveplayer() function after you set the meta 🤣

i just set player detail (first lastname, bod, sex, height, etc) as a meta, but i have issue when get the meta, give me nil value

GetCharacters = function(source,data,slots)
	local characters = {}
	local license = ESX.GetIdentifier(source)
	local id = Config.Prefix..'%:'..license
	local data = MySQL.query.await('SELECT * FROM users WHERE identifier LIKE ?', {'%'..id..'%'})
	if data then
		for k,v in pairs(data) do
			local job, grade = v.job or 'imigran', tostring(v.job_grade)
			local accounts = json.decode(v.accounts)
			local id = tonumber(string.sub(v.identifier, #Config.Prefix+1, string.find(v.identifier, ':')-1))
			local xPlayer = ESX.GetPlayerFromId(source)
			print(xPlayer.getMeta('detail','firstname'))
		end
	end
	return {characters = characters , slots = slots}
end

Hi! If you print json.encode(xPlayer.getMeta('detail')) what is get?

@mrscriptsid
Copy link

mrscriptsid commented Feb 26, 2023

cool, its posible to direct save when set meta?

If you are using the ESX.Saveplayer() function after you set the meta 🤣

i just set player detail (first lastname, bod, sex, height, etc) as a meta, but i have issue when get the meta, give me nil value

GetCharacters = function(source,data,slots)
	local characters = {}
	local license = ESX.GetIdentifier(source)
	local id = Config.Prefix..'%:'..license
	local data = MySQL.query.await('SELECT * FROM users WHERE identifier LIKE ?', {'%'..id..'%'})
	if data then
		for k,v in pairs(data) do
			local job, grade = v.job or 'imigran', tostring(v.job_grade)
			local accounts = json.decode(v.accounts)
			local id = tonumber(string.sub(v.identifier, #Config.Prefix+1, string.find(v.identifier, ':')-1))
			local xPlayer = ESX.GetPlayerFromId(source)
			print(xPlayer.getMeta('detail','firstname'))
		end
	end
	return {characters = characters , slots = slots}
end

Hi! If you print json.encode(xPlayer.getMeta('detail')) what is get?

image
still error, fyi: i have string and number value on detail meta

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 26, 2023

cool, its posible to direct save when set meta?

If you are using the ESX.Saveplayer() function after you set the meta 🤣

i just set player detail (first lastname, bod, sex, height, etc) as a meta, but i have issue when get the meta, give me nil value

GetCharacters = function(source,data,slots)
	local characters = {}
	local license = ESX.GetIdentifier(source)
	local id = Config.Prefix..'%:'..license
	local data = MySQL.query.await('SELECT * FROM users WHERE identifier LIKE ?', {'%'..id..'%'})
	if data then
		for k,v in pairs(data) do
			local job, grade = v.job or 'imigran', tostring(v.job_grade)
			local accounts = json.decode(v.accounts)
			local id = tonumber(string.sub(v.identifier, #Config.Prefix+1, string.find(v.identifier, ':')-1))
			local xPlayer = ESX.GetPlayerFromId(source)
			print(xPlayer.getMeta('detail','firstname'))
		end
	end
	return {characters = characters , slots = slots}
end

Hi! If you print json.encode(xPlayer.getMeta('detail')) what is get?

image still error, fyi: i have string and number value on detail meta

Why don't you use the data from sql? v.meta its there is v.job

@Rav3n95
Copy link
Member Author

Rav3n95 commented Feb 26, 2023

Also you have a modified server bud, don't be surprise.

@Gellipapa
Copy link
Member

@gerung It's works perfectly, i think you've got the problem.
image

@Rav3n95 Rav3n95 merged commit e8ac189 into esx-framework:dev Feb 26, 2023
@mrscriptsid
Copy link

@gerung It's works perfectly, i think you've got the problem. image

I got an issue when I first spawn when the player already loaded everything fine, but when first spawn xPlayer was not ready to read so I got the issue. I'm using multicharacter and I thing that is the issue

@Gellipapa
Copy link
Member

Gellipapa commented Feb 27, 2023

@gerung
I also use multicharacter, I don't understand what first spawn is. So when you see your character you already have xPlayer so you will getMeta as well as other xPlayer function. It won't before since you get xPlayer in the playerLoad event.

@Gellipapa
Copy link
Member

Gellipapa commented Feb 27, 2023

I assume you mean when you're in the "lobby" or when you're choosing a character. There will be no xPlayer there yet so yes getMeta will not work as well as xPlayer.identifier because xPlayer is nil.

If this is your problem you will have to write a database query to get the meta data. It's like a column that can be queried by just json.decode the contents of the column to get a usable LUA table that you can index later.

@Gellipapa
Copy link
Member

If you still don't have this problem, write down a sequence of reproducible steps that we can use to trigger the problem.

@CsokiHUN
Copy link
Member

For multicharacter, as long as the player is not spawned, only the character is in the selector, xPlayer has no value in my opinion

@mrscriptsid
Copy link

I assume you mean when you're in the "lobby" or when you're choosing a character. There will be no xPlayer there yet so yes getMeta will not work as well as xPlayer.identifier because xPlayer is nil.

If this is your problem you will have to write a database query to get the meta data. It's like a column that can be queried by just json.decode the contents of the column to get a usable LUA table that you can index later.

solved, thanks

@mrscriptsid
Copy link

@Rav3n95 is there any option to get meta on client side?

@Rav3n95
Copy link
Member Author

Rav3n95 commented Mar 1, 2023

If you are using Legacy it's synced into Playerdata

@mrscriptsid
Copy link

mrscriptsid commented Mar 5, 2023

i have issue when set the meta, for example i have this meta on db
{"chardata":{"dateofbirth":"2023-03-14","height":100,"injail":0,"isdead":false,"firstname":"Herman","ishandcuffed":false,"lastname":"Ringgo","ispunishment":0,"sex":"m"}}
and trying to test with this command

RegisterCommand('test', function(source)
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src)
    xPlayer.setMeta('chardata', 'ishandcuffed', true)
end, true)

but the existing meta is replaced with this {"chardata":{"ishandcuffed":true}}

hmm

@Rav3n95
Copy link
Member Author

Rav3n95 commented Mar 5, 2023

Are you using the Dev branch of esx?

@mrscriptsid
Copy link

Are you using the Dev branch of esx?

no, using the "Main" esx

@Rav3n95
Copy link
Member Author

Rav3n95 commented Mar 5, 2023

It's not even on the main yet

@mrscriptsid
Copy link

It's not even on the main yet

i just tried your metadata on main esx

@Rav3n95
Copy link
Member Author

Rav3n95 commented Mar 5, 2023

You forgot to copy something then, cuz it's already been use on a live server

@Gellipapa
Copy link
Member

es_extended_currenty_dev.zip

@ucingoyen Hi! Download this zip and drag and drop and overwrite your es_extended(but make backup save) this is include metadata system.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants