Jump to content

Some questions


MaddDogg

Recommended Posts

Hi!

I just switched from SA:MP to MTA, because SA:MP p*ssed me off more and more, and so I just started learning LUA from yesterday on.

Luckily, I can connect several behaviours and syntaxes from LUA with Pascal and ActionScript, in which I'm quite experienced.

But still I got some (noob) questions, for which I couldn't figure out an answer yet.

It would be very nice, if you could help me with the following:

How to call a function from a lua script inside the same resource? For example a function in the clientside script, which I need to call by the serverside script.

I already tried with something like this..

call(getResourceFromName("test"), "setSomeVar", var, "string")

..but it didn't work. Also just calling the function like it would be inside the same script didn't work. Or do I always have to use event triggering?

And yes, I added an export node to the meta.xml to export my function.

Also, how call an outside function then, which returns values?

Is there a resource or something like that that provides a graphical interface for the inbuilt SQL server? Or is there a way to use an external server, so that I could use phpMyAdmin?

It's not that I'm too unskilled in MySQL, but it would spare me the scripting of an ingame GUI for it.

You don't have to, if you think this question is too nooby, but can you explain to me the meaning of 'in ipairs' and 'in pairs' as used in for loops?

What is the LUA equivalent of "new const IM_A_CONST[] = {100, 200, 300};"?

Thanks, if you could help me with all this, I would really appreciate it.

And respect to the MTA team, I'm just amazed by the mass of manipulable things ingame =D>

Link to comment

Aww.. this topic touches my heart. :')

For the export issue, you will have access to another, neater form.

Suppose you have declared and exported this function in a resource:

function asd(foo, bar)
 
end

Assuming you've exported it correctly (and restarted the resource in which it's declared) you can call it from any other resource with

exports.myResource:asd( "value of foo here" , "this would be the value of bar" )

The database file is called server/mods/deathmatch/registry.db and is standard SQLite. You can open it with any SQLite editor, for example this.

As for your third question, it's pretty simple. I don't know of any Lua equivalent for "const", so.. just don't change the variable. :mrgreen:

IM_A_CONST = {100, 200, 300}

If you haven't seen it already, I think you might find my scripting introduction helpful.

http://robhol.net/guide/basics

Edit: oh, I misunderstood. For intra-resource function calls, it really couldn't be simpler. Make sure your functions are not local, and you will be able to trigger them as if they were declared in the same file. Just call the function normally, you don't need call(), exports or events for that. If you need server-client communications, you must use events, though.

Link to comment
You don't have to, if you think this question is too nooby, but can you explain to me the meaning of 'in ipairs' and 'in pairs' as used in for loops?

This page at the Lua wiki should be a good source to learn about tables and arrays and of course it will also answer your questions ;)

What is the LUA equivalent of "new const IM_A_CONST[] = {100, 200, 300};"?

Tbh i can't think of a situation where you would need a constant in Lua. Just create a variable that holds an array like this:

simple_array = {100, 200, 300}

Making a variable constant is pretty complicated though and would probably just work with table/array type vars.

Is there a resource or something like that that provides a graphical interface for the inbuilt SQL server? Or is there a way to use an external server, so that I could use phpMyAdmin?

It's not that I'm too unskilled in MySQL, but it would spare me the scripting of an ingame GUI for it.

https://community.multitheftauto.com/index.php?p= ... ils&id=495

Thats probably what you're looking for but you can also just open up the registry.db file which is located in server\mods\deathmatch with any SQLite browser.

Also note the the inbuilt sql server is using SQlite but you can also get a well working MySQL module (mta equivalent to plugins) at our wiki.

Link to comment

You both misunderstood his question about call.

Yes, generally, between server and client lua files in the same resource you use events, and you will need a secondary event to get a returned value. As a side note however, if you don't actually need a return value and just want to trigger a function on the "other side", look at these 2 code examples:

https://wiki.multitheftauto.com/wiki/CallClientFunction

https://wiki.multitheftauto.com/wiki/CallServerFunction

Lua doesn't support constants by design, but usually, you don't need to protect a variable from changes either, so a variable will suffice. If you do need to protect a variable from changes, an example is here:

http://blog.stranadurakov.com/2009/05/05/lua-constants/

(note that is just standard Lua, not MTA related. Also it deals with metatables, which you shouldn't attempt while you are unfamiliar with standard tables.)

The difference between pairs and ipairs is usually just a matter of processing cost in the majority of cases. When you assign values to a table, if you don't provide a key, Lua assigns an integer key, starting at 1 and incrementing for every new value added. ipairs iterates over the table in order, starting at key 1, and stopping when it finds a nil key. (even if there are higher-numbered keys later on) Whereas pairs iterates the whole table, regardless of what keys are there, in whatever order it finds them (which may or may not be numeric/alphabetical/order they were added in)

So if the order you iterate the table matters and you used integer keys, use ipairs, otherwise, pairs will suffice and costs less processing time.

Link to comment

First of all thanks for the answers :)

It really cleared up some things for me.

So, when I want to call a custom function, which lies in a second serverside script of the resource, I just call it normally by for example..

local value = getSomePlayerValue(player)

But if this function is in a clientside script and I want to call it out of the serverside script, I have to use events?

But how do I get the value that is returned? Because of course I can't fetch this from triggerClientEvent.

And another question:

I have an account system and fetch the account data of an user by a query.

What would be the best way to store the data? I want to store the data in a big table called pData, but how do I do that exactly?

The players don't have fixed server slot IDs, so I can't just put them into pData[5] for player in slot 5.

