This commit is contained in:
guava
2016-12-15 13:40:07 +01:00
commit ee4dd89693
95 changed files with 7368 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
client_scripts {
"mapmanager_client.lua",
"mapmanager_shared.lua"
}
server_scripts {
"mapmanager_server.lua",
"mapmanager_shared.lua"
}

View File

@@ -0,0 +1,200 @@
maps = {}
gametypes = {}
AddEventHandler('getResourceInitFuncs', function(isPreParse, add)
if not isPreParse then
add('map', function(file)
addMap(file, GetInvokingResource())
end)
add('resource_type', function(type)
return function(params)
local resourceName = GetInvokingResource()
if type == 'map' then
maps[resourceName] = params
elseif type == 'gametype' then
gametypes[resourceName] = params
end
end
end)
end
end)
mapFiles = {}
function addMap(file, owningResource)
if not mapFiles[owningResource] then
mapFiles[owningResource] = {}
end
table.insert(mapFiles[owningResource], file)
end
AddEventHandler('onClientResourceStart', function(res)
-- parse metadata for this resource
-- map files
local num = GetNumResourceMetadata(res, 'map')
if num then
for i = 0, num-1 do
local file = GetResourceMetadata(res, 'map', i)
if file then
addMap(file, res)
end
end
end
-- resource type data
local type = GetResourceMetadata(res, 'resource_type', 0)
if type then
Citizen.Trace("type " .. res .. " " .. type .. "\n")
local extraData = GetResourceMetadata(res, 'resource_type_extra', 0)
if extraData then
extraData = json.decode(extraData)
else
extraData = {}
end
if type == 'map' then
maps[res] = extraData
elseif type == 'gametype' then
gametypes[res] = extraData
end
end
-- handle starting
if mapFiles[res] then
for _, file in ipairs(mapFiles[res]) do
parseMap(file, res)
end
end
-- defer this to the next game tick to work around a lack of dependencies
Citizen.CreateThread(function()
Citizen.Wait(15)
if maps[res] then
TriggerEvent('onClientMapStart', res)
elseif gametypes[res] then
TriggerEvent('onClientGameTypeStart', res)
end
end)
end)
AddEventHandler('onClientResourceStop', function(res)
if maps[res] then
TriggerEvent('onClientMapStop', res)
elseif gametypes[res] then
TriggerEvent('onClientGameTypeStop', res)
end
if undoCallbacks[res] then
for _, cb in ipairs(undoCallbacks[res]) do
cb()
end
undoCallbacks[res] = nil
mapFiles[res] = nil
end
end)
undoCallbacks = {}
function parseMap(file, owningResource)
if not undoCallbacks[owningResource] then
undoCallbacks[owningResource] = {}
end
local env = {
math = math, pairs = pairs, ipairs = ipairs, next = next, tonumber = tonumber, tostring = tostring,
type = type, table = table, string = string, _G = env
}
TriggerEvent('getMapDirectives', function(key, cb, undocb)
env[key] = function(...)
local state = {}
state.add = function(k, v)
state[k] = v
end
local result = cb(state, ...)
local args = table.pack(...)
table.insert(undoCallbacks[owningResource], function()
undocb(state)
end)
return result
end
end)
local mt = {
__index = function(t, k)
if rawget(t, k) ~= nil then return rawget(t, k) end
-- as we're not going to return nothing here (to allow unknown directives to be ignored)
local f = function()
return f
end
return function() return f end
end
}
setmetatable(env, mt)
local fileData = LoadResourceFile(owningResource, file)
local mapFunction, err = load(fileData, file, 't', env)
if not mapFunction then
Citizen.Trace("Couldn't load map " .. file .. ": " .. err .. " (type of fileData: " .. type(fileData) .. ")\n")
return
end
mapFunction()
end
AddEventHandler('getMapDirectives', function(add)
add('vehicle_generator', function(state, name)
return function(opts)
local x, y, z, heading
local color1, color2
if opts.x then
x = opts.x
y = opts.y
z = opts.z
else
x = opts[1]
y = opts[2]
z = opts[3]
end
heading = opts.heading or 1.0
color1 = opts.color1 or -1
color2 = opts.color2 or -1
local hash = GetHashKey(name)
RequestModel(hash)
LoadAllObjectsNow()
local carGen = CreateScriptVehicleGenerator(x, y, z, heading, 5.0, 3.0, hash, color1, color2, -1, -1, true, false, false, true, true, -1)
SetScriptVehicleGenerator(carGen, true)
SetAllVehicleGeneratorsActive(true)
state.add('cargen', carGen)
end
end, function(state, arg)
Citizen.Trace("deleting car gen " .. tostring(state.cargen) .. "\n")
DeleteScriptVehicleGenerator(state.cargen)
end)
end)

View File

