-
Notifications
You must be signed in to change notification settings - Fork 3
/
server.lua
143 lines (119 loc) · 5.85 KB
/
server.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
local hasAnyUGCDirectives = false
local foundMapDirectiveData = false
local mapDirectiveDataType = false
local defaultFallbackUrl = "https://prod.cloud.rockstargames.com/ugc/gta5mission/0000/vyTABS5xR06--t_w6e9t0w/0_0_en.json" -- Stunt - Chiliad
AddEventHandler("onMapStart", function(mapName)
-- Save the name of the current resource as we can't get it from getMapDirectives
-- We'll do it in GlobalState as it may be useful! (and exports are meh)
GlobalState.CurrentMap = mapName
-- So that connected clients don't go to load things just right now, we'll set a variable for them to poll
GlobalState.CurrentMapMissionJSONChecked = false
end)
-- Map directive stuff
AddEventHandler('getMapDirectives', function(add)
-- Refresh the map directive state storage stuff
hasAnyUGCDirectives = false
foundMapDirectiveData = false
mapDirectiveDataType = false
-- Raw MissionJSON right in the map.lua file
add('missionjson', function(state, jsonString)
-- Only accept one of any type
if hasAnyUGCDirectives then return end
-- This directive can only be a string and has to seem like valid JSON
if type(jsonString) ~= "string" and SeemsLikeValidMissionJSON(jsonString) then return end
-- This is directly a MissionJSON string (or at least it should be...) so this is what we use as the map.
foundMapDirectiveData = jsonString
mapDirectiveDataType = "raw"
hasAnyUGCDirectives = true
end, function()
-- We actually don't need to delete anything from state as that's handled when maps are loaded...
end)
-- A file name pointing to a file containing MissionJSON
add('missionjson_file', function(state, filename)
-- Only accept one of any type
if hasAnyUGCDirectives then return end
-- This directive can only be a string
if type(filename) ~= "string" then return end
-- We need to process the file somewhere else otherwise we'll cause resource warnings on mapmanager
foundMapDirectiveData = filename
mapDirectiveDataType = "resourcefile"
hasAnyUGCDirectives = true
end, function() end)
-- A (cacheable) URL pointing to MissionJSON (probably a rockstar URL)
add('missionjson_url', function(state, url)
-- Only accept one of any type
if hasAnyUGCDirectives then return end
-- This directive can only be a string
if type(url) ~= "string" then return end
-- We need to process the url somewhere else otherwise we'll cause resource warnings on mapmanager
foundMapDirectiveData = url
mapDirectiveDataType = "url"
hasAnyUGCDirectives = true
end, function() end)
-- This is the same as a URL but we get it from a variable in GlobalState so that it can be changed in accordance with an external voting system.
add('missionjson_surrogate', function(state, acknowledgement)
-- Only accept one of any type
if hasAnyUGCDirectives then return end
-- Stop stupid people from being stupid
if acknowledgement ~= "Yes, I understand that what surrogate maps are and that I shouldn't be using this map directive if I don't." then return end
-- Save the URL from GlobalState or use the fallback
local url = GlobalState.MissionJSONLoaderSurrogateURL or GetConvar("missionJsonLoader_surrogateFallbackUrl", defaultFallbackUrl)
-- This directive can only be a string
if type(url) ~= "string" then return end
foundMapDirectiveData = url
mapDirectiveDataType = "url"
hasAnyUGCDirectives = true
end, function() end)
end)
AddEventHandler("onServerResourceStart", function(resourceName)
-- Only do anything when the current map is the resource given
if resourceName ~= GlobalState.CurrentMap then return end
-- Once we've processed directives, get our MissionJSON string and update the GlobalState for clients to have fun with (om nom nom)
if hasAnyUGCDirectives then
-- Make a variable to save the JSON for server-side processing
local MissionJSON = false
-- Process whatever data we got depending on the directive type
if mapDirectiveDataType == "raw" and foundMapDirectiveData then
-- The easiest type to deal with, just chuck it on GlobalState and it can cause errors if whoever set the map up was stupid.
MissionJSON = foundMapDirectiveData
elseif mapDirectiveDataType == "resourcefile" and foundMapDirectiveData then
-- Seeing as we have the resource name, it's trivial to just grab the file.
local fileContent = LoadResourceFile(resourceName, foundMapDirectiveData)
-- If the file is empty or there wasn't a file to begin with, something went wrong.
if fileContent ~= nil and fileContent ~= "" then
MissionJSON = fileContent
end
elseif mapDirectiveDataType == "url" and foundMapDirectiveData then
-- We have a nice little function to get and cache URLs so we'll just call that.
local urlContent = GetUGCURLContent(foundMapDirectiveData)
-- If there is no url content returned, something went wrong
if urlContent then
MissionJSON = urlContent
end
end
-- Process the MissionJSON if its a truthy value otherwise, provide a detailed error
if MissionJSON then
local parserOutput, err = ParseMissionJSON(MissionJSON)
if type(parserOutput) == "table" then
-- Put the parsed table directly on GlobalState. Why wasn't I doing this before? I don't know.
GlobalState.CurrentMapUGC = parserOutput
else
print(string.format(
"MissionJSONLoader: The map %s contained or pointed to MissionJSON that we were unable to process.%s",
resourceName,
err and ("\nParser Error: "..err) or ""
))
end
else
-- It may have a directive but we couldn't get the data, oh well..
print(string.format(
"MissionJSONLoader: The map %s contained a MissionJSON map directive but we were unable to retrieve it.\n\tType: %s\n\tData: %s",
resourceName,
mapDirectiveDataType,
foundMapDirectiveData
))
end
end
-- Update the polling variable for connected clients, connecting clients will just be able to load it as it will be part of state!
GlobalState.CurrentMapMissionJSONChecked = true
end)