And I also want to clear the data again, when the player leaves.

Thank you guys for your help!

Link to comment

Correct for your first question - when both files are serverside or both are clientside in the same resource, you just call your function just like any other (as long as you didn't declare the function local that is)

For a returned variable, you'll need to triggerServerEvent with another event for the reply.

MTA uses elements rather than ID's, so you would assign your table as

function myFunction(thePlayer, value)
if pData == nil then pData = {} end
   pData[thePlayer] = value
end
 
--example
myFunction(getPlayerFromName("Bob"), "someString")

and to clear:

function cleanUp()
   pData[source] = nil     --look up hidden variables in the events wiki page
end
addEventHandler(onPlayerQuit, getRootElement(), cleanUp)

Note that the value can be anything - string, number, even another table.

Link to comment

Welcome!

You can't directly call client or server functions from the other side - this is mainly for security reasons - you should use events. You can't get return values because the function may take a substantial amount of time to return, and if you waited it'd pause all the other scripts on the server/client while that happened. Events are pretty easy to use though.

I'd advise against using the callServerFunction/callClientFunction functions on the wiki at least until you've got a good understanding of scripting. They may seem like they make your life easier, but they won't help you learn how MTA scripts should really be written, and they potentially open your script up to hackers.

I'd also suggest that using the built-in SQLite server is better than using the MySQL module, it should be able to cope with anything except the most extreme amounts of data, and should be easier to get to grips with.

Link to comment

Thanks for the answers!

So, would the following be correct?

addEventHandler("onCorrectLoginData", getRootElement(), 
function (player, loginname)
  pData[player] = executeSQLQuery("SELECT level, money, points FROM playerdata WHERE name = '" .. loginname .. "'")
outputChatBox("You're now logged in!", player)
end
)

The result should be a table which can be used like this:

...
if pData[player]["level"] > 1 then
outputChatBox("You are an admin!", player)
end
...

Thank you again!

Link to comment

Close.

Returns

Returns a table with the result of the query if it was a SELECT query, or false if otherwise. In case of a SELECT query the result table may be empty (if there are no result rows). The table is of the form:

{
{ colname1=value1, colname2=value2, ... },
{ colname1=value3, colname2=value4, ... },
   ...
}

So your returned table would look like:

pData[player][1]["level"] == 1  --for the first returned row of values
pData[player][2]["level"] == 1  --if the query finds a second matching row
...

Link to comment

Okay, so the following is then giving me my wanted result?:

pData = { "name" = {}, "password" = {}, "level" = {}, "points" = {} }
pDataValueTypes = {"name", "password", "level", "points"}
 
 
function getAccountValues(player, loginname)
local tmpvalues = executeSQLQuery("SELECT name, password, level, points FROM playerdata WHERE name = '" .. loginname .. "'")
 
for i=1, types in ipairs(pDataValueTypes) do
	pData[player][types] = tmpvalues[1][types]
end
 
outputChatBox("#FF0000Data successfully read!", player, 0, 0, 0, true)
end

Everything correct here? The table correctly initialized?

Is there perhaps an example or published account system, at which I can take a look to see how it's done there? Or any tutorial?

Link to comment

Alright, thanks for the help! :)

I now did it with the MySQL module, because later on I want to be able to modify the data through a web browser UCP.

Here's my example code, if it helps anyone to create his account system:

pData = {}
pDataValueTypes = {"name", "password", "level", "points"}
 
 
function CheckMySQLConnection()
if mysqlCon == nil or mysql_ping(mysqlCon) == false then
outputServerLog("Establishing MYSQL connection..")
	mysqlCon = mysql_connect("localhost", "CHANGEME", "CHANGEME", "CHANGEME", 3306, "/var/run/mysqld/mysqld.sock")
 
if mysqlCon == nil then
outputServerLog("ERROR: Couldn't connect to database!")
return false
end
end
 
return true
end
 
 
function getAccountValues(player, cmd, loginname, password)
if CheckMySQLConnection() == false then
return outputChatBox("#FF0000Wasn't able to connect to database!", player, 0, 0, 0, true)
end
 
if pData[player] ~= nil then -- if player table already exists --> player is already logged in
return outputChatBox("#FF0000You're already logged in!", player, 0, 0, 0, true)
end
 
if loginname == nil or password == nil then -- if parameters are not given
return outputChatBox("#55FF55Use this syntax: /testlogin [NAME] [PASSWORD]", player, 0, 0, 0, true)
end
 
tmpResult = mysql_query(mysqlCon, "SELECT name, password, level, points FROM pdata WHERE name = '" .. loginname .."'") -- getting account data
 
if(mysql_num_rows(tmpResult) == 0) then -- if name is not existent
return outputChatBox("#FF0000This name is not registered!", player, 0, 0, 0, true)
end
 
-- fetching the data
local tmpValues = mysql_fetch_assoc(tmpResult)
mysql_free_result(tmpResult)
 
if password ~= tmpValues["password"] then -- if given password is not matching saved one
return outputChatBox("#FF0000The password is not correct!", player, 0, 0, 0, true)
end
 
pData[player] = {} -- initialize player table
 
-- fill player table with fetched data
for i,types in pairs(pDataValueTypes) do
	pData[player][types] = tmpValues[types]
end
 
outputChatBox("#FF0000You were successfully logged in! Your points: #00FFFF" .. pData[player]["points"], player, 0, 0, 0, true) -- success message
end
 
addCommandHandler("testlogin", getAccountValues, false, false)

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...