Jump to content

[REL] Map loader 1.0.2 (uncompiled now)


IIYAMA

Recommended Posts

  • Moderators

Map loader

This is a map loader, which can let specific players download a map of choice. Maps will be generated clientside and the resource is capable of loading extreme large maps. Loading the map will be done with a speed the pc can handle. The code execution time will be reduced to circa 10 ms. Which is the frame time of a player with 100 fps. So technically when you have 100 fps you still have 98/100 fps when this resource is loading a map. But this is based on running only this resource and based on predictions/knowledge. Which you can't trust...

The .map files are unloaded afterwards reading them. But the resource will keep a buffer of the processed data until no more players are using that map. This will speed up the resource when it is used for multiply players.

 

The resource can be managed with the following functions (serverside):

loadMapForTarget()
Require: element player/root, string mapName
Returns: boolean success, string message
 
unloadMapForTarget()
Require: element player/root, string mapName
Returns: boolean success, string message
 
getPlayerDownloadProgress()
Require: element player
Returns: int percentages or boolean false

Version 1.0.1 or higher

getPlayerMapStatus()
Require: element player, string mapName
Returns: string status or boolean false

Status list:

  • string "DOWNLOADING" -- Player is downloading the map.
  • string "LOADING" -- Player is generating/loading the map
  • string "LOADED" -- Player has loaded the map.
  • boolean false -- Player value is invalid or the player hasn't started downloading this map.

 


 

Events(serverside):

"onPlayerLoadedMap"
Source: element player
Parameters: string mapName int loadTime
 
"onPlayerUnloadedMap"
Source: element player
Arguments: string mapName

Version 1.0.1 or higher

"onPlayerCancelMapDownload"
Source: element player
Arguments: string mapName

 

Events(clientside):

"onClientPlayerLoadedMap"
Source: element localPlayer
Arguments: string mapName, int loadTime
 
"onClientPlayerUnloadedMap"
Source: element localPlayer
Arguments: string mapName


 

The same information about the functions and the events can be found inside the meta.xml

Element types that are supported:

objects, peds, vehicles, markers and pickups 
 

If you found any bugs, which might be in there. Don't be shy and let me know, I will exterminate them.

And don't forget, this resource require some rights in order to read map files from other resources:

DOWNLOAD 1.0.2

 

For developers a quick source code preview:

Server

Spoiler


--[[ 
	Player data
]]
local loadedPlayers = {} -- < Players that have loaded the resource
local downloadStatusPlayerData = {}
local mapsDownloadedBy = {}

--[[
	Map data
]]
local mapsBuffer = {} -- < Maps are saved inside of the memory to improving the loading speed.
local mapElementIndex = 1 -- < create unique identifiers
local mapElements = {} -- < Table with CUSTOM serverside map elements: mapElements[mapName] = element
local mapsLoadedBy = {} -- < Table with players that have loaded specific maps: mapsLoadedBy[mapName][player] = status true/nil