@@ -0,0 +1,273 @@
-- loosely based on MTA's https://code.google.com/p/mtasa-resources/source/browse/trunk/%5Bmanagers%5D/mapmanager/mapmanager_main.lua
maps = {}
gametypes = {}
AddEventHandler('getResourceInitFuncs', function(isPreParse, add)
add('resource_type', function(type)
return function(params)
local resourceName = GetInvokingResource()
if type == 'map' then
maps[resourceName] = params
elseif type == 'gametype' then
gametypes[resourceName] = params
end
end
end)
add('map', function(file)
AddAuxFile(file)
end)
end)
AddEventHandler('onResourceStarting', function(resource)
if maps[resource] then
if getCurrentMap() and getCurrentMap() ~= resource then
if doesMapSupportGameType(getCurrentGameType(), resource) then
print("Changing map from " .. getCurrentMap() .. " to " .. resource)
changeMap(resource)
else
-- check if there's only one possible game type for the map
local map = maps[resource]
local count = 0
local gt
for type, flag in pairs(map.gameTypes) do
if flag then
count = count + 1
gt = type
end
end
if count == 1 then
print("Changing map from " .. getCurrentMap() .. " to " .. resource .. " (gt " .. gt .. ")")
changeGameType(gt)
changeMap(resource)
end
end
CancelEvent()
end
elseif gametypes[resource] then
if getCurrentGameType() and getCurrentGameType() ~= resource then
print("Changing gametype from " .. getCurrentGameType() .. " to " .. resource)
changeGameType(resource)
CancelEvent()
end
end
end)
math.randomseed(GetInstanceId())
local currentGameType = nil
local currentMap = nil
AddEventHandler('onResourceStart', function(resource)
if maps[resource] then
if not getCurrentGameType() then
for gt, _ in pairs(maps[resource].gameTypes) do
changeGameType(gt)
break
end
end
if getCurrentGameType() and not getCurrentMap() then
if doesMapSupportGameType(currentGameType, resource) then
if TriggerEvent('onMapStart', resource, maps[resource]) then
if maps[resource].name then
SetMapName(maps[resource].name)
else
SetMapName(resource)
end
currentMap = resource
else
currentMap = nil
end
end
end
elseif gametypes[resource] then
if not getCurrentGameType() then
if TriggerEvent('onGameTypeStart', resource, gametypes[resource]) then
currentGameType = resource
local gtName = gametypes[resource].name or resource
SetGameType(gtName)
print('Started gametype ' .. gtName)
TriggerClientEvent('onClientGameTypeStart', -1, getCurrentGameType())
SetTimeout(50, function()
if not currentMap then
local possibleMaps = {}
for map, data in pairs(maps) do
if data.gameTypes[currentGameType] then
table.insert(possibleMaps, map)
end
end
if #possibleMaps > 0 then
local rnd = math.random(#possibleMaps)
changeMap(possibleMaps[rnd])
end
end
end)
else
currentGameType = nil
end
end
end
end)
local function handleRoundEnd()
local possibleMaps = {}
for map, data in pairs(maps) do
if data.gameTypes[currentGameType] then
table.insert(possibleMaps, map)
end
end
if #possibleMaps > 0 then
local rnd = math.random(#possibleMaps)
changeMap(possibleMaps[rnd])
end
end
AddEventHandler('mapmanager:roundEnded', function()
-- set a timeout as we don't want to return to a dead environment
SetTimeout(50, handleRoundEnd) -- not a closure as to work around some issue in neolua?
end)
AddEventHandler('onResourceStop', function(resource)
if resource == currentGameType then
TriggerEvent('onGameTypeStop', resource)
currentGameType = nil
if currentMap then
StopResource(currentMap)
end
elseif resource == currentMap then
TriggerEvent('onMapStop', resource)
currentMap = nil
end
end)
AddEventHandler('rconCommand', function(commandName, args)
if commandName == 'map' then
if #args ~= 1 then
RconPrint("usage: map [mapname]\n")
end
if not maps[args[1]] then
RconPrint('no such map ' .. args[1] .. "\n")
CancelEvent()
return
end
if currentGameType == nil or not doesMapSupportGameType(currentGameType, args[1]) then
local map = maps[args[1]]
local count = 0
local gt
for type, flag in pairs(map.gameTypes) do
if flag then
count = count + 1
gt = type
end
end
if count == 1 then
print("Changing map from " .. getCurrentMap() .. " to " .. args[1] .. " (gt " .. gt .. ")")
changeGameType(gt)
changeMap(args[1])
RconPrint('map ' .. args[1] .. "\n")
else
RconPrint('map ' .. args[1] .. ' does not support ' .. currentGameType .. "\n")
end
CancelEvent()
return
end
changeMap(args[1])
RconPrint('map ' .. args[1] .. "\n")
CancelEvent()
elseif commandName == 'gametype' then
if #args ~= 1 then
RconPrint("usage: gametype [name]\n")
end
if not gametypes[args[1]] then
RconPrint('no such gametype ' .. args[1] .. "\n")
CancelEvent()
return
end
changeGameType(args[1])
RconPrint('gametype ' .. args[1] .. "\n")
CancelEvent()
end
end)
function getCurrentGameType()
return currentGameType
end
function getCurrentMap()
return currentMap
end
function changeGameType(gameType)
if currentMap and not doesMapSupportGameType(gameType, currentMap) then
StopResource(currentMap)
end
if currentGameType then
StopResource(currentGameType)
end
StartResource(gameType)
end
function changeMap(map)
if currentMap then
StopResource(currentMap)
end
StartResource(map)
end
function doesMapSupportGameType(gameType, map)
if not gametypes[gameType] then
return false
end
if not maps[map] then
return false
end
if not maps[map].gameTypes then
return true
end
return maps[map].gameTypes[gameType]
end

View File

@@ -0,0 +1 @@
-- shared logic file for map manager - don't call any subsystem-specific functions here