· 8 years ago · Feb 06, 2018, 08:38 AM
1-- https://github.com/danielga/gmod_luasocket/releases
2ad = ad or {}
3
4local id_seller = "»-- идентификатор продавца
5local password = "" --пароль
6
7local auth = {
8 Host = "db1.myarena.ru", --Ð·Ð´ÐµÑ ÑƒÐºÐ°Ð¶Ð¸ Ð°Ð´Ñ€ÐµÑ Ð±Ð´
9 Port = 3306, --Ð·Ð´ÐµÑ ÑƒÐºÐ°Ð¶Ð¸ порт бд
10 Username = "", --Ð·Ð´ÐµÑ ÑƒÐºÐ°Ð¶Ð¸ Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð±Ð´
11 Password = "", --Ð·Ð´ÐµÑ ÑƒÐºÐ°Ð¶Ð¸ пароль Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð±Ð´
12 Database = "vvbnnn_donatefust" --от"
13 тово что мы в итемÑторе поÑелимÑÑ Ð½Ð¸Ñ‡Ðµ плохово не будет таблицы то разные
14}
15
16
17local sql = {}
18sql.Connected = false
19sql.Queries = {}
20
21file.CreateDir("autodonate")
22local function log(text, silent)
23 text = text.."\n"
24 if !silent then Msg("[autodonate] "..text) end
25 file.Append(os.date("autodonate/%d-%m-%y.txt"), os.date("[%c] ")..text)
26end
27
28function sql:Log( text )
29 print( "[autodonate MySQL] " .. text )
30end
31
32function sql:Initialize()
33 require( "mysqloo" )
34
35 sql.Database = mysqloo.connect( auth.Host, auth.Username, auth.Password, auth.Database, auth.Port )
36
37 sql.Database.onConnected = function( )
38 self.Connected = true
39
40 self:Query( "CREATE TABLE IF NOT EXISTS ad_pdata ( infoid VARCHAR( 32 ) NOT NULL, value BLOB NULL, PRIMARY KEY ( infoid ) );" )
41 --for _, v in ipairs( sql.Queries ) do
42 while ( #sql.Queries > 0 ) do
43 local query = table.remove( sql.Queries, 1 )
44 self:Query( query[ 1 ], query[ 2 ], unpack( query[ 3 ] ) )
45 end
46
47 self:Log( "Connection succesful!" )
48 end
49
50 sql.Database.onConnectionFailed = function( db, err )
51 sql:Log( "Connection failed: " .. err )
52
53 self.Connected = false
54
55 timer.Simple( 10, function()
56 db:connect()
57 end )
58 end
59
60 self:Log( "Connecting to database..." )
61
62 sql.Database:connect()
63end
64
65function sql:Query( sql, callback, ... )
66 if ( self.Database and self.Connected ) then
67 local args = {}
68 for _, val in ipairs( { ... } ) do
69 val = tostring( val )
70 val = self.Database:escape( val )
71
72 table.insert( args, val )
73 end
74
75 local formatted = string.format( sql, unpack( args ) )
76 local query = self.Database:query( formatted )
77 query.onSuccess = function( _, data )
78 if ( callback ) then
79 callback( data )
80 end
81 end
82
83 query.onError = function( _, err )
84 if ( self.Database:status() == mysqloo.DATABASE_NOT_CONNECTED ) then
85 table.insert( self.Queries, { formatted, callback, {} } )
86 self.Database:connect()
87
88 self.Connected = false
89
90 self:Log( "Lost connection to server, reconnecting..." )
91 else
92 self:Log( "Query failed: " .. err )
93 end
94 end
95
96 query:start()
97 else
98 self:Log( "Query attempted while disconnected." )
99 table.insert( self.Queries, { sql, callback, { ... } } )
100 end
101end
102
103function sql:GetPData(steamid, callback)
104 if !isstring(steamid) then steamid = steamid:SteamID64() end
105 self:Query( "SELECT value FROM ad_pdata WHERE infoid = '%s' LIMIT 1", callback, steamid )
106end
107
108local function retryRemove(steamid)
109 sql:GetPData(steamid, function(a)
110 if a or a[1] or a[1].value then
111 log("БД не удалила значение, пробуем ещё раз через пол Ñекунды", true)
112 timer.Simple(0.5, function()
113 sql:RemovePData(steamid)
114 retryRemove(steamid)
115 end)
116 end
117 end)
118end
119
120function sql:RemovePData( steamid )
121 if !isstring(steamid) then steamid = steamid:SteamID64() end
122 self:Query( "DELETE FROM ad_pdata WHERE infoid = '%s'", nil, steamid )
123 timer.Simple(0.1, function() retryRemove(steamid) end)
124end
125
126local function retrySet(steamid, value)
127 sql:GetPData(steamid, function(a)
128 if !a or !a[1] or !a[1].value or a[1].value != value then
129 timer.Simple(0.5, function()
130 sql:SetPData(steamid, value)
131 retrySet(steamid, value)
132 end)
133 end
134 end)
135end
136
137function sql:SetPData( steamid, value )
138 if !isstring(steamid) then steamid = steamid:SteamID64() end
139 self:Query( "REPLACE INTO ad_pdata ( infoid, value ) VALUES ( '%s', '%s' )", nil, steamid, value )
140 timer.Simple(0.1, function() retrySet(steamid, value) end)
141end
142
143
144sql:Initialize()
145
146ad.sql = sql
147
148------------------------------------------------------------
149
150local md5 = include("ad_md5.lua")
151
152local red = Color(255, 0, 0)
153local function onError(reason, sid, code)
154 reason = "\n============AUTODONATE ERROR============\n "..reason.."\n========================================\n SteamID: "..sid.." || code: "..code.."\n========================================\n\n"
155 log(reason, true)
156 MsgC(red, reason, color_white)
157end
158
159
160local invKeys = (file.Read("autodonate/invkeys.txt") or ""):Split("\n")
161
162local function processData(statuscode, body, sid, code)
163 if statuscode != 200 then return onError("код ответа равен не 200 ("..statuscode..")", sid, code) end
164 body = util.JSONToTable(body)
165 if !body then return onError("ответ пришел не в JSON формате", sid, code) end
166 if body.retval != "0" then return onError("Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ðµ выполнен!\n код: "..body.retval.."\n опиÑание ошибки: "..body.retdesc, sid, code) end
167 if util.SteamIDFrom64(sid) == "STEAM_0:0:0" then return onError("SteamID неверен!", sid, code) end
168
169 body.inv = tostring(body.inv)
170
171 for k in pairs(invKeys) do
172 if tostring(k) == body.inv then return log("Ignoring duped inv key "..k) end
173 end
174
175 local val = math.floor(tonumber(body.cnt_goods:Replace(",", ".")))
176 if !val then return onError("JOPA ERROR CNT_GOODS IS NIL:\n"..util.TableToJSON(body, true), sid, code) end
177 log(sid.." byed "..val.."p")
178
179 local ply = player.GetBySteamID64(sid)
180 if ply then
181 ad.add(ply, val, true)
182 else
183 log(sid.." is offline, adding "..val.."p to MySQL")
184 sql:GetPData(sid, function(a)
185 local data = util.JSONToTable(a and a[1] and a[1].value or "{\"balance\":0}")
186 data.balance = data.balance+val
187 sql:SetPData(sid, util.TableToJSON(data))
188 end)
189 end
190
191 invKeys[body.inv] = true
192 file.Append("autodonate/invkeys.txt", body.inv.."\n")
193 log("writed inv key "..body.inv)
194end
195
196local b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
197
198function dec(data)
199 data = string.gsub(data, '[^'..b..'=]', '')
200 return (data:gsub('.', function(x)
201 if (x == '=') then return '' end
202 local r,f='',(b:find(x)-1)
203 for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
204 return r;
205 end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
206 if (#x ~= 8) then return '' end
207 local c=0
208 for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
209 return string.char(c)
210 end))
211end
212
213concommand.Add("ad_go", function(ply, _, req)
214 if IsValid(ply) then return ply:Kick("net") end
215 req = dec(req[1]):Split("&"..ad.config.param.."=")
216
217 if !req[1] or !req[2] then
218 log("wrong request: "..tostring(req[1]).." sid: "..tostring(req[2]))
219 return
220 end
221
222 local code, sid = req[1], req[2]
223 log("sending POST: code: ["..code.."] sid: ["..sid.."]")
224 HTTP{
225 method = "POST",
226 url = "http://shop.digiseller.ru/xml/check_unique_code.asp",
227 type = "application/json",
228 body = [[{"id_seller":"]]..id_seller..[[","unique_code":"]]..code..[[","sign":"]]..md5.sumhexa(id_seller..":"..code..":"..password)..[["}]],
229 failed = function(reason) onError(reason, sid, code) end,
230 success = function(status, body) processData(status, body, sid, code) end
231 }
232end)
233
234concommand.Add("ad_retry",function(ply, _, arg)
235 if IsValid(ply) then return end
236 local code, sid = arg[1], arg[2]
237 if !code or !sid then return print("ad_retry wrong arguments") end
238 log("sending POST: code: "..code.." sid: "..sid)
239 HTTP{
240 method = "POST",
241 url = "http://shop.digiseller.ru/xml/check_unique_code.asp",
242 type = "application/json",
243 body = [[{"id_seller":"]]..id_seller..[[","unique_code":"]]..code..[[","sign":"]]..md5.sumhexa(id_seller..":"..code..":"..password)..[["}]],
244 failed = function(reason) onError(reason, sid, code) end,
245 success = function(status, body) processData(status, body, sid, code) end
246 }
247end)
248
249------------------------------------------------------
250local sip = "autodonate_error_what"
251timer.Simple(1, function()
252 sip = game.GetIPAddress()
253 ad.sip = sip
254 if sip == "0.0.0.0:27015" then
255 http.Fetch("https://api.ipify.org", function(ip)
256 sip = ip..":27015"
257 ad.sip = sip
258 end)
259 end
260end)
261
262util.AddNetworkString("autodonate")
263
264local function update(ply)
265 local tbl = {balance = ply.ad.balance}
266 if ply.ad[sip] then
267 tbl.group = ply.ad[sip].group
268 tbl.group_expires = ply.ad[sip].group_expires
269 end
270 net.Start("autodonate")
271 net.WriteTable(tbl)
272 net.WriteString(ply:GetPData("ad_weapons", ""))
273 net.WriteBool(false)
274 net.Send(ply)
275end
276
277function ad.save(ply, upd)
278 sql:SetPData(ply, util.TableToJSON(ply.ad))
279 if upd then update(ply) end
280end
281
282function ad.set(ply, value)
283 ply = isentity(ply) and ply or false
284 assert(ply, "игрок не на Ñервере!")
285 log("изменение Ñчёта "..ply:SteamID64()..", было "..ply.ad.balance.."p, Ñтало: "..value, true)
286 ply.ad.balance = value
287 ad.save(ply, true)
288end
289
290
291function ad.add(ply, amount, msg)
292 ply = isentity(ply) and ply or false
293 assert(ply, "игрок не на Ñервере!")
294 ad.set(ply, ply.ad.balance+amount)
295 log(ply:SteamID64().." пополнил Ñчет на "..amount.."Ñ€, Ñчет равен "..ply.ad.balance.."p", true)
296 if msg then ad.msg(ply, "Ð’Ñ‹ пополнили Ñчет на "..amount.."Ñ€") end
297end
298
299function ad.msg(ply, msg, err)
300 local tbl = {balance = ply.ad.balance}
301 if ply.ad[sip] then
302 tbl.group = ply.ad[sip].group
303 tbl.group_expires = ply.ad[sip].group_expires
304 end
305 net.Start("autodonate")
306 net.WriteTable(tbl)
307 net.WriteString(ply:GetPData("ad_weapons", ""))
308 net.WriteBool(true)
309 net.WriteString(msg)
310 net.WriteBool(err)
311 net.Send(ply)
312end
313
314function ad.removeGroup(sid)
315 if !isstring(sid) then sid = sid:SteamID64() end
316 sql:GetPData(sid, function(a)
317 local data = util.JSONToTable(a and a[1] and a[1].value or "{\"balance\":0}")
318 data[sip] = nil
319 sql:SetPData(sid, util.TableToJSON(data))
320 end)
321end
322
323local function timedGroup(ply, group)
324 ulx.adduser(NULL, ply, group)
325 ply.ad[sip] = {}
326 ply.ad[sip].group = group
327 ply.ad[sip].group_expires = os.time()+2591999
328end
329
330
331hook.Add("PlayerInitialSpawn", "autodonate", function(ply)
332 if !ply:IsBot() then
333 sql:GetPData(ply, function(a)
334 ply.ad = util.JSONToTable(a and a[1] and a[1].value or "{\"balance\":0}")
335 update(ply)
336 end)
337 end
338end)
339
340timer.Create("ad.checkGroups", 1, 0, function()
341 for _, ply in pairs(player.GetAll()) do
342 if !ply:IsBot() and ply.ad and ply.ad[sip] and ply.ad[sip].group:gsub("_inf", "") != ply:GetUserGroup() then
343 ply.ad[sip] = nil
344 update(ply)
345 elseif !ply:IsBot() and ply.ad and ply.ad[sip] and ply.ad[sip].group_expires and ply.ad[sip].group_expires-os.time() <= 0 then
346 if ply.ad[sip].group == ply:GetUserGroup() then
347 log(ply:SteamID64().." был ÑнÑÑ‚ Ñ Ð¿Ñ€Ð¸Ð²ÐµÐ»ÐµÐ½Ð¸Ð¸ "..ply.ad[sip].group, true)
348 ulx.adduser(NULL, ply, "user")
349 ad.msg(ply, "МеÑÑц прошёл - донат группа ÑнÑта")
350 end
351 ply.ad[sip] = nil
352 if ply.ad.balance == 0 then
353 sql:RemovePData(ply)
354 else ad.save(ply) end
355 update(ply)
356 end
357 end
358end)
359
360hook.Add("PostPlayerDeath", "ad_death", function(ply)
361 ply.ad_weps = nil
362 ply.ad_jmp = nil
363 ply.ad_hp = nil
364 ply.ad_ar = nil
365end)
366
367concommand.Add("ad_get", function(ply, _, arg)
368
369 arg = arg[1]
370 if table.HasValue(ply:GetPData("ad_weapons", ""):Split(" "), arg) then
371 ply.ad_weps = ply.ad_weps or {}
372
373 if arg == "_hp" and !ply.ad_hp then
374 ply.ad_hp = true
375 ply:SetHealth(250)
376 ad.msg(ply, "Ð’Ñ‹ взÑли 250 хп")
377 elseif arg == "_ar" and !ply.ad_ar then
378 ply.ad_ar = true
379 ply:SetArmor(228)
380 ad.msg(ply, "Ð’Ñ‹ взÑли 228 брони")
381 elseif arg == "_jmp" and !ply.ad_jmp then
382 ply.ad_jmp = true
383 ply:SetJumpPower(ply:GetJumpPower()*2)
384 ad.msg(ply, "Вы активировали двойной прыжок")
385 elseif !ply.ad_weps[arg] then
386 ply:Give(arg)
387 ply.ad_weps[arg] = true
388 ad.msg(ply, "Ð’Ñ‹ взÑли "..arg)
389 end
390 end
391end)
392
393concommand.Add("ad_buywep", function(ply, _, arg)
394 arg = arg[1]
395 for _, v in pairs(ad.categories) do
396 local try = v[arg]
397 if try then
398 if ply.ad.balance < try.p then
399 log(ply:SteamID64().." попыталÑÑ Ð½Ð°ÐµÐ±Ð°Ñ‚ÑŒ донат (PLUS) => Что: "..arg..", Ð‘Ð°Ð»Ð°Ð½Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ°:"..(ply.ad.balance.."p")..", Цена предмета: "..try.p)
400 return ply:Kick("siebalsa")
401 end
402 if os.time()-(ply.ad_lastByed or 0) < 5 then return ad.msg(ply, "Подождите 5 Ñекунд перед покупкой Ñледующего предмета", true) end
403
404 log(ply:SteamID64().." купил(PLUS) "..arg.." за "..try.p.."p", true)
405 local err, msg = try.func(ply)
406 ad.msg(ply, msg)
407 if err then
408 ply.ad_lastByed = os.time()
409 return
410 end
411 ad.set(ply, ply.ad.balance-try.p)
412 ply.ad_lastByed = os.time()
413 end
414 end
415end)
416
417concommand.Add("autodonate_buy", function(ply, _, arg)
418 arg = arg[1]
419 local try = ad.config.items[arg]
420 if !try or ply.ad.balance < try.p or (ply.ad[sip] and ply.ad[sip].group == try) then
421 log(ply:SteamID64().." попыталÑÑ Ð½Ð°ÐµÐ±Ð°Ñ‚ÑŒ донат => Что: "..arg..", Ð‘Ð°Ð»Ð°Ð½Ñ Ð¸Ð³Ñ€Ð¾ÐºÐ°:"..(ply.ad.balance.."p")..(try and ", Цена предмета: "..try.p or "").." ещё инфа: "..(ply.ad[sip] and ply.ad[sip].group == try and " уже имеет Ñту привилегию" or "нет") , true)
422 return ply:Kick("siebalsa")
423 end
424 if os.time()-(ply.ad_lastByed or 0) < 5 then return ad.msg(ply, "Подождите 5 Ñекунд перед покупкой Ñледующего предмета", true) end
425
426 log(ply:SteamID64().." купил "..arg.." за "..try.p.."p", true)
427 if try.func then
428 local err, msg = try.func(ply)
429 ad.msg(ply, msg)
430 if err then
431 ply.ad_lastByed = os.time()
432 return
433 end
434 else
435 timedGroup(ply, arg)
436 ad.msg(ply, "Ð’Ñ‹ уÑпешно купили привилегию "..try[1].." за "..try.p.."Ñ€")
437 end
438 ad.set(ply, ply.ad.balance-try.p)
439 ply.ad_lastByed = os.time()
440end)