· 6 years ago · Oct 11, 2019, 06:48 PM
1MySQL = module("vrp_mysql", "MySQL")
2
3local Proxy = module("lib/Proxy")
4local Tunnel = module("lib/Tunnel")
5local Lang = module("lib/Lang")
6Debug = module("lib/Debug")
7
8local config = module("cfg/base")
9local version = module("version")
10Debug.active = config.debug
11MySQL.debug = config.debug
12
13-- open MySQL connection
14MySQL.createConnection("vRP", config.db.host,config.db.user,config.db.password,config.db.database)
15
16-- versioning
17print("[vRP] launch version "..version)
18--[[
19PerformHttpRequest("https://raw.githubusercontent.com/ImagicTheCat/vRP/master/vrp/version.lua",function(err,text,headers)
20 if err == 0 then
21 text = string.gsub(text,"return ","")
22 local r_version = tonumber(text)
23 if version ~= r_version then
24 print("[vRP] WARNING: A new version of vRP is available here https://github.com/ImagicTheCat/vRP, update to benefit from the last features and to fix exploits/bugs.")
25 end
26 else
27 print("[vRP] unable to check the remote version")
28 end
29end, "GET", "")
30--]]
31
32vRP = {}
33Proxy.addInterface("vRP",vRP)
34
35tvRP = {}
36Tunnel.bindInterface("vRP",tvRP) -- listening for client tunnel
37
38-- load language
39local dict = module("cfg/lang/"..config.lang) or {}
40vRP.lang = Lang.new(dict)
41
42-- init
43vRPclient = Tunnel.getInterface("vRP","vRP") -- server -> client tunnel
44
45vRP.users = {} -- will store logged users (id) by first identifier
46vRP.rusers = {} -- store the opposite of users
47vRP.user_tables = {} -- user data tables (logger storage, saved to database)
48vRP.user_tmp_tables = {} -- user tmp data tables (logger storage, not saved)
49vRP.user_sources = {} -- user sources
50
51-- queries
52MySQL.createCommand("vRP/base_tables",[[
53CREATE TABLE IF NOT EXISTS vrp_users(
54 id INTEGER AUTO_INCREMENT,
55 last_login VARCHAR(100),
56 whitelisted BOOLEAN,
57 banned BOOLEAN,
58 CONSTRAINT pk_user PRIMARY KEY(id)
59);
60CREATE TABLE IF NOT EXISTS vrp_user_ids(
61 identifier VARCHAR(100),
62 user_id INTEGER,
63 CONSTRAINT pk_user_ids PRIMARY KEY(identifier),
64 CONSTRAINT fk_user_ids_users FOREIGN KEY(user_id) REFERENCES vrp_users(id) ON DELETE CASCADE
65);
66CREATE TABLE IF NOT EXISTS vrp_user_data(
67 user_id INTEGER,
68 dkey VARCHAR(100),
69 dvalue TEXT,
70 CONSTRAINT pk_user_data PRIMARY KEY(user_id,dkey),
71 CONSTRAINT fk_user_data_users FOREIGN KEY(user_id) REFERENCES vrp_users(id) ON DELETE CASCADE
72);
73CREATE TABLE IF NOT EXISTS vrp_srv_data(
74 dkey VARCHAR(100),
75 dvalue TEXT,
76 CONSTRAINT pk_srv_data PRIMARY KEY(dkey)
77);
78]])
79
80MySQL.createCommand("vRP/create_user","INSERT INTO vrp_users(whitelisted,banned) VALUES(false,false); SELECT LAST_INSERT_ID() AS id")
81MySQL.createCommand("vRP/add_identifier","INSERT INTO vrp_user_ids(identifier,user_id) VALUES(@identifier,@user_id)")
82MySQL.createCommand("vRP/userid_byidentifier","SELECT user_id FROM vrp_user_ids WHERE identifier = @identifier")
83
84MySQL.createCommand("vRP/set_userdata","REPLACE INTO vrp_user_data(user_id,dkey,dvalue) VALUES(@user_id,@key,@value)")
85MySQL.createCommand("vRP/get_userdata","SELECT dvalue FROM vrp_user_data WHERE user_id = @user_id AND dkey = @key")
86
87MySQL.createCommand("vRP/set_srvdata","REPLACE INTO vrp_srv_data(dkey,dvalue) VALUES(@key,@value)")
88MySQL.createCommand("vRP/get_srvdata","SELECT dvalue FROM vrp_srv_data WHERE dkey = @key")
89
90MySQL.createCommand("vRP/get_banned","SELECT banned FROM vrp_users WHERE id = @user_id")
91MySQL.createCommand("vRP/set_banned","UPDATE vrp_users SET banned = @banned WHERE id = @user_id")
92MySQL.createCommand("vRP/get_whitelisted","SELECT whitelisted FROM vrp_users WHERE id = @user_id")
93MySQL.createCommand("vRP/set_whitelisted","UPDATE vrp_users SET whitelisted = @whitelisted WHERE id = @user_id")
94MySQL.createCommand("vRP/set_last_login","UPDATE vrp_users SET last_login = @last_login WHERE id = @user_id")
95MySQL.createCommand("vRP/get_last_login","SELECT last_login FROM vrp_users WHERE id = @user_id")
96
97MySQL.createCommand("vRP/get_hours_played","SELECT * FROM vrp_users WHERE id = @user_id")
98MySQL.createCommand("vRP/update_hours_played","UPDATE vrp_users SET hoursPlayed = hoursPlayed + @hours WHERE id = @user_id")
99
100hoursPlayed = {}
101-- init tables
102print("[vRP] init base tables")
103MySQL.execute("vRP/base_tables")
104
105-- identification system
106
107--- sql.
108-- cbreturn user id or nil in case of error (if not found, will create it)
109function vRP.getUserIdByIdentifiers(ids, cbr)
110 local task = Task(cbr)
111
112 if ids ~= nil and #ids then
113 local i = 0
114
115 -- search identifiers
116 local function search()
117 i = i+1
118 if i <= #ids then
119 if not config.ignore_ip_identifier or (string.find(ids[i], "ip:") == nil) then -- ignore ip identifier
120 MySQL.query("vRP/userid_byidentifier", {identifier = ids[i]}, function(rows, affected)
121 if #rows > 0 then -- found
122 task({rows[1].user_id})
123 else -- not found
124 search()
125 end
126 end)
127 else
128 search()
129 end
130 else -- no ids found, create user
131 MySQL.query("vRP/create_user", {}, function(rows, affected)
132 if #rows > 0 then
133 local user_id = rows[1].id
134 -- add identifiers
135 for l,w in pairs(ids) do
136 if not config.ignore_ip_identifier or (string.find(w, "ip:") == nil) then -- ignore ip identifier
137 MySQL.execute("vRP/add_identifier", {user_id = user_id, identifier = w})
138 end
139 end
140
141 task({user_id})
142 else
143 task()
144 end
145 end)
146 end
147 end
148
149 search()
150 else
151 task()
152 end
153end
154
155-- return identification string for the source (used for non vRP identifications, for rejected players)
156function vRP.getSourceIdKey(source)
157 local ids = GetPlayerIdentifiers(source)
158 local idk = "idk_"
159 for k,v in pairs(ids) do
160 idk = idk..v
161 end
162
163 return idk
164end
165
166function vRP.getPlayerEndpoint(player)
167 return GetPlayerEP(player) or "0.0.0.0"
168end
169
170function vRP.getPlayerName(player)
171 return GetPlayerName(player) or "unknown"
172end
173
174--- sql
175function vRP.isBanned(user_id, cbr)
176 local task = Task(cbr, {false})
177
178 MySQL.query("vRP/get_banned", {user_id = user_id}, function(rows, affected)
179 if #rows > 0 then
180 task({rows[1].banned})
181 else
182 task()
183 end
184 end)
185end
186
187--- sql
188function vRP.setBanned(user_id,banned)
189 MySQL.execute("vRP/set_banned", {user_id = user_id, banned = banned})
190end
191
192--- sql
193function vRP.isWhitelisted(user_id, cbr)
194 local task = Task(cbr, {false})
195
196 MySQL.query("vRP/get_whitelisted", {user_id = user_id}, function(rows, affected)
197 if #rows > 0 then
198 task({rows[1].whitelisted})
199 else
200 task()
201 end
202 end)
203end
204
205--- sql
206function vRP.setWhitelisted(user_id,whitelisted)
207 MySQL.execute("vRP/set_whitelisted", {user_id = user_id, whitelisted = whitelisted})
208end
209
210--- sql
211function vRP.getLastLogin(user_id, cbr)
212 local task = Task(cbr,{""})
213 MySQL.query("vRP/get_last_login", {user_id = user_id}, function(rows, affected)
214 if #rows > 0 then
215 task({rows[1].last_login})
216 else
217 task()
218 end
219 end)
220end
221
222function vRP.setUData(user_id,key,value)
223 MySQL.execute("vRP/set_userdata", {user_id = user_id, key = key, value = value})
224end
225
226function vRP.getUData(user_id,key,cbr)
227 local task = Task(cbr,{""})
228
229 MySQL.query("vRP/get_userdata", {user_id = user_id, key = key}, function(rows, affected)
230 if #rows > 0 then
231 task({rows[1].dvalue})
232 else
233 task()
234 end
235 end)
236end
237
238function vRP.setSData(key,value)
239 MySQL.execute("vRP/set_srvdata", {key = key, value = value})
240end
241
242function vRP.getSData(key, cbr)
243 local task = Task(cbr,{""})
244
245 MySQL.query("vRP/get_srvdata", {key = key}, function(rows, affected)
246 if #rows > 0 then
247 task({rows[1].dvalue})
248 else
249 task()
250 end
251 end)
252end
253
254-- return user data table for vRP internal persistant connected user storage
255function vRP.getUserDataTable(user_id)
256 return vRP.user_tables[user_id]
257end
258
259function vRP.getUserTmpTable(user_id)
260 return vRP.user_tmp_tables[user_id]
261end
262
263function vRP.isConnected(user_id)
264 return vRP.rusers[user_id] ~= nil
265end
266
267function vRP.isFirstSpawn(user_id)
268 local tmp = vRP.getUserTmpTable(user_id)
269 return tmp and tmp.spawns == 1
270end
271
272function vRP.getUserId(source)
273 if source ~= nil then
274 local ids = GetPlayerIdentifiers(source)
275 if ids ~= nil and #ids > 0 then
276 return vRP.users[ids[1]]
277 end
278 end
279
280 return nil
281end
282
283-- return map of user_id -> player source
284function vRP.getUsers()
285 local users = {}
286 for k,v in pairs(vRP.user_sources) do
287 users[k] = v
288 end
289
290 return users
291end
292
293-- return source or nil
294function vRP.getUserSource(user_id)
295 return vRP.user_sources[user_id]
296end
297
298function vRP.ban(source,reason)
299 local user_id = vRP.getUserId(source)
300
301 if user_id ~= nil then
302 vRP.setBanned(user_id,true)
303 vRP.kick(source,"[Banned] "..reason)
304 end
305end
306
307function vRP.kick(source,reason)
308 DropPlayer(source,reason)
309end
310
311function vRP.getUserHoursPlayed(user_id)
312 if(hoursPlayed[user_id] ~= nil)then
313 return math.floor(hoursPlayed[user_id])
314 else
315 return 0
316 end
317end
318
319function tvRP.updateHoursPlayed(hours)
320 user_id = vRP.getUserId(source)
321 MySQL.execute("vRP/update_hours_played", {hours = hours, user_id = user_id})
322 hoursPlayed[user_id] = hoursPlayed[user_id] + hours
323 vRPsb.updateScoreboardPlayer({user_id, hours})
324end
325
326-- tasks
327
328function task_save_datatables()
329 TriggerEvent("vRP:save")
330
331 Debug.pbegin("vRP save datatables")
332 for k,v in pairs(vRP.user_tables) do
333 vRP.setUData(k,"vRP:datatable",json.encode(v))
334 end
335
336 Debug.pend()
337 SetTimeout(config.save_interval*1000, task_save_datatables)
338end
339task_save_datatables()
340
341-- handlers
342
343AddEventHandler("playerConnecting",function(name,setMessage, deferrals)
344 deferrals.defer()
345
346 local source = source
347 Debug.pbegin("playerConnecting")
348 local ids = GetPlayerIdentifiers(source)
349
350 if ids ~= nil and #ids > 0 then
351 deferrals.update("[vRP] Checking identifiers...")
352 vRP.getUserIdByIdentifiers(ids, function(user_id)
353 -- if user_id ~= nil and vRP.rusers[user_id] == nil then -- check user validity and if not already connected (old way, disabled until playerDropped is sure to be called)
354 if user_id ~= nil then -- check user validity
355 deferrals.update("[vRP] Checking banned...")
356 vRP.isBanned(user_id, function(banned)
357 if not banned then
358 deferrals.update("[vRP] Checking whitelisted...")
359 vRP.isWhitelisted(user_id, function(whitelisted)
360 if not config.whitelist or whitelisted then
361 Debug.pbegin("playerConnecting_delayed")
362 if vRP.rusers[user_id] == nil then -- not present on the server, init
363 -- init entries
364 vRP.users[ids[1]] = user_id
365 vRP.rusers[user_id] = ids[1]
366 vRP.user_tables[user_id] = {}
367 vRP.user_tmp_tables[user_id] = {}
368 vRP.user_sources[user_id] = source
369
370 -- load user data table
371 deferrals.update("[vRP] Loading datatable...")
372 vRP.getUData(user_id, "vRP:datatable", function(sdata)
373 local data = json.decode(sdata)
374 if type(data) == "table" then vRP.user_tables[user_id] = data end
375
376 -- init user tmp table
377 local tmpdata = vRP.getUserTmpTable(user_id)
378
379 deferrals.update("[vRP] Getting last login...")
380 vRP.getLastLogin(user_id, function(last_login)
381 tmpdata.last_login = last_login or ""
382 tmpdata.spawns = 0
383
384 -- set last login
385 local ep = vRP.getPlayerEndpoint(source)
386 local last_login_stamp = ep.." "..os.date("%H:%M:%S %d/%m/%Y")
387 MySQL.execute("vRP/set_last_login", {user_id = user_id, last_login = last_login_stamp})
388
389 -- trigger join
390 print("[vRP] "..name.." ("..vRP.getPlayerEndpoint(source)..") joined (user_id = "..user_id..")")
391 TriggerEvent("vRP:playerJoin", user_id, source, name, tmpdata.last_login)
392 deferrals.done()
393 end)
394 end)
395 else -- already connected
396 print("[vRP] "..name.." ("..vRP.getPlayerEndpoint(source)..") re-joined (user_id = "..user_id..")")
397 TriggerEvent("vRP:playerRejoin", user_id, source, name)
398 deferrals.done()
399
400 -- reset first spawn
401 local tmpdata = vRP.getUserTmpTable(user_id)
402 tmpdata.spawns = 0
403 end
404
405 Debug.pend()
406 else
407 print("[vRP] "..name.." ("..vRP.getPlayerEndpoint(source)..") rejected: not whitelisted (user_id = "..user_id..")")
408 deferrals.done("[vRP] Not whitelisted (user_id = "..user_id..").")
409 end
410 end)
411 else
412 print("[vRP] "..name.." ("..vRP.getPlayerEndpoint(source)..") rejected: banned (user_id = "..user_id..")")
413 deferrals.done("[vRP] Banned (user_id = "..user_id..").")
414 end
415 end)
416 else
417 print("[vRP] "..name.." ("..vRP.getPlayerEndpoint(source)..") rejected: identification error")
418 deferrals.done("[vRP] Identification error.")
419 end
420 end)
421 else
422 print("[vRP] "..name.." ("..vRP.getPlayerEndpoint(source)..") rejected: missing identifiers")
423 deferrals.done("[vRP] Missing identifiers.")
424 end
425 Debug.pend()
426end)
427
428AddEventHandler("playerDropped",function(reason)
429 local source = source
430 Debug.pbegin("playerDropped")
431
432 -- remove player from connected clients
433 vRPclient.removePlayer(-1,{source})
434
435
436 local user_id = vRP.getUserId(source)
437
438 if user_id ~= nil then
439 TriggerEvent("vRP:playerLeave", user_id, source)
440
441 -- save user data table
442 vRP.setUData(user_id,"vRP:datatable",json.encode(vRP.getUserDataTable(user_id)))
443
444 print("[vRP] "..vRP.getPlayerEndpoint(source).." disconnected (user_id = "..user_id..")")
445 vRP.users[vRP.rusers[user_id]] = nil
446 vRP.rusers[user_id] = nil
447 vRP.user_tables[user_id] = nil
448 vRP.user_tmp_tables[user_id] = nil
449 vRP.user_sources[user_id] = nil
450 end
451 Debug.pend()
452end)
453
454RegisterServerEvent("vRPcli:playerSpawned")
455AddEventHandler("vRPcli:playerSpawned", function()
456 Debug.pbegin("playerSpawned")
457 -- register user sources and then set first spawn to false
458 local user_id = vRP.getUserId(source)
459 local player = source
460 if user_id ~= nil then
461 vRP.user_sources[user_id] = source
462 local tmp = vRP.getUserTmpTable(user_id)
463 tmp.spawns = tmp.spawns+1
464 local first_spawn = (tmp.spawns == 1)
465
466 if first_spawn then
467 -- first spawn, reference player
468 -- send players to new player
469 for k,v in pairs(vRP.user_sources) do
470 vRPclient.addPlayer(source,{v})
471 end
472 -- send new player to all players
473 vRPclient.addPlayer(-1,{source})
474 end
475
476 -- set client tunnel delay at first spawn
477 Tunnel.setDestDelay(player, config.load_delay)
478
479 -- show loading
480 vRPclient.setProgressBar(player,{"vRP:loading", "botright", "Loading...", 0,0,0, 100})
481
482 SetTimeout(2000, function() -- trigger spawn event
483 TriggerEvent("vRP:playerSpawn",user_id,player,first_spawn)
484
485 SetTimeout(config.load_duration*1000, function() -- set client delay to normal delay
486 Tunnel.setDestDelay(player, config.global_delay)
487 vRPclient.removeProgressBar(player,{"vRP:loading"})
488 end)
489 end)
490 end
491
492 Debug.pend()
493end)
494
495RegisterServerEvent("vRP:playerDied")