Jump to content

DiSaMe

Helpers
  • Posts

    1,447
  • Joined

  • Last visited

  • Days Won

    32

Everything posted by DiSaMe

  1. I don't know why I even have to point this out since this is something I figured out automatically in my early days of MTA scripting. But it seems necessary because I see people using Lua tables but not taking advantage of their flexibility. Very brief overview of tables as arrays Anyway, Lua tables are often used as arrays - that is, data structures that store values under consecutive integer keys starting at 1 (0 in most other languages, but that's another story), making a sequence. Various functions that operate on tables, including those in table namespace, treat them as arrays. Take this example: local fruits = {} table.insert(fruits, "apple") table.insert(fruits, "banana") table.insert(fruits, "lemon") table.insert(fruits, "orange") It creates an empty table, then uses table.insert to insert values. Because table.insert treats the table as an array and because it inserts at the end of the sequence if position argument is omitted, we end up with values "apple", "banana", "lemon" and "orange" values under keys 1, 2, 3 and 4 respectively. Using index operator [], you can retrieve the associated value from the key: -- assuming standalone Lua, using print -- replace with outputChatBox or another output function if running in MTA print(fruits[1]) -- outputs: apple print(fruits[2]) -- outputs: banana print(fruits[3]) -- outputs: lemon print(fruits[4]) -- outputs: orange Tables as sets However, table keys don't have to be integers. You can use any value except nil and nan. Strings, other tables, MTA elements. Therefore, if the order of values is irrelevant and the values are unique, instead of inserting the value under some key, you can use that value itself as the key. And set the associated value to true: local fruits = {} fruits["apple"] = true fruits["banana"] = true fruits["lemon"] = true fruits["orange"] = true Now we have a table with keys "apple", "banana", "lemon" and "orange", while the associated value true is only used to indicate the presence of key and nothing else. That effectively makes the table a set, a collection of unique values with no particular order. Usage and comparison Insertion So we have two different ways to insert values: -- array table.insert(fruits, "apple") -- set fruits["apple"] = true This alone doesn't say much. Both operations are simple and take a roughly constant amount of time to execute. However, it makes other operations very different. Removal Because arrays require you to know the key to remove the value, you have to loop through the array to find it. In contrast, with sets you can just assign nil (because nil is the value for unassigned fields): -- array function removeFromArray(array, value) for i, v in ipairs(array) do if v == value then table.remove(array, i) end end end removeFromArray(fruits, "banana") -- set fruits["banana"] = nil Arrays are very inefficient for this if there is a large number of values, because the more values there are in total, the longer the removal of a single value will take - whereas removing from the set will take more or less the same. Checking if exists Checking for presence of a value is a lot like removal, you need to know where the value is, so arrays require looping. With sets, you just retrieve the associated value. If the checked value exists, the associated value will be true, otherwise it will be nil. -- array function existsInArray(array, value) for i, v in ipairs(array) do if v == value then return true end end return false end if existsInArray(fruits, "lemon") then print("found") else print("not found") end -- set if fruits["lemon"] then print("found") else print("not found") end Arrays are again inefficient in the same way. Looping Looping is roughly the same, but as far as I know, Lua tables are optimized to be used as arrays, so I guess looping may be a little faster for arrays than sets. I have never checked this myself. -- array for key, value in ipairs(fruits) do print("found value: "..value) end -- set for value in pairs(fruits) do print("found value: "..value) end Notice that ipairs is used for the array and pairs is used for the set. pairs will work for the array as well, but the order will be unspecified. ipairs is meant to be used on arrays, it starts at index 1 and increments until no value is found. Size retrieval Lua has length operator #, which returns the array length when used on tables. But there is no built-in operator or function to retrieve the total number of fields in a table, so it takes more to get the size of a set. -- array local count = #fruits print("fruit count: "..count) -- set function getSetSize(set) local count = 0 for value in pairs(set) do count = count+1 end return count end local count = getSetSize(fruits) print("fruit count: "..count) This makes size retrieval much more efficient for arrays than sets because the more values the set has, the longer it takes to loop through them. That's speaking of sets in their simplest form though. You can have a structure like this: local fruits = { count = 0, values = {} } And modify the count every time a value is inserted or removed. Then you can retrieve the size simply by reading fruits.count, which is efficient. But then other operations have to be altered too so we're not getting into this here. Checking if empty Checking if a collection is empty means checking if its size is 0. For arrays, nothing changes, but for sets it can be done efficiently. -- array if #fruits == 0 then print("array is empty") else print("array is not empty") end -- set if next(fruits) == nil then print("set is empty") else print("set is not empty") end next is a Lua function for traversing the table. It's used by pairs too, called once for each pair. But here we call next directly. Its first returned value is one of the keys in the table, or nil if no key is found. Conclusion For some of the most common operations, sets are both more efficient and simpler to operate on than arrays. In its simplest form, it loses against array in size retrieval, but you can keep track of size separately. When you want to store unique values and their order is unimportant, using tables as sets is probably the right choice. Syntax summary: tbl = {} -- insertion tbl[value] = true -- removal tbl[value] = nil -- checking if exists if tbl[value] then end -- looping for value in pairs(tbl) do end -- checking if empty if next(tbl) == nil then end
  2. It means you pass a boolean to ipairs, which means "result" is a boolean. According to dbPoll documentation, it returns false if there's something wrong, in which case it returns two more values indicating what went wrong. So if you change this: local result = dbPoll(qh, 0) to this: local result, error_code, msg = dbPoll(qh, 0) if result == false then outputDebugString("Error code: "..error_code) outputDebugString("Error message: "..msg) end it will display a more detailed message.
  3. The variable name in that function's parameter list is "targett", but you're checking "target", so it's a different variable.
  4. My mistake, I meant if isElementSyncer(source) then But now I looked at your code more closely and realized that this checking will prevent the code inside "if boss == "Mutant" then" block from working when the attacker is not the syncer, because that code requires the attacker to be the local player. So that would require more changes. Or you can just keep using "attacker == localPlayer" instead of isElementSyncer after all.
  5. Player damages won't duplicate, right, but you probably didn't notice my first reply. If you use isElementSyncer instead of checking "attacker == localPlayer", the damage will be synced by the player who syncs the ped, and there will be no duplications whether the attacker is a player or a ped.
  6. The damage will still be triggered multiple times if multiple players see the ped damaging another ped.
  7. This has the advantage that the damage event will necessarily be triggered if the attacker sees himself hitting the ped. However, the attacker is not necessarily a player, and the server side code indicates that peds are supposed to damage each other too. Therefore, this code prevents the event from triggering in cases where a ped damages another ped. It's better to check if you are the syncer of the ped: if isElementSyncer(ped) then end This way, the ped will be damaged if the player who syncs the ped sees him getting damaged. It's also more consistent this way because that's exactly what the syncer is for: controlling what happens to the synced element.
  8. There's a simpler solution: use function getAccountsByData. If no account has the value, the returned table will be empty. So this expression will evaluate to true if the number is already taken: #getAccountsByData("bank", bank_number) != 0 Apart from being easier, using getAccountsByData has the advantage of working correctly even if new bank numbers get added from outside your script - which may or may not be relevant in your case. And if you still decide to keep track of them yourself, the problem with the script is that in_table function loops through the whole list of bank numbers whenever you check if a number is registered. That's inefficient because the more registered numbers you have, the slower it gets. Instead of using bankNumbers table as an array (where numbers are stored as values in a sequence), you should use it as a set (where numbers are stored as keys). -- adding a bank number bankNumbers[bankNum] = true -- instead of: table.insert(bankNumbers, bankNum) -- checking for a bank number: while bankNumbers[bankNum] do -- instead of: while in_table(bankNumbers, bankNum) do
  9. By "remove only the 3 big cities", do you mean remove the cities but keep the rest of the map? Then I suggest you make a list of object model IDs and positions to be removed, then loop through that list and call removeWorldModel for each entry. But building the list itself is the hard part. I don't know if MTA map editor has any functionality that helps this. If it doesn't, then there are several things you can do. You can use some GTA SA map editor to pick out the objects. You can take the IDs and positions directly from .ipl files in GTA SA data. processLineOfSight returns model and position of the world object if it hits one. You can either use it to pick out the objects manually or make a loop that goes through a large area and collects the object data. processLineOfSight won't work on objects that are not loaded so you have to make sure you are close enough to objects you're trying to pick. Another potential problem with looping over an area is that you may miss small objects, and if you shoot lines of sight more densely, it will take longer to process the whole area. But since that only needs to be done once, it's okay as long as all objects are detected. Or you can loop over the area, then go through it manually to pick the remaining objects.
  10. No, the wiki says setPedControlState was made to work for the local player as well (in addition to peds, because previously it only worked for peds). It was setControlState that only worked for players, and because setPedControlState now works for both player and peds, setControlState has been deprecated on the client side. Anyway, if that still doesn't work, I guess the ped has not been streamed in yet when the function gets called. Another thing I just realized that needs to be taken into account is that when you hold the fire control, you only shoot missiles once. Not repeatedly. In order to keep shooting repeatedly, you need to press it repeatedly. The same holds true for peds, you need to keep switching the control state between true and false. A timer can do this: local hunter = createVehicle(425,x,y,z) local ped = createPed(0,x,y,z) warpPedIntoVehicle(ped, hunter) local function toggleFireControl() local old_state = getPedControlState(ped, "vehicle_fire") setPedControlState(ped, "vehicle_fire", not old_state) end setTimer(toggleFireControl, 100, 0)
  11. setPedAnalogControlState takes a third argument, which is a number between 0 (no effect) to 1 (full effect). For the control to take full effect, it should be like this: setPedAnalogControlState(ped, "vehicle_fire", 1) But I don't know if it's even valid to use analog control state for vehicle_fire, because you can either be shooting or not, there's no "in-between". For this reason, maybe it makes more sense to use setPedControlState: setPedControlState(ped, "vehicle_fire", true)
  12. Aš kažkada scriptus dariau, ir dar pats savo serverį su savo gamemode sukūręs buvau. Bet laiko nebuvo, tai viską nutraukiau, o po to iš viso nustojau MTA forume lankytis ir apskritai su MTA kažką daryti. Dabar keli metai praėjo. Pasiilgau MTA, sugrįžau čia į forumą. Nekoks jausmas, kad taip ilgai nesilankiau. Nežinau, ar ką nors vėl scriptinsiu, tik norisi prie MTA būti. Bet šitam subforume, žiūriu, tikrai veiksmo beveik nėra.
  13. Hey folks So, I joined this community back in 2008, when MTA SA DM DP1 was released. It was great. I played in servers. I scripted stuff. The scripting part is especially important here, because I was amazed to see what possibilities to customize the game MTA SA gives to the scripters, and that's what got me involved so much. It was by scripting on MTA that I got lots of coding experience. I had such a great time that 2008 was one of the most memorable years for me, because I can still remember the good moments, including my first time playing the non-race version (I played MTA SA Race in 2007, but only a little bit, and didn't think much of it) and my first attempts to script. As time went by, I set goals for myself. I thought of making my own server with my own gamemode. I didn't just want it for my own gains, I wanted it for the good of MTA, too! I wanted to make use of MTA scripting possibilities, to let the greatness of MTA be known! However, as I still wasn't that good at scripting nor at setting goals (they were huge), I wasn't exactly being productive. I experimented a lot and learned a lot, but apart from that, it didn't really go anywhere. After a few years of playing around, I realized my goals weren't going to come true. I decided I just wanted to be useful to MTA community. That's when I made and released a few scripts, including Drawtag, Gravity gun and NPC traffic. Later I made my own server after all, with a gamemode very different from what I had originally planned. But I was too busy with crap in my life to continue working on it, so I had to end it. I didn't want to abandon MTA. All those dreams that never came true. But I didn't see any other way. I stopped playing and scripting on MTA. Eventually I drifted away and stopped visiting this forum altogether. During the time I was away, I was just living life, but not really feeling like I was enjoying it. There were ups and downs. You know, everyone goes through different phases of life. But now I feel bad about it. It wasn't necessarily my fault that I left, but it was my fault that I didn't come back for so long. Now that I finally did, it seems there have been people who were looking for me, but I don't even know if it's of any use to reply to messages I received 3 to 5 years ago. I'm regularly on YouTube though, but even there, often I didn't feel like replying to comments right away and forgot about them later. I'm feeling like a busta who ran away and left his homies when there was no reason to. I'm feeling like I have betrayed MTA because it gave me so much, but I didn't manage to benefit it as much as I thought it deserved. Things have surely changed around here while I was gone. I see there are admins and moderators who weren't even on this forum when I left. And honestly, I don't remember many people in particular. I don't remember well who was and who wasn't here back in those days. I don't know if anyone here misses me. I'm so out of touch. Kinda sucks, doesn't it? After wandering for years, I'm finally back home, but I'm not even sure if it's still the same home that I've been missing because I don't even know if people here are still the same people that I left. But I see some usernames that look familiar and I can take comfort in that. MTA seems to be doing much better than before. I didn't expect it to become so popular! I'm supposed to be happy about this, because it was my dream to see MTA achieve the popularity that it deserves. But it feels like yet another thing I missed out on. I wasn't a part of MTA community during the time that it grew so much. What a shame. Unfortunately, I don't have plans to resume MTA scripting, not big ones at least. It's a pity, seeing how MTA now has scripting features that I used to dream of. But I just don't think I currently can focus on it. Still, it feels tempting to try. I'm curious, how much have peds been improved? In the old days, I would run into problems because the peds would lose information about health, ammo and many other things, when they got streamed out, so I couldn't have them properly synced and had to resort to workarounds. What about model/texture replacing? I see there are some new related functions, so this functionality must have been improved, right? I remember trying to import Liberty City and Vice City back in 2010, and I managed to convert Liberty City, but I couldn't load it all at once, because 512 MB of RAM was not enough to replace that many models at the same time. And replacing the models dynamically (based on distance to the player) wasn't working well, there were bugs and some models weren't actually getting replaced. My scripts website is no longer there. I still have the files, but I see someone made a GitHub repository and uploaded the resources there, so I guess it's okay as it is. The resources are available to everyone and I'm thankful for that. If I ever decided to make scripts for the community to use, I would start from scratch rather than continue working on the old ones. The same can be said about the server I had, I have the gamemode and the database, but if I wanted to run a server again, I would start the gamemode all over. While the future of my involvement in MTA scripting is uncertain, I'm seeking to be active on this forum once again. I want to be in touch with MTA and the community. Maybe I should try helping people in scripting section or something like that. Perhaps make some tutorial. I'm much better at programming than I used to be. I'm working on my own game engine, but I don't want to make it sound like I'm doing something big or anything like that. This is another thing that I took my time to play around with. I started it long ago, I learned a lot, but I have little results. Either way, it was MTA that inspired me to do it. And I have an idea to make a common scripting interface for MTA and my engine so that scripts made using this interface would work on both. Not stating that's what's going to happen, I'm just thinking of ways to make scripts for MTA even when I have to focus on something else. With things I learned in the recent years, some MTA script ideas that I once considered difficult to implement, look much easier now. Hell, even if I made the mistake of leaving MTA for so long, these years were still far from wasted. That's pretty much all I wanted to say for now. I left for several years, now I feel bad about it, "but now I'm back, and I know what I've been missing". Not sure how much I'm going to be involved in MTA scripting, if at all, but I just want to be a part of this community again.
  14. MTA 1.5 and greater versions seem to have problem with launching under Wine. I need to test if that's true someday. https://wiki.multitheftauto.com/wiki/Cl ... nux_Manual The last time I tested, I had problems running it on 64-bit wine prefix, but it worked on 32-bit.
  15. I have done this on Linux by running two instances of Wine and an instance of MTA in each of them. Not sure if there's any solution other than virtual machines on Windows.
  16. You can change the ped's position on the client without changing it on the server. But you can't do the opposite. You can't change the server-side position (which determines who's the syncer, and some other stuff) without making this change visible for all players.
  17. Scripting-wise peds are almost as good as they need to be. Most problems are related to sync and/or element streaming, not scripting. To make the peds function properly, we need the changes which I could classify into 3 parts: 1. Sync more of the peds' properties and make them retainable between streamout and streamin on the client. Lots of times people have wondered why the ped only shoots 1 bullet, or why the ped doesn't play the animation. That's because some of the important properties are synced improperly or are not retained on the client. Those include weapon ammo, health and stats. If the server sets the property when the ped is streamed in for the client, it seems fine. Then you go away and come back, it's not the way it was. Or you join the server after it was set, you don't see it. This problem can be worked around by creating a timer which keeps setting the property every few seconds or so, but it consumes CPU and bandwidth, therefore, it's the most important issue about ped sync to fix. 2. Ability to set the element properties in server without syncing them with the clients. For example, if you set the element's position, it will be sent to all clients, so that all of them would see it in the new position. But what if the element is far away from the client? The position will still be updated, even if it's not necessary since the client might not need to see what's happening miles away. Take my traffic resource, for example. Since the peds which have no streamer are not affected by physics and I still need them to move, I simulate this movement by setting their positions on the server every two seconds or so. If the players are spread all around the map, there are peds all around the map as well, and they are all updated for all players all the time, which is very bandwidth-inefficient. Every player only needs to be aware of correct positions of a small fraction of peds. So if we could set the element's position (and other properties) on the server without syncing it with the clients (or only syncing it for particular clients), we could move the peds without syncers without using up lots of bandwidth. 3. Peds entering/exiting vehicles. This one is the least important, since as AlexTMjugador has said, it can be achieved by scripting. Actually, I was once going to make it (but didn't). It's still preferable to have a built-in one, because making use of existing gameplay mechanics is better than creating the new one. But it's not as important as the other two issues. With these issues taken care of, MTA would give us pretty much of what we need to have properly functioning peds.
  18. Excuse me, but you're kind of putting words in my mouth, because that's not what I've said. Actually, Lua is my favorite language. I'm making a game engine in C and it's scriptable in Lua. That's because it's inspired by MTA. OOP is one of the aspects where I can see the beauty of Lua's simplicity. Instead of providing us with a built-in class system, it allows us to control the behavior of individual tables, which enables us to make classes ourselves. Not sure where C fits into this OOP thing, since it doesn't have any syntax for OOP at all. I do write OOP in C using opaque pointers and functions that receive those pointers as arguments. That's what I pretty much got used to doing in C, but that's not as convenient as OOP in Lua. Lua does allow you to make variables only accessible via particular objects. Consider this example: function Person(name) local self = {} local person_name = name function self.getName() return person_name end return self end Calling 'Person' function will create and return a table (an 'object'), and the value passed as the first argument can only be read by calling getName field of this table, and it cannot be accessed from outside the 'Person' function. C/C++ easier, really? Easier how? I mean... Strong typing, pointers, all that stuff... How is that easier than Lua? Speaking of performance, one of the reasons C/C++ are so fast is because there are many things that have undefined behavior. Which allows the optimizer to pretend that those situations will not occur, making more assumptions about execution of code during the compilation. Undefined behavior would totally kill security in MTA, because the servers can execute code on clients' computers. To avoid this problem, all behavior needs to be defined, and such implementation of C/C++ wouldn't be that fast. Though it would probably still be faster than Lua can be made, because Lua is more dynamic, the point is, what makes C/C++ fast, the same thing makes the language unsuitable for software that lets the servers execute code on clients' computers.
  19. I've heard that having 65536 slots (back when the player limit was that high) caused the RAM usage to go up by 512 MB, even though those slots were empty. So if it still works the same way, 4096 slots would take 32 MB.
  20. DiSaMe

    Coroutines

    Seriously, what does that even mean, "coroutines are useless"? Coroutines are the way to separate the procedure that's performed in steps (rather than all at once) from the rest of the program. If they are useless, aren't functions useless as well?
  21. Calling dbPoll with -1 timeout parameter will wait for response. That's how it will return the result to the calling function. If you instead want to suspend the execution of function and resume it when result is available (without forcing the whole server to wait), use coroutines (http://www.lua.org/manual/5.1/manual.html#2.11).
  22. If you rotate an object 180 degrees around X axis and then 180 degrees around Z axis, you get the same result which you do by rotating the object 180 degrees around Y axis. Whether it's in degrees or radians, it's still the same.
  23. object:method(arg1, arg2, ...) Is the same as object.method(object, arg1, arg2, ...) Therefore player:setMuted(muted) Is the same as setPlayerMuted(player, muted)
  24. Of course you can't cancel the damage that has already been done. You can't prevent the event from having occurred because you can't change the past. This is the case with server-side damage events, they are triggered after the ped/player was damaged.
  25. Or, when the player is still aiming, but in another direction, they will stop aiming at the objet too...
×
×
  • Create New...