Jump to content

Mr_Moose

Members
  • Posts

    866
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by Mr_Moose

  1. Seller protection is always a good thing to check. If you don't have that, Paypal could charge you $20 if you lose a chargeback case. "item not received" is indeed a strange claim for donations but it might also be just a stupid way to request a refund. If you use an IPN callback script you could also validate some of the information Paypal send back to you such as the country code. A mismatching country code (compared to the client IP) could be a sign of unauthorized access (stolen CC/PP).

    Paypal is a good payment processor for customers/donators but terrible for merchants and service providers. As a final controversial solution, I'd suggest you throw away Paypal (or hide it deeply somewhere) then add Coinbase or Cryptonator instead. With cryptocurrencies, you're in charge of your own money which is brilliant for merchants. 

  2. Shared plans may return sooner than expected. I can't reveal to much information about when or how it will work but it will be different from traditional shared solutions. High security and privacy will be the main goal so expect a solution without accounts and passwords that can be forgotten or hacked. Thanks to simplicity and the usage of our own cloud infrastructure, prices will start from as little as $0.5/month. 

    • Like 1
  3. This was originally created 5 years ago, back then it was literally impossible to get or set which track the train should spawn in other than actually spawn at a hardcoded position and then check if it's on the right track. First version used 200 hardcoded locations. 4.5 years ago I've released the full code of this as open source and today it's fully dynamic. It still doesn't check which track to spawn on but it does check when it'll reach the end of a track and stop the train before it goes off track. v-40 has been even further improved and optimized for perfection including the sync issues regarding trailers in MTA.

  4. About the project

    GTW-RPG is one of the oldest open source RPG game modes for MTA, initially launched in year 2012 and currently at version 3.0. Right now we're building v4.0 which provides a lot of new features, including a project wide system for language translations. Now this job is easy script wise but requires a high amount of time to make sure everything is correct which is why we've decided to spend 0.1 BTC (~$115) to finally fix the translations. 

    About the job

    The job includes, not only the actual translations but most important the conversation from the current system in where all text is hard coded into the files to a table with a strict structure holding ID's and corresponding text in multiple languages (organized by language) which is then dynamically collected from the files itself. GTW-RPG has 45 resources in the affected folder and on average 40 static strings in each resource that needs to be converted. Due to the open source nature of the project we'll pay per resource (even at string level) so that multiple users can contribute and still get their fair share of the money listed above.

    How to participate

    Simply fork the GTW-RPG v4.0 development branch, implement the new language system (or add translations to already existing implementations) then do a push to the project, if approved (yes there are some conditions, see below for more details) we'll ask for a BTC address via Github to where we can send your payment within 48 hours.

    How o implement the new language system:

    This is a detailed description of the job, step by step:

    • Add the file lang.lua to the resource if it's not there, it should have the same structure as this example: 
    Spoiler
    
    --[[
    ********************************************************************************
    	Project owner:		RageQuit community
    	Project name: 		GTW-RPG
    	Developers:   		<YOUR_NAME_HERE>
    
    	Source code:		https://github.com/GTWCode/GTW-RPG
    	Bugtracker: 		https://discuss.404rq.com/t/issues
    	Suggestions:		https://discuss.404rq.com/t/suggestions
    	Donations:			1HNoLvQJxkH7YtRcUynwUeqfBJp3uSLXMf
    
    	Version:    		Open source
    	License:    		BSD 2-Clause
    	Status:     		Stable release
    ********************************************************************************
    ]]--
    
    -- Definition of default language for this resource
    r_lang = exports.GTWcore:getLanguage() or "en_US"
    
    -- Language text storage for this resource
    lang_txt = {
    	-- English/English
    	["en_US"] = {
    		["msg_rental_shop"] 	= "This is a rental shop from where you can get a car",
    		["msg_fuel"] 		= "All vehicles need fuel, you can buy fuel at any gas station",
    		["msg_skin_shop"] 	= "This is a skin shop, walk inside to buy a new skin",
    		["msg_gym"] 		= "Visit the gym to improve your stamina or muscles",
    		["msg_health"] 		= "You can regain your health by eating, literally anything",
    		["msg_gang"] 		= "Create/join a gang by pressing F6 to open your gang/goup/clan panel",
    		["msg_gang2"] 		= "When you're in a gang you can capture turfs to gain money and respect",
    		["msg_work"] 		= "This is a work place, you can get a job here to make money",
    		["msg_initialize"]	= "Initializing...",
    	},
    
    	-- Swedish/Svenska
    	["sv_SE"] = {
    		["msg_rental_shop"] 	= "Här kan du hyra en bil för en fast timkostnad",
    		["msg_fuel"] 		= "Alla fordon behöver bränsle, här kan du tanka bilen",
    		["msg_skin_shop"] 	= "Detta är en skinshop, här kan du ändra utseende",
    		["msg_gym"] 		= "Besök gymmet om du vill bygga muskler eller förbättra konditionen",
    		["msg_health"] 		= "Du kan höja din hälsa genom att äta",
    		["msg_gang"] 		= "Klicka på F6 för att öppna panelen där du kan skapa grupper och gäng",
    		["msg_gang2"] 		= "Ta över och kontrollera områden för att tjäna pengar som gängmedlem",
    		["msg_work"] 		= "Detta är ett arbete, här kan du söka jobb och tjäna pengar på hederligt vis",
    		["msg_initialize"]	= "Initialiserar intro...",
    	},
    }

     

    • Add an entry for lang.lua in meta.xml right below the info line, like this:
        <info author="GTWGames" version="98" name="GTWaccounts" decription="Account system with GTW GUI" type="script" />
        
        <!-- Language support: must be located at the top -->
        <script src="lang.lua" type="shared" />
    • Localize all static string outputs in each file of the resource you're dealing with, GUI elements(), outputChatBox(), exports.GTWtopbar:dm() etc and replace them with this line:
    lang_txt[getElementData(source, "GTWcore.language") or r_lang]["msg_CHANGE_THIS_TO_IDENTIFIER"]

    * GTWcore.language holds a language value like: en_US in standard ISO format, this is used to identify the language in the file lang.lua. r_lang holds the default server language set in GTWcore and last but not least, the value msg_CHANGE_THIS_TO_IDENTIFIER must be an identifier for the string to load at the specific position in the code, change this to a non conflicting relevant value and make sure it's the same for all languages, i.e:

    -- Language text storage for this resource
    lang_txt = {
        -- English/Simplified English
        ["en_US"] = {
    		["msg_welcome"] 	= "This is a welcome message in English",
        },
    
        -- English/English
        ["en_UK"] = {
    		["msg_welcome"] 	= "This is a welcome message in Brittish English",
        },
    }
    • Test with /debugscript 3 and look for error in server log. Any syntax errors or issues with the structure will lead to a rejection of your pull request. Please note that we do accept not fully accurate translations, minor spelling errors etc but issues with the code structure or introduced errors is strictly forbidden.

    The job is available from this exact moment and forth as long there is money left, I'll keep this topic updated after each approved contribution. Payouts are made with Bitcoins only and will be listed here for maximum transparency and lowest possible fees.

    Requirements

    • Your work will be open source and a part of the GTW-RPG project on Github
    • Your push must be to the v4.0-development branch
    • The code structure must be strictly according to specification, tested and working, see GTWantispam for an example of a finished conversation
    • The job must be 100% finished for a resource in order for a push to be approved, and for you to be paid
    • A finished conversation of a resource with static strings must contain all current English translations
    • You should have decent knowledge in Lua and Github and have a working BTC wallet
    • The commit message should be: misc: language update for NAME_OF_RESOURCE
    • The commit must not contain anything outside of specification

    If you're interested, start a topic in the issues page: https://github.com/404rq/GTW-RPG/issues and let me know which resources you plan to work on so that we don't get any duplicates.

  5. It's probably best to ask the devs how objects actually are loaded internally, but I'm guessing it's all based on the already existing systems in GTA sa. No matter if you're using custom objects or built in objects the loading time should be equal. So to figure out why .lua maps would be slower than .map maps (which does seems to be the case when loading maps with over 1000 objects or so). I've had a deeper look on the code itself to see what's differ. This line here:

    <object id="object (a51_jetdoor) (1)" breakable="true" interior="0" collisions="true" alpha="255" model="3095" doublesided="true" scale="1" dimension="0" posX="2522.3999" posY="-1273.19995" posZ="32.9" rotX="0" rotY="270" rotZ="359.75"></object>

    Corresponds to this line in Lua code:

    {3095,2522.3999,-1273.19995,32.9,0,270,359.75,1,0,0,255,true,true,true}

    Note that the first line in the Lua code is the model number and not the ID from the map file saying "object (a51_jetdoor) (1)". Now that wouldn't be there if it wasn't used for something right? It's possible that MTA when loading a .map file into memory process the data within by sorting, hashing or indexing in a way that makes it faster to find and load a specific object during stream in. While in the converted Lua code you need to loop through the whole table in order to find the specific object you want to load. Obviously that will have a negative impact on the CPU.

    Luckily since we're dealing with Lua it wouldn't be that hard to process the data differently, like only loading the 1000 objects that is close to a player instead of say 50´000 objects at once, a timer could also be used to load blocks of objects with a few seconds delay between each block. In any case there need to be an index so I'll guess I'll add a few different versions, one with index from 1 to N and one with a hash sum of the ID as index so that all of you with big maps can test the difference in performance, it might even be possible to make the .lua maps load faster than .map maps.

    Quote
    • Lua map converted with OP's website, without blips attribute (I also highly suggest removing the said feature as it may cause significant changes in performance & loading times) & ran client side

    The plan is to make all additional features optional and select able, for now I've disabled that line.

  6. Any ideas why .lua maps would be more laggy than regular .map maps? I think that depends on which properties are included in the conversation. This tool tries to detect as many properties as possible unlike the other converters. Thanks to xeon17 I found some more properties that I don't have in my own maps which I initially tested with such as LOD objects, collisions, and radius. Anyway, if the conversation is 100% accurate and the same mechanism is used to render the maps no matter if the source is .lua or .map it shouldn't be any difference. 

    If .lua maps does get more laggy than .map maps then I might as well create a map minimize tools which compress and removes default values. :)

    • Like 3
  7. The file db.sql contains all database tables and structures required. Currently these won't be created automatically when using MySQL so you'll have to import that file into your database. What management software are you using? PhpMyAdmin, MySQL workbench, command line or anything else. Methods to setup a database properly varies between these.

  8. Thanks to lower operational costs we are now lowering our prices, especially on our big plans. Here's some examples:

    Compute VPS (squirrel)

    • 25 GB SSD, M.2 storage
    • 1 vCore at @2.4GHz (Intel)
    • 1,024 MB RAM
    • Backup & live snapshots (from $0.002/hour)
    • Dedicated low latency DDoS protection (from $0.015/hour)

    For reasonable $0.009 per hour

    Compute VPS (hedgehog)

    • 40 GB SSD, M.2 storage
    • 1 vCore at @2.4GHz (Intel)
    • 2,048 MB RAM
    • Backup & live snapshots (from $0.0034/hour)
    • Dedicated low latency DDoS protection (from $0.015/hour)

    For reasonable $0.017 per hour (save $0.001 per hour compared to squirrel)

    Compute VPS (rabbit)

    • 60 GB SSD, M.2 storage
    • 2 vCore at @2.4GHz (Intel)
    • 4,096 MB RAM
    • Backup & live snapshots (from $0.0064/hour)
    • Dedicated low latency DDoS protection (from $0.015/hour)

    For reasonable $0.032 per hour (save $0.004 per hour compared to squirrel)

    Compute VPS (beaver)

    • 100 GB SSD, M.2 storage
    • 4 vCore at @2.4GHz (Intel)
    • 8,192 MB RAM
    • Backup & live snapshots (from $0.0124/hour)
    • Dedicated low latency DDoS protection (from $0.015/hour)

    For reasonable $0.062 per hour (save $0.010 per hour compared to squirrel)

    www.99stack.com

    • Like 2
    • Thanks 1
  9. That's strange, I was somehow convinced that all those calculations was the reason for the FPS drops. Have you considered using icon shaders on default blips instead? from what I can see this is some kind resource for managing custom blips, and those are usually pretty resource hungry no matter how you implement them. 

  10. Processing blips all over the map is a heavy task, maybe you could process blips within a distance of 180 distance units only (same size as the radar area). Try replacing line 4-5:

    if (localPlayer ~= getElementAttachedTo(blip) and getElementInterior(localPlayer) == getElementInterior(blip) and getElementDimension(localPlayer) == getElementDimension(blip)) then
            local blipDistance = getDistanceBetweenPoints2D(blipX, blipY, playerX, playerY)

    with this:

    local blipDistance = getDistanceBetweenPoints2D(blipX, blipY, playerX, playerY)
    if blipDistance < 180 and (localPlayer ~= getElementAttachedTo(blip) and getElementInterior(localPlayer) == getElementInterior(blip) and getElementDimension(localPlayer) == getElementDimension(blip)) then
            

     

  11. Well there's a few things you can do to optimize but I can't guarantee that it would make any big difference, but it's still worth a try tho. First of all, in this case you can replace ipairs with pairs which is slightly faster. As long as you don't need to process your blips in a certain order that change should be safe. 

    for _, blip in pairs(getElementsByType('blip', resourceRoot, true)) do

    The function getElementsByType can also be instructed to look into this resource only (or further down the element tree), in case that you have blips in other resources that shouldn't be processed by this loop. Last but not least since this appears to handle the mini map, you may want to look for streamed in blips only as well (all blips within a 180m radius from a player).  

  12. The only reason for choosing 10ms is that you'll get 1 update per frame on a server running at 100FPS. In reality however default FPS rate for a server is 36 (27.77..ms sync interval) and most displays today runs at 60FPS (16.66..ms sync interval). My test server runs at 60FPS so in my case I wouldn't have noticed any difference if I've used say 20ms, other than support for more players and objects before noticing any lag. I did try this with Crystals bot resource however and 50-75 bots works just fine with a 10ms sync interval, first after spawning more than 75 bots and vehicles I did notice some lag. 

    Without testing I think a 100ms sync interval should be sufficient as well. Luckily it's easy to change these values while testing what works best for individual servers.

    • Like 1
  13.  

    This is a complex problem but you can make it work almost perfect in most cases. Changing unoccupied_vehicle_sync_interval like 3aGl3 suggested (and the other sync intervals too) is a good start. I'm using 10ms on all of them except lightweight sync where 100ms is used:

    <!-- Player sync interval. Default: 100 -->
    <player_sync_interval>10</player_sync_interval>
    <!-- Lightweight (player) sync interval. Used when players are far apart. Default: 1500 -->
    <lightweight_sync_interval>100</lightweight_sync_interval>
    <!-- Camera sync interval. Default: 500 -->
    <camera_sync_interval>10</camera_sync_interval>
    <!-- Ped sync interval. Default: 400 -->
    <ped_sync_interval>10</ped_sync_interval>
    <!-- Unoccupied_vehicle sync interval. Default: 400 -->
    <unoccupied_vehicle_sync_interval>10</unoccupied_vehicle_sync_interval>
    <!-- Keysync mouse rotation sync interval. For limiting key sync packets due to mouse movement. Default: 100 -->
    <keysync_mouse_sync_interval>10</keysync_mouse_sync_interval>
    <!-- Keysync analog movement sync interval. For limiting key sync packets due to joystick movement. Default: 100 -->
    <keysync_analog_sync_interval>10</keysync_analog_sync_interval>

    This high sync intervals are barely noticeable on the server's CPU usage (Debian 8.7, mtasa-1.5.3), same applies for the network speed (Avg: 30 kBit/s) with 2 players online. Now this isn't everything you need, you would also need something that detects and update differences in positioning. Here's one potential solution, first the server side code which will obtain the current coordinates of a first (and a second trailer attached to an invisible Tanker semi truck attached to the first trailer). Coordinates server side will match the element syncer which should be the player who is driving the big rig.

    -- Trailer sync function 
    trailerSyncTimers[client] = setTimer(function(client) 
    	-- Sync first truck trailer if there is any
    	if vehicles and vehicles[client] and isElement(vehicles[client]) and isElement(getElementData(vehicles[client], "GTWvehicles.attachedTrailer")) then
    		local tx,ty,tz = getElementPosition(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
    		local trx,try,trz = getElementRotation(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
    		setElementData(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
    	else
    		killTimer(trailerSyncTimers[client])
    	end
        
    	-- Sync first truck trailer if there is any
    	if trailers and trailers[client] and trailers[client][1] and isElement(trailers[client][1]) and 
    		isElement(getElementData(trailers[client][1], "GTWvehicles.second_trailer")) then
    		local tx,ty,tz = getElementPosition(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
    		local trx,try,trz = getElementRotation(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
    		setElementData(getElementData(trailers[client][1], "GTWvehicles.second_trailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
    	end
    end, 250, 0, client)

    Now on the client side. This is where the coordinates are obtained from the trailer object itself which we set on the server earlier. Here's where we'll look for the big changes like if the trailer is rotated ~45 degrees for a player looking at the rig from the outside while everything looks perfectly normal to the driver. We'll also check for differences in positioning, in this case a distance of 20 units are used while the difference in rotation are π/6 rad (30 degrees) 

    setTimer(function() 
    	for k,v in pairs(getElementsByType("vehicle", root, true)) do
    		if getVehicleType(v) == "Trailer" and getElementData(v, "GTWvehicles.trailer.location") and 
    			getElementData(v, "GTWvehicles.towingVehicle") and getElementData(v, "GTWvehicles.towingVehicle") ~= 
    			getPedOccupiedVehicle(localPlayer) then
    			local data = fromJSON(getElementData(v, "GTWvehicles.trailer.location"))
    			--outputChatBox("Trailer "..k.." is streamed in at position: {"..math.floor(data[1])..", "..
    			--	math.floor(data[2])..", "..math.floor(data[3]).."} with rotation: {"..math.floor(data[4])..", "..
    			--	math.floor(data[5])..", "..math.floor(data[6]).."}")
    			
    			local tx,ty,tz = getElementPosition(v)
    			local trx,try,trz = getElementRotation(v)
    			--local sx,sy,sz = getElementVelocity(v)
    			--outputChatBox("Updated trailer position for player: "..getPlayerName(localPlayer)..", Diff: x: "..
    			--	math.floor(math.abs(tx-data[1])).." sx: ("..math.floor(sx).."), y: "..
    			--	math.floor(math.abs(ty-data[2])).." sy: ("..math.floor(sy).."), z: "..
    			--	math.floor(math.abs(tz-data[3])).." sz: ("..math.floor(sz)..
    			--	"), Diff rot: rx: "..math.floor(math.abs(trx-data[4]))..
    			--	", ry: "..math.floor(math.abs(try-data[5]))..", rz: "..math.floor(math.abs(trz-data[6])))
    			local t_tower = getElementData(v, "GTWvehicles.towingVehicle")
    			if t_tower and isElement(t_tower) then
    				setTimer(attachTrailerToVehicle, 100, 1, t_tower, v)
    			end
    			local t2_tower = getElementData(t_tower, "GTWvehicles.second_tower")
    			if t2_tower and isElement(t2_tower) then
    				setTimer(attachTrailerToVehicle, 100, 1, t2_tower, v)
    			end
    			
    			if math.abs(tx-data[1]) > 20 or math.abs(ty-data[2]) > 20 or math.abs(tz-data[3]) > 20 or (math.abs(trz-data[6]) > 30 and math.abs(trz-data[6]) < 150) then
    				--outputChatBox("Old pos: "..math.floor(tx)..", "..math.floor(ty)..", "..math.floor(tz))
    				setElementPosition(v, data[1],data[2],data[3])
    				setElementRotation(v, data[4],data[5],data[6])
    				--local tx,ty,tz = getElementPosition(v)
    				--outputChatBox("New pos: "..math.floor(tx)..", "..math.floor(ty)..", "..math.floor(tz))
    			end
    		end
    	end
    end, 500, 0)

    Next thing to do here would be to not allow an element to stream out. This is slightly easier tho since you only need to pass the newly created trailer element (and the semi truck) to the client and then use setElementStreamable client side. Here's an example I've been using to solve this issue with trains carrying 20-30 trailers.

    Server:

    triggerClientEvent(root, "GTWvehicles.onStreamOut", root, vehicles[client])

    Client:

    function check_stream_out(c_train)
    	setElementStreamable(c_train, true)
    end
    addEvent("GTWvehicles.onStreamOut", true)
    addEventHandler("GTWvehicles.onStreamOut", root, check_stream_out)

    This code is a part of https://github.com/404rq/GTW-RPG/tree/v4.0-development and might need a few adjustments to work in your server but it shows the principles. vehicles[client] contains the semi truck and trailers[client][1] contains the first trailer. The trailer can identify it's tower from it's element data set to: GTWvehicles.towingVehicle which is set upon creation. If you're having any trouble, try changing the values in this line, that's pretty much how aggressive the sync will be, if it's too aggressive you may experience other issues:

    if math.abs(tx-data[1]) > 20 or math.abs(ty-data[2]) > 20 or math.abs(tz-data[3]) > 20 or (math.abs(trz-data[6]) > 30 and math.abs(trz-data[6]) < 150) then

    I hope this works for you too

    • Like 2
  14. Backup snapshots and improvements in billing history is now available, a transaction page has also been added in where you can trace your payments and their current status. That and many other minor improvements has been made to the layout for a better overview of your active services.

    ec.png

    We've also added support for http2 to our control panel/dashboard which made it load 3 times faster than before.

    • Thanks 1
  15. You may consider using both, an unstable connection may after all result in data loss so while a freeze called server side may sync across all other players the affected player might not receive the freeze call, client side will freeze the affected player and thus theoretically stop him from moving but due to eventual data loss that signal might not reach the server, that could cause other players to see the affected player continue to move while he should be frozen.

    • Like 1
×
×
  • Create New...