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