Skip to content

Commit 287be3b

Browse files
Merge: refactor(esx_multicharacter): complete UI/Backend overhaul
refactor(esx_multicharacter): complete UI/Backend overhaul
2 parents 5d7dd07 + 87e13f3 commit 287be3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1168
-918
lines changed

[core]/esx_multicharacter/client/main.lua

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,3 @@
1-
2-
-- Connection Logic
3-
4-
local function AwaitContext()
5-
while GetResourceState("esx_context") ~= "started" do
6-
Wait(100)
7-
end
8-
return true
9-
end
10-
111
CreateThread(function()
122

133
while not ESX.PlayerLoaded do
@@ -16,13 +6,8 @@ CreateThread(function()
166
if NetworkIsPlayerActive(ESX.playerId) then
177
ESX.DisableSpawnManager()
188
DoScreenFadeOut(0)
19-
20-
local ready = AwaitContext()
21-
if ready then
22-
23-
Multicharacter:SetupCharacters()
24-
break
25-
end
9+
Multicharacter:SetupCharacters()
10+
break
2611
end
2712
end
2813
end)
Lines changed: 25 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
11
Menu = {}
2-
Menu._index = Menu
3-
Menu.currentElements = {}
4-
5-
function Menu:OpenMenu()
6-
ESX.OpenContext("left", self.currentElements, self.onUse, nil, false)
7-
end
8-
9-
function Menu:Close()
10-
self.currentElements = {}
11-
ESX.CloseContext()
12-
end
132

143
function Menu:CheckModel(character)
154
if not character.model and character.skin then
@@ -23,18 +12,6 @@ function Menu:CheckModel(character)
2312
end
2413
end
2514

26-
function Menu:AddCharacters()
27-
for _, v in pairs(Multicharacter.Characters) do
28-
self:CheckModel(v)
29-
30-
local label = ("%s %s"):format(v.firstname, v.lastname)
31-
self.currentElements[#self.currentElements + 1] = { title = label, icon = "fa-regular fa-user", value = v.id}
32-
end
33-
if #self.currentElements - 1 < Multicharacter.slots then
34-
self.currentElements[#self.currentElements + 1] = { title = TranslateCap("create_char"), icon = "fa-solid fa-plus", value = (#self.currentElements + 1), new = true }
35-
end
36-
end
37-
3815
local GetSlot = function()
3916
for i = 1, Multicharacter.slots do
4017
if not Multicharacter.Characters[i] then
@@ -44,7 +21,6 @@ local GetSlot = function()
4421
end
4522

4623
function Menu:NewCharacter()
47-
self:Close()
4824
local slot = GetSlot()
4925

5026
TriggerServerEvent("esx_multicharacter:CharacterChosen", slot, true)
@@ -59,133 +35,43 @@ function Menu:NewCharacter()
5935
end
6036

6137

62-
function Menu:SelectCharacter()
38+
function Menu:InitCharacter()
6339
local Characters = Multicharacter.Characters
6440
local Character = next(Characters)
6541
self:CheckModel(Characters[Character])
6642

6743
if not Multicharacter.spawned then
6844
Multicharacter:SetupCharacter(Character)
6945
end
70-
71-
self.currentElements = {
72-
{
73-
title = TranslateCap("select_char"),
74-
icon = "fa-solid fa-users",
75-
description = TranslateCap("select_char_description"),
76-
unselectable = true
46+
Wait(500)
47+
48+
SendNUIMessage({
49+
action = "ToggleMulticharacter",
50+
data = {
51+
show = true,
52+
Characters = Characters,
53+
CanDelete = Config.CanDelete,
54+
AllowedSlot = Multicharacter.slots,
55+
Locale = Locales[Config.Locale].UI,
7756
}
78-
}
79-
80-
self:AddCharacters()
81-
self.onUse = function(_, SelectedCharacter)
82-
if SelectedCharacter.new then
83-
self:NewCharacter()
84-
else
85-
if SelectedCharacter.value ~= Multicharacter.spawned then
86-
Multicharacter:SetupCharacter(SelectedCharacter.value)
87-
local playerPed = PlayerPedId()
88-
SetPedAoBlobRendering(playerPed, true)
89-
ResetEntityAlpha(playerPed)
90-
end
91-
self:CharacterOptions()
92-
end
93-
end
57+
})
9458

95-
self:OpenMenu()
59+
SetNuiFocus(true, true)
9660
end
9761

98-
99-
function Menu:CharacterOptions()
100-
local currentCharacter = Multicharacter.Characters[Multicharacter.spawned]
101-
local elements = {
102-
{
103-
title = TranslateCap("character", currentCharacter.firstname .. " " .. currentCharacter.lastname),
104-
icon = "fa-regular fa-user",
105-
unselectable = true
106-
},
107-
{
108-
title = TranslateCap("return"),
109-
unselectable = false,
110-
icon = "fa-solid fa-arrow-left",
111-
description = TranslateCap("return_description"),
112-
action = "return"
113-
},
114-
}
115-
116-
if not currentCharacter.disabled then
117-
elements[3] = {
118-
title = TranslateCap("char_play"),
119-
description = TranslateCap("char_play_description"),
120-
icon = "fa-solid fa-play",
121-
action = "play",
122-
}
123-
else
124-
elements[3] = {
125-
title = TranslateCap("char_disabled"),
126-
icon = "fa-solid fa-xmark",
127-
description = TranslateCap("char_disabled_description")
128-
}
129-
end
130-
if Config.CanDelete then
131-
elements[4] = {
132-
title = TranslateCap("char_delete"),
133-
icon = "fa-solid fa-xmark",
134-
description = TranslateCap("char_delete_description"),
135-
action = "delete",
136-
}
137-
end
138-
139-
self.currentElements = elements
140-
self.onUse = function(_, Action)
141-
if Action.action == "play" then
142-
Multicharacter:CloseUI()
143-
self:Close()
144-
145-
TriggerServerEvent("esx_multicharacter:CharacterChosen", Multicharacter.spawned, false)
146-
elseif Action.action == "delete" then
147-
self:ConfirmDeletion()
148-
elseif Action.action == "return" then
149-
self:SelectCharacter()
150-
end
151-
end
152-
153-
self:OpenMenu()
62+
function Menu:SelectCharacter(index)
63+
Multicharacter:SetupCharacter(index)
64+
local playerPed = PlayerPedId()
65+
SetPedAoBlobRendering(playerPed, true)
66+
ResetEntityAlpha(playerPed)
15467
end
15568

156-
function Menu:ConfirmDeletion()
157-
self.currentElements = {
158-
{
159-
title = TranslateCap("char_delete_confirmation"),
160-
icon = "fa-solid fa-users",
161-
description = TranslateCap("char_delete_confirmation_description"),
162-
unselectable = true
163-
},
164-
{
165-
title = TranslateCap("char_delete"),
166-
icon = "fa-solid fa-xmark",
167-
description = TranslateCap("char_delete_yes_description"),
168-
action = "delete",
169-
},
170-
{
171-
title = TranslateCap("return"),
172-
unselectable = false,
173-
icon = "fa-solid fa-arrow-left",
174-
description = TranslateCap("char_delete_no_description"),
175-
action = "return"
176-
},
177-
}
178-
179-
self.onUse = function(_, Action)
180-
if Action.action == "delete" then
181-
self:Close()
182-
183-
TriggerServerEvent("esx_multicharacter:DeleteCharacter", Multicharacter.spawned)
184-
Multicharacter.spawned = false
185-
elseif Action.action == "return" then
186-
self:CharacterOptions()
187-
end
188-
end
69+
function Menu:PlayCharacter()
70+
Multicharacter:CloseUI()
71+
TriggerServerEvent("esx_multicharacter:CharacterChosen", Multicharacter.spawned, false)
72+
end
18973

190-
self:OpenMenu()
74+
function Menu:DeleteCharacter()
75+
TriggerServerEvent("esx_multicharacter:DeleteCharacter", Multicharacter.spawned)
76+
Multicharacter.spawned = false
19177
end

[core]/esx_multicharacter/client/modules/multicharacter.lua

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ function Multicharacter:SetupCamera()
1212

1313
local offset = GetOffsetFromEntityInWorldCoords(self.playerPed, 0, 1.7, 0.4)
1414

15-
SetCamCoord(self.cam, offset.x, offset.y, offset.z)
16-
PointCamAtCoord(self.cam, self.spawnCoords.x, self.spawnCoords.y, self.spawnCoords.z + 1.3)
15+
SetCamCoord(self.cam, offset.x + 0.7, offset.y , offset.z)
16+
PointCamAtCoord(self.cam, self.spawnCoords.x + 0.4, self.spawnCoords.y, self.spawnCoords.z + 1.3)
1717
end
1818

1919
function Multicharacter:AwaitFadeIn()
@@ -116,14 +116,17 @@ function Multicharacter:ChangeExistingPed()
116116
local newCharacter = self.Characters[self.tempIndex]
117117
local spawnedCharacter = self.Characters[self.spawned]
118118

119+
if not newCharacter.model then
120+
newCharacter.model = newCharacter.sex == TranslateCap("male") and `mp_m_freemode_01` or `mp_f_freemode_01`
121+
end
122+
119123
if spawnedCharacter and spawnedCharacter.model then
120124
local model = ESX.Streaming.RequestModel(newCharacter.model)
121125
if model then
122126
SetPlayerModel(ESX.playerId, newCharacter.model)
123127
SetModelAsNoLongerNeeded(newCharacter.model)
124128
end
125129
end
126-
127130
TriggerEvent("skinchanger:loadSkin", newCharacter.skin)
128131
end
129132

@@ -135,8 +138,12 @@ end
135138

136139
function Multicharacter:CloseUI()
137140
SendNUIMessage({
138-
action = "closeui",
141+
action = "ToggleMulticharacter",
142+
data = {
143+
show = false
144+
}
139145
})
146+
SetNuiFocus(false, false)
140147
end
141148

142149
function Multicharacter:SetupCharacter(index)
@@ -152,10 +159,6 @@ function Multicharacter:SetupCharacter(index)
152159
self.spawned = index
153160
self.playerPed = PlayerPedId()
154161
self:PrepForUI()
155-
SendNUIMessage({
156-
action = "openui",
157-
character = character,
158-
})
159162
end
160163

161164
function Multicharacter:SetupUI(characters, slots)
@@ -180,7 +183,7 @@ function Multicharacter:SetupUI(characters, slots)
180183
TriggerEvent("esx_identity:showRegisterIdentity")
181184
end)
182185
else
183-
Menu:SelectCharacter()
186+
Menu:InitCharacter()
184187
end
185188
end
186189

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
RegisterNuiCallback('SelectCharacter', function (data, cb)
2+
local selectedIndex = tonumber(data.id)
3+
4+
if selectedIndex then
5+
Menu:SelectCharacter(selectedIndex)
6+
end
7+
cb('ok')
8+
end)
9+
10+
RegisterNuiCallback('PlayCharacter', function (data, cb)
11+
Menu:PlayCharacter()
12+
cb('ok')
13+
end)
14+
15+
RegisterNuiCallback('DeleteCharacter', function (data, cb)
16+
Menu:DeleteCharacter()
17+
cb('ok')
18+
end)
19+
20+
RegisterNuiCallback('CreateCharacter', function (data, cb)
21+
Menu:NewCharacter()
22+
cb('ok')
23+
end)

[core]/esx_multicharacter/config.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Config.CanDelete = true
77
if IsDuplicityVersion() then
88
-- This is the default number of slots for EVERY player
99
-- If you want to manage extra slots for specific players you can do it by using '/setslots' and '/remslots' commands
10-
Config.Slots = 4
10+
Config.Slots = 3
1111
--------------------
1212

1313
-- Text to prepend to each character (char#:identifier) - keep it short

[core]/esx_multicharacter/fxmanifest.lua

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
fx_version 'cerulean'
2-
32
game 'gta5'
43
author 'ESX-Framework - Linden - KASH'
54
description 'Allows players to have multiple characters on the same account.'
@@ -21,6 +20,6 @@ client_scripts {
2120
'client/*.lua'
2221
}
2322

24-
ui_page { 'html/ui.html' }
23+
ui_page 'web/build/index.html'
2524

26-
files { 'html/ui.html', 'html/css/main.css', 'html/js/app.js', 'html/locales/*.js' }
25+
files { 'web/build/index.html', 'web/build/**/*.*'}

0 commit comments

Comments
 (0)