Wert Multicharacter System

You can access the setup information you need about this product

INSTALLATION

1 - Upload the script folder to the location of your resources

2 - Check config and editable file settings. Don’t forget to configure the core settings (like the framework) through the config file to match your setup.

3 - Make sure that the ox_lib resource is installed and running. (https://github.com/overextended/ox_lib)

4 - You are ready. Restart ur server and use it. For more options, don’t forget to check the configuration files.

5 - Installation successful, have a good funs

INFORMATION

The script comes with default settings. There are many settings in the configuration file, and you can customize all of them to your personal preferences. Below are the configuration files, feel free to check them out.

OPEN FILES

config.lua

Config = {}

Config.Framework = 'qbox' -- 'qb', 'esx', 'qbox'

Config.CameraDuration = 2000
Config.HiddenCoords = vector4(-2173.76, 5203.01, 17.42, 18.64)
Config.ClothingSystem = 'illenium-appearance' -- 'IzzyAppearance' | 'qb-cloting' | 'illenium-appearance' | 'skinchanger'
Config.DefaultNationality = "United States"
Config.UseSpawnSelector = true -- # Default

Config.DefaultSpawn = vector3(-1035.71, -2731.87, 12.86)
Config.NewSpawnPoint = vector4(4474.09, -4476.97, 4.0, 201.98)

Config.CreateCharacterPosition = vector4(-1042.180176, -2745.059326, 21.343628, 334.488190)

Config.LoadQBHouses = false
Config.UseQBApartments = false
Config.UseQBXProperties = false


Config.LoginSystemCinematic = {
    vector4(-2169.78, 5197.44, 16.88, 194.08),
    vector4(-2168.43, 5192.29, 16.5, 192.35),
    vector4(-2167.55, 5186.87, 15.88, 210.05),
    vector4(-2166.75, 5185.53, 15.7, 251.47)
}

Config.SkipSelection = false
Config.IsInterior = false

Config.DefaultCharacters = {
    male = `mp_m_freemode_01`,
    female = `mp_f_freemode_01`,
}

Config.Logout = {
    active = true,
    -- Command settings
    name = 'logout',
    description = 'Log out a player (Only Admins)',
    group = 'admin', -- Min permission name
    -- Arg
    paramID = 'playerID',
    paramDesc = 'Player ID',
}

Config.SpawnCamAnimation = {
    distance = 1.0, -- geri gitme mesafesi (metre)
    height = 0.1,   -- yukarı çıkma miktarı
    duration = 2000 -- kaç ms'de tamamlanacak
}

Config.Characters = {
    [1] = {
        slotLocked = false, -- # For the default character slot is locked ?
        pedPosition = vector4(-2165.85, 5185.25, 15.5, 80.77),
        camPosition = vector4(-2166.75, 5185.53, 15.7, 251.47),
        defaultGender = 'male',
        animation = {
            dict = "timetable@maid@couch@",
            clip = "base",
            flag = 1,
            scenario = nil, -- If u want scenario select this
        },
        spawnAnimation = { -- When click spwan button (If u dont want set nil)
            dict = nil,
            clip = nil,
            flag = nil,
            scenario = "WORLD_HUMAN_DRUG_DEALER", -- If u want scenario select this
            prop = nil, -- If u want set prop like my other example
            waitTime = 3000,
        },
        cameras = {
            ['2'] = {  -- 1 Character to 2 Character Camera way
                vector4(-2166.75, 5185.53, 15.7, 251.47),
                vector4(-2167.27, 5183.79, 15.65, 140.26)
            },
            ['3'] = {  -- 1 Character to 3 Character Camera way
                vector4(-2166.75, 5185.53, 15.7, 251.47),
                vector4(-2168.81, 5185.25, 15.94, 149.18)
            },
            ['4'] = { -- 1 Character to 4 Character Camera way
                vector4(-2166.75, 5185.53, 15.7, 251.47),
                vector4(-2170.84, 5188.22, 16.33, 103.48),
            },
            ['5'] = { -- 1 Character to 5 Character Camera way
                vector4(-2166.75, 5185.53, 15.7, 251.47),
                vector4(-2164.44, 5189.29, 15.73, 313.52),
            },
            ['6'] = { -- 1 Character to 6 Character Camera way
                vector4(-2166.75, 5185.53, 15.7, 251.47),
                vector4(-2165.92, 5193.55, 16.42, 12.5),
            },
            
        }
    },
    [2] = {
        slotLocked = false, -- # For the default character slot is locked ?
        pedPosition = vector4(-2168.25, 5182.7, 15.69, 337.22),
        camPosition = vector4(-2167.27, 5183.79, 15.65, 140.26),
        defaultGender = 'male',
        animation = {
            dict = "timetable@ron@ig_3_couch",
            clip = "base",
            flag = 1,
            scenario = nil, -- If u want scenario select this
        },
        spawnAnimation = { -- When click spwan button (If u dont want set nil)
            dict = nil,
            clip = nil,
            flag = nil,
            scenario = "WORLD_HUMAN_DRUG_DEALER", -- If u want scenario select this
            prop = nil, -- If u want set prop like my other example
            waitTime = 3000,
        },
        cameras = {
            ['1'] = { -- 2 Character to 1 Character
                vector4(-2167.27, 5183.79, 15.65, 140.26),
                vector4(-2166.75, 5185.53, 15.7, 251.47),
            },
            ['3'] = { -- 2 Character to 3 Character
                vector4(-2167.27, 5183.79, 15.65, 140.26),
                vector4(-2168.81, 5185.25, 15.94, 149.18)
            },
            ['4'] = { -- 2 Character to 4 Character
                vector4(-2167.27, 5183.79, 15.65, 140.26),
                vector4(-2170.84, 5188.22, 16.33, 103.48),
            },
            ['5'] = { -- 2 Character to 5 Character
                vector4(-2167.27, 5183.79, 15.65, 140.26),
                vector4(-2164.44, 5189.29, 15.73, 313.52),
            },
            ['6'] = { -- 2 Character to 6 Character
                vector4(-2167.27, 5183.79, 15.65, 140.26),
                vector4(-2165.92, 5193.55, 16.42, 12.5),
            },
        },
    },
    [3] = {
        slotLocked = false, -- # For the default character slot is locked ?
        pedPosition = vector4(-2169.07, 5183.96, 15.88, 295.52),
        camPosition = vector4(-2168.81, 5185.25, 15.94, 149.18),
        defaultGender = 'male',
        animation = {
            dict = "timetable@ron@ig_5_p3",
            clip = "ig_5_p3_base",
            flag = 1,
            scenario = nil, -- If u want scenario select this
        },
        spawnAnimation = { -- When click spwan button (If u dont want set nil)
            dict = nil,
            clip = nil,
            flag = nil,
            scenario = "WORLD_HUMAN_DRUG_DEALER", -- If u want scenario select this
            prop = nil, -- If u want set prop like my other example
            waitTime = 3000,
        },
        cameras = {
            ['1'] = {
                vector4(-2168.81, 5185.25, 15.94, 149.18),
                vector4(-2166.75, 5185.53, 15.7, 251.47),
            },
            ['2'] = {
                vector4(-2168.81, 5185.25, 15.94, 149.18),
                vector4(-2167.27, 5183.79, 15.65, 140.26),
            },
            ['4'] = {
                vector4(-2168.81, 5185.25, 15.94, 149.18),
                vector4(-2170.84, 5188.22, 16.33, 103.48),
            },
            ['5'] = {
                vector4(-2168.81, 5185.25, 15.94, 149.18),
                vector4(-2164.44, 5189.29, 15.73, 313.52),
            },
            ['6'] = {
                vector4(-2168.81, 5185.25, 15.94, 149.18),
                vector4(-2165.92, 5193.55, 16.42, 12.5),
            },
        }
    },
    [4] = {
        slotLocked = false, -- # For the default character slot is locked ?
        pedPosition = vector4(-2172.27, 5187.92, 16.47, 280.84),
        camPosition = vector4(-2170.84, 5188.22, 16.33, 103.48),
        defaultGender = 'male',
        animation = {
            dict = "amb@world_human_leaning@female@wall@back@holding_elbow@idle_a",
            clip = "idle_a",
            flag = 1,
            scenario = nil, -- If u want scenario select this
        },
        spawnAnimation = { -- When click spwan button (If u dont want set nil)
            dict = nil,
            clip = nil,
            flag = nil,
            scenario = "WORLD_HUMAN_DRUG_DEALER", -- If u want scenario select this
            prop = nil, -- If u want set prop like my other example
            waitTime = 3000,
        },
        cameras = {
            ['1'] = {
                vector4(-2170.84, 5188.22, 16.33, 103.48),
                vector4(-2166.75, 5185.53, 15.7, 251.47),
            },
            ['2'] = {
                vector4(-2170.84, 5188.22, 16.33, 103.48),
                vector4(-2167.27, 5183.79, 15.65, 140.26),
            },
            ['3'] = {
                vector4(-2170.84, 5188.22, 16.33, 103.48),
                vector4(-2168.81, 5185.25, 15.94, 149.18),
            },
            ['5'] = {
                vector4(-2170.84, 5188.22, 16.33, 103.48),
                vector4(-2164.44, 5189.29, 15.73, 313.52),
            },
            ['6'] = {
                vector4(-2170.84, 5188.22, 16.33, 103.48),
                vector4(-2165.92, 5193.55, 16.42, 12.5),
            },
        },
    },
    [5] = {
        slotLocked = true, -- # For the default character slot is locked ?
        pedPosition = vector4(-2163.63, 5190.09, 15.7, 126.97),
        camPosition = vector4(-2164.44, 5189.29, 15.73, 313.52),
        defaultGender = 'male',
        animation = {
            dict = "timetable@jimmy@mics3_ig_15@",
            clip = "mics3_15_base_tracy",
            flag = 1,
            scenario = nil, -- If u want scenario select this
            prop = {
                model = `prop_drink_whisky`,
                bone = 28422,
                pos = {0.01, -0.01, -0.06},
                rot = {0.0, 0.0, 0.0},
            },
        },
        spawnAnimation = { -- When click spwan button (If u dont want set nil)
            dict = nil,
            clip = nil,
            flag = nil,
            scenario = "WORLD_HUMAN_DRUG_DEALER", -- If u want scenario select this
            prop = nil, -- If u want set prop like my other example
            waitTime = 3000,
        },
        cameras = {
            ['1'] = {
                vector4(-2164.44, 5189.29, 15.73, 313.52),
                vector4(-2166.75, 5185.53, 15.7, 251.47),
            },
            ['2'] = {
                vector4(-2164.44, 5189.29, 15.73, 313.52),
                vector4(-2167.27, 5183.79, 15.65, 140.26),
            },
            ['3'] = {
                vector4(-2164.44, 5189.29, 15.73, 313.52),
                vector4(-2168.81, 5185.25, 15.94, 149.18),
            },
            ['4'] = {
                vector4(-2164.44, 5189.29, 15.73, 313.52),
                vector4(-2170.84, 5188.22, 16.33, 103.48),
            },
            ['6'] = {
                vector4(-2164.44, 5189.29, 15.73, 313.52),
                vector4(-2165.92, 5193.55, 16.42, 12.5),
            },
        },
    },
    [6] = {
        slotLocked = true, -- # For the default character slot is locked ?
        pedPosition = vector4(-2166.14, 5194.47, 16.52, 192.08),
        camPosition = vector4(-2165.92, 5193.55, 16.42, 12.5),
        defaultGender = 'male',
        animation = {
            dict = "amb@world_human_leaning@male@wall@back@foot_up@idle_a",
            clip = "idle_a",
            flag = 1,
            scenario = nil, -- If u want scenario select this
        },
        spawnAnimation = { -- When click spwan button (If u dont want set nil)
            dict = nil,
            clip = nil,
            flag = nil,
            scenario = "WORLD_HUMAN_DRUG_DEALER", -- If u want scenario select this
            prop = nil, -- If u want set prop like my other example
            waitTime = 3000,
        },
        cameras = {
            ['1'] = {
                vector4(-2165.92, 5193.55, 16.42, 12.5),
                vector4(-2166.75, 5185.53, 15.7, 251.47),
            },
            ['2'] = {
                vector4(-2165.92, 5193.55, 16.42, 12.5),
                vector4(-2167.27, 5183.79, 15.65, 140.26),
            },
            ['3'] = {
                vector4(-2165.92, 5193.55, 16.42, 12.5),
                vector4(-2168.81, 5185.25, 15.94, 149.18),
            },
            ['4'] = {
                vector4(-2165.92, 5193.55, 16.42, 12.5),
                vector4(-2170.84, 5188.22, 16.33, 103.48),
            },
            ['5'] = {
                vector4(-2165.92, 5193.55, 16.42, 12.5),
                vector4(-2164.44, 5189.29, 15.73, 313.52),
            },
        },
    },
}

Config.CreatePedOffsetminus = 1.0


-- # Spawn button

Config.AfterClickSpawnButtonWaitTime = 1800 -- 1 Second

-- # Spawn points

-- # Plane And New Spawn UI Settings

Config.UsePlane = false -- # Enable : true | Disable : false

Config.CreateCharacterPlaneIndex = 1 -- # For example this index like order so when player create character player go airport with plane.

Config.UseSpawnCameraEffect = true -- # The camera effect from top to bottom

Config.LastLocationButton = true

Config.newSpawnAreas = {
    {
        label = 'Los Santos International Airport (LSIA)',
        spawnPoint = vector4(-1035.82, -2848.968, 26.404, 62.3), -- # After plane player spawn position
        icon = 'fa-solid fa-map-location-dot', -- # In select ui icon | https://fontawesome.com/icons
        planeModel = `miljet`, -- # Plane model
        planeDriverModel = `csb_reporter`, -- Plane driver model
        planeStartLocation = vector4(-464.19, -3454.57, 143.44, 61.38), -- # Plane spawn,
        planeEndLocation = vector4(-870.86, -3216.99, 13.94, 61.38), -- # Until this position, the plane will be airborne.
        planeLandStartLocation = vector2(-964.98, -3106.51), -- # The plane will be on the ground in this position.
        planeTaxiEndLocation = vector4(-1049.77, -3030.56, 13.94, 29.04), -- # It will move on the ground from the `planeLandStartLocation` to this location.
        finishLocation = vector4(-1138.08, -2967.45, 13.94, 60.4), -- # "It will start from the planeTaxiEndLocation and come to this location. Once it arrives, a black screen will appear and the player will exit the plane, marking the end of the plane phase and the transition into gameplay.
    },
    {
        label = 'Cayo Perico',
        spawnPoint = vector4(4474.09, -4476.97, 4.0, 201.98), -- # After plane player spawn position
        icon = 'fa-solid fa-map-location-dot', -- # In select ui icon | https://fontawesome.com/icons
        planeModel = `miljet`, -- # Plane model
        planeDriverModel = `csb_reporter`, -- Plane driver model
        planeStartLocation = vector4(3140.83, -4975.77, 133.67, 290.99), -- # Plane spawn,
        planeEndLocation = vector4(3986.2, -4677.65, 4.18, 290.99), -- # Until this position, the plane will be airborne.
        planeLandStartLocation = vector2(3991.52, -4678.12), -- # The plane will be on the ground in this position.
        planeTaxiEndLocation = vector4(4240.50, -4585.25, 4.18, 287.98), -- # It will move on the ground from the `planeLandStartLocation` to this location.
        finishLocation = vector4(4457.52, -4510.99, 4.18, 290.27), -- # "It will start from the planeTaxiEndLocation and come to this location. Once it arrives, a black screen will appear and the player will exit the plane, marking the end of the plane phase and the transition into gameplay.
    },
    {
        label = 'Legion Square',
        spawnPoint = vector4(162.34, -990.29, 30.09, 164.5), -- # After plane player spawn position
        icon = 'fa-solid fa-map-location-dot', -- # In select ui icon | https://fontawesome.com/icons
        planeModel = `miljet`, -- # Plane model
        planeDriverModel = `csb_reporter`, -- Plane driver model
        planeStartLocation = vector4(-464.19, -3454.57, 143.44, 61.38), -- # Plane spawn,
        planeEndLocation = vector4(-870.86, -3216.99, 13.94, 61.38), -- # Until this position, the plane will be airborne.
        planeLandStartLocation = vector2(-964.98, -3106.51), -- # The plane will be on the ground in this position.
        planeTaxiEndLocation = vector4(-1049.77, -3030.56, 13.94, 29.04), -- # It will move on the ground from the `planeLandStartLocation` to this location.
        finishLocation = vector4(-1138.08, -2967.45, 13.94, 60.4), -- # "It will start from the planeTaxiEndLocation and come to this location. Once it arrives, a black screen will appear and the player will exit the plane, marking the end of the plane phase and the transition into gameplay.
    },
    {
        label = 'Sandy Airport',
        spawnPoint = vector4(1716.606, 3272.609, 41.151, 173.434), -- # After plane player spawn position
        icon = 'fa-solid fa-map-location-dot', -- # In select ui icon | https://fontawesome.com/icons
        planeModel = `miljet`, -- # Plane model
        planeDriverModel = `csb_reporter`, -- Plane driver model
        planeStartLocation = vector4(794.68, 3009.0, 171.21, 283.99), -- # Plane spawn,
        planeEndLocation = vector4(1174.4, 3107.88, 40.41, 283.99), -- # Until this position, the plane will be airborne.
        planeLandStartLocation = vector2(1216.48, 3119.2), -- # The plane will be on the ground in this position.
        planeTaxiEndLocation = vector4(1503.85, 3196.58, 40.41, 283.99), -- # It will move on the ground from the `planeLandStartLocation` to this location.
        finishLocation = vector4(1629.85, 3230.5, 40.41, 283.99), -- # "It will start from the planeTaxiEndLocation and come to this location. Once it arrives, a black screen will appear and the player will exit the plane, marking the end of the plane phase and the transition into gameplay.
    },
}

Config.StarterItems = {
    ['phone'] = { amount = 1, item = 'phone' },
    ['id_card'] = { amount = 1, item = 'id_card' },
    ['driver_license'] = { amount = 1, item = 'driver_license' },
}


-- # Default skin load for ESX
Config.Default = {
    ["m"] = {
        mom = 43,
        dad = 29,
        face_md_weight = 61,
        skin_md_weight = 27,
        nose_1 = -5,
        nose_2 = 6,
        nose_3 = 5,
        nose_4 = 8,
        nose_5 = 10,
        nose_6 = 0,
        cheeks_1 = 2,
        cheeks_2 = -10,
        cheeks_3 = 6,
        lip_thickness = -2,
        jaw_1 = 0,
        jaw_2 = 0,
        chin_1 = 0,
        chin_2 = 0,
        chin_13 = 0,
        chin_4 = 0,
        neck_thickness = 0,
        hair_1 = 76,
        hair_2 = 0,
        hair_color_1 = 61,
        hair_color_2 = 29,
        tshirt_1 = 4,
        tshirt_2 = 2,
        torso_1 = 23,
        torso_2 = 2,
        decals_1 = 0,
        decals_2 = 0,
        arms = 1,
        arms_2 = 0,
        pants_1 = 28,
        pants_2 = 3,
        shoes_1 = 70,
        shoes_2 = 2,
        mask_1 = 0,
        mask_2 = 0,
        bproof_1 = 0,
        bproof_2 = 0,
        chain_1 = 22,
        chain_2 = 2,
        helmet_1 = -1,
        helmet_2 = 0,
        glasses_1 = 0,
        glasses_2 = 0,
        watches_1 = -1,
        watches_2 = 0,
        bracelets_1 = -1,
        bracelets_2 = 0,
        bags_1 = 0,
        bags_2 = 0,
        eye_color = 0,
        eye_squint = 0,
        eyebrows_2 = 0,
        eyebrows_1 = 0,
        eyebrows_3 = 0,
        eyebrows_4 = 0,
        eyebrows_5 = 0,
        eyebrows_6 = 0,
        makeup_1 = 0,
        makeup_2 = 0,
        makeup_3 = 0,
        makeup_4 = 0,
        lipstick_1 = 0,
        lipstick_2 = 0,
        lipstick_3 = 0,
        lipstick_4 = 0,
        ears_1 = -1,
        ears_2 = 0,
        chest_1 = 0,
        chest_2 = 0,
        chest_3 = 0,
        bodyb_1 = -1,
        bodyb_2 = 0,
        bodyb_3 = -1,
        bodyb_4 = 0,
        age_1 = 0,
        age_2 = 0,
        blemishes_1 = 0,
        blemishes_2 = 0,
        blush_1 = 0,
        blush_2 = 0,
        blush_3 = 0,
        complexion_1 = 0,
        complexion_2 = 0,
        sun_1 = 0,
        sun_2 = 0,
        moles_1 = 0,
        moles_2 = 0,
        beard_1 = 11,
        beard_2 = 10,
        beard_3 = 0,
        beard_4 = 0,
    },
    ["f"] = {
        mom = 28,
        dad = 6,
        face_md_weight = 63,
        skin_md_weight = 60,
        nose_1 = -10,
        nose_2 = 4,
        nose_3 = 5,
        nose_4 = 0,
        nose_5 = 0,
        nose_6 = 0,
        cheeks_1 = 0,
        cheeks_2 = 0,
        cheeks_3 = 0,
        lip_thickness = 0,
        jaw_1 = 0,
        jaw_2 = 0,
        chin_1 = -10,
        chin_2 = 10,
        chin_13 = -10,
        chin_4 = 0,
        neck_thickness = -5,
        hair_1 = 43,
        hair_2 = 0,
        hair_color_1 = 29,
        hair_color_2 = 35,
        tshirt_1 = 111,
        tshirt_2 = 5,
        torso_1 = 25,
        torso_2 = 2,
        decals_1 = 0,
        decals_2 = 0,
        arms = 3,
        arms_2 = 0,
        pants_1 = 12,
        pants_2 = 2,
        shoes_1 = 20,
        shoes_2 = 10,
        mask_1 = 0,
        mask_2 = 0,
        bproof_1 = 0,
        bproof_2 = 0,
        chain_1 = 85,
        chain_2 = 0,
        helmet_1 = -1,
        helmet_2 = 0,
        glasses_1 = 33,
        glasses_2 = 12,
        watches_1 = -1,
        watches_2 = 0,
        bracelets_1 = -1,
        bracelets_2 = 0,
        bags_1 = 0,
        bags_2 = 0,
        eye_color = 8,
        eye_squint = -6,
        eyebrows_2 = 7,
        eyebrows_1 = 32,
        eyebrows_3 = 52,
        eyebrows_4 = 9,
        eyebrows_5 = -5,
        eyebrows_6 = -8,
        makeup_1 = 0,
        makeup_2 = 0,
        makeup_3 = 0,
        makeup_4 = 0,
        lipstick_1 = 0,
        lipstick_2 = 0,
        lipstick_3 = 0,
        lipstick_4 = 0,
        ears_1 = -1,
        ears_2 = 0,
        chest_1 = 0,
        chest_2 = 0,
        chest_3 = 0,
        bodyb_1 = -1,
        bodyb_2 = 0,
        bodyb_3 = -1,
        bodyb_4 = 0,
        age_1 = 0,
        age_2 = 0,
        blemishes_1 = 0,
        blemishes_2 = 0,
        blush_1 = 0,
        blush_2 = 0,
        blush_3 = 0,
        complexion_1 = 0,
        complexion_2 = 0,
        sun_1 = 0,
        sun_2 = 0,
        moles_1 = 12,
        moles_2 = 8,
        beard_1 = 0,
        beard_2 = 0,
        beard_3 = 0,
        beard_4 = 0,
    },
}
lang.lua

LANG = {
    invalid_id = 'Invalid Player ID! Please check again ...',
    target_not_online = 'Target not online!',
    prints = {
        charNotFound = 'Character not found!',
    },
    ui = {
        areaMenuLabel = 'Select an Airport',
        areaClick = 'Click for play!',
        areaLastLocation = 'Last Location',
        areaPlay = 'Play!',
        selected = 'SELECTED',
        createNewChar = 'CREATE NEW CHARACTER',
        slotLocked = 'This slot locked for the now!',
        clickForCreate = 'Click for create new character!',
        selectCharacter = 'SELECT CHARACTER',
        slotsUsed = 'SLOTS USED',
        firstnameLabel = '* First name',
        firstnamePlaceholder = 'John',
        lastnameLabel = '* Last name',
        lastnamePlaceholder = 'Doe',
        returnBack = 'Return Back',
        registerCharacter = 'Register Character',
        selectGender = 'SELECT GENDER',
        male = 'Male',
        female = 'Female',
        information = 'INFORMATION',
        informationText = 'Please Check your information. Edit inapprapriate characters.',
        birthdateLabel = '* Birth Date',
        height = 'Height',
        cmText = 'CM',
        informationAboutCharacter = 'INFORMATION ABOUT CHARACTER',
        cashLabel = 'Money In Cash',
        bankLabel = 'Money In Bank',
        nationalityLabel = 'Nationality',
        dobLabel = 'Date Of Birth',
        genderLabel = 'Gender',
        deletePopuiLabel = 'Are you sure you want to delete your character ?',
        deletePopuiDesc = 'This character will be permanently deleted from the database and cannot be recovered. Please use the buttons below to confirm or cancel the action.',
        deleteConfirm = 'Confirm',
        deleteCancel = 'Cancel',
        
    },
}
editable_client.lua

function WeatherSystemControl(disable)
    if disable then
        TriggerEvent('qb-weathersync:client:DisableSync')
    else
        TriggerEvent('qb-weathersync:client:EnableSync')
    end
end

function BeforeCreateFirstCharacter()
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        TriggerServerEvent('QBCore:Server:OnPlayerLoaded')
        TriggerEvent('QBCore:Client:OnPlayerLoaded')
        TriggerServerEvent('qb-houses:server:SetInsideMeta', 0, false)
        TriggerServerEvent('qb-apartments:server:SetInsideMeta', 0, 0, false)
    else
        -- ESX
        
    end
end

function OpenCreateFirstCharacter()
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        TriggerEvent('qb-clothes:client:CreateFirstCharacter')
    else
        -- ESX
        
    end
end

function ApplyPedAppearance(charPed, skin)
    if Config.ClothingSystem == 'IzzyAppearance' then
        TriggerEvent('sh-creation:client:loadData', skin, charPed)
    elseif Config.ClothingSystem == 'qb-cloting' then
        TriggerEvent('qb-clothing:client:loadPlayerClothing', skin, charPed)
    elseif Config.ClothingSystem == 'illenium-appearance' then
        exports['illenium-appearance']:setPedAppearance(charPed, skin)
    elseif Config.ClothingSystem == 'skinchanger' then
        -- Empty for the now.
        ApplySkin(charPed, skin)
    end
end

function SpawnTriggers(isNew, citizenid)
    -- # This function using when player character spawned!
    -- isNew : boolean : If player created new character
    if Config.Framework == 'esx' then
        -- Empty for the now!
    else
        TriggerServerEvent('QBCore:Server:OnPlayerLoaded')
        TriggerEvent('QBCore:Client:OnPlayerLoaded')
    end
end

RegisterNetEvent('wert-multicharacter:client:custom-spawn-selector', function(citizenid)
    -- # If u want another spawn selector system u can add trigger / export there
    -- citizenid : Player Character citizenid / identifier ( For ESX )
end)

if Config.UseQBApartments then
    RegisterNetEvent('apartments:client:WertMulticharacter', function(citizenid)
        QBCore.Functions.TriggerCallback('apartments:GetOwnedApartment', function(result)
            if not result then
                local startApskey = "apartment1" -- # When player spawn player must be spawn in which aps ?
                BeforeCreateFirstCharacter()
                TriggerServerEvent('apartments:server:CreateApartment', startApskey, Apartments.Locations[startApskey].label, true)
            end
        end, citizenid)
    end)
end

RegisterNetEvent("esx:playerLoaded", function(playerData, isNew, skin)
    if Config.ClothingSystem == 'skinchanger' or Config.ClothingSystem == 'illenium-appearance' then

        if isNew or not skin or #skin == 1 then
            local finished = false
            skin = Config.Default[playerData.sex]
            skin.sex = playerData.sex == "m" and 0 or 1
            local model = skin.sex == 0 and `mp_m_freemode_01` or `mp_m_freemode_01`

            RequestModel(model)
            while not HasModelLoaded(model) do
                RequestModel(model)
                Wait(0)
            end
            SetPlayerModel(PlayerId(), model)
            SetModelAsNoLongerNeeded(model)

            if isNew then
                FreezeEntityPosition(PlayerPedId(), true)
                SetEntityCoords(PlayerPedId(), Config.CreateCharacterPosition.x, Config.CreateCharacterPosition.y, Config.CreateCharacterPosition.z)
                SetEntityVisible(PlayerPedId(), true)
                Wait(500)
                DoScreenFadeIn(1500)
                TriggerServerEvent('wert-multicharacter:server:reset-bucket-new')
                WeatherSystemControl(false)

                CreateThread(function()
                    while true do
                        local distance = #(GetEntityCoords(PlayerPedId()) - vector3(Config.CreateCharacterPosition.x, Config.CreateCharacterPosition.y, Config.CreateCharacterPosition.z))
                        if distance <= 1.0 then
                            break
                        else
                            SetEntityCoords(PlayerPedId(), Config.CreateCharacterPosition.x, Config.CreateCharacterPosition.y, Config.CreateCharacterPosition.z) 
                        end
                        Wait(1000)
                    end
                    FreezeEntityPosition(PlayerPedId(), false)
                    SetEntityHeading(PlayerPedId(), Config.CreateCharacterPosition.w)
                    DoScreenFadeIn(1500)
                end)
            end

            TriggerEvent("skinchanger:loadSkin", skin, function()
                local playerPed = PlayerPedId()
                SetPedAoBlobRendering(playerPed, true)
                ResetEntityAlpha(playerPed)
                TriggerEvent("esx_skin:openSaveableMenu", function()
                    finished = true
                end, function()
                    finished = true
                end)
            end)
            repeat
                Wait(200)
            until finished
        end
        if not isNew then
            TriggerEvent("skinchanger:loadSkin", skin)
        end
    end
    Wait(500)
    TriggerServerEvent("esx:onPlayerSpawn")
    TriggerEvent("esx:onPlayerSpawn")
    TriggerEvent("playerSpawned")
    TriggerEvent("esx:restoreLoadout")
end)

RegisterNetEvent("wert-multicharacter:esx:setPlayerData", function(data)
    --[[ local Identity = {
        firstName = formattedFirstName,
        lastName = formattedLastName,
        dateOfBirth = tostring(data.birthdate),
        sex = data.sex,
        height = data.height,
        nationality = data.nationality,
        charSlot = tostring(data.cid),
    } ]]
    SetTimeout(1, function()
        Bridge.framework.SetPlayerData("name", ("%s %s"):format(data.firstName, data.lastName))
        Bridge.framework.SetPlayerData("firstName", data.firstName)
        Bridge.framework.SetPlayerData("lastName", data.lastName)
        Bridge.framework.SetPlayerData("dateofbirth", data.dateOfBirth)
        Bridge.framework.SetPlayerData("sex", data.sex)
        Bridge.framework.SetPlayerData("height", data.height)
    end)
end)


if Config.ClothingSystem == 'skinchanger' then
    function ApplySkin(playerPed, skin)
        local Character = {}
        for k, v in pairs(skin) do
            Character[k] = v
        end
        local face_weight = (Character["face_md_weight"] / 100) + 0.0
        local skin_weight = (Character["skin_md_weight"] / 100) + 0.0
        SetPedHeadBlendData(playerPed, Character["mom"], Character["dad"], 0, Character["mom"], Character["dad"], 0, face_weight, skin_weight, 0.0, false)
        SetPedFaceFeature(playerPed, 0, (Character["nose_1"] / 10) + 0.0) -- Nose Width
        SetPedFaceFeature(playerPed, 1, (Character["nose_2"] / 10) + 0.0) -- Nose Peak Height
        SetPedFaceFeature(playerPed, 2, (Character["nose_3"] / 10) + 0.0) -- Nose Peak Length
        SetPedFaceFeature(playerPed, 3, (Character["nose_4"] / 10) + 0.0) -- Nose Bone Height
        SetPedFaceFeature(playerPed, 4, (Character["nose_5"] / 10) + 0.0) -- Nose Peak Lowering
        SetPedFaceFeature(playerPed, 5, (Character["nose_6"] / 10) + 0.0) -- Nose Bone Twist
        SetPedFaceFeature(playerPed, 6, (Character["eyebrows_5"] / 10) + 0.0) -- Eyebrow height
        SetPedFaceFeature(playerPed, 7, (Character["eyebrows_6"] / 10) + 0.0) -- Eyebrow depth
        SetPedFaceFeature(playerPed, 8, (Character["cheeks_1"] / 10) + 0.0) -- Cheekbones Height
        SetPedFaceFeature(playerPed, 9, (Character["cheeks_2"] / 10) + 0.0) -- Cheekbones Width
        SetPedFaceFeature(playerPed, 10, (Character["cheeks_3"] / 10) + 0.0) -- Cheeks Width
        SetPedFaceFeature(playerPed, 11, (Character["eye_squint"] / 10) + 0.0) -- Eyes squint
        SetPedFaceFeature(playerPed, 12, (Character["lip_thickness"] / 10) + 0.0) -- Lip Fullness
        SetPedFaceFeature(playerPed, 13, (Character["jaw_1"] / 10) + 0.0) -- Jaw Bone Width
        SetPedFaceFeature(playerPed, 14, (Character["jaw_2"] / 10) + 0.0) -- Jaw Bone Length
        SetPedFaceFeature(playerPed, 15, (Character["chin_1"] / 10) + 0.0) -- Chin Height
        SetPedFaceFeature(playerPed, 16, (Character["chin_2"] / 10) + 0.0) -- Chin Length
        SetPedFaceFeature(playerPed, 17, (Character["chin_3"] / 10) + 0.0) -- Chin Width
        SetPedFaceFeature(playerPed, 18, (Character["chin_4"] / 10) + 0.0) -- Chin Hole Size
        SetPedFaceFeature(playerPed, 19, (Character["neck_thickness"] / 10) + 0.0) -- Neck Thickness

        SetPedHairColor(playerPed, Character["hair_color_1"], Character["hair_color_2"]) -- Hair Color
        SetPedHeadOverlay(playerPed, 3, Character["age_1"], (Character["age_2"] / 10) + 0.0) -- Age + opacity
        SetPedHeadOverlay(playerPed, 0, Character["blemishes_1"], (Character["blemishes_2"] / 10) + 0.0) -- Blemishes + opacity
        SetPedHeadOverlay(playerPed, 1, Character["beard_1"], (Character["beard_2"] / 10) + 0.0) -- Beard + opacity
        SetPedEyeColor(playerPed, Character["eye_color"]) -- Eyes color
        SetPedHeadOverlay(playerPed, 2, Character["eyebrows_1"], (Character["eyebrows_2"] / 10) + 0.0) -- Eyebrows + opacity
        SetPedHeadOverlay(playerPed, 4, Character["makeup_1"], (Character["makeup_2"] / 10) + 0.0) -- Makeup + opacity
        SetPedHeadOverlay(playerPed, 8, Character["lipstick_1"], (Character["lipstick_2"] / 10) + 0.0) -- Lipstick + opacity
        SetPedComponentVariation(playerPed, 2, Character["hair_1"], Character["hair_2"], 2) -- Hair
        SetPedHeadOverlayColor(playerPed, 1, 1, Character["beard_3"], Character["beard_4"]) -- Beard Color
        SetPedHeadOverlayColor(playerPed, 2, 1, Character["eyebrows_3"], Character["eyebrows_4"]) -- Eyebrows Color
        SetPedHeadOverlayColor(playerPed, 4, 2, Character["makeup_3"], Character["makeup_4"]) -- Makeup Color
        SetPedHeadOverlayColor(playerPed, 8, 1, Character["lipstick_3"], Character["lipstick_4"]) -- Lipstick Color
        SetPedHeadOverlay(playerPed, 5, Character["blush_1"], (Character["blush_2"] / 10) + 0.0) -- Blush + opacity
        SetPedHeadOverlayColor(playerPed, 5, 2, Character["blush_3"]) -- Blush Color
        SetPedHeadOverlay(playerPed, 6, Character["complexion_1"], (Character["complexion_2"] / 10) + 0.0) -- Complexion + opacity
        SetPedHeadOverlay(playerPed, 7, Character["sun_1"], (Character["sun_2"] / 10) + 0.0) -- Sun Damage + opacity
        SetPedHeadOverlay(playerPed, 9, Character["moles_1"], (Character["moles_2"] / 10) + 0.0) -- Moles/Freckles + opacity
        SetPedHeadOverlay(playerPed, 10, Character["chest_1"], (Character["chest_2"] / 10) + 0.0) -- Chest Hair + opacity
        SetPedHeadOverlayColor(playerPed, 10, 1, Character["chest_3"]) -- Torso Color

        if Character["bodyb_1"] == -1 then
            SetPedHeadOverlay(playerPed, 11, 255, (Character["bodyb_2"] / 10) + 0.0) -- Body Blemishes + opacity
        else
            SetPedHeadOverlay(playerPed, 11, Character["bodyb_1"], (Character["bodyb_2"] / 10) + 0.0)
        end

        if Character["bodyb_3"] == -1 then
            SetPedHeadOverlay(playerPed, 12, 255, (Character["bodyb_4"] / 10) + 0.0)
        else
            SetPedHeadOverlay(playerPed, 12, Character["bodyb_3"], (Character["bodyb_4"] / 10) + 0.0) -- Blemishes 'added body effect' + opacity
        end

        if Character["ears_1"] == -1 then
            ClearPedProp(playerPed, 2)
        else
            SetPedPropIndex(playerPed, 2, Character["ears_1"], Character["ears_2"], 2) -- Ears Accessories
        end

        SetPedComponentVariation(playerPed, 8, Character["tshirt_1"], Character["tshirt_2"], 2) -- Tshirt
        SetPedComponentVariation(playerPed, 11, Character["torso_1"], Character["torso_2"], 2) -- torso parts
        SetPedComponentVariation(playerPed, 3, Character["arms"], Character["arms_2"], 2) -- Arms
        SetPedComponentVariation(playerPed, 10, Character["decals_1"], Character["decals_2"], 2) -- decals
        SetPedComponentVariation(playerPed, 4, Character["pants_1"], Character["pants_2"], 2) -- pants
        SetPedComponentVariation(playerPed, 6, Character["shoes_1"], Character["shoes_2"], 2) -- shoes
        SetPedComponentVariation(playerPed, 1, Character["mask_1"], Character["mask_2"], 2) -- mask
        SetPedComponentVariation(playerPed, 9, Character["bproof_1"], Character["bproof_2"], 2) -- bulletproof
        SetPedComponentVariation(playerPed, 7, Character["chain_1"], Character["chain_2"], 2) -- chain
        SetPedComponentVariation(playerPed, 5, Character["bags_1"], Character["bags_2"], 2) -- Bag

        if Character["helmet_1"] == -1 then
            ClearPedProp(playerPed, 0)
        else
            SetPedPropIndex(playerPed, 0, Character["helmet_1"], Character["helmet_2"], 2) -- Helmet
        end

        if Character["glasses_1"] == -1 then
            ClearPedProp(playerPed, 1)
        else
            SetPedPropIndex(playerPed, 1, Character["glasses_1"], Character["glasses_2"], 2) -- Glasses
        end

        if Character["watches_1"] == -1 then
            ClearPedProp(playerPed, 6)
        else
            SetPedPropIndex(playerPed, 6, Character["watches_1"], Character["watches_2"], 2) -- Watches
        end

        if Character["bracelets_1"] == -1 then
            ClearPedProp(playerPed, 7)
        else
            SetPedPropIndex(playerPed, 7, Character["bracelets_1"], Character["bracelets_2"], 2) -- Bracelets
        end
    end
end
editable_server.lua

hasDonePreloading = {}

local discordWebhook = ''

function GiveStarterItems(src)
    local Player = Bridge.GetPlayer(src)
    if not Player then return end
    for _, v in pairs(Config.StarterItems) do
        local info = {}
        if Config.Framework == 'qb' or Config.Framework == 'qbox' then
            if v.item == "id_card" then
                info.citizenid = Player.PlayerData.citizenid
                info.firstname = Player.PlayerData.charinfo.firstname
                info.lastname = Player.PlayerData.charinfo.lastname
                info.birthdate = Player.PlayerData.charinfo.birthdate
                info.gender = Player.PlayerData.charinfo.gender
                info.nationality = Player.PlayerData.charinfo.nationality
            elseif v.item == "driver_license" then
                info.firstname = Player.PlayerData.charinfo.firstname
                info.lastname = Player.PlayerData.charinfo.lastname
                info.birthdate = Player.PlayerData.charinfo.birthdate
                info.type = "Class C Driver License"
            end
        else
            -- About the esx if u want manage item metadatas
        end
        Bridge.AddItem(src, { name = v.item, amount = v.amount, slot = false, info = info })
    end
end

function loadHouseData(src)
    if not Config.LoadQBHouses then return end
    local HouseGarages = {}
    local Houses = {}
    local result = MySQL.query.await('SELECT * FROM houselocations', {})
    if result[1] ~= nil then
        for _, v in pairs(result) do
            local owned = false
            if tonumber(v.owned) == 1 then
                owned = true
            end
            local garage = v.garage ~= nil and json.decode(v.garage) or {}
            Houses[v.name] = {
                coords = json.decode(v.coords),
                owned = owned,
                price = v.price,
                locked = true,
                adress = v.label,
                tier = v.tier,
                garage = garage,
                decorations = {},
            }
            HouseGarages[v.name] = {
                label = v.label,
                takeVehicle = garage,
            }
     end
    end
    TriggerClientEvent("qb-garages:client:houseGarageConfig", src, HouseGarages)
    TriggerClientEvent("qb-houses:client:setHouseConfig", src, Houses)
end

function DeleteCharacter(src, identifier)
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        Bridge.framework.Player.DeleteCharacter(src, identifier)
    else
        -- ESX
        local DB_TABLES = { users = "identifier" }
        local query = "DELETE FROM `%s` WHERE %s = ?"
        local queries = {}
        local count = 0
        for table, column in pairs(DB_TABLES) do
            count = count + 1
            queries[count] = { query = query:format(table, column), values = { identifier } }
        end
        MySQL.transaction(queries, function(result)
            if result then
                print(("[^2INFO^7] Player ^5%s %s^7 has deleted a character ^5(%s)^7"):format(GetPlayerName(src), src, identifier))
                Wait(50)
            else
                error("\n^1Transaction failed while trying to delete " .. identifier .. "^0")
            end
        end)
    end
    TriggerClientEvent('ox_lib:notify', src, { title = 'Character Deleted!', type = 'success' })
end

function DiscordLog(src, new, identifier)
    local title = nil
    local message = nil
    if new then
        message = "**".. GetPlayerName(src) .. "** (<@"..(Bridge.GetIdentifier(src, 'discord') and Bridge.GetIdentifier(src, 'discord'):gsub("discord:", "") or "unknown").."> |  ||"  ..(Bridge.GetIdentifier(src, 'ip') or 'undefined') ..  "|| | " ..(Bridge.GetIdentifier(src, 'license') or 'undefined') .." | "..src..") Created new character : .. \n " .. json.encode(new, {indent=true})
    else
        title = 'Player Loaded ( Joined )'
        message = "**".. GetPlayerName(src) .. "** (<@"..(Bridge.GetIdentifier(src, 'discord') and Bridge.GetIdentifier(src, 'discord'):gsub("discord:", "") or "unknown").."> |  ||"  ..(Bridge.GetIdentifier(src, 'ip') or 'undefined') ..  "|| | " ..(Bridge.GetIdentifier(src, 'license') or 'undefined') .." | " ..identifier.." | "..src..") loaded.."
    end
    local embedData = {
        {
            ['title'] = title,
            ['color'] = '65280',
            ['footer'] = { ['text'] = os.date('%c') },
            ['description'] = message,
            ['author'] = { ['name'] = "Multicharacter" },
        }
    }
    PerformHttpRequest(discordWebhook, function() end, 'POST', json.encode({ username = 'Multicharacter', embeds = embedData}), { ['Content-Type'] = 'application/json' })
end

local function extractCharNumber(str)
    local num = string.match(str, "^char(%d+):")
    return tonumber(num)
end

local function containsCharKeyword(str)
    return string.find(str, "char") ~= nil
end

local function GetPlayerCitizenIDDatas(src)
    local data = {}
    local license2, license = GetPlayerIdentifierByType(src, 'license2'), GetPlayerIdentifierByType(src, 'license')
    local promise = promise.new()
    if Config.Framework ~= 'esx' then
        local result = MySQL.query.await('SELECT citizenid, cid, UNIX_TIMESTAMP(last_logged_out) AS lastLoggedOutUnix FROM players WHERE license = ? OR license = ? ORDER BY cid', {license, license2})
        for i = 1, #result do
            data[#data + 1] = { citizenid = result[i].citizenid, cid = result[i].cid }
        end
    else
        -- Esx
        local PREFIX = Config.Prefix or "char"
        local identifier = GetIdentifier(src)
        local pattern     = PREFIX .. "%:" .. identifier
        local result = MySQL.query.await([[
            SELECT identifier, skin
            FROM   users
            WHERE  identifier = ?
               OR  identifier LIKE ?
        ]], { identifier, pattern })
        for i = 1, #result do
            if extractCharNumber(result[i].identifier) then
                data[#data + 1] = { citizenid = result[i].identifier, cid = extractCharNumber(result[i].identifier), skin = result[i].skin and json.decode(result[i].skin) or {} }
            end
        end
    end
    return data
end

AddEventHandler('QBCore:Server:PlayerLoaded', function(Player)
    Wait(1000) -- 1 second should be enough to do the preloading in other resources
    hasDonePreloading[Player.PlayerData.source] = true
end)

AddEventHandler('QBCore:Server:OnPlayerUnload', function(src)
    hasDonePreloading[src] = false
end)

-- # Callbacks

lib.callback.register('wert-multicharacter:server:get-player-ui-data', function(source)
    local src = source
    local license2, license = GetPlayerIdentifierByType(src, 'license2'), GetPlayerIdentifierByType(src, 'license')
    local plyChars = {}
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        local result = MySQL.query.await('SELECT citizenid, charinfo, money, job, gang, position, cid, UNIX_TIMESTAMP(last_logged_out) AS lastLoggedOutUnix FROM players WHERE license = ? OR license = ? ORDER BY cid', {license, license2})
        for i = 1, #result do
            local cid = tostring(result[i].cid)
            result[i].charinfo = json.decode(result[i].charinfo)
            result[i].money = json.decode(result[i].money)
            result[i].job = json.decode(result[i].job)
            plyChars[cid] = result[i]
        end
    else
        -- ESX

        local function ESXGetJobLabel(name, grade)
            local isLabel = MySQL.scalar.await('SELECT `label` FROM `job_grades` WHERE `job_name` = ? AND `grade` = ? LIMIT 1', { name, tonumber(grade) })
            if not isLabel then isLabel = 'Unemployed' end
            return { grade = { name = isLabel } }
        end

        local PREFIX = Config.Prefix or "char"
        local identifier = GetIdentifier(src)
        local pattern     = PREFIX .. "%:" .. identifier
        local result = MySQL.query.await([[
            SELECT identifier, accounts, job, job_grade, firstname, lastname, dateofbirth, sex, nationality
            FROM   users
            WHERE  identifier = ?
               OR  identifier LIKE ?
        ]], { identifier, pattern })
        for i = 1, #result do
            if extractCharNumber(result[i].identifier) then
                local cid = extractCharNumber(result[i].identifier)
                cid = tostring(cid)
                local accounts = result[i].accounts and json.decode(result[i].accounts) or {}
                plyChars[cid] = {
                    citizenid = result[i].identifier,
                    cid = tonumber(cid),
                    job = ESXGetJobLabel(result[i].job, result[i].job_grade),
                    money = { cash = accounts.money or 0, bank = accounts.bank or 0 },
                    charinfo = {
                        gender = result[i].sex == 'f' and 1 or 0,
                        birthdate = result[i].dateofbirth,
                        firstname = result[i].firstname,
                        lastname = result[i].lastname,
                        nationality = result[i].nationality or Config.DefaultNationality
                    }
                }
            end
        end
    end
    return plyChars
end)

lib.callback.register('wert-multicharacter:server:get-spawn-peds', function(source)
    local src = source

    if Config.Framework == 'esx' then
        Bridge.framework.Players[GetIdentifier(src)] = true
    end

    local plyChars = GetPlayerCitizenIDDatas(src)
    if #plyChars > 0 then
        local skins = {}
        local citizenTable = {}
        local queryTable = {}
        for i=1, #plyChars do
            queryTable[#queryTable+1] = plyChars[i].citizenid
            citizenTable[plyChars[i].citizenid] = plyChars[i].cid
            if Config.ClothingSystem == 'skinchanger' then
                local selectCid = tostring(plyChars[i].cid)
                local model = `mp_m_freemode_01`
                if plyChars[i].skin and plyChars[i].skin == 1 then model = `mp_f_freemode_01` end
                skins[selectCid] = { model = model, skin = plyChars[i].skin }
            end
        end
        if Config.ClothingSystem ~= 'skinchanger' then
            local result = MySQL.query.await('SELECT * FROM playerskins WHERE citizenid IN (?) AND active = 1', { queryTable })
            if result then
                for _, row in ipairs(result) do
                    local selectCid = citizenTable[row.citizenid]
                    selectCid = tostring(selectCid)
                    if Config.ClothingSystem == 'illenium-appearance' then
                        local mySkinData = json.decode(row.skin)
                        skins[selectCid] = {model = mySkinData.model, skin = mySkinData}
                    else
                        skins[selectCid] = {model = row.model, skin = json.decode(row.skin)}
                    end
                end
            end
        end
        return skins
    else
        return {}
    end
end)

-- # Logout command

if Config.Logout.active then
    lib.addCommand(Config.Logout.name, {
        help = Config.Logout.description,
        restricted = 'group.' .. Config.Logout.group
    }, function(source, args, raw)
        local src = source
        local ply = Bridge.GetPlayer(src)
        if not ply then
            TriggerClientEvent('ox_lib:notify', src, { title = LANG.target_not_online, type = 'error' })
            return
        end
        if Config.Framework == 'qb' or Config.Framework == 'qbox' then
            Bridge.framework.Player.Logout(src)
        else
            TriggerEvent("esx:playerLogout", src)
        end
        TriggerClientEvent('wert-multicharacter:client:chooseChar', src)
    end)
end

if Config.Framework == 'esx' then

    local PREFIX = Config.Prefix or "char"
    local PRIMARY_IDENTIFIER = Bridge.framework.GetConfig().Identifier or GetConvar("sv_lan", "") == "true" and "ip" or "license"
    local oneSyncState = GetConvar("onesync", "off")

    CreateThread(function()
        Wait(1000)
        if next(Bridge.framework.Players) then
            local players = table.clone(Bridge.framework.Players)
            table.wipe(Bridge.framework.Players)
            for _, v in pairs(players) do
                Bridge.framework.Players[GetIdentifier(v.source)] = true
            end
        else
            Bridge.framework.Players = {}
        end
    end)

    AddEventHandler("playerConnecting", function(_, _, deferrals)
        deferrals.defer()
        local identifier = GetIdentifier(source)

        if oneSyncState == "off" or oneSyncState == "legacy" then
            return deferrals.done(("[ESX] ESX Requires Onesync Infinity to work. This server currently has Onesync set to: %s"):format(oneSyncState))
        end

        if identifier then
            if not Bridge.framework.GetConfig().EnableDebug then
                if Bridge.framework.Players[identifier] then
                    deferrals.done(("[Wert Multicharacter] A player is already connected to the server with this identifier.\nYour identifier: %s:%s"):format(PRIMARY_IDENTIFIER, identifier))
                else
                    deferrals.done()
                end
            else
                deferrals.done()
            end
        else
            deferrals.done(("Unable to retrieve player identifier.\nIdentifier type: %s"):format(PRIMARY_IDENTIFIER))
        end
    end)


    MySQL.ready(function()
        Wait(1000)
        while not next(Bridge.framework.Jobs) do
            Wait(500)
            Bridge.framework.Jobs = Bridge.framework.GetJobs()
        end
    end)

    AddEventHandler("playerDropped", function()
        hasDonePreloading[source] = false
        Bridge.framework.Players[GetIdentifier(source)] = nil
    end)

    function GetIdentifier(source)
        local fxDk = GetConvarInt("sv_fxdkMode", 0)
        if fxDk == 1 then return "ESX-DEBUG-LICENCE" end
        local identifier = GetPlayerIdentifierByType(source, PRIMARY_IDENTIFIER)
        return identifier and identifier:gsub(PRIMARY_IDENTIFIER .. ":", "")
    end

end
bridge/client.lua

Bridge = {}

-- # Get core
if Config.Framework == 'qb' then
    Bridge.framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'qbox' then
    Bridge.framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'esx' then
    Bridge.framework = exports["es_extended"]:getSharedObject()
end
bridge/server.lua

Bridge = {}

-- # Get core
if Config.Framework == 'qb' then
    Bridge.framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'qbox' then
    Bridge.framework = exports['qb-core']:GetCoreObject()
elseif Config.Framework == 'esx' then
    Bridge.framework = exports["es_extended"]:getSharedObject()
end

function Bridge.GetPlayer(src)
    if not src then return nil end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        return Bridge.framework.Functions.GetPlayer(src)
    else
        return Bridge.framework.GetPlayerFromId(src)
    end
end

function Bridge.GetIdentifier(src, idtype)
    if GetConvarInt('sv_fxdkMode', 0) == 1 then return 'license:fxdk' end
    return GetPlayerIdentifierByType(src, idtype or 'license')
end

function Bridge.AddItem(src, data)
    if not src then return false end
    local ply = Bridge.GetPlayer(src)
    if not ply then return end
    if GetResourceState('ox_inventory') == 'started' then
        exports.ox_inventory:AddItem(src, data.name, data.amount, data.info, data.slot)
        return
    end
    if Config.Framework == 'qb' or Config.Framework == 'qbox' then
        ply.Functions.AddItem(data.name, data.amount, data.slot, data.info)
    else
        ply.addInventoryItem(data.name, data.amount)
    end
end

Last updated