--[[ 
	Config
]]
local validVehicleIDS = { [602] = true, [545] = true, [496] = true, [517] = true, [401] = true, [410] = true, [518] = true, [600] = true, [527] = true, [436] = true, [589] = true, [580] = true, [419] = true, [439] = true, [533] = true, [549] = true, [526] = true, [491] = true, [474] = true, [445] = true, [467] = true, [604] = true, [426] = true, [507] = true, [547] = true, [585] = true, [405] = true, [587] = true, [409] = true, [466] = true, [550] = true, [492] = true, [566] = true, [546] = true, [540] = true, [551] = true, [421] = true, [516] = true, [529] = true, [592] = true, [553] = true, [577] = true, [488] = true, [511] = true, [497] = true, [548] = true, [563] = true, [512] = true, [476] = true, [593] = true, [447] = true, [425] = true, [519] = true, [520] = true, [460] = true, [417] = true, [469] = true, [487] = true, [513] = true, [581] = true, [510] = true, [509] = true, [522] = true, [481] = true, [461] = true, [462] = true, [448] = true, [521] = true, [468] = true, [463] = true, [586] = true, [472] = true, [473] = true, [493] = true, [595] = true, [484] = true, [430] = true, [453] = true, [452] = true, [446] = true, [454] = true, [485] = true, [552] = true, [431] = true, [438] = true, [437] = true, [574] = true, [420] = true, [525] = true, [408] = true, [416] = true, [596] = true, [433] = true, [597] = true, [427] = true, [599] = true, [490] = true, [432] = true, [528] = true, [601] = true, [407] = true, [428] = true, [544] = true, [523] = true, [470] = true, [598] = true, [499] = true, [588] = true, [609] = true, [403] = true, [498] = true, [514] = true, [524] = true, [423] = true, [532] = true, [414] = true, [578] = true, [443] = true, [486] = true, [515] = true, [406] = true, [531] = true, [573] = true, [456] = true, [455] = true, [459] = true, [543] = true, [422] = true, [583] = true, [482] = true, [478] = true, [605] = true, [554] = true, [530] = true, [418] = true, [572] = true, [582] = true, [413] = true, [440] = true, [536] = true, [575] = true, [534] = true, [567] = true, [535] = true, [576] = true, [412] = true, [402] = true, [542] = true, [603] = true, [475] = true, [449] = true, [537] = true, [538] = true, [570] = true, [441] = true, [464] = true, [501] = true, [465] = true, [564] = true, [568] = true, [557] = true, [424] = true, [471] = true, [504] = true, [495] = true, [457] = true, [539] = true, [483] = true, [508] = true, [571] = true, [500] = true, [444] = true, [556] = true, [429] = true, [411] = true, [541] = true, [559] = true, [415] = true, [561] = true, [480] = true, [560] = true, [562] = true, [506] = true, [565] = true, [451] = true, [434] = true, [558] = true, [494] = true, [555] = true, [502] = true, [477] = true, [503] = true, [579] = true, [400] = true, [404] = true, [489] = true, [505] = true, [479] = true, [442] = true, [458] = true, [606] = true, [607] = true, [610] = true, [590] = true, [569] = true, [611] = true, [584] = true, [608] = true, [435] = true, [450] = true, [591] = true, [594] = true}
local validPaintJobs = {[0]=true, [1]=true, [2]=true, [3]=true}
local validMarkerTypes = {["checkpoint"]=true, ["ring"]=true, ["cylinder"]=true, ["arrow"]=true, ["corona"]=true}
local validPedModels = {}
local downloadSpeed = 1024 * 1024

if true then
	local validPedModelsArray = getValidPedModels()
	for i=1,#validPedModelsArray do
		validPedModels[validPedModelsArray[i]] = true
	end
end

local hex2rgb = function (hex) -- < function source: https://gist.github.com/jasonbradley/4357406
    hex = hex:gsub("#", "")
    return tonumber("0x"..hex:sub(1, 2)), tonumber("0x"..hex:sub(3, 4)), tonumber("0x"..hex:sub(5, 6))
end

function loadMapForTarget (target, mapName)
    if mapName ~= "" and isElement(target) and (getElementType(target) == "player" or target == root) then
		if target == root or downloadStatusPlayerData[target] then 
			local mapContent = mapsBuffer[mapName]
			if not mapContent then
				local mapResource = getResourceFromName (mapName)
				if mapResource and getResourceInfo ( mapResource, "type" ) == "map" then
					local metaXmlNote = xmlLoadFile ( ":" .. mapName .. "/meta.xml" )
					if metaXmlNote then
						mapContent = {}
						--[[
							Support for multiple map files inside of a single resource
						]]
						local mapNoteIndex = 0
						repeat
							local mapNote = xmlFindChild ( metaXmlNote, "map", mapNoteIndex )
							if mapNote then
								local mapFileName = xmlNodeGetAttribute ( mapNote, "src" )
								if mapFileName then
									local mapNote = xmlLoadFile ( ":" .. mapName .. "/" .. mapFileName )
									if mapNote then
										local mapNoteChildren = xmlNodeGetChildren ( mapNote)
										if mapNoteChildren and #mapNoteChildren > 0 then
											--[[
												Reading the map
											]]
											for i=1, #mapNoteChildren do
												local child = mapNoteChildren[i]
												local childName = xmlNodeGetName (child)
												if childName == "object" then
													local content = {}
													
													local model = tonumber(xmlNodeGetAttribute ( child, "model" ))
													local pos = {tonumber(xmlNodeGetAttribute ( child, "posX" )) or 0,tonumber(xmlNodeGetAttribute ( child, "posY")) or 0,tonumber(xmlNodeGetAttribute ( child, "posZ")) or 0}
													local rot = {tonumber(xmlNodeGetAttribute ( child, "rotX" )) or 0,tonumber(xmlNodeGetAttribute ( child, "rotY")) or 0,tonumber(xmlNodeGetAttribute ( child, "rotZ")) or 0}
													local int = tonumber(xmlNodeGetAttribute ( child, "interior")) or 0
													local dim = tonumber(xmlNodeGetAttribute ( child, "dimension")) or 0
													local scale = tonumber(xmlNodeGetAttribute ( child, "scale")) or 1
													local col = xmlNodeGetAttribute ( child, "collisions") or "true"
													local alpha = tonumber(xmlNodeGetAttribute ( child, "alpha")) or 255
													local frozen = xmlNodeGetAttribute ( child, "frozen") or "false"
													local sided = xmlNodeGetAttribute ( child, "doublesided") or "false"
													local breakable = xmlNodeGetAttribute ( child, "breakable") or "true"
													if model and pos and rot and int and dim and scale and (breakable == "true" or breakable == "false") and (col == "true" or col == "false" ) and (alpha and (alpha >= 0 or alpha <= 255)) and (frozen == "true" or frozen == "false") and (sided == "true" or sided == "false") then
														content["type"] = "object"
														content["model"] = model
														content["pos"] = pos
														content["rot"] = rot
														content["int"] = int
														content["dim"] = dim
														content["scale"] = scale
														content["col"] = col == "true"
														content["alpha"] = alpha
														content["frozen"] = frozen == "true"
														content["sided"] = sided == "true"
														content["breakable"] = breakable == "true"
														mapContent[#mapContent+1] = content
													end
												elseif childName == "marker" then
													local content = {}
													local pos = {tonumber(xmlNodeGetAttribute ( child, "posX" )) or 0,tonumber(xmlNodeGetAttribute ( child, "posY")) or 0,tonumber(xmlNodeGetAttribute ( child, "posZ")) or 0}
													local markerType = xmlNodeGetAttribute ( child, "type" )
													local size = tonumber(xmlNodeGetAttribute ( child, "size")) or 4
													local int = tonumber(xmlNodeGetAttribute ( child, "interior")) or 0
													local dim = tonumber(xmlNodeGetAttribute ( child, "dimension")) or 0
													local color = xmlNodeGetAttribute ( child,"color")
													local R,G,B = 0, 0, 255, 255
													if color and color ~=  "" then
														local R2, G2, B2 = hex2rgb(color)
														if R2 and G2 and B2 then
															R, G, B = R2, G2, B2
														end
													end
													if pos and validMarkerTypes[markerType] and size and int and dim then
														
														content["type"] = "marker"
														content["pos"] = pos
														content["int"] = int
														content["dim"] = dim
														content["size"] = size
														content["markerType"] = markerType
														content["color"] = {R, G, B} 
														
														
														mapContent[#mapContent + 1] = content
													end
												elseif childName == "vehicle" then
													local content = {}
													local model = tonumber(xmlNodeGetAttribute ( child, "model" ))
													local pos = {tonumber(xmlNodeGetAttribute ( child, "posX" )) or 0,tonumber(xmlNodeGetAttribute ( child, "posY")) or 0,tonumber(xmlNodeGetAttribute ( child, "posZ")) or 0}
													local rot = {tonumber(xmlNodeGetAttribute ( child, "rotX" )) or 0,tonumber(xmlNodeGetAttribute ( child, "rotY")) or 0,tonumber(xmlNodeGetAttribute ( child, "rotZ")) or 0}
													local plate = xmlNodeGetAttribute ( child, "plate" )
													local int = tonumber(xmlNodeGetAttribute ( child,"interior")) or 0
													local dim = tonumber(xmlNodeGetAttribute ( child,"dimension")) or 0
													local paintjob = tonumber(xmlNodeGetAttribute ( child,"paintjob")) or 0
													local color = xmlNodeGetAttribute ( child,"color")
													if color and color ~= "" then
														color = split(color,",")
														if color and #color == 0 then
															color = nil
														end
													else
														color = nil
													end
													local upgrades = xmlNodeGetAttribute ( child,"upgrades")
													if upgrades and upgrades ~= "" then
														upgrades = split(upgrades,",")
														if upgrades and #upgrades == 0 then
															upgrades = nil
														end
													else
														upgrades = nil
													end
													if validVehicleIDS[model] and pos and rot and plate and int and dim and validPaintJobs[paintjob] then
														content["type"] = "vehicle"
														content["model"] = model
														content["pos"] = pos
														content["rot"] = rot
														content["plate"] = tostring(plate)
														content["int"] = int
														content["dim"] = dim
														content["paintjob"] = paintjob
														if upgrades then
															content["upgrades"] = upgrades
														end
														if color then
															content["color"] = color
														end
														mapContent[#mapContent+1] = content
													end
												elseif childName == "ped" then
													local content = {}
													local model = tonumber(xmlNodeGetAttribute ( child, "model" ))
													local pos = {tonumber(xmlNodeGetAttribute ( child, "posX" )) or 0,tonumber(xmlNodeGetAttribute ( child, "posY")) or 0,tonumber(xmlNodeGetAttribute ( child, "posZ")) or 0}
													local rot = tonumber(xmlNodeGetAttribute ( child, "rotZ" )) or 0
													local int = tonumber(xmlNodeGetAttribute ( child,"interior")) or 0
													local dim = tonumber(xmlNodeGetAttribute ( child,"dimension")) or 0
													local frozen = xmlNodeGetAttribute ( child,"frozen") or "false"
													local alpha = tonumber(xmlNodeGetAttribute ( child,"alpha")) or 255
													if validPedModels[model] and pos and rot and int and dim and (frozen == "true" or frozen == "false") and alpha then
														content["type"] = "ped"
														content["model"] = model
														content["pos"] = pos
														content["rot"] = rot
														content["int"] = int
														content["dim"] = dim
														content["alpha"] = alpha
														content["frozen"] = frozen == "true"
														mapContent[#mapContent+1] = content
													end
												elseif childName == "pickup" then
													local content = {}
													local pos = {tonumber(xmlNodeGetAttribute ( child, "posX" )) or 0,tonumber(xmlNodeGetAttribute ( child, "posY")) or 0,tonumber(xmlNodeGetAttribute ( child, "posZ")) or 0}
													local int = tonumber(xmlNodeGetAttribute ( child,"interior")) or 0
													local dim = tonumber(xmlNodeGetAttribute ( child,"dimension")) or 0
													local theType = xmlNodeGetAttribute ( child,"type")
													local pickupType = theType == "health" and 0 or theType == "armor" and 1 or 2
													if tonumber(theType) then
														theType = tonumber(theType)
													end
													if pos and pickupType and theType and theType ~= "" and int and dim then
														content["type"] = "pickup"
														content["pickupType"] = pickupType
														content["theType"] = theType
														content["int"] = int
														content["dim"] = dim
														content["pos"] = pos
														local amount = tonumber(xmlNodeGetAttribute ( child,"amount"))
														if amount then
															content["amount"] = amount
														end
														local respawn = tonumber(xmlNodeGetAttribute ( child,"respawn"))
														if respawn then
															content["respawn"] = respawn
														end
														mapContent[#mapContent + 1] = content
													end
												end
											end
										end
										xmlUnloadFile(mapNote)
									end
								end
							end
							mapNoteIndex = mapNoteIndex + 1
						until not mapNote
						xmlUnloadFile (metaXmlNote)
						if #mapContent > 0 then
							mapsBuffer[mapName] = mapContent
						else
							mapContent = nil
						end
					end
				end
			end
			if mapContent then
				local mapElement = mapElements[mapName]
				if not mapElement then
					
					mapElement = createElement("serverMapElement", "map-index-" .. mapElementIndex)
					mapElementIndex = mapElementIndex + 1
					mapElements[mapName] = mapElement
				end
				
				local playersDownloadThisMap = mapsDownloadedBy[mapName]
				if not playersDownloadThisMap then
					mapsDownloadedBy[mapName] = {}
					playersDownloadThisMap = mapsDownloadedBy[mapName]
				end
				
				
				if target == root then
					local downloadingPlayers = 0
					for i=1, #loadedPlayers do
						local player = loadedPlayers[i]
						if not playersDownloadThisMap[player] then
							triggerLatentClientEvent(player,"onClientMapReceive",downloadSpeed,resourceRoot,mapName,mapContent,mapElement)
							local playerData = downloadStatusPlayerData[player]
							local handles = getLatentEventHandles (player)
							local handler = handles[#handles]
							playerData[#playerData+1] = handler
							playersDownloadThisMap[player] = handler
							downloadingPlayers = downloadingPlayers + 1
						end
					end
					local playerCount = getPlayerCount()
					return true,downloadingPlayers .. "/" .. playerCount .. " loaded players are downloading and " .. #loadedPlayers-downloadingPlayers .. "/" .. playerCount ..  " already have downloaded the map: " .. mapName
				else
					local player = target
					if not playersDownloadThisMap[player] then 
						triggerLatentClientEvent(player,"onClientMapReceive",downloadSpeed,resourceRoot,mapName,mapContent,mapElement)
						local playerData = downloadStatusPlayerData[player]
						local handles = getLatentEventHandles (player)
						local handler = handles[#handles]
						playerData[#playerData+1] = handler
						playersDownloadThisMap[player] = handler
						return true, getPlayerName(player) .. " started downloading the map: " .. mapName
					else
						return false, getPlayerName(player) .. " has/is already downloaded/downloading this map: " .. mapName
					end
				end
			else
				return false,"No valid map/content found."
			end
		else
			return false,"This player can't receive maps yet. His resource hasn't been loaded."
		end
    end
	return false,"Incorrect arguments."
end

function unloadMapForTarget (target,mapName)
	if mapName ~= "" and isElement(target) and (getElementType(target) == "player" or target == root) then
		local targetingAll = target == root
		
		local destroyedForPlayer = false
		
		local usingThisMap = 0
		local playersDownloadThisMap = mapsDownloadedBy[mapName]
		if playersDownloadThisMap then
			
			for player,handler in pairs(playersDownloadThisMap) do
                local playerIsElement = isElement(player)
				if targetingAll then
                    if playerIsElement then
                        local status = getLatentEventStatus(player,handler)
                        if status and status["percentComplete"] ~= 100 then
                            if cancelLatentEvent( player, handler ) then
								triggerEvent("onPlayerCancelMapDownload",player,mapName)
							end
                        end
                    end
				
				elseif player == target then
                    if playerIsElement then
                        local status = getLatentEventStatus(player,handler)
                        if status and status["percentComplete"] ~= 100 then
                            if cancelLatentEvent( player, handler ) then
								triggerEvent("onPlayerCancelMapDownload",player,mapName)
							end
                        end
                    end
					destroyedForPlayer = true
					playersDownloadThisMap[player] = nil
				else
                    if playerIsElement then
					   usingThisMap = usingThisMap + 1
                    else
                        playersDownloadThisMap[player] = nil
                    end
				end
			end
			if targetingAll or usingThisMap == 0 then
				mapsDownloadedBy[mapName] = nil
			end
		end
		
		local mapElement = mapElements[mapName]
		if mapElement then
			if isElement(mapElement) then
				if targetingAll or usingThisMap == 0 then
					destroyElement(mapElement)
				else
					local player = target 
					triggerClientEvent(player,"onClientMapReceiveCancel",resourceRoot,mapElement,mapName)
				end
			end
		end
		if targetingAll or usingThisMap == 0 then
			mapElements[mapName] = nil
			local removeStatus = mapsBuffer[mapName] and true or false
			mapsBuffer[mapName] = nil
			mapsLoadedBy[mapName] = nil
			if removeStatus then
				return true, "Map buffer cleaned and destroyed for target/player."
			else
				return false, "Can't find loaded map."
			end
		end
		if destroyedForPlayer then
			return true, "Destroyed for player."
		end
	end
	return false
end

function getPlayerDownloadProgress(player)
	if isElement(player) then
		local handles = downloadStatusPlayerData[player]
		local activeHandles = 0
		local percentCompleteTotal = 0
		for i=#handles,1,-1 do
			local handler = handles[i]
			local status = getLatentEventStatus(player,handler)
			if status and status["percentComplete"] ~= 100 then
				activeHandles = activeHandles + 1
				percentCompleteTotal = percentCompleteTotal + status["percentComplete"]
			else
				table.remove(handles,i)
			end
		end
		if activeHandles > 0 then
			return math.floor(percentCompleteTotal/activeHandles)
		else
			return 100
		end
	end
    return false
end


function getPlayerMapStatus (player, mapName)
	if isElement(player) then
		local playersDownloadThisMap = mapsDownloadedBy[mapName]
		if playersDownloadThisMap then
			local handler = playersDownloadThisMap[player]
			if handler then
				local status = getLatentEventStatus(player, handler)
				if status and status["percentComplete"] ~= 100 then
					return "DOWNLOADING"
				else
					local loadedBy = mapsLoadedBy[mapName]
					if loadedBy and loadedBy[player] then
						return "LOADED"
					else
						return "LOADING"
					end
				end
			end
		end
	end
	return false
end

addEvent("onClientMapDownloadResourceStart",true)
addEventHandler("onClientMapDownloadResourceStart",resourceRoot,
function (player)
	if player == client and source == resourceRoot and isElement(player) then
		loadedPlayers[#loadedPlayers+1] = client
		downloadStatusPlayerData[client] = {}
	end
end)

addEventHandler("onPlayerQuit",root,
function ()
	downloadStatusPlayerData[source] = nil
	for i=1,#loadedPlayers do
		if loadedPlayers[i] == source then
			table.remove(loadedPlayers,i)
			break
		end
	end
	
	for mapName, playersThatDownloaded in pairs(mapsDownloadedBy) do
		if playersThatDownloaded[source] then
			playersThatDownloaded[source] = nil
		end
		local playerCount = 0
		for player,hanler in pairs(playersThatDownloaded) do
            if isElement(player) then
                playerCount = playerCount+1
            else -- < Just in case... Yet it will never be used.
                playersThatDownloaded[player] = nil
            end
		end
		if playerCount == 0 then	
			local mapElement = mapElements[mapName]
			if mapElement then
				if isElement(mapElement) then
					destroyElement(mapElement)
				end
				mapElements[mapName] = nil
			end
			mapsBuffer[mapName] = nil
			mapsLoadedBy[mapName] = nil
		end
	end
	
	for mapName,loadedBy in pairs(mapsLoadedBy) do
		if loadedBy[source] then
			loadedBy[source] = nil
		end
		local playersLoadedThisMap = 0
		for player,boolean in pairs(loadedBy) do
			if isElement(player) then
				playersLoadedThisMap = playersLoadedThisMap + 1
			else
				loadedBy[player] = nil
			end
		end
		if playersLoadedThisMap == 0 then
			mapsLoadedBy[mapName] = nil
		end
	end
	
end)


addEvent("playerHasLoadedMap", true)
addEventHandler("playerHasLoadedMap", resourceRoot,
function (player, mapName, loadTime)
    if player == client then
		local loadedBy = mapsLoadedBy[mapName]
		if not loadedBy then
			mapsLoadedBy[mapName] = {}
			loadedBy = mapsLoadedBy[mapName]
		end
		loadedBy[player] = true
        triggerEvent("onPlayerLoadedMap", player, mapName, loadTime)
    end
end)

addEvent("playerHasUnloadMap", true)
addEventHandler("playerHasUnloadMap", resourceRoot,
function (player, mapName)
    if player == client then
	
		local loadedBy = mapsLoadedBy[mapName]
		if loadedBy then
			loadedBy[player] = nil
			local playersLoadedThisMap = 0
			for player,boolean in pairs(loadedBy) do
				if isElement(player) then
					playersLoadedThisMap = playersLoadedThisMap + 1
				else
					loadedBy[player] = nil
				end
			end
			if playersLoadedThisMap == 0 then
				mapsLoadedBy[mapName] = nil
			end
		end
		
        triggerEvent("onPlayerUnloadedMap", player, mapName)
    end
end)

 

Client

Spoiler
local loadedMaps = {}

local renderMapDownloadStatus = false
local renderMapDownloadFunction
local renderMapDownloadContent = {}
renderMapDownloadFunction = function ()
	--[[
		10 ms delay* = 100 fps, which means that technically this script should not drop your fps lower than circa 100 fps.
		I hope this is true/true.
	]]
	local loopTime = math.ceil(10/#renderMapDownloadContent) -- *10 ms delay divide by amount of maps.
    for mapIndex=#renderMapDownloadContent,1,-1 do
        local mapData = renderMapDownloadContent[mapIndex]
        local mapContent = mapData["mapContent"]
        local endLoop = false
		--local loops = 0
		local endLoading = getTickCount()+loopTime
		local mapElement = mapData["mapElement"]
		local clientMapElement = mapData["clientMapElement"]
		local isMapElement 
        repeat
			--loops = loops+1 
            local startIndex = mapData["startIndex"]
            isMapElement = isElement(mapElement)
            if startIndex > #mapContent or not isMapElement then
				--outputChatBox("startIndex: " .. startIndex .. ", #mapContent: " .. #mapContent)
                endLoop = true
            else
                local elementData = mapContent[startIndex]
                local elementType = elementData["type"]
                if elementType == "object" then
                    local objectPos = elementData["pos"]
                    local objectRot = elementData["rot"]
                    local x,y,z = objectPos[1],objectPos[2],objectPos[3]
                    local object = createObject(elementData["model"],x,y,z,objectRot[1],objectRot[2],objectRot[3],elementData["lowLOD"])
                    if object then
                        setElementInterior(object,elementData["int"], x,y,z)
                        setElementDimension (object,elementData["dim"])
                        setObjectScale (object,elementData["scale"])
                        setElementCollisionsEnabled (object,elementData["col"])
                        setElementAlpha(object,elementData["alpha"])
                        setElementFrozen(object,elementData["frozen"])
                        setElementDoubleSided (object,elementData["sided"])
						setObjectBreakable(object,elementData["breakable"])
                        setElementParent(object,clientMapElement)
                    end
                elseif elementType == "marker" then
                    local markerPos = elementData["pos"]
					local color = elementData["color"]
                    local marker = createMarker ( markerPos[1], markerPos[2], markerPos[3], elementData["markerType"],elementData["size"],color[1],color[2],color[3])
                    if marker then
						setElementInterior(marker,elementData["int"])
						setElementDimension(marker,elementData["dim"])
                        setElementParent(marker,clientMapElement)  
                    end
				elseif elementType == "vehicle" then
					local vehiclePos = elementData["pos"]
					local vehicleRot = elementData["rot"]
					local vehicle = createVehicle (elementData["model"], vehiclePos[1],vehiclePos[2],vehiclePos[3],vehicleRot[1],vehicleRot[2],vehicleRot[3],elementData["plate"] )
					if vehicle then
						local upgrades = elementData["upgrades"]
						if upgrades then
							for i=1,#upgrades do
								addVehicleUpgrade ( vehicle, upgrades[i])
							end
						end
						setVehicleColor (vehicle,unpack(elementData["color"] or {0,0,0,0,0,0,0,0,0,0,0,0})) -- Set colors of vehicle clientside directly after creation doesn't work, BUG for now****.
						
						setElementParent(vehicle,clientMapElement)  
					end
			   elseif elementType == "ped" then
                    local markerPos = elementData["pos"]
                    local ped = createPed(elementData["model"],markerPos[1], markerPos[2], markerPos[3],elementData["rot"])
					if ped then
						setElementInterior(ped,elementData["int"])
						setElementFrozen(ped,elementData["frozen"])
						setElementDimension(ped,elementData["dim"])
						setElementAlpha(ped,elementData["alpha"])
						setElementParent(ped,clientMapElement)  
					end
				elseif elementType == "pickup" then
					local pickupPos = elementData["pos"]
					local pickup 
					if elementData["respawn"] then
						if elementData["amount"] then
							pickup = createPickup(pickupPos[1],pickupPos[2],pickupPos[3],elementData["pickupType"],elementData["theType"],elementData["respawn"],elementData["amount"])
						else
							pickup = createPickup(pickupPos[1],pickupPos[2],pickupPos[3],elementData["pickupType"],elementData["theType"],elementData["respawn"])
						end
					else
						pickup = createPickup(pickupPos[1],pickupPos[2],pickupPos[3],elementData["pickupType"],elementData["theType"])
					end
					if pickup then
						setElementDimension(pickup,elementData["dim"])
						setElementInterior(pickup,elementData["int"])
						setElementParent(pickup,clientMapElement)
					end
                end
                mapData["startIndex"] = startIndex+1
            end
			--outputChatBox(tostring(getTickCount() > endLoading) .. " " .. tostring(endLoop))
        until (getTickCount() > endLoading or endLoop)
		--outputChatBox("loops: " .. loops .. ", elements: " .. #mapContent .. ", startIndex: " .. mapData["startIndex"])
        if endLoop then
            if isMapElement then
                local mapName = mapData["mapName"]
                loadedMaps[mapName] = true
				local loadTime = getTickCount()-mapData["startLoadingTime"]
                triggerEvent("onClientPlayerLoadedMap",localPlayer,mapName,loadTime)
                triggerServerEvent("playerHasLoadedMap",resourceRoot,localPlayer,mapName,loadTime)
            end
            table.remove(renderMapDownloadContent,mapIndex)
        end
    end
    if #renderMapDownloadContent == 0 then
        removeEventHandler("onClientPreRender",root,renderMapDownloadFunction)
    end
end

addEvent("onClientMapReceiveCancel",true)
addEventHandler("onClientMapReceiveCancel",resourceRoot,
function (mapElement,mapName)
	for i=1,#renderMapDownloadContent do
		local mapData = renderMapDownloadContent[i]
		if mapData and mapData["mapName"] == mapName then
			table.remove(renderMapDownloadContent,i)
			break
		end
	end
    if isElement(mapElement) then
		local clientMapElement = getElementChild (mapElement, 0 )
		if clientMapElement then
			destroyElement(clientMapElement)
		end
    end
    if loadedMaps[mapName] then
        triggerEvent("onClientPlayerUnloadedMap",localPlayer,mapName)
        triggerServerEvent("playerHasUnloadMap",resourceRoot,localPlayer,mapName)
        loadedMaps[mapName] = nil
    end
end)

addEvent("onClientMapReceive",true)
addEventHandler("onClientMapReceive",resourceRoot,
function (mapName,mapContent,mapElement)
    if type(mapContent) == "table" and source == resourceRoot then
		local previousClientMapElement = getElementChild (mapElement, 0 )
		if previousClientMapElement then
			outputDebugString("ERROR: Map_loader, something went wrong clientside! Fixing it now.")
			destroyElement(previousClientMapElement)
		end
		local clientMapElement = createElement("clientMapElement")
		if clientMapElement then
			setElementParent(clientMapElement,mapElement)
			renderMapDownloadContent[#renderMapDownloadContent+1] = {["mapName"]=mapName,["clientMapElement"]=clientMapElement,["startLoadingTime"]=getTickCount(),["mapContent"]=mapContent,["startIndex"]=1,["mapElement"]=mapElement}
			if not renderMapDownloadStatus then
				addEventHandler("onClientPreRender",root,renderMapDownloadFunction,true,"high+5")
			end
		end
    end
end)

addEventHandler("onClientResourceStart",resourceRoot,
function ()
	triggerServerEvent("onClientMapDownloadResourceStart",resourceRoot,localPlayer)
end)


-- the structure --
--[[
{
    {-- object
        ["model"]=1,
        ["pos"]={x,y,z},
        ["rot"]={xr,yr,zr},
        ["lowLOD"]=false,
        ["int"]=1,
        ["dim"]=1,
        ["scale"]=1,
        ["col"]=true,
        ["alpha"]=255,
        ["frozen"]=false
    },



]]


 

 

 

 

 

  • Like 1
Link to comment
  • Moderators

Another function will be implemented soon: (it is already finished, but for next version 1.0.1)

[b]getPlayerMapStatus()[/b] 
Require: [i][color=#00FF00]element [/color]player, [color=#00FF00]string [/color]mapName[/i] 
Returns: [i][color=#00FF00]string [/color]status[/i] 
Or [i][color=#00FF00]boolean [/color]false[/i] 
  

Possible status:

"DOWNLOADING"   [color=#00FF00]-- Player is downloading the map.[/color] 
"LOADING"       [color=#00FF00]-- Player is generating/loading the map[/color] 
"LOADED"       [color=#00FF00] -- Player has loaded the map.[/color] 
false           [color=#00FF00]-- Player variable is invalid or the player hasn't started downloading this map.[/color] 

And a new event:

[color=#0000FF]"onPlayerCancelMapDownload"[/color] 
Source: [i][color=#00FF00]element [/color]player  
Arguments: [color=#00FF00]string [/color]mapName[/i] 
  

RELEASED 1.0.1

Link to comment
  • 6 months later...
  • Moderators
Where the hell do I need to add my map name and target player name?
local target = getPlayerFromName("myName") 
if target  then 
    exports["map_loader"]:loadMapForTarget(target, "sth-jackson") 
end 
  

This map loader is for scripters, there is no CLI(command line interface) or GUI because it is irrelevant for the target user.

Link to comment
  • Moderators

That .lua file is only for controlling the map_loader resource, it can be merged with any kind of resource. From there it can load every map you want.

And what if I want the map to be for everyone?
exports["map_loader"]:loadMapForTarget(root, "sth-jackson") 

Read the instructions at the top carefully.

Link to comment
  • 4 years later...
  • 8 months later...
  • Moderators
31 minutes ago, enesbayrktar said:

script name?

1.

It is the resourceName. (the folder that contains the meta.xml, that is the name that should be used)

As you can see here:

"sth-jackson"

https://community.multitheftauto.com/index.php?p=resources&s=details&id=527

 

2.

The script will detect all map files inside of the meta.xml and combine those.

 

3.

As far as I can remember the resource must be unzipped.

 

Edited by IIYAMA
Link to comment
  • Moderators
On 02/02/2021 at 23:57, enesbayrktar said:

İ have one question about that script usage.

For example i have one .map file, how can i execute .map file with this resource? can you give a example?


exports["map_loader"]:loadMapForTarget(root, "sth-jackson")  -- sth-jackson is .map file name or script name?

@IIYAMA

Did you got it to work?

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...