FrameworkZ 4.4.2
Provides a framework for Project Zomboid with various systems.
Loading...
Searching...
No Matches
Players.lua
Go to the documentation of this file.
1--! \page global_variables Global Variables
2--! \section Players Players
3--! FrameworkZ.Players\n
4--! See Players for the module on players.\n\n
5--! FrameworkZ.Players.List\n
6--! A list of all instanced players in the game.
7
8local getPlayer = getPlayer
9local isClient = isClient
10
11FrameworkZ = FrameworkZ or {}
12
13--! \brief Players module for FrameworkZ. Defines and interacts with PLAYER object.
14--! \class FrameworkZ.Players
15FrameworkZ.Players = {}
16
17--! \brief List of all instanced players in the game.
18FrameworkZ.Players.List = {}
19
20--! \brief Roles for players in FrameworkZ.
21FrameworkZ.Players.Roles = {
22 User = "User",
23 Operator = "Operator",
24 Moderator = "Moderator",
25 Admin = "Admin",
26 Super_Admin = "Super Admin",
27 Owner = "Owner"
28}
29FrameworkZ.Players = FrameworkZ.Foundation:NewModule(FrameworkZ.Players, "Players")
30
31--! \class PLAYER
32--! \brief Player class for FrameworkZ.
33local PLAYER = {}
34PLAYER.__index = PLAYER
36--! \brief Initializes the player object.
37--! \return \string The username of the player.
38function PLAYER:Initialize()
39 if not self.isoPlayer then return end
40
41 local firstConnection = false
42 local characterModData = self.isoPlayer:getModData()["FZ_PLY"] or nil
44 if not characterModData then
45 firstConnection = true
46
47 self:InitializeDefaultFactionWhitelists()
48
49 self.isoPlayer:getModData()["FZ_PLY"] = {
50 username = self.username,
51 steamID = self.steamID,
52 role = self.role,
53 maxCharacters = self.maxCharacters,
54 previousCharacter = self.previousCharacter,
55 whitelists = self.whitelists,
56 characters = self.characters
57 }
58
59 if isClient() then
60 self.isoPlayer:transmitModData()
61 end
62 end
63
64 self:ValidatePlayerData()
65
66 --[[if isClient() then
67 FrameworkZ.Timers:Simple(5, function()
68 sendClientCommand("FZ_PLY", "initialize", {self.isoPlayer:getUsername()})
69 end)
70 end--]]
71
72 return FrameworkZ.Players:Initialize(self.username, self)
73end
75--! \brief Saves the player's data.
76--! \param shouldTransmit \boolean (Optional) Whether or not to transmit the player's data to the server.
77--! \return \boolean Whether or not the player was successfully saved.
78--! \todo Test if localized variable (playerData) maintains referential integrity for transmitModData() to work on it.
79function PLAYER:Save(shouldTransmit)
80 if shouldTransmit == nil then shouldTransmit = true end
81
82 if not self.isoPlayer then return false end
83
84 local playerData = self:GetStoredData()
85
86 if not playerData then return false end
87
88 playerData.role = self.role
89 playerData.maxCharacters = self.maxCharacters
90 playerData.previousCharacter = self.previousCharacter
91 playerData.whitelists = self.whitelists
92 playerData.characters = self.characters
93
94 if shouldTransmit then
95 self.isoPlayer:transmitModData()
96 end
97
98 return true
99end
100
101--! \brief Destroys the player object.
102--! \return \mixed of \boolean Whether or not the player was successfully destroyed and \string The message on success or failure.
103function PLAYER:Destroy()
104 if not self.isoPlayer then return false, "Critical save fail: Iso Player is nil." end
105
106 local username = self.isoPlayer:getUsername()
107 local success1, success2, message
108
109 if FrameworkZ.Players.List[username] then
110 success1, message = FrameworkZ.Players:Save(username)
111 end
113 if FrameworkZ.Characters.List[username] then
114 FrameworkZ.Characters.List[username] = nil
115 end
117 if FrameworkZ.Players.List[username] then
118 FrameworkZ.Players.List[username] = nil
119 end
120
121 if success1 and success2 then
122 return true, message
123 end
124
125 return false, message
126end
127
128function PLAYER:InitializeDefaultFactionWhitelists()
129 local factions = FrameworkZ.Factions.List
131 for k, v in pairs(factions) do
132 if v.isWhitelistedByDefault then
133 self.whitelists[v.id] = true
134 end
135 end
136end
137
138function PLAYER:ValidatePlayerData()
139 local characterModData = self.isoPlayer:getModData()["FZ_PLY"]
141 if not characterModData then return false end
142
143 local initializedNewData = false
145 if not characterModData.username then
146 initializedNewData = true
147 characterModData.username = self.username or getPlayer():getUsername()
148 end
149
150 if not characterModData.steamID then
151 initializedNewData = true
152 characterModData.steamID = self.steamID or getPlayer():getSteamID()
153 end
154
155 if not characterModData.role then
156 initializedNewData = true
157 characterModData.role = self.role or FrameworkZ.Players.Roles.User
158 end
159
160 if not characterModData.maxCharacters then
161 initializedNewData = true
162 characterModData.maxCharacters = self.maxCharacters or FrameworkZ.Config.DefaultMaxCharacters
163 end
164
165 if not characterModData.previousCharacter then
166 initializedNewData = true
167 characterModData.previousCharacter = self.previousCharacter or nil
168 end
169
170 if not characterModData.whitelists then
171 self:InitializeDefaultFactionWhitelists()
172 initializedNewData = true
173 characterModData.whitelists = self.whitelists
174 end
175
176 if not characterModData.characters then
177 initializedNewData = true
178 characterModData.characters = self.characters or {}
179 end
181 if isClient() then
182 self.isoPlayer:transmitModData()
183 end
184
185 self.username = characterModData.username
186 self.steamID = characterModData.steamID
187 self.role = characterModData.role
188 self.maxCharacters = characterModData.maxCharacters
189 self.previousCharacter = characterModData.previousCharacter
190 self.whitelists = characterModData.whitelists
191 self.characters = characterModData.characters
193 return initializedNewData
194end
195
196--! \brief Gets the stored player mod data table. Used internally. Do not use this unless you know what you are doing. Updating data on the mod data will cause inconsistencies between the mod data and the FrameworkZ player object.
197--! \return \table The stored player mod data table.
198function PLAYER:GetStoredData()
199 return self.isoPlayer:getModData()["FZ_PLY"]
200end
201
202function PLAYER:GetWhitelists()
203 return self.whitelists
204end
205
206function PLAYER:SetWhitelisted(factionID, whitelisted)
207 if not factionID then return false end
209 self.whitelists[factionID] = whitelisted
210 self:GetStoredData().whitelists[factionID] = whitelisted
211
212 return true
213end
215function PLAYER:IsWhitelisted(factionID)
216 if not factionID then return false end
217
218 return self.whitelists[factionID] or false
219end
221--! \brief Plays a sound for the player that only they can hear.
222--! \param soundName \string The name of the sound to play.
223--! \return \integer The sound's ID.
224function PLAYER:PlayLocalSound(soundName)
225 return self.isoPlayer:getEmitter():playSoundImpl(soundName, nil)
226end
227
228--! \brief Stops a sound for the player.
229--! \param soundNameOrID \mixed of \string or \integer The name or ID of the sound to stop.
230function PLAYER:StopSound(soundNameOrID)
231 if type(soundNameOrID) == "number" then
232 self.isoPlayer:getEmitter():stopSound(soundNameOrID)
233 elseif type(soundNameOrID) == "string" then
234 self.isoPlayer:getEmitter():stopSoundByName(soundNameOrID)
235 end
236end
237
238function FrameworkZ.Players:New(isoPlayer)
239 if not isoPlayer then return false end
241 local object = {
242 username = isoPlayer:getUsername(),
243 isoPlayer = isoPlayer,
244 steamID = isoPlayer:getSteamID(),
245 role = FrameworkZ.Players.Roles.User,
246 loadedCharacter = nil,
247 maxCharacters = FrameworkZ.Config.DefaultMaxCharacters,
248 previousCharacter = nil,
249 whitelists = {},
250 characters = {}
251 }
253 setmetatable(object, PLAYER)
255 return object
256end
257
258function FrameworkZ.Players:Initialize(username, player)
259 self.List[username] = player
261 return username
262end
263
264function FrameworkZ.Players:GetPlayerByID(username)
265 if not username then return false end
267 local player = self.List[username]
268
269 if player then
270 return player
271 end
272
273 return false
274end
275
276function FrameworkZ.Players:GetCharacterByID(username, characterID)
277 if not username or not characterID then return false end
278
279 local player = self:GetPlayerByID(username)
280
281 if player then
282 local character = player.characters[characterID]
283
284 if character then
285 return character
286 end
287 end
288
289 return false
290end
291
292--! \brief Gets saved character data by their ID.
293--! \param username \string The username of the player.
294--! \param characterID \integer The ID of the character.
295--! \return \table or \boolean The character data or false if the data failed to be retrieved.
296function FrameworkZ.Players:GetCharacterDataByID(username, characterID)
297 if not username or not characterID then return false end
298
299 local player = FrameworkZ.Players:GetPlayerByID(username)
300
301 if player then
302 local character = player.characters[characterID]
303
304 if character then
305 return character
306 end
307 end
308
309 return false
310end
311
312function FrameworkZ.Players:ResetCharacterSaveInterval()
313 if FrameworkZ.Timers:Exists("FZ_CharacterSaveInterval") then
314 FrameworkZ.Timers:Start("FZ_CharacterSaveInterval")
315 end
316end
317
318function FrameworkZ.Players:CreateCharacter(username, data)
319 if not username or not data then return false end
320
321 local player = self:GetPlayerByID(username)
322
323 if player and player.characters then
324 FrameworkZ.Players:ResetCharacterSaveInterval()
325
326 data.META_ID = #player.characters + 1
327 data.META_FIRST_LOAD = true
328
329 table.insert(player.characters, data)
330 player:GetStoredData().characters = player.characters
331
332 if isClient() then
333 player.isoPlayer:transmitModData()
334 end
335
336 return true, #player.characters
337 end
338
339 return false
340end
341
342--! \brief Saves the player and their currently loaded character.
343--! \param username \string The username of the player.
344--! \param continueOnFailure \boolean (Optional) Whether or not to continue saving either the player or character if either should fail. Default = false. True not recommended.
345--! \return \boolean Whether or not the player was successfully saved.
346--! \return \string The failure message if the player or character failed to save.
347function FrameworkZ.Players:Save(username, continueOnFailure)
348 if continueOnFailure == nil then continueOnFailure = false end
349
350 local player = FrameworkZ.Players:GetPlayerByID(username)
351
352 if not player then return false end
353
354 local saved = false
355 local failureMessage = ""
356 local character = player.loadedCharacter
357 local characterSaved = false
358 local playerSaved = player:Save(false)
359 saved = playerSaved
360
361 if not saved and not continueOnFailure then
362 return false, "Failed to save player data."
363 elseif not saved and continueOnFailure then
364 failureMessage = "Failed to save player data."
365 end
366
367 if character then
368 characterSaved = character:Save(false)
369 saved = characterSaved
370
371 if not saved and not continueOnFailure then
372 return false, "Failed to save character data."
373 elseif not saved and continueOnFailure then
374 failureMessage = failureMessage == "Failed to save player data." and "Failed to save both player data and character data." or "Player data saved, but failed to save character data."
375 end
376 else
377 characterSaved = true -- No character loaded, set true to prevent returning false.
378 end
379
380 if isClient() then
381 player.isoPlayer:transmitModData()
382 end
383
384 if playerSaved and characterSaved then
385 saved = true
386 else
387 saved = false
388 end
389
390 return saved, failureMessage
391end
392
393function FrameworkZ.Players:Destroy(username)
394 local properlyDestroyed = false
395 local message = "Failed to destroy player."
396 local player = self:GetPlayerByID(username)
397
398 if player then
399 properlyDestroyed, message = player:Destroy()
400 end
401
402 return properlyDestroyed, message
403end
404
405function FrameworkZ.Players:SaveCharacter(username, character)
406 local player = FrameworkZ.Players:GetPlayerByID(username)
407
408 if not player or not character then return false end
409
410 local isoPlayer = player.isoPlayer
411
412 character.INVENTORY_PHYSICAL = {}
413 local inventory = isoPlayer:getInventory():getItems()
414 for i = 0, inventory:size() - 1 do
415 table.insert(character.INVENTORY_PHYSICAL, {id = inventory:get(i):getFullType()})
416 end
417
418 character.INVENTORY_LOGICAL = FrameworkZ.Characters:GetCharacterInventoryByID(username).items
419
420 character.EQUIPMENT_SLOT_HEAD = isoPlayer:getWornItem(EQUIPMENT_SLOT_HEAD) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_HEAD):getFullType()} or nil
421 character.EQUIPMENT_SLOT_FACE = isoPlayer:getWornItem(EQUIPMENT_SLOT_FACE) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_FACE):getFullType()} or nil
422 character.EQUIPMENT_SLOT_EARS = isoPlayer:getWornItem(EQUIPMENT_SLOT_EARS) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_EARS):getFullType()} or nil
423 character.EQUIPMENT_SLOT_BACKPACK = isoPlayer:getWornItem(EQUIPMENT_SLOT_BACKPACK) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_BACKPACK):getFullType()} or nil
424 character.EQUIPMENT_SLOT_GLOVES = isoPlayer:getWornItem(EQUIPMENT_SLOT_GLOVES) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_GLOVES):getFullType()} or nil
425 character.EQUIPMENT_SLOT_UNDERSHIRT = isoPlayer:getWornItem(EQUIPMENT_SLOT_UNDERSHIRT) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_UNDERSHIRT):getFullType()} or nil
426 character.EQUIPMENT_SLOT_OVERSHIRT = isoPlayer:getWornItem(EQUIPMENT_SLOT_OVERSHIRT) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_OVERSHIRT):getFullType()} or nil
427 character.EQUIPMENT_SLOT_VEST = isoPlayer:getWornItem(EQUIPMENT_SLOT_VEST) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_VEST):getFullType()} or nil
428 character.EQUIPMENT_SLOT_BELT = isoPlayer:getWornItem(EQUIPMENT_SLOT_BELT) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_BELT):getFullType()} or nil
429 character.EQUIPMENT_SLOT_PANTS = isoPlayer:getWornItem(EQUIPMENT_SLOT_PANTS) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_PANTS):getFullType()} or nil
430 character.EQUIPMENT_SLOT_SOCKS = isoPlayer:getWornItem(EQUIPMENT_SLOT_SOCKS) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_SOCKS):getFullType()} or nil
431 character.EQUIPMENT_SLOT_SHOES = isoPlayer:getWornItem(EQUIPMENT_SLOT_SHOES) and {id = isoPlayer:getWornItem(EQUIPMENT_SLOT_SHOES):getFullType()} or nil
432
433 -- Save character position/direction angle
434 character.POSITION_X = isoPlayer:getX()
435 character.POSITION_Y = isoPlayer:getY()
436 character.POSITION_Z = isoPlayer:getZ()
437 character.DIRECTION_ANGLE = isoPlayer:getDirectionAngle()
438
439 local getStats = isoPlayer:getStats()
440 character.STAT_HUNGER = getStats:getHunger()
441 character.STAT_THIRST = getStats:getThirst()
442 character.STAT_FATIGUE = getStats:getFatigue()
443 character.STAT_STRESS = getStats:getStress()
444 character.STAT_PAIN = getStats:getPain()
445 character.STAT_PANIC = getStats:getPanic()
446 character.STAT_BOREDOM = getStats:getBoredom()
447 --character.STAT_UNHAPPINESS = getStats:getUnhappyness()
448 character.STAT_DRUNKENNESS = getStats:getDrunkenness()
449 character.STAT_ENDURANCE = getStats:getEndurance()
450 --character.STAT_TIREDNESS = getStats:getTiredness()
451
452 --[[
453 modData.status.health = character:getBodyDamage():getOverallBodyHealth()
454 modData.status.injuries = character:getBodyDamage():getInjurySeverity()
455 modData.status.hyperthermia = character:getBodyDamage():getTemperature()
456 modData.status.hypothermia = character:getBodyDamage():getColdStrength()
457 modData.status.wetness = character:getBodyDamage():getWetness()
458 modData.status.hasCold = character:getBodyDamage():HasACold()
459 modData.status.sick = character:getBodyDamage():getSicknessLevel()
460 --]]
461
462 if isClient() then
463 isoPlayer:transmitModData()
464 end
465
466 return true
467end
468
469function FrameworkZ.Players:SaveCharacterByID(username, characterID)
470
471end
472
473--[[
474 Steps:
475 1. Load equipment/items
476 2. Teleport
477 3. Ungod
478 4. Apply damage/wounds/moodles (if applicable)
479 5. Make visible
480 6. Unmute
481 7. Save
482 8. Post load
483 9. Return true
484--]]
485function FrameworkZ.Players:LoadCharacter(username, characterData, survivorDescriptor)
486 local player = FrameworkZ.Players:GetPlayerByID(username)
487
488 if not player or not characterData then return false end
489
490 local isoPlayer = player.isoPlayer
491
492 if characterData.META_FIRST_LOAD == true then
493 isoPlayer:setX(FrameworkZ.Config.SpawnX)
494 isoPlayer:setY(FrameworkZ.Config.SpawnY)
495 isoPlayer:setZ(FrameworkZ.Config.SpawnZ)
496 isoPlayer:setLx(FrameworkZ.Config.SpawnX)
497 isoPlayer:setLy(FrameworkZ.Config.SpawnY)
498 isoPlayer:setLz(FrameworkZ.Config.SpawnZ)
499 else
500 isoPlayer:setX(characterData.POSITION_X)
501 isoPlayer:setY(characterData.POSITION_Y)
502 isoPlayer:setZ(characterData.POSITION_Z)
503 isoPlayer:setLx(characterData.POSITION_X)
504 isoPlayer:setLy(characterData.POSITION_Y)
505 isoPlayer:setLz(characterData.POSITION_Z)
506 isoPlayer:setDirectionAngle(characterData.DIRECTION_ANGLE)
507 end
508
509 isoPlayer:clearWornItems()
510 isoPlayer:getInventory():clear()
511
512 for k, v in pairs(characterData) do
513 if string.match(k, "EQUIPMENT_SLOT_") then
514 if v and v.id then
515 local item = isoPlayer:getInventory():AddItem(v.id)
516 isoPlayer:setWornItem(item:getBodyLocation(), item)
517 end
518 end
519 end
520
521 local isFemale = survivorDescriptor:isFemale()
522 isoPlayer:setFemale(isFemale)
523 isoPlayer:getDescriptor():setFemale(isFemale)
524 isoPlayer:getHumanVisual():clear()
525 isoPlayer:getHumanVisual():copyFrom(survivorDescriptor:getHumanVisual())
526 isoPlayer:resetModel()
527
528 isoPlayer:setGodMod(false)
529 isoPlayer:setInvincible(false)
530
531 -- Apply damage/wounds/moodles
532
533 isoPlayer:setInvisible(false)
534 isoPlayer:setGhostMode(false)
535 isoPlayer:setNoClip(false)
536
537 if VoiceManager:playerGetMute(username) then
538 VoiceManager:playerSetMute(username)
539 end
540
541 local postLoadSuccessful, character = FrameworkZ.Characters:PostLoad(isoPlayer, characterData)
542
543 if not postLoadSuccessful or not character then return false end
544
545 player.loadedCharacter = character
546 character:OnPostLoad(characterData.META_FIRST_LOAD)
547
548 if characterData.META_FIRST_LOAD then
549 characterData.META_FIRST_LOAD = false
550 end
551
552 if not self:SaveCharacter(username, characterData) then return false end
553
554 return true
555end
556
557function FrameworkZ.Players:LoadCharacterByID(username, characterID)
558
559end
560
561function FrameworkZ.Players:DeleteCharacter(username, character)
562
563end
564
565function FrameworkZ.Players:DeleteCharacterByID(username, characterID)
566
567end
568
569function FrameworkZ.Players:InitializeClient(isoPlayer)
570 local player = FrameworkZ.Players:New(isoPlayer)
571
572 if player then
573 player:Initialize()
574 end
575end
576
577if not isClient() then
578 function FrameworkZ.Players.OnClientCommand(module, command, isoPlayer, args)
579 if module == "FZ_PLY" then
580 if command == "initialize" then
581 local player = FrameworkZ.Players:New(isoPlayer)
582
583 if player then
584 player:Initialize()
585 end
586 elseif command == "remove_limbo_protection" then
587 isoPlayer:setGodMod(false)
588 isoPlayer:setInvincible(false)
589 isoPlayer:setInvisible(false)
590 isoPlayer:setGhostMode(false)
591 isoPlayer:setNoClip(false)
592 sendPlayerExtraInfo(isoPlayer)
593 elseif command == "on_first_load" then
594 isoPlayer:setX(FrameworkZ.Config.SpawnX)
595 isoPlayer:setY(FrameworkZ.Config.SpawnY)
596 isoPlayer:setZ(FrameworkZ.Config.SpawnZ)
597 isoPlayer:setLx(FrameworkZ.Config.SpawnX)
598 isoPlayer:setLy(FrameworkZ.Config.SpawnY)
599 isoPlayer:setLz(FrameworkZ.Config.SpawnZ)
600 elseif command == "destroy" then
601 local username = args[1]
602 local player = FrameworkZ.Players:GetPlayerByID(username)
603
604 if player then
605 player:Destroy()
606 end
607
608 FrameworkZ.Characters.List[username] = nil
609 elseif command == "update" then
610 local username = args[1]
611 local field = args[2]
612 local newData = args[3]
613
614 FrameworkZ.Players.List[username][field] = newData
615 end
616 end
617 end
618 Events.OnClientCommand.Add(FrameworkZ.Players.OnClientCommand)
619end
620
621FrameworkZ.Foundation:RegisterModule(FrameworkZ.Players)
void module()
void player
void self isoPlayer
void self self
Definition MainMenu.lua:85
void local newData()
void characterSaved()
void local getStats()
void local getPlayer()
void self username()
void local character()
void local isClient()
void local player()
void elseif command()
void local item()
void local field()
void saved()
void initializedNewData()
void failureMessage()
void local postLoadSuccessful
Definition Players.lua:260
void local isFemale()
void FrameworkZ()
Characters module for FrameworkZ. Defines and interacts with CHARACTER object.
FrameworkZ Characters List
Players module for FrameworkZ. Defines and interacts with PLAYER object.
Definition Players.lua:13
void DeleteCharacter(username, character)
table GetCharacterDataByID(username, characterID)
Gets saved character data by their ID.
void CreateCharacter(username, data)
void LoadCharacterByID(username, characterID)
void LoadCharacter(username, characterData, survivorDescriptor)
void ResetCharacterSaveInterval()
void SaveCharacterByID(username, characterID)
void OnClientCommand(module, command, isoPlayer, args)
void SaveCharacter(username, character)
FrameworkZ Players Roles
Roles for players in FrameworkZ.
Definition Players.lua:23
void New(isoPlayer)
void Initialize(username, player)
void GetCharacterByID(username, characterID)
void Destroy(username)
void InitializeClient(isoPlayer)
FrameworkZ Players List
List of all instanced players in the game.
Definition Players.lua:18
void GetPlayerByID(username)
void DeleteCharacterByID(username, characterID)
boolean Save(username, continueOnFailure)
Saves the player and their currently loaded character.
FrameworkZ global table.
Player class for FrameworkZ.
Definition Players.lua:86
void InitializeDefaultFactionWhitelists()
boolean Save(shouldTransmit)
Saves the player's data.
void StopSound(soundNameOrID)
Stops a sound for the player.
void GetWhitelists()
PLAYER __index
Definition Players.lua:88
mixed Destroy()
Destroys the player object.
integer PlayLocalSound(soundName)
Plays a sound for the player that only they can hear.
table GetStoredData()
Gets the stored player mod data table. Used internally. Do not use this unless you know what you are ...
string Initialize()
Initializes the player object.
void SetWhitelisted(factionID, whitelisted)
void ValidatePlayerData()
void IsWhitelisted(factionID)