· 6 years ago · Jan 28, 2020, 08:18 PM
1
2--[[---------------------------------------------------------
3 Name: Setup
4-----------------------------------------------------------]]
5local Ply = {}
6
7Ply.Data = VoidChar.Ply and VoidChar.Ply.Data or {}
8
9util.AddNetworkString("VoidChar.RequestCharacters")
10util.AddNetworkString("VoidChar.SelectCharacter")
11util.AddNetworkString("VoidChar.Whitelist")
12util.AddNetworkString("VoidChar.CreateCharacter")
13util.AddNetworkString("VoidChar.DeleteCharacter")
14util.AddNetworkString("VoidChar.DeployFail")
15util.AddNetworkString("VoidChar.DeploySuccess")
16util.AddNetworkString("VoidChar.ChangeJob")
17util.AddNetworkString("VoidChar.ChangeIdentity")
18
19util.AddNetworkString("VoidChar.SendBWhitelistFactions")
20util.AddNetworkString("VoidChar.RequestFactions")
21
22util.AddNetworkString("VoidChar.ForceOpenMenu")
23
24util.AddNetworkString("VoidChar.AdminGetCharacters")
25util.AddNetworkString("VoidChar.AdminModifyCharacter")
26util.AddNetworkString("VoidChar.AdminDeleteCharacter")
27util.AddNetworkString("VoidChar.AdminGetWhitelist")
28util.AddNetworkString("VoidChar.AdminRemoveWhitelist")
29util.AddNetworkString("VoidChar.AdminAddWhitelist")
30
31
32local function phrase(...)
33 return VoidChar.Lang.GetPhrase(...)
34end
35
36--[[---------------------------------------------------------
37 Name: Functions
38-----------------------------------------------------------]]
39function Ply.Initalize(ply)
40 Ply.Data[ply] = Ply.Data[ply] or {}
41
42 ply:KillSilent()
43
44 ply:SetTeam(TEAM_SPECTATOR)
45
46 VoidChar.SQL.GetCharacters(ply, function(succ, tbl)
47 VoidChar.Print("Loaded (".. #tbl.. ") characters from ".. ply:Name())
48 end)
49
50
51 VoidChar.SQL.GetWhitelists(ply:SteamID64(), function(data)
52 local jobs = data == {} and data or data[1] and util.JSONToTable(data[1].jobs) or data.data and util.JSONToTable(data.jobs) or {}
53
54 if VoidChar.Config.ULXRanks[ply:GetUserGroup()] then
55 local groupCheck = (VoidChar.Config.xAdminSupport and ply:xAdminGetTag()) or ply:GetUserGroup()
56 for k, v in pairs(VoidChar.Config.ULXRanks[groupCheck]) do
57 jobs[k] = true
58 end
59 end
60
61 for k, v in pairs(VoidChar.Config.DefaultJobs) do
62 jobs[k] = true
63 end
64
65 if VoidChar.Config.WhitelistSteamID[ply:SteamID()] or VoidChar.Config.WhitelistRanks[ply:GetUserGroup()] then
66 for k, v in pairs(RPExtraTeams) do
67 jobs[v.team] = true
68 end
69 end
70
71 Ply.Data[ply].whitelist = jobs
72 end)
73end hook.Add("PlayerInitialSpawn", "VoidChar.Ply.Initalize", Ply.Initalize)
74
75function Ply.DarkRPVarChanged(ply, varname, oldValue, newValue)
76 if !VoidChar.Config.LevelSystemSupport then return end
77 if varname != "xp" then return end
78 if !Ply.Data[ply] then return end
79
80 local character = ply:GetCharacterID()
81 if !character then return end
82
83
84 Ply.Data[ply].character.xp = newValue
85 Ply.Data[ply].character.level = ply:getDarkRPVar("level")
86
87 VoidChar.SQL.UpdateValue(character, "xp", newValue )
88 VoidChar.SQL.UpdateValue(character, "level", ply:getDarkRPVar("level") )
89
90end hook.Add("DarkRPVarChanged", "VoidChar.Ply.DarkRPVarChanged", Ply.DarkRPVarChanged)
91
92hook.Add("PlayerSay", "VoidChar.Ply.PlayerSayCommands", function (ply, text)
93
94 if (!VoidChar.Config.AdminMenu[ply:GetUserGroup()]) then return end
95
96 text = string.lower(text)
97
98 local args = string.Split(text, " ")
99
100 if (args[1] != "!setcharjob") then return end
101
102 local playerName = table.concat( args, " ", 2, #args - 1 )
103
104 local charPly
105 for k, v in pairs(player.GetAll()) do
106 if (string.StartWith(string.lower(v:Nick()), playerName)) then
107 charPly = v
108 break
109 end
110 end
111
112 if (!charPly) then return end
113
114 local job = DarkRP.getJobByCommand(args[#args])
115 if (!job) then return end
116
117 Ply.Data[charPly].character.job = job.team
118 Ply.Data[charPly].character.model = (type(job.model) == "table" and job.model[1]) or job.model
119
120 VoidChar.SQL.UpdateValue(charPly:GetCharacterID(), "job", "\'".. job.command .. "\'")
121 VoidChar.SQL.UpdateValue(charPly:GetCharacterID(), "model", "\'".. Ply.Data[charPly].character.model .. "\'")
122
123 VoidChar.SQL.UpdateCharacters(charPly, function()
124 local characters = ply:GetCharacters()
125
126 characters = util.TableToJSON(characters)
127 characters = util.Compress(characters)
128
129 net.Start("VoidChar.RequestCharacters")
130 net.WriteUInt(#characters, 32)
131 net.WriteData(characters, #characters)
132 net.WriteBool(false)
133 net.Send(ply)
134 end)
135
136 charPly:changeTeam(job.team, true)
137
138 ply:ChatPrint("Successfully set " .. playerName .. "'s job to " .. job.name .. "!")
139 return "";
140
141end)
142
143function Ply.SaveItemStoreInv(ply)
144 if !VoidChar.Config.ItemStoreSupport then return end
145
146 local character = ply:GetCharacterID()
147 if !character then return end
148
149 local inventoryItems = ply.Inventory:GetItems()
150 for k, v in pairs(inventoryItems) do
151 inventoryItems[k].Container = nil
152 end
153 local inventoryJSON = util.TableToJSON(inventoryItems)
154
155 Ply.Data[ply].character.inventory = inventoryJSON
156
157 VoidChar.SQL.UpdateValue(character, "inventory", "\'".. inventoryJSON .. "\'" )
158end
159
160function Ply.SaveClothes(ply)
161 if !VoidChar.Config.CharacterClothesSupport then return end
162
163 local character = ply:GetCharacterID()
164 if !character then return end
165
166 local clothingJSON = util.TableToJSON(ply:CM_GetInfos())
167
168 Ply.Data[ply].character.clothing = clothingJSON
169
170 VoidChar.SQL.UpdateValue(character, "clothing", "\'".. clothingJSON .. "\'" )
171end
172
173if VoidChar.Config.ItemStoreSupport then
174
175 // thanks for adding no hooks....
176 gameevent.Listen( "player_disconnect" )
177 hook.Add( "player_disconnect", "VoidChar.Ply.ItemStoreSaveOnDisconnect", function( data )
178 if itemstore.config.SaveOnWrite then return end
179
180 local pl = player.GetBySteamID( data.networkid )
181 if not IsValid( pl ) then return end
182
183 Ply.SaveItemStoreInv(pl)
184 end )
185
186 hook.Add( "Tick", "VoidChar.Ply.ItemStoreSaveOnWrite", function()
187 if not itemstore.config.SaveOnWrite then return end
188
189 for _, pl in ipairs( player.GetAll() ) do
190 if pl.NextInventorySave and pl.NextInventorySave < CurTime() + 0.02 then // for real??
191 Ply.SaveItemStoreInv(pl)
192 end
193 end
194 end )
195end
196
197if VoidChar.Config.CharacterClothesSupport then
198
199 hook.Add("ClothesMod.OnInfosSaved", "VoidChar.Ply.CharacterClothesSave", function (pl)
200 Ply.SaveClothes(pl)
201 end)
202
203end
204
205
206function Ply.SelectCharacter(ply, character, callback)
207 Ply.Data[ply] = Ply.Data[ply] or {}
208
209 if Ply.Data[ply].changing then
210 ply:ChatPrint(phrase("changing"))
211 return
212 end
213
214 Ply.IsPlayerWhitelisted(ply, character.job, function (result)
215
216 if !result and !VoidChar.Config.EnableUsingNonWhitelistedJobs then
217 net.Start("VoidChar.DeployFail")
218 net.WriteString("whitelist_fail")
219 net.Send(ply)
220 return
221 end
222
223 // check if can change team
224 local canDeploy, reason, add = ply:CanDeploy(tonumber(character.job), false)
225
226 if (!add) then
227 add = ""
228 end
229
230
231 if !canDeploy then
232 net.Start("VoidChar.DeployFail")
233 net.WriteString(reason)
234 net.WriteString(add)
235 net.Send(ply)
236 return
237 end
238
239 local onlinePlayers = player.GetCount()
240
241
242 local isFactionFull = false
243 if VoidChar.Config.FactionSystem and !VoidChar.Config.IgnoreExistingCharactersFactionLimit and table.Count(VoidChar.Config.FactionMaxPlayerPercent) > 0 and VoidChar.Config.FactionMaxPlayerPercent[character.faction] then
244 if VoidChar.Config.FactionMaxPlayerPercent[character.faction] != 0 then
245
246 local plyCountFaction = 0
247 for k, v in pairs(player.GetAll()) do
248 if v==ply then continue end
249 if v:GetCharacter() then
250 local plyChar = v:GetCharacter()
251
252 if plyChar.faction == character.faction then
253 plyCountFaction = plyCountFaction + 1
254 end
255 end
256 end
257
258 if (onlinePlayers * (VoidChar.Config.FactionMaxPlayerPercent[character.faction]/100) <= plyCountFaction) then
259 isFactionFull = true
260 end
261 end
262 end
263
264 if isFactionFull then
265 net.Start("VoidChar.DeployFail")
266 net.WriteString(phrase("faction_full"))
267 net.Send(ply)
268 return
269 end
270
271
272 local CTeam = RPExtraTeams[tonumber(character.job)]
273
274 if (CTeam.vote or CTeam.RequiresVote) and ply:Team() != tonumber(character.job) then
275 if CTeam.canStartVote and not CTeam.canStartVote(ply) then
276 net.Start("VoidChar.DeployFail")
277 net.WriteString("vote_error")
278 net.Send(ply)
279 return
280 end
281 ply.LastVoteCop = ply.LastVoteCop or -80
282
283 if CurTime() - ply.LastVoteCop < 80 then
284 net.Start("VoidChar.DeployFail")
285 net.WriteString("vote_error")
286 net.Send(ply)
287 return
288 end
289 net.Start("VoidChar.DeployFail")
290 net.WriteString("vote_created")
291 net.Send(ply)
292 DarkRP.createVote(DarkRP.getPhrase("wants_to_be", ply:Nick(), CTeam.name), "job", ply, 20, function(vote, choice)
293 local target = vote.target
294 if not IsValid(target) then return end
295
296 if choice >= 0 then
297 ply:changeTeam(tonumber(character.job), true, true)
298 net.Start("VoidChar.DeploySuccess")
299 net.Send(ply)
300 else
301 DarkRP.notifyAll(1, 4, DarkRP.getPhrase("has_not_been_made_team", target:Nick(), CTeam.name))
302 net.Start("VoidChar.DeployFail")
303 net.WriteString("vote_failed")
304 net.Send(ply)
305 end
306 end, nil, nil, {
307 targetTeam = tonumber(character.job)
308 })
309
310 ply.LastVoteCop = CurTime()
311 else
312 net.Start("VoidChar.DeploySuccess")
313 net.Send(ply)
314 ply:changeTeam(tonumber(character.job), true, true)
315 end
316
317 local prevCharacter = Ply.Data[ply].character
318 Ply.Data[ply].character = character
319
320 hook.Run("VoidChar.CharacterSelected", ply, character)
321
322 if VoidChar.Config.LevelSystemSupport then
323 ply:setDarkRPVar("level", tonumber(character.level) )
324 ply:setDarkRPVar("xp", tonumber(character.xp) )
325 end
326
327 if VoidChar.Config.CharacterClothesSupport then
328 if !CLOTHESMOD then VoidChar.PrintError("Character & Clothes support is enabled, but the addon was not found!") return end
329
330 local clothing = util.JSONToTable(character.clothing)
331
332 if clothing and table.Count(clothing) > 0 then
333 VoidChar.Print("Setting clothesmod info")
334 CLOTHESMOD.PlayerInfos[ply:SteamID64()] = clothing
335 timer.Simple(1, function ()
336 ply:CM_ApplyModel()
337 end)
338 end
339
340 end
341
342 if VoidChar.Config.BodygroupOption then
343 local bodygroups = (character.bodygroups and util.JSONToTable(character.bodygroups)) or nil
344
345 if bodygroups then
346 for k, v in pairs(bodygroups) do
347 ply:SetBodygroup(k,v)
348 end
349 end
350 end
351
352 if VoidChar.Config.ItemStoreSupport then
353 local inventory = util.JSONToTable(character.inventory)
354
355 for k, v in pairs(ply.Inventory:GetItems()) do
356 local amount = 0
357 if !v.Data or !v.Data.Amount then
358 amount = 1
359 else
360 amount = v.Data.Amount
361 end
362 ply.Inventory:TakeItems(v.Class, amount)
363 end
364
365 for k, v in pairs(inventory) do
366 if v.Data then
367 ply.Inventory:SetItem(v.Slot, itemstore.Item(v.Class, v.Data))
368 else
369 ply.Inventory:SetItem(v.Slot, itemstore.Item(v.Class))
370 end
371 end
372 end
373
374 if character.clone_id != "NULL" and character.clone_id != false and VoidChar.Config.EnableCloneID then
375 local hashtag = (VoidChar.Config.ShowHashtag and "#") or ""
376
377 if VoidChar.Config.DisplayAsSuffix then
378 ply:setDarkRPVar("rpname", hashtag .. character.clone_id.. " " .. character.name)
379 else
380 ply:setDarkRPVar("rpname", character.name.. " " .. hashtag .. character.clone_id)
381 end
382 else
383 ply:setDarkRPVar("rpname", character.name)
384 end
385
386 ply:setDarkRPVar("money", character.wallet)
387
388 end)
389
390 if callback then callback() end
391end
392
393function Ply.ChangeIdentity(len, ply)
394 if not ply:GetCharacterID() then return end
395
396
397 local name = net.ReadString()
398 local model = net.ReadString()
399 local bodygroups = net.ReadTable()
400
401 if !ply:canAfford(VoidChar.Config.IdentityChangeCost) then
402 DarkRP.notify(ply, 1, 5, phrase("cant_afford"))
403 return
404 end
405
406 if #name > VoidChar.Config.MaxNameLength then
407 DarkRP.notify(ply, 1, 5, string.format(phrase("name_long"), VoidChar.Config.MaxNameLength) )
408 return
409 end
410
411 if #name < VoidChar.Config.MinNameLength then
412 DarkRP.notify(ply, 1, 5, string.format(phrase("name_short"), VoidChar.Config.MinNameLength))
413 return
414 end
415
416 local plyJob = RPExtraTeams[ply:Team()]
417
418 if (( type(plyJob.model) == "table" and !table.HasValue(plyJob.model, model) ) or ( type(plyJob.model) == "string" and plyJob.model != model )) then
419 return
420 end
421
422 local nameWords = string.Explode(" ", name)
423 if VoidChar.Config.ForceTwoNames and ((VoidChar.Config.RestrictThreeNames and #nameWords ~= 3) or #nameWords > 3 or #nameWords < 2) then
424 local maxWords = 2
425 if !VoidChar.Config.RestrictThreeNames then
426 maxWords = 3
427 end
428 DarkRP.notify(ply, 1, 5, string.format(phrase("too_many_words"), maxWords) )
429 return
430 end
431
432 if Ply.Data[ply].character.clone_id != "NULL" and Ply.Data[ply].character.clone_id != false and VoidChar.Config.EnableCloneID then
433 local hashtag = (VoidChar.Config.ShowHashtag and "#") or ""
434
435 if VoidChar.Config.DisplayAsSuffix then
436 ply:setDarkRPVar("rpname", hashtag .. Ply.Data[ply].character.clone_id.. " " .. Ply.Data[ply].character.name)
437 else
438 ply:setDarkRPVar("rpname", Ply.Data[ply].character.name.. " " .. hashtag .. Ply.Data[ply].character.clone_id)
439 end
440 else
441 ply:setDarkRPVar("rpname", name)
442 end
443
444 Ply.Data[ply].character.name = name
445 Ply.Data[ply].character.model = model
446
447 VoidChar.SQL.UpdateValue(ply:GetCharacterID(), "name", "\'".. name .. "\'")
448 VoidChar.SQL.UpdateValue(ply:GetCharacterID(), "model", "\'".. model .. "\'")
449
450 if (VoidChar.Config.BodygroupOption and VoidChar.Config.BodygroupChangeInNPCs) then
451 if (bodygroups) then
452 for k, v in pairs(bodygroups) do
453 ply:SetBodygroup(k,v)
454 end
455 end
456
457 local bodygroupsJSON = util.TableToJSON(bodygroups)
458
459
460 Ply.Data[ply].character.bodygroups = bodygroupsJSON
461 VoidChar.SQL.UpdateValue(ply:GetCharacterID(), "bodygroups", "\'".. bodygroupsJSON .. "\'")
462 end
463
464 ply:SetModel(model)
465
466 local characters = ply:GetCharacters()
467
468 characters = util.TableToJSON(characters)
469 characters = util.Compress(characters)
470
471 net.Start("VoidChar.RequestCharacters")
472 net.WriteUInt(#characters, 32)
473 net.WriteData(characters, #characters)
474 net.WriteBool(false)
475 net.Send(ply)
476
477 ply:addMoney(-VoidChar.Config.IdentityChangeCost)
478
479 DarkRP.notify(ply, 0, 5, phrase("success_identity"))
480
481end net.Receive("VoidChar.ChangeIdentity", Ply.ChangeIdentity)
482
483function Ply.ChangeJob(len, ply)
484 if not ply:GetCharacterID() then return end
485
486 local job = net.ReadInt(20)
487 local model = net.ReadString()
488 local jobNPC = net.ReadString()
489 local bodygroups = net.ReadTable()
490
491
492 local jobChangeCost = (jobNPC != "" and VoidChar.Config.JobNPCs[jobNPC].changeCost) or VoidChar.Config.JobChangeCost
493
494
495 if !ply:canAfford(jobChangeCost) then
496 DarkRP.notify(ply, 1, 5, phrase("cant_afford"))
497 return
498 end
499
500 local plyChar = ply:GetCharacter()
501
502 if VoidChar.Config.FactionSystem and !VoidChar.Config.DifferentFactionJobSwitch and !VoidChar.Config.Factions[plyChar.faction][job] then return end
503
504 local canDeploy, reason, add = ply:CanDeploy(job, true)
505
506 if !canDeploy then
507 if (add) then
508 DarkRP.notify(ply, 1, 5, string.format(phrase(reason), add))
509 else
510 DarkRP.notify(ply, 1, 5, phrase(reason))
511 end
512 return
513 end
514
515 if ply.lastSwitchedCharJob and ply.lastSwitchedCharJob + (VoidChar.Config.JobSwitchCooldown * 60) > CurTime() then
516
517 local cooldownExpire = math.ceil( (ply.lastSwitchedCharJob + (VoidChar.Config.JobSwitchCooldown * 60) - CurTime()) / 60)
518
519 DarkRP.notify(ply, 1, 5, string.format(phrase("char_jobswitch_cooldown"), cooldownExpire) )
520 return
521 end
522 ply.lastSwitchedCharJob = CurTime()
523
524
525
526 Ply.IsPlayerWhitelisted(ply, job, function (result)
527
528
529 if !result then return end
530
531 if job == ply:Team() then return end
532
533
534
535 Ply.Data[ply].character.job = job
536 Ply.Data[ply].character.model = model
537
538 local jobCommand = RPExtraTeams[job].command
539
540
541 VoidChar.SQL.UpdateValue(ply:GetCharacterID(), "job", "\'".. jobCommand .. "\'")
542 VoidChar.SQL.UpdateValue(ply:GetCharacterID(), "model", "\'".. model .. "\'")
543
544 if (VoidChar.Config.BodygroupOption and VoidChar.Config.BodygroupChangeInNPCs) then
545
546 if (bodygroups) then
547 for k, v in pairs(bodygroups) do
548 ply:SetBodygroup(k,v)
549 end
550 end
551
552 local bodygroupsJSON = util.TableToJSON(bodygroups)
553
554
555 Ply.Data[ply].character.bodygroups = bodygroupsJSON
556 VoidChar.SQL.UpdateValue(ply:GetCharacterID(), "bodygroups", "\'".. bodygroupsJSON .. "\'")
557 end
558
559 local CTeam = RPExtraTeams[tonumber(job)]
560
561 if (CTeam.vote or CTeam.RequiresVote) then
562 if CTeam.canStartVote and not CTeam.canStartVote(ply) then
563 DarkRP.notify(ply, 1, 5, phrase("vote_error"))
564 return
565 end
566 ply.LastVoteCop = ply.LastVoteCop or -80
567
568 if CurTime() - ply.LastVoteCop < 80 then
569 DarkRP.notify(ply, 1, 5, phrase("vote_error"))
570 return
571 end
572 DarkRP.notify(ply, 0, 5, phrase("vote_created"))
573 DarkRP.createVote(DarkRP.getPhrase("wants_to_be", ply:Nick(), CTeam.name), "job", ply, 20, function(vote, choice)
574 local target = vote.target
575 if not IsValid(target) then return end
576
577 if choice >= 0 then
578 ply:changeTeam(job, true, true)
579 else
580 DarkRP.notifyAll(1, 4, DarkRP.getPhrase("has_not_been_made_team", target:Nick(), CTeam.name))
581 DarkRP.notify(ply, 1, 5, phrase("vote_failed"))
582 end
583 end, nil, nil, {
584 targetTeam = job
585 })
586
587 ply.LastVoteCop = CurTime()
588 else
589 ply:changeTeam(job, true, true)
590 end
591
592 DarkRP.notify(ply, 0, 5, phrase("success_job"))
593
594 ply:addMoney(-jobChangeCost)
595
596 local characters = ply:GetCharacters()
597
598 characters = util.TableToJSON(characters)
599 characters = util.Compress(characters)
600
601 net.Start("VoidChar.RequestCharacters")
602 net.WriteUInt(#characters, 32)
603 net.WriteData(characters, #characters)
604 net.WriteBool(false)
605 net.Send(ply)
606
607 end)
608end net.Receive("VoidChar.ChangeJob", Ply.ChangeJob)
609
610function Ply.UpdateWallet(ply, amount, money)
611 if not ply:GetCharacterID() then return end
612
613 Ply.Data[ply].character.wallet = money + amount
614 VoidChar.SQL.UpdateValue(ply:GetCharacterID(), "wallet", money + amount)
615end hook.Add("playerWalletChanged", "VoidChar.Ply.Wallet", Ply.UpdateWallet)
616
617function Ply.GetCharacter(ply)
618 return Ply.Data[ply].character or {}
619end
620
621function Ply.SaveAllNPCs(ply)
622 if !VoidChar.Config.AdminMenu[ply:GetUserGroup()] then return end
623
624
625
626 local npcTable = {}
627 npcTable["job"] = {}
628 npcTable["identity"] = {}
629
630 for k, v in pairs(ents.FindByClass("vc_jobnpc")) do
631 local posArray = {}
632 posArray[1] = v:GetPos()
633 posArray[2] = v:GetAngles()
634 if v.npcType then
635 posArray[3] = v.npcType
636 end
637 table.insert(npcTable["job"], posArray)
638 end
639
640 for k, v in pairs(ents.FindByClass("vc_identitynpc")) do
641 local posArray = {}
642 posArray[1] = v:GetPos()
643 posArray[2] = v:GetAngles()
644 table.insert(npcTable["identity"], posArray)
645 end
646
647 local json = util.TableToJSON(npcTable)
648 file.Write("voidchar_npclocations.txt", json)
649
650 ply:ChatPrint("[VoidChar] Successfully saved all NPCs.")
651
652end concommand.Add( "voidchar_savenpc", Ply.SaveAllNPCs)
653
654function Ply.LoadAllNPCs()
655 local text = file.Read("voidchar_npclocations.txt")
656
657 if !text then return end
658
659 local npcTable = util.JSONToTable(text)
660 if !npcTable["job"] then
661 npcTable["job"] = {}
662 end
663 if !npcTable["identity"] then
664 npcTable["identity"] = {}
665 end
666 for k, v in pairs(npcTable["job"]) do
667 local npc = ents.Create("vc_jobnpc")
668 npc:SetPos(v[1])
669 npc:SetAngles(v[2])
670 if v[3] then
671 npc:SetNWString("npcType", v[3])
672 npc.npcType = v[3]
673 end
674
675 npc:Spawn()
676
677 if v[3] then
678 npc:SetNPCModel(VoidChar.Config.JobNPCs[v[3]].npcModel)
679 end
680 end
681 for k, v in pairs(npcTable["identity"]) do
682 local npc = ents.Create("vc_identitynpc")
683 npc:SetPos(v[1])
684 npc:SetAngles(v[2])
685 npc:Spawn()
686 end
687
688 VoidChar.Print("Successfully loaded all NPCs.")
689
690end
691
692--[[---------------------------------------------------------
693 Name: Meta
694-----------------------------------------------------------]]
695local PLAYER = FindMetaTable("Player")
696
697function PLAYER:GetCharacters()
698 return VoidChar.SQL.PlayerInfo[self:SteamID64()] or {}
699end
700
701
702function PLAYER:CanDeploy(t, switch)
703
704 local CTeam = RPExtraTeams[tonumber(t)]
705
706 if (CTeam.vote or CTeam.RequiresVote) and self:Team() == tonumber(t) then
707 return true
708 end
709
710 if self:isArrested() then
711 return false, "arrested"
712 end
713
714 local allowed, time = self:changeAllowed(t)
715 if t ~= GAMEMODE.DefaultTeam and not allowed and not force then
716 return false, "demoted"
717 end
718
719 if self.IsBeingDemoted then
720 self:teamBan()
721 self.IsBeingDemoted = false
722 self:changeTeam(GAMEMODE.DefaultTeam, true)
723 return false, "try_demote"
724 end
725
726 local TEAM = RPExtraTeams[t]
727 if not TEAM then return false end
728
729 if TEAM.customCheck and not TEAM.customCheck(self) and (not force or force and not GAMEMODE.Config.adminBypassJobRestrictions) then
730 return false, "noperms"
731 end
732
733 if (TEAM.NeedToChangeFrom and self:Team() != TEAM.NeedToChangeFrom) and (switch or !VoidChar.Config.NeedToChangeFromOnlyInJobNPC) then // We need to check if player used the job npc to change his character
734 return false, "char_diffntcf", team.GetName(TEAM.NeedToChangeFrom)
735 end
736
737 local max = TEAM.max
738 local numPlayers = team.NumPlayers(t)
739 if max ~= 0 and -- No limit
740 (max >= 1 and numPlayers >= max or -- absolute maximum
741 max < 1 and (numPlayers + 1) / player.GetCount() > max) then -- fractional limit (in percentages) [655615ee9481efcebe24c7991b5cc95ed551f3ea59da2ed78542506e0b5dbeb9]
742 return false, "limit_reached"
743 end
744
745 return true
746
747end
748
749function PLAYER:GetCharacterID()
750 return Ply.GetCharacter(self).id or nil
751end
752
753function PLAYER:SelectCharacter(character, callback)
754 return Ply.SelectCharacter(self, character, callback)
755end
756
757function PLAYER:GetCharacterByID(id)
758 for k, v in pairs(self:GetCharacters()) do
759 if tonumber(v.id) == tonumber(id) then
760 return v
761 end
762 end
763
764 return nil
765end
766
767function PLAYER:GetCharacter()
768 return Ply.GetCharacter(self)
769end
770
771function PLAYER:GetReserved()
772 local allowed = {}
773
774 for k, v in pairs(VoidChar.Config.CharacterRank) do
775 if v.customCheck(self) then
776 allowed[k] = true
777 end
778 end
779
780 return allowed
781end
782
783--[[---------------------------------------------------------
784 Name: Networking
785-----------------------------------------------------------]]
786function Ply.RequestCharacters(len, ply)
787 if Ply.Data[ply] and Ply.Data[ply].sent then return end
788
789 local characters = ply:GetCharacters()
790
791 characters = util.TableToJSON(characters)
792 characters = util.Compress(characters)
793
794 net.Start("VoidChar.RequestCharacters")
795 net.WriteUInt(#characters, 32)
796 net.WriteData(characters, #characters)
797 net.WriteBool(true)
798 net.Send(ply)
799
800 Ply.Data[ply] = Ply.Data[ply] or {}
801 Ply.Data[ply].sent = true
802end net.Receive("VoidChar.RequestCharacters", Ply.RequestCharacters)
803
804function Ply.RequestFactions(len, ply)
805 if VoidChar.Config.UseBWhitelistFactions then
806 local tbl = VoidChar.GetBWhitelistFactions()
807 if tbl then
808 tbl = util.TableToJSON(tbl)
809 tbl = util.Compress(tbl)
810 net.Start("VoidChar.SendBWhitelistFactions")
811 net.WriteUInt(#tbl, 32)
812 net.WriteData(tbl, #tbl )
813 net.Send(ply)
814 end
815 end
816end net.Receive("VoidChar.RequestFactions", Ply.RequestFactions)
817
818function Ply.SelectCharacterNet(len, ply)
819 Ply.Data[ply] = Ply.Data[ply] or {}
820
821 -- if Ply.Data[ply].character then return end
822
823 local char_id = net.ReadInt(20)
824
825 if not ply:GetCharacterByID(char_id) then return end
826
827 ply:SelectCharacter(ply:GetCharacterByID(char_id), function()
828 net.Start("VoidChar.SelectCharacter")
829 net.WriteInt(char_id, 20)
830 net.Send(ply)
831 end)
832end net.Receive("VoidChar.SelectCharacter", Ply.SelectCharacterNet)
833
834function Ply.RequestWhitelist(len, ply, override)
835 if VoidChar.Config.UseBWhitelist then
836 local AccessibleJobs, AccessibleJobsCount = GAS.JobWhitelist:GetPlayerAccessibleJobs(ply)
837
838 AccessibleJobs = util.TableToJSON(AccessibleJobs)
839 AccessibleJobs = util.Compress(AccessibleJobs)
840
841 net.Start("VoidChar.Whitelist")
842 net.WriteUInt(#AccessibleJobs, 32)
843 net.WriteData(AccessibleJobs, #AccessibleJobs)
844 net.Send(ply)
845 end
846
847 Ply.Data[ply] = Ply.Data[ply] or {}
848
849 if Ply.Data[ply].sentwhitelist and not override then return end
850
851 local data = {}
852
853 if VoidChar.Config.WhitelistSteamID[ply:SteamID()] or VoidChar.Config.WhitelistRanks[ply:GetUserGroup()] then
854 for k, v in pairs(RPExtraTeams) do
855 data[k] = true
856 end
857
858 Ply.Data[ply].sentwhitelist = true
859
860 data = util.TableToJSON(data)
861 data = util.Compress(data)
862
863 net.Start("VoidChar.Whitelist")
864 net.WriteUInt(#data, 32)
865 net.WriteData(data, #data)
866 net.Send(ply)
867
868 return
869 end
870
871 VoidChar.SQL.GetWhitelists(ply:SteamID64(), function(data)
872 data = data or {}
873
874 local jobs = data == {} and data or data[1] and util.JSONToTable(data[1].jobs) or data.data and util.JSONToTable(data.jobs) or {}
875
876 local groupCheck = (VoidChar.Config.xAdminSupport and ply:xAdminGetTag()) or ply:GetUserGroup()
877 if VoidChar.Config.ULXRanks[groupCheck] then
878 for k, v in pairs(VoidChar.Config.ULXRanks[groupCheck]) do
879 jobs[k] = true
880 end
881 end
882
883 Ply.Data[ply].sentwhitelist = jobs
884
885 jobs = util.TableToJSON(jobs)
886 jobs = util.Compress(jobs)
887
888 net.Start("VoidChar.Whitelist")
889 net.WriteUInt(#jobs, 32)
890 net.WriteData(jobs, #jobs)
891 net.Send(ply)
892 end)
893end net.Receive("VoidChar.Whitelist", Ply.RequestWhitelist)
894
895function Ply.RequestCreateCharacter(len, ply)
896 Ply.Data[ply] = Ply.Data[ply] or {}
897
898 if table.Count(VoidChar.SQL.PlayerInfo[ply:SteamID64()]) > VoidChar.Config.MaxCharacters - (table.Count(VoidChar.Config.CharacterRank) - table.Count(ply:GetReserved())) then
899 error("Player ".. ply:Nick().. " attempted to create more characters than allowed.")
900 return
901 end
902
903
904 local data = net.ReadTable() or {}
905
906 local restrictedFound = false
907 for k, v in pairs(VoidChar.Config.RestrictedWords) do
908 if string.find(data.name, string.lower(v) ) then
909 restrictedFound = true
910 end
911 end
912
913
914
915 if ply.lastCreatedCharacter and ply.lastCreatedCharacter + (VoidChar.Config.CharacterCreateCooldown * 60) > CurTime() then return end
916 ply.lastCreatedCharacter = CurTime()
917
918 if not data.name or data.name == "" then return end
919 if not data.job or data.job == 0 then return end
920 if not data.model or data.model == "" then return end
921
922 if VoidChar.Config.FactionSystem and !VoidChar.Config.Factions[data.faction][data.job] then return end
923
924 if restrictedFound then return end
925
926 if data.bodygroups then
927 data.bodygroups = util.TableToJSON(data.bodygroups)
928 end
929
930 Ply.IsPlayerWhitelisted(ply, data.job, function (result)
931
932 if !result then return end
933
934 if VoidChar.Config.DisableCreationWhitelist and !VoidChar.Config.DefaultJobs[data.job] then return end
935
936 if VoidChar.Config.ForceCloneID then
937 data.clone_id = true
938 end
939
940 if VoidChar.Config.CharacterClothesSupport then
941 net.Start("ClothesMod:CharacterCreationMenu")
942 net.Send(ply)
943 end
944
945 hook.Run("VoidChar.CharacterCreated", ply, data)
946
947 if data.clone_id then // Clone Counter :v <3
948 if VoidChar.Config.CloneID then
949 VoidChar.SQL.GetCloneID(function(number)
950 data.clone_id = number
951
952 VoidChar.SQL.CreateCharacter(ply, {
953 name = data.name,
954 clone_id = data.clone_id,
955 job = data.job,
956 model = data.model,
957 wallet = VoidChar.Config.DefaultMoney or 200,
958 faction = data.faction,
959 bodygroups = data.bodygroups or ""
960 }, function(succ, tbl, index)
961
962 if !succ then return end
963
964 Ply.SelectCharacter(ply, tbl[index])
965
966 local characters = ply:GetCharacters()
967
968 characters = util.TableToJSON(characters)
969 characters = util.Compress(characters)
970
971 net.Start("VoidChar.RequestCharacters")
972 net.WriteUInt(#characters, 32)
973 net.WriteData(characters, #characters)
974 net.WriteBool(false)
975 net.Send(ply)
976
977 net.Start("VoidChar.SelectCharacter")
978 net.WriteInt(tbl[index].id, 20)
979 net.Send(ply)
980 end)
981 end)
982
983 return
984 else
985 data.clone_id = math.random(1000, 9999)
986 end
987 end
988
989 VoidChar.SQL.CreateCharacter(ply, {
990 name = data.name,
991 clone_id = data.clone_id,
992 job = data.job,
993 model = data.model,
994 wallet = VoidChar.Config.DefaultMoney or 200,
995 faction = data.faction,
996 bodygroups = data.bodygroups or ""
997 }, function(succ, tbl, index)
998
999 if !succ then return end
1000
1001 Ply.SelectCharacter(ply, tbl[index])
1002
1003 local characters = ply:GetCharacters()
1004
1005 characters = util.TableToJSON(characters)
1006 characters = util.Compress(characters)
1007
1008 net.Start("VoidChar.RequestCharacters")
1009 net.WriteUInt(#characters, 32)
1010 net.WriteData(characters, #characters)
1011 net.WriteBool(false)
1012 net.Send(ply)
1013
1014 net.Start("VoidChar.SelectCharacter")
1015 net.WriteInt(tbl[index].id, 20)
1016 net.Send(ply)
1017 end)
1018 end)
1019end net.Receive("VoidChar.CreateCharacter", Ply.RequestCreateCharacter)
1020
1021function Ply.RequestDeleteCharacter(len, ply)
1022 Ply.Data[ply] = Ply.Data[ply] or {}
1023
1024 local char_id = net.ReadInt(20)
1025
1026 if not char_id then return end
1027 if not ply:GetCharacterByID(char_id) then return end
1028
1029 hook.Run("VoidChar.CharacterDeleted", ply, ply:GetCharacterByID(char_id))
1030
1031 VoidChar.SQL.DeleteCharacter(ply, char_id)
1032end net.Receive("VoidChar.DeleteCharacter", Ply.RequestDeleteCharacter)
1033
1034--[[---------------------------------------------------------
1035 Name: Admin Menu
1036-----------------------------------------------------------]]
1037function Ply.AdminGetCharacters(len, ply)
1038 if not VoidChar.Config.AdminMenu[ply:GetUserGroup()] then return end
1039
1040 VoidChar.SQL.GetAllCharacters(function(characters)
1041 characters = util.TableToJSON(characters)
1042 characters = util.Compress(characters)
1043
1044 net.Start("VoidChar.AdminGetCharacters")
1045 net.WriteUInt(#characters, 32)
1046 net.WriteData(characters, #characters)
1047 net.WriteBool(false)
1048 net.Send(ply)
1049
1050 end)
1051end net.Receive("VoidChar.AdminGetCharacters", Ply.AdminGetCharacters)
1052
1053function Ply.AdminGetWhitelist(len, ply)
1054 if VoidChar.Config.UseBWhitelist then return end
1055 if not VoidChar.Config.AdminMenu[ply:GetUserGroup()] then return end
1056
1057 local sid = net.ReadString()
1058
1059 VoidChar.SQL.GetWhitelists(sid, function(data)
1060 net.Start("VoidChar.AdminGetWhitelist")
1061 net.WriteTable(data)
1062 net.Send(ply)
1063 end)
1064end net.Receive("VoidChar.AdminGetWhitelist", Ply.AdminGetWhitelist)
1065
1066function Ply.AdminRemoveWhitelist(len, ply)
1067 if VoidChar.Config.UseBWhitelist then return end
1068 if not VoidChar.Config.AdminMenu[ply:GetUserGroup()] then return end
1069
1070 local sid = net.ReadString()
1071 local job = net.ReadFloat()
1072
1073 local pl = player.GetBySteamID64(sid)
1074
1075 VoidChar.SQL.RemoveWhitelist(sid, job)
1076
1077 if (IsValid(pl)) then
1078 Ply.Data[pl].whitelist[tonumber(job)] = true
1079
1080 Ply.RequestWhitelist(0, ply, true)
1081 Ply.RequestWhitelist(0, pl, true)
1082 end
1083
1084
1085
1086end net.Receive("VoidChar.AdminRemoveWhitelist", Ply.AdminRemoveWhitelist)
1087
1088function Ply.AdminAddWhitelist(len, ply)
1089 if VoidChar.Config.UseBWhitelist then return end
1090 if not VoidChar.Config.AdminMenu[ply:GetUserGroup()] then return end
1091
1092
1093 local sid = net.ReadString()
1094 local job = net.ReadFloat()
1095
1096 local pl = player.GetBySteamID64(sid)
1097 Ply.Data[pl].whitelist[tonumber(job)] = true
1098
1099 VoidChar.SQL.AddWhitelist(sid, job)
1100 Ply.RequestWhitelist(0, ply, true)
1101 Ply.RequestWhitelist(0, pl, true)
1102
1103
1104end net.Receive("VoidChar.AdminAddWhitelist", Ply.AdminAddWhitelist)
1105
1106function Ply.AdminRemoveCharacter(len, ply)
1107 if not VoidChar.Config.AdminMenu[ply:GetUserGroup()] then return end
1108
1109 local characterid = net.ReadInt(32)
1110
1111 if not characterid then return end
1112
1113 local plySid
1114 VoidChar.SQL.GetCharacterByCharID(characterid, function (result)
1115 if (result and #result > 0) then
1116 plySid = result[1].sid
1117 end
1118
1119 if (plySid) then
1120
1121
1122 local charPly = player.GetBySteamID64(plySid)
1123 if (charPly) then
1124 VoidChar.SQL.DeleteCharacter(charPly, characterid)
1125 end
1126
1127 if (VoidChar.Config.ForceCharSelectionOnDelete) then
1128 net.Start("VoidChar.ForceOpenMenu")
1129 net.Send(charPly)
1130 end
1131
1132 end
1133
1134
1135
1136 hook.Run("VoidChar.CharacterDeleted", nil, characterid)
1137
1138
1139 end)
1140
1141end net.Receive("VoidChar.AdminDeleteCharacter", Ply.AdminRemoveCharacter)
1142
1143function Ply.AdminModifyCharacter(len, ply)
1144 if not VoidChar.Config.AdminMenu[ply:GetUserGroup()] then return end
1145
1146
1147 local character = net.ReadTable()
1148
1149 if not character.id then return end
1150
1151 ply = player.GetBySteamID64(character.sid)
1152
1153
1154 local jobCheck = DarkRP.getJobByCommand(character.job)
1155 local factionCheck = (VoidChar.Config.FactionSystem and VoidChar.Config.Factions[character.faction]) or false
1156
1157 VoidChar.SQL.GetCharacterByID(character.id, function(char)
1158 for k, v in pairs(character) do
1159 VoidChar.SQL.UpdateValue(character.id, "wallet", character.wallet)
1160 if jobCheck then
1161 VoidChar.SQL.UpdateValue(character.id, "job", "\"".. character.job.. "\"")
1162 end
1163 VoidChar.SQL.UpdateValue(character.id, "name", "\"".. character.name.. "\"")
1164 if factionCheck then
1165 VoidChar.SQL.UpdateValue(character.id, "faction", "\"".. character.faction.. "\"")
1166 end
1167 end
1168
1169 local prevChar = character.job
1170 local tbl, i = DarkRP.getJobByCommand(character.job)
1171 character.job = i
1172
1173
1174 if ply and ply:GetCharacter().id == character.id then
1175 ply:setDarkRPVar("money", character.wallet)
1176 if jobCheck then
1177 ply:changeTeam(tonumber(character.job), true, true)
1178 end
1179
1180 if character.clone_id != "NULL" and character.clone_id != false and VoidChar.Config.EnableCloneID then
1181 local hashtag = (VoidChar.Config.ShowHashtag and "#") or ""
1182
1183
1184 if VoidChar.Config.DisplayAsSuffix then
1185 ply:setDarkRPVar("rpname", hashtag .. character.clone_id.. " " .. character.name)
1186 else
1187 ply:setDarkRPVar("rpname", character.name.. " " .. hashtag .. character.clone_id)
1188 end
1189 else
1190 ply:setDarkRPVar("rpname", character.name)
1191 end
1192
1193
1194 character.job = prevChar
1195 if !jobCheck then
1196 character.job = ply:GetCharacter().job
1197 end
1198
1199
1200 VoidChar.SQL.UpdateCharacters(ply, function()
1201 local characters = ply:GetCharacters()
1202
1203 characters = util.TableToJSON(characters)
1204 characters = util.Compress(characters)
1205
1206 net.Start("VoidChar.RequestCharacters")
1207 net.WriteUInt(#characters, 32)
1208 net.WriteData(characters, #characters)
1209 net.WriteBool(false)
1210 net.Send(ply)
1211 end)
1212
1213 end
1214 end)
1215end net.Receive("VoidChar.AdminModifyCharacter", Ply.AdminModifyCharacter)
1216
1217--[[---------------------------------------------------------
1218 Name: Character API
1219-----------------------------------------------------------]]
1220
1221function PLAYER:SetCharacterVar(key, value)
1222 if !key or !value then return end
1223
1224 Ply.Data[self].character[key] = value
1225end
1226
1227function PLAYER:GetCharacterVar(key)
1228 if !key then return end
1229
1230 local value = Ply.Data[self].character[key]
1231 if !value then return end
1232 return value
1233end
1234
1235--[[---------------------------------------------------------
1236 Name: Whitelist API
1237-----------------------------------------------------------]]
1238
1239function Ply.IsPlayerWhitelisted(sid, job, callback)
1240
1241 if !IsEntity(sid) and VoidChar.Config.UseBWhitelist then
1242 callback(false)
1243 return false
1244 end
1245
1246 if VoidChar.Config.UseBWhitelist then
1247 if !GAS.JobWhitelist:IsWhitelistEnabled( job ) then
1248 callback(true)
1249 return true
1250 else
1251 local AccessibleJobs, AccessibleJobsCount = GAS.JobWhitelist:GetPlayerAccessibleJobs( sid )
1252 if (AccessibleJobs[job] or GAS.JobWhitelist:IsWhitelisted( sid, job )) then
1253 callback(true)
1254 return true
1255 else
1256 callback(false)
1257 return false
1258 end
1259 end
1260 end
1261
1262 local ply = (IsEntity(sid) and sid) or nil
1263
1264 sid = (IsEntity(sid) and sid:SteamID64()) or sid
1265
1266 VoidChar.SQL.GetWhitelists(sid, function(data)
1267 local jobs = {}
1268
1269 for k, v in pairs(VoidChar.Config.DefaultJobs) do
1270 jobs[k] = true
1271 end
1272
1273 if ply then
1274 local groupCheck = (VoidChar.Config.xAdminSupport and ply:xAdminGetTag()) or ply:GetUserGroup()
1275 if VoidChar.Config.ULXRanks[groupCheck] then
1276 for k, v in pairs(VoidChar.Config.ULXRanks[groupCheck]) do
1277 jobs[k] = true
1278 end
1279 end
1280
1281 if VoidChar.Config.WhitelistSteamID[ply:SteamID()] or VoidChar.Config.WhitelistRanks[ply:GetUserGroup()] then
1282 for k, v in pairs(RPExtraTeams) do
1283 jobs[v.team] = true
1284 end
1285 end
1286 end
1287
1288 if data and data[1] then
1289 local _jobs = util.JSONToTable(data[1].jobs)
1290 for k, v in pairs(_jobs) do
1291 jobs[k] = v
1292 end
1293 end
1294
1295 if jobs[tonumber(job)] then
1296 callback(true)
1297 return true
1298 end
1299
1300 callback(false)
1301 end)
1302end
1303
1304function Ply.WhitelistPlayer(sid, job)
1305 local pl = player.GetBySteamID64(sid)
1306 if pl and IsValid(pl) then
1307 Ply.Data[pl].whitelist[tonumber(job)] = true
1308 end
1309
1310 VoidChar.SQL.AddWhitelist(sid, job)
1311 if pl and IsValid(pl) then
1312 Ply.RequestWhitelist(0, pl, true)
1313 end
1314end
1315
1316function Ply.UnWhitelistPlayer(sid, job)
1317 local pl = player.GetBySteamID64(sid)
1318 if pl and IsValid(pl) then
1319 Ply.Data[pl].whitelist[tonumber(job)] = false
1320 end
1321
1322 VoidChar.SQL.RemoveWhitelist(sid, job)
1323 if pl and IsValid(pl) then
1324 Ply.RequestWhitelist(0, pl, true)
1325 end
1326end
1327
1328
1329VoidChar.Ply = Ply