· 9 years ago · Oct 26, 2016, 04:04 PM
1--[[
2 Name: sv_mysql_player.lua
3 For: TalosLife
4 By: TalosLife, Thanks to TehBigA for help!
5]]--
6
7GM.SQL.m_tblDiffFlags = (GAMEMODE or GM).SQL.m_tblDiffFlags or {}
8GM.SQL.m_intSnapshotInterval = (GAMEMODE or GM).Config.SQLSnapshotRate
9
10function GM.SQL:LogPlayerQuery( intCharID, strQuery )
11 if true then return end
12
13 if not file.IsDir( "sql_log", "DATA" ) then file.CreateDir( "sql_log" ) end
14 if not file.Exists( "sql_log/log_".. intCharID.. ".txt", "DATA" ) then
15 file.Write( "sql_log/log_".. intCharID.. ".txt", "" )
16 end
17
18 file.Append( "sql_log/log_".. intCharID.. ".txt", os.date().. " - ".. strQuery.. "\n\n" )
19end
20
21function GM.SQL:LogPlayerDiff( strSID64, strData )
22 if true then return end
23
24 if not file.IsDir( "sql_diff_log", "DATA" ) then file.CreateDir( "sql_diff_log" ) end
25 if not file.Exists( "sql_diff_log/log_".. strSID64.. ".txt", "DATA" ) then
26 file.Write( "sql_diff_log/log_".. strSID64.. ".txt", "" )
27 end
28
29 file.Append( "sql_diff_log/log_".. strSID64.. ".txt", os.date().. " - ".. strData.. "\n\n" )
30end
31
32function GM.SQL:InitGamemodeTables()
33 self:LogMsg( "Initializing gamemode tables..." )
34
35 self:PooledQueryWrite( 1, [[CREATE TABLE IF NOT EXISTS `players` (
36 `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
37 `steamid` VARCHAR(255) NOT NULL,
38 PRIMARY KEY (`id`),
39 INDEX `steamid` (`steamid`)
40 ) ENGINE=InnoDB;]] )
41
42 self:PooledQueryWrite( 2, [[CREATE TABLE IF NOT EXISTS `characters` (
43 `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
44 `player_id` INT(10) UNSIGNED NOT NULL,
45 `first_name` VARCHAR(255) NOT NULL DEFAULT 'Minge',
46 `last_name` VARCHAR(255) NOT NULL DEFAULT 'Bag',
47 `sex` ENUM('male','female') NULL DEFAULT NULL,
48 `model` VARCHAR(255) NOT NULL,
49 `model_override` VARCHAR(255) NULL DEFAULT NULL,
50 `skin` SMALLINT NOT NULL DEFAULT 0,
51 `money_held` INT(10) UNSIGNED NOT NULL DEFAULT '0',
52 `money_bank` INT(10) UNSIGNED NOT NULL DEFAULT '0',
53 `vehicles` LONGTEXT NULL,
54 `created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
55 PRIMARY KEY (`id`),
56 INDEX `player_id` (`player_id`),
57 INDEX `first_name_last_name` (`first_name`, `last_name`)
58 ) ENGINE=InnoDB;]] )
59
60 self:PooledQueryWrite( 3, [[CREATE TABLE IF NOT EXISTS `character_inventory` (
61 `character_id` INT(10) UNSIGNED NOT NULL,
62 `item_name` VARCHAR(255) NOT NULL,
63 `item_count` INT(10) UNSIGNED NOT NULL,
64 UNIQUE INDEX `character_id_item_name` (`character_id`, `item_name`),
65 INDEX `character_id` (`character_id`)
66 ) ENGINE=InnoDB;]] )
67
68 self:PooledQueryWrite( 4, [[CREATE TABLE IF NOT EXISTS `character_equipped` (
69 `character_id` INT(10) UNSIGNED NOT NULL,
70 `slot_name` VARCHAR(255) NOT NULL,
71 `item_name` VARCHAR(255) NOT NULL,
72 UNIQUE INDEX `character_id_slot_name` (`character_id`, `slot_name`),
73 INDEX `character_id` (`character_id`)
74 ) ENGINE=InnoDB;]] )
75
76 self:PooledQueryWrite( 5, [[CREATE TABLE IF NOT EXISTS `character_data_store` (
77 `character_id` INT(10) UNSIGNED NOT NULL,
78 `key` VARCHAR(255) NOT NULL,
79 `value` LONGTEXT NULL,
80 UNIQUE INDEX `character_id_key` (`character_id`, `key`),
81 INDEX `character_id` (`character_id`),
82 INDEX `key` (`key`)
83 ) ENGINE=InnoDB;]] )
84
85 hook.Call( "GamemodeInitSQLTables", GAMEMODE )
86end
87
88--Player data
89local pmeta = debug.getregistry().Player
90function pmeta:GetPlayerSQLID()
91 return self.m_intSQLID
92end
93
94function pmeta:SetPlayerSQLID( intID )
95 self.m_intSQLID = tonumber( intID )
96end
97
98function GM.SQL:LoadPlayerID( pPlayer, funcOnLoaded )
99 self:QueryReadOnly( ([[SELECT p.id FROM players p WHERE p.steamid = '%s']]):format(pPlayer:SteamID()), function( tblData, q )
100 if not IsValid( pPlayer ) then return end
101
102 local pl = tblData[1]
103 if not pl or not pl.id then
104 self:InsertNewPlayer( pPlayer, funcOnLoaded )
105 else
106 pPlayer:SetPlayerSQLID( pl.id )
107 funcOnLoaded( pl.id )
108 end
109 end )
110end
111
112function GM.SQL:InsertNewPlayer( pPlayer, funcOnInsert )
113 self:PooledQueryWrite( self:GetPlayerPoolID(pPlayer:SteamID64()), ([[INSERT INTO players SET steamid='%s']]):format(pPlayer:SteamID()), function( tblData, q )
114 if not IsValid( pPlayer ) then return end
115
116 local plID = q.lastid
117 pPlayer:SetPlayerSQLID( plID )
118 funcOnInsert( plID )
119 end )
120end
121
122--Character data
123function GM.SQL:InsertNewCharacter( pPlayer, tblCharData, funcCallback )
124 self:PooledQueryWrite( self:GetPlayerPoolID(pPlayer:SteamID64()), ([[INSERT INTO characters SET
125 player_id=%d,
126 first_name='%s',
127 last_name='%s',
128 sex='%s',
129 model='%s',
130 model_override='%s',
131 skin=%d,
132 money_held=%d,
133 money_bank=%d,
134 vehicles='%s'
135 ]] ):format(
136 pPlayer:GetPlayerSQLID(),
137 SQLStr( tblCharData.Name.First, true ),
138 SQLStr( tblCharData.Name.Last, true ),
139 tblCharData.Sex == 0 and "male" or "female",
140 tblCharData.Model.Base,
141 tblCharData.Model.Overload,
142 tblCharData.Skin,
143 tblCharData.Money.Wallet,
144 tblCharData.Money.Bank,
145 util.TableToJSON( tblCharData.Vehicles )
146 ), function( tblData, q )
147 local charID = q.lastid
148 local workerID = self:GetPlayerPoolID( pPlayer:SteamID64() )
149
150 --insert inventory
151 self:InsertCharacterFullInventory( workerID, charID, tblCharData.Inventory )
152 --insert equipped
153 self:InsertCharacterFullEquippedItems( workerID, charID, tblCharData.Equipped )
154 --insert save table
155 self:InsertCharacterFullDataStore( workerID, charID, tblCharData.SaveTable )
156
157 if not IsValid( pPlayer ) then return end
158 funcCallback( charID )
159 end )
160end
161
162function GM.SQL:LoadPlayerCharacters( pPlayer, funcOnLoaded )
163 self:QueryReadOnly( ([[SELECT c.* FROM characters c JOIN players p ON p.id = c.player_id WHERE p.steamid = '%s']]):format(pPlayer:SteamID()), function( tblData, q )
164 if not IsValid( pPlayer ) then return end
165 local characters = {}
166 local to_load = #tblData
167 local char_loaded = function()
168 to_load = to_load - 1
169
170 if to_load == 0 then
171 funcOnLoaded( characters )
172 end
173 end
174
175 if to_load == 0 then
176 funcOnLoaded( characters )
177 return
178 end
179
180 for k, v in ipairs( tblData ) do
181 local char = {
182 Id = v.id,
183 Name = {
184 First = v.first_name,
185 Last = v.last_name,
186 },
187 Sex = v.sex == "male" and 0 or 1,
188 Model = {
189 Base = v.model,
190 Overload = v.model_override,
191 },
192 Skin = v.skin,
193 Money = {
194 Wallet = v.money_held,
195 Bank = v.money_bank,
196 },
197 Vehicles = util.JSONToTable( v.vehicles or "" ),
198 }
199
200 characters[v.id] = char
201
202 self:LoadCharacterData( char, char_loaded )
203 end
204 end )
205end
206
207function GM.SQL:LoadCharacterData( tblCharacter, funcOnLoaded )
208 local inv, equip, data_store
209 local part_loaded = function()
210 if inv and equip and data_store then
211 funcOnLoaded()
212 end
213 end
214
215 self:LoadCharacterInventory( tblCharacter.Id, function( tblData )
216 tblCharacter.Inventory = tblData
217 inv = true
218 part_loaded()
219 end )
220
221 self:LoadCharacterEquippedItems( tblCharacter.Id, function( tblData )
222 tblCharacter.Equipped = tblData
223 equip = true
224 part_loaded()
225 end )
226
227 self:LoadCharacterDataStore( tblCharacter.Id, function( tblData )
228 tblCharacter.SaveTable = tblData
229 data_store = true
230 part_loaded()
231 end )
232end
233
234function GM.SQL:GetPlayerNumCharacters( intPlyID, funcCallback )
235 self:QueryReadOnly( ([[SELECT COUNT(1) count FROM characters c WHERE player_id = %d]]):format(intPlyID), function( tblData, q )
236 funcCallback( tblData[1].count )
237 end )
238end
239
240function GM.SQL:CheckCharacterNameTaken( strFirstName, strLastName, funcCallback )
241 self:QueryReadOnly( ([[SELECT 1 FROM characters c WHERE first_name = '%s' AND last_name = '%s']]):format(SQLStr(strFirstName, true), SQLStr(strLastName, true)), function( tblData, q )
242 funcCallback( tblData[1] and true or false )
243 end )
244end
245
246--Functions to update character vars
247function GM.SQL:UpdateCharacterFirstName( intPoolID, intCharID, strNameFirst )
248 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET first_name='%s' WHERE id=%d]]):format(SQLStr(strNameFirst, true), intCharID) )
249 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET first_name='%s' WHERE id=%d]]):format(SQLStr(strNameFirst, true), intCharID) )
250end
251
252function GM.SQL:UpdateCharacterLastName( intPoolID, intCharID, strNameLast )
253 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET last_name='%s' WHERE id=%d]]):format(SQLStr(strNameLast, true), intCharID) )
254 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET last_name='%s' WHERE id=%d]]):format(SQLStr(strNameLast, true), intCharID) )
255end
256
257function GM.SQL:UpdateCharacterModel( intPoolID, intCharID, strModel )
258 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET model='%s' WHERE id=%d]]):format(SQLStr(strModel, true), intCharID) )
259 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET model='%s' WHERE id=%d]]):format(SQLStr(strModel, true), intCharID) )
260end
261
262function GM.SQL:UpdateCharacterModelOverload( intPoolID, intCharID, strModelOverload )
263 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET model_override='%s' WHERE id=%d]]):format(SQLStr(strModelOverload, true), intCharID) )
264 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET model_override='%s' WHERE id=%d]]):format(SQLStr(strModelOverload, true), intCharID) )
265end
266
267function GM.SQL:UpdateCharacterSex( intPoolID, intCharID, intSex )
268 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET sex='%s' WHERE id=%d]]):format(intSex == 0 and "male" or "female", intCharID) )
269 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET sex='%s' WHERE id=%d]]):format(intSex == 0 and "male" or "female", intCharID) )
270end
271
272function GM.SQL:UpdateCharacterSkin( intPoolID, intCharID, intSkin )
273 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET skin=%d WHERE id=%d]]):format(intSkin, intCharID) )
274 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET skin=%d WHERE id=%d]]):format(intSkin, intCharID) )
275end
276
277function GM.SQL:UpdateCharacterMoneyWallet( intPoolID, intCharID, intWalletMoney )
278 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET money_held=%d WHERE id=%d]]):format(intWalletMoney, intCharID) )
279 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET money_held=%d WHERE id=%d]]):format(intWalletMoney, intCharID) )
280end
281
282function GM.SQL:UpdateCharacterMoneyBank( intPoolID, intCharID, intBankMoney )
283 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET money_bank=%d WHERE id=%d]]):format(intBankMoney, intCharID) )
284 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET money_bank=%d WHERE id=%d]]):format(intBankMoney, intCharID) )
285end
286
287function GM.SQL:UpdateCharacterVehicles( intPoolID, intCharID, tblVehicles )
288 self:LogPlayerQuery( intCharID, ([[UPDATE characters SET vehicles='%s' WHERE id=%d]]):format(util.TableToJSON(tblVehicles), intCharID) )
289 self:PooledQueryWrite( intPoolID, ([[UPDATE characters SET vehicles='%s' WHERE id=%d]]):format(util.TableToJSON(tblVehicles), intCharID) )
290end
291
292--Character inventory data
293function GM.SQL:LoadCharacterInventory( intCharID, funcOnLoaded )
294 self:QueryReadOnly( ([[SELECT inv.* FROM character_inventory inv WHERE inv.character_id = %d]]):format(intCharID), function( tblData, q )
295 local decoded = {}
296 for idx, v in ipairs( tblData ) do
297 if not GAMEMODE.Inv:GetItem( v.item_name ) then continue end
298 decoded[v.item_name] = v.item_count
299 end
300
301 funcOnLoaded( decoded )
302 end )
303end
304
305function GM.SQL:InsdupCharacterInventoryItem( intPoolID, intCharID, strItemID, intAmount )
306 self:LogPlayerQuery( intCharID, ([[INSERT INTO character_inventory (character_id, item_name, item_count) VALUES (%d, '%s', %d) ON DUPLICATE KEY UPDATE item_count=%d]]):format(intCharID, SQLStr(strItemID, true), intAmount, intAmount) )
307 self:PooledQueryWrite( intPoolID, ([[INSERT INTO character_inventory (character_id, item_name, item_count) VALUES (%d, '%s', %d) ON DUPLICATE KEY UPDATE item_count=%d]]):format(intCharID, SQLStr(strItemID, true), intAmount, intAmount) )
308end
309
310function GM.SQL:InsertCharacterInventoryItem( intPoolID, intCharID, strItemID, intAmount )
311 self:LogPlayerQuery( intCharID, ([[INSERT INTO character_inventory SET character_id=%d, item_name='%s', item_count=%d]]):format(intCharID, SQLStr(strItemID, true), intAmount) )
312 self:PooledQueryWrite( intPoolID, ([[INSERT INTO character_inventory SET character_id=%d, item_name='%s', item_count=%d]]):format(intCharID, SQLStr(strItemID, true), intAmount) )
313end
314
315function GM.SQL:UpdateCharacterInventoryItem( intPoolID, intCharID, strItemID, intAmount )
316 self:LogPlayerQuery( intCharID, ([[UPDATE character_inventory SET item_count=%d WHERE character_id=%d AND item_name='%s']]):format(intAmount, intCharID, SQLStr(strItemID, true)) )
317 self:PooledQueryWrite( intPoolID, ([[UPDATE character_inventory SET item_count=%d WHERE character_id=%d AND item_name='%s']]):format(intAmount, intCharID, SQLStr(strItemID, true)) )
318end
319
320function GM.SQL:RemoveCharacterInventoryItem( intPoolID, intCharID, strItemID )
321 self:LogPlayerQuery( intCharID, ([[DELETE FROM character_inventory WHERE character_id=%d AND item_name='%s']]):format(intCharID, SQLStr(strItemID, true)) )
322 self:PooledQueryWrite( intPoolID, ([[DELETE FROM character_inventory WHERE character_id=%d AND item_name='%s']]):format(intCharID, SQLStr(strItemID, true)) )
323end
324
325function GM.SQL:InsertCharacterFullInventory( intPoolID, intCharID, tblInventory )
326 for itemName, itemAmount in pairs( tblInventory ) do
327 self:InsdupCharacterInventoryItem( intPoolID, intCharID, itemName, itemAmount )
328 end
329end
330
331--Character equip data
332function GM.SQL:LoadCharacterEquippedItems( intCharID, funcOnLoaded )
333 self:QueryReadOnly( ([[SELECT eq.* FROM character_equipped eq WHERE eq.character_id = %d]]):format(intCharID), function( tblData, q )
334 local decoded = {}
335 for idx, v in ipairs( tblData ) do
336 if v.item_name and v.item_name ~= "" then
337 if not GAMEMODE.Inv:GetItem( v.item_name ) then continue end
338 end
339
340 decoded[v.slot_name] = v.item_name
341 end
342
343 funcOnLoaded( decoded )
344 end )
345end
346
347function GM.SQL:InsdupCharacterEquippedItem( intPoolID, intCharID, strSlotID, strItemID )
348 self:LogPlayerQuery( intCharID, ([[INSERT INTO character_equipped (character_id, slot_name, item_name) VALUES (%d, '%s', '%s') ON DUPLICATE KEY UPDATE item_name='%s']]):format(intCharID, SQLStr(strSlotID, true), SQLStr(strItemID, true), SQLStr(strItemID, true)) )
349 self:PooledQueryWrite( intPoolID, ([[INSERT INTO character_equipped (character_id, slot_name, item_name) VALUES (%d, '%s', '%s') ON DUPLICATE KEY UPDATE item_name='%s']]):format(intCharID, SQLStr(strSlotID, true), SQLStr(strItemID, true), SQLStr(strItemID, true)) )
350end
351
352function GM.SQL:InsertCharacterEquippedItem( intPoolID, intCharID, strSlotID, strItemID )
353 self:LogPlayerQuery( intCharID, ([[INSERT INTO character_equipped SET character_id=%d, slot_name='%s', item_name='%s']]):format(intCharID, SQLStr(strSlotID, true), SQLStr(strItemID, true)) )
354 self:PooledQueryWrite( intPoolID, ([[INSERT INTO character_equipped SET character_id=%d, slot_name='%s', item_name='%s']]):format(intCharID, SQLStr(strSlotID, true), SQLStr(strItemID, true)) )
355end
356
357function GM.SQL:UpdateCharacterEquippedSlot( intPoolID, intCharID, strSlotID, strItemID )
358 self:LogPlayerQuery( intCharID, ([[UPDATE character_equipped SET item_name='%s' WHERE character_id=%d AND slot_name='%s']]):format(SQLStr(strItemID, true), intCharID, SQLStr(strSlotID, true)) )
359 self:PooledQueryWrite( intPoolID, ([[UPDATE character_equipped SET item_name='%s' WHERE character_id=%d AND slot_name='%s']]):format(SQLStr(strItemID, true), intCharID, SQLStr(strSlotID, true)) )
360end
361
362function GM.SQL:RemoveCharacterEquippedSlot( intPoolID, intCharID, strSlotID )
363 self:LogPlayerQuery( intCharID, ([[DELETE FROM character_equipped WHERE character_id=%d AND slot_name='%s']]):format(intCharID, SQLStr(strSlotID, true)) )
364 self:PooledQueryWrite( intPoolID, ([[DELETE FROM character_equipped WHERE character_id=%d AND slot_name='%s']]):format(intCharID, SQLStr(strSlotID, true)) )
365end
366
367function GM.SQL:InsertCharacterFullEquippedItems( intPoolID, intCharID, tblEquipped )
368 for slotName, itemName in pairs( tblEquipped ) do
369 self:InsdupCharacterEquippedItem( intPoolID, intCharID, slotName, itemName )
370 end
371end
372
373--Character data store
374function GM.SQL:LoadCharacterDataStore( intCharID, funcOnLoaded )
375 self:QueryReadOnly( ([[SELECT ds.* FROM character_data_store ds WHERE ds.character_id = %d]]):format(intCharID), function( tblData, q )
376 local decoded = {}
377 for idx, v in ipairs( tblData ) do
378 decoded[v.key] = util.JSONToTable( v.value )
379 end
380
381 funcOnLoaded( decoded )
382 end )
383end
384
385function GM.SQL:InsdupCharacterDataStoreVar( intPoolID, intCharID, strVar, vaValue )
386 local strValue = util.TableToJSON( vaValue )
387 self:LogPlayerQuery( intCharID, ([[INSERT INTO character_data_store (character_id, `key`, value) VALUES (%d, '%s', '%s') ON DUPLICATE KEY UPDATE value='%s']]):format(intCharID, SQLStr(strVar, true), SQLStr(strValue, true), SQLStr(strValue, true)) )
388 self:PooledQueryWrite( intPoolID, ([[INSERT INTO character_data_store (character_id, `key`, value) VALUES (%d, '%s', '%s') ON DUPLICATE KEY UPDATE value='%s']]):format(intCharID, SQLStr(strVar, true), SQLStr(strValue, true), SQLStr(strValue, true)) )
389end
390
391function GM.SQL:InsertCharacterDataStoreVar( intPoolID, intCharID, strVar, vaValue )
392 local strValue = util.TableToJSON( vaValue )
393 self:LogPlayerQuery( intCharID, ([[INSERT INTO character_data_store SET character_id=%d, `key`='%s', value='%s']]):format(intCharID, SQLStr(strVar, true), SQLStr(strValue, true)) )
394 self:PooledQueryWrite( intPoolID, ([[INSERT INTO character_data_store SET character_id=%d, `key`='%s', value='%s']]):format(intCharID, SQLStr(strVar, true), SQLStr(strValue, true)) )
395end
396
397function GM.SQL:UpdateCharacterDataStoreVar( intPoolID, intCharID, strVar, vaValue )
398 local strValue = util.TableToJSON( vaValue )
399 self:LogPlayerQuery( intCharID, ([[UPDATE character_data_store SET value='%s' WHERE character_id=%d AND `key`='%s']]):format(SQLStr(strVar, true), intCharID, SQLStr(strValue, true)) )
400 self:PooledQueryWrite( intPoolID, ([[UPDATE character_data_store SET value='%s' WHERE character_id=%d AND `key`='%s']]):format(SQLStr(strVar, true), intCharID, SQLStr(strValue, true)) )
401end
402
403function GM.SQL:RemoveCharacterDataStoreVar( intPoolID, intCharID, strVar )
404 self:LogPlayerQuery( intCharID, ([[DELETE FROM character_data_store WHERE character_id=%d AND `key`='%s']]):format(intCharID, SQLStr(strVar, true)) )
405 self:PooledQueryWrite( intPoolID, ([[DELETE FROM character_data_store WHERE character_id=%d AND `key`='%s']]):format(intCharID, SQLStr(strVar, true)) )
406end
407
408function GM.SQL:InsertCharacterFullDataStore( intPoolID, intCharID, tblSaveTable )
409 for k, v in pairs( tblSaveTable ) do
410 self:InsdupCharacterDataStoreVar( intPoolID, intCharID, tostring(k), util.TableToJSON{ [1] = v } ) --JSON ONLY TAKES TABLES? FUCK YOU GARRY.
411 end
412end
413
414-- ------------------------------------------------------------------------------
415-- Snapshot Updates
416
417function GM.SQL:CommitPlayerDiffs( strSID64 )
418 local gameData = GAMEMODE.Player:GetData( strSID64 )
419 if not gameData then return end
420
421 local charID = gameData.SelectedCharacter
422 if not charID then return end
423
424 local charData = gameData.Characters[charID]
425 if not charData then return end
426
427 local workerID = self:GetPlayerPoolID( strSID64 ) or 1
428 local diffFlags = gameData.SQLDiffTable
429 if not diffFlags or not diffFlags.Flags then return end
430
431 self:LogPlayerDiff( strSID64, "NumDiff = ".. table.Count(diffFlags.Flags).. " - DataPointer = ".. tostring(gameData).. " - CharDataPointer = ".. tostring(charData) )
432
433 for k, v in pairs( diffFlags.Flags ) do
434 self.m_tblDiffFlags[k]( workerID, charID, charData, diffFlags.Flags )
435 end
436
437 self:ClearPlayerDiffTable( strSID64 )
438end
439
440function GM.SQL:RegisterDiffFlag( strFlagID, funcUpdate )
441 self.m_tblDiffFlags[strFlagID] = funcUpdate
442end
443
444function GM.SQL:ClearPlayerDiffTable( strSID64 )
445 if not GAMEMODE.Player:GetData( strSID64 ) then return end
446 GAMEMODE.Player:GetData( strSID64 ).SQLDiffTable = {
447 Flags = {},
448 NextSnapshot = CurTime() +(self.m_intSnapshotInterval or 300)
449 }
450end
451
452function GM.SQL:MarkDiffDirty( pPlayer, strFlagID, strSubFlag )
453 local data = pPlayer:GetGamemodeData()
454 if not data or not data.SQLDiffTable then return end
455 if not self.m_tblDiffFlags[strFlagID] then return end
456
457 if strSubFlag then
458 data.SQLDiffTable.Flags[strFlagID] = data.SQLDiffTable.Flags[strFlagID] or {}
459 data.SQLDiffTable.Flags[strFlagID][strSubFlag] = true
460 else
461 data.SQLDiffTable.Flags[strFlagID] = true
462 end
463end
464
465function GM.SQL:GetPlayerDiffFlags( pPlayer )
466 if not pPlayer:GetGamemodeData() or not pPlayer:GetGamemodeData().SQLDiffTable then return {} end
467 return pPlayer:GetGamemodeData().SQLDiffTable.Flags or {}
468end
469
470function GM.SQL:TickPlayerIntervals()
471 if CurTime() <= (self.m_intLastInterval or 0) then return end
472 self.m_intLastInterval = CurTime() +1
473
474 local time, data = CurTime(), nil
475 for k, v in pairs( player.GetAll() ) do
476 data = v:GetGamemodeData()
477 if not data or not data.SQLDiffTable or not data.SQLDiffTable.Flags then continue end
478 if data.SQLDiffTable.NextSnapshot >= time then continue end
479 self:CommitPlayerDiffs( v:SteamID64() )
480 end
481end
482
483GM.SQL:RegisterDiffFlag( "money_wallet", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
484 GAMEMODE.SQL:UpdateCharacterMoneyWallet( intWorkerID, intCharID, tblCharData.Money.Wallet )
485end )
486
487GM.SQL:RegisterDiffFlag( "money_bank", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
488 GAMEMODE.SQL:UpdateCharacterMoneyBank( intWorkerID, intCharID, tblCharData.Money.Bank )
489end )
490
491GM.SQL:RegisterDiffFlag( "skin", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
492 GAMEMODE.SQL:UpdateCharacterSkin( intWorkerID, intCharID, tblCharData.Skin )
493end )
494
495GM.SQL:RegisterDiffFlag( "model_overload", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
496 GAMEMODE.SQL:UpdateCharacterModelOverload( intWorkerID, intCharID, tblCharData.Model.Overload )
497end )
498
499GM.SQL:RegisterDiffFlag( "vehicles", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
500 GAMEMODE.SQL:UpdateCharacterVehicles( intWorkerID, intCharID, tblCharData.Vehicles )
501end )
502
503GM.SQL:RegisterDiffFlag( "inventory", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
504 if not tblDiffFlags["inventory"] then return end
505 if not tblCharData.Inventory then return end
506
507 for itemName, _ in pairs( tblDiffFlags["inventory"] ) do
508 local itemNum = tblCharData.Inventory[itemName] or 0
509 if itemNum <= 0 then
510 GAMEMODE.SQL:RemoveCharacterInventoryItem( intWorkerID, intCharID, itemName )
511 else
512 GAMEMODE.SQL:InsdupCharacterInventoryItem( intWorkerID, intCharID, itemName, itemNum )
513 end
514 end
515end )
516
517GM.SQL:RegisterDiffFlag( "equipped", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
518 if not tblDiffFlags["equipped"] then return end
519 if not tblCharData.Equipped then return end
520
521 for slotName, _ in pairs( tblDiffFlags["equipped"] ) do
522 local itemName = tblCharData.Equipped[slotName]
523 if not itemName then
524 GAMEMODE.SQL:RemoveCharacterEquippedSlot( intWorkerID, intCharID, slotName )
525 else
526 GAMEMODE.SQL:InsdupCharacterEquippedItem( intWorkerID, intCharID, slotName, itemName )
527 end
528 end
529end )
530
531GM.SQL:RegisterDiffFlag( "data_store", function( intWorkerID, intCharID, tblCharData, tblDiffFlags )
532 if not tblDiffFlags["data_store"] then return end
533 if not tblCharData.SaveTable then return end
534
535 for tableName, _ in pairs( tblDiffFlags["data_store"] ) do
536 local data = tblCharData.SaveTable[tableName]
537 if not data then
538 GAMEMODE.SQL:RemoveCharacterDataStoreVar( intWorkerID, intCharID, tableName )
539 else
540 GAMEMODE.SQL:InsdupCharacterDataStoreVar( intWorkerID, intCharID, tableName, data )
541 end
542 end
543end )