ed
This commit is contained in:
parent
510e3ffcf2
commit
f43cf424cf
305 changed files with 34683 additions and 0 deletions
|
@ -0,0 +1,53 @@
|
|||
Shells = Shells or {}
|
||||
|
||||
|
||||
--Data table
|
||||
Shells.Targets = Shells.Targets or {
|
||||
['entrance'] = {
|
||||
['enter'] = {
|
||||
label = 'Enter',
|
||||
icon = 'fa-solid fa-door-open',
|
||||
onSelect = function(entity, shellId, objectId)
|
||||
TriggerServerEvent('community_bridge:server:EnterShell', shellId, objectId)
|
||||
end
|
||||
},
|
||||
},
|
||||
['exit'] = {
|
||||
['leave'] = {
|
||||
label = 'Exit',
|
||||
icon = 'fa-solid fa-door-closed',
|
||||
onSelect = function(entity, shellId, objectId)
|
||||
TriggerServerEvent('community_bridge:server:ExitShell', shellId, objectId)
|
||||
end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
--Functions to set data table
|
||||
Shells.Target = {
|
||||
Set = function(shellType, options)
|
||||
assert(shellType, "Shells.Target.Set: 'shellType' is required")
|
||||
options = options or {}
|
||||
for key, value in pairs(options) do
|
||||
if Shells.Targets[shellType] and Shells.Targets[shellType][key] then
|
||||
value.onSelect = Shells.Targets[shellType][key].onSelect
|
||||
end
|
||||
Shells.Targets[shellType] = Shells.Targets[shellType] or {}
|
||||
Shells.Targets[shellType][key] = value
|
||||
end
|
||||
return true
|
||||
end,
|
||||
Get = function(shellType, shellId, objectId)
|
||||
local aOptions = {}
|
||||
for key, value in pairs(Shells.Targets[shellType] or {}) do
|
||||
local onSelect = value.onSelect
|
||||
value.onSelect = function(entity)
|
||||
onSelect(entity, shellId, objectId)
|
||||
end
|
||||
table.insert(aOptions, value)
|
||||
end
|
||||
return aOptions
|
||||
end
|
||||
}
|
||||
|
||||
return Shells
|
|
@ -0,0 +1,269 @@
|
|||
local Target = Require('modules/target/_default/init.lua')
|
||||
local ClientEntity = Require("lib/entities/client/client_entity.lua")
|
||||
|
||||
|
||||
Shells = Shells or Require("lib/shells/client/config.lua")
|
||||
Shells.All = Shells.All or {}
|
||||
local insideShell = false
|
||||
Shells.Events = {
|
||||
OnSpawn = {},
|
||||
OnRemove = {},
|
||||
}
|
||||
|
||||
--Set Target lang or additionals
|
||||
-- Shells.Target.Set('entrance', {
|
||||
-- enter = {
|
||||
-- label = 'yerp',
|
||||
-- icon = 'fa-solid fa-door-open',
|
||||
-- },
|
||||
-- })
|
||||
|
||||
-- Shells.Target.Set('exit', {
|
||||
-- leave = {
|
||||
-- label = 'leerp',
|
||||
-- icon = 'fa-solid fa-door-closed',
|
||||
-- },
|
||||
-- })
|
||||
|
||||
Shells.Event = {
|
||||
Add = function(eventName, callback)
|
||||
if Shells.Events[eventName] then
|
||||
table.insert(Shells.Events[eventName], callback)
|
||||
else
|
||||
print(string.format("Shells.Event.Add: Invalid event name '%s'", eventName))
|
||||
end
|
||||
end,
|
||||
Trigger = function(eventName, ...)
|
||||
if Shells.Events[eventName] then
|
||||
for _, callback in ipairs(Shells.Events[eventName]) do
|
||||
callback(...)
|
||||
end
|
||||
else
|
||||
print(string.format("Shells.Event.Trigger: Invalid event name '%s'", eventName))
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
-- Shells.Event.Add('OnSpawn', function(pointData, entity)
|
||||
-- print(string.format("Exterior point created with ID: %s, Type: %s, Entity: %s", pointData.id, pointData.type, entity))
|
||||
-- end)
|
||||
-- Shells.Event.Add('OnRemove', function(pointData)
|
||||
-- print(string.format("Interior point created with ID: %s, Type: %s", pointData.id, pointData.type))
|
||||
-- end)
|
||||
|
||||
function Shells.AddInteriorObject(shell, objectData)
|
||||
objectData.OnSpawn = function(pointData)
|
||||
Shells.Event.Trigger('OnSpawn', objectData, pointData.spawned)
|
||||
local targetOptions = Shells.Target.Get(objectData.type, shell.id, objectData.id)
|
||||
if targetOptions then
|
||||
local size = vector3(objectData.distance / 2, objectData.distance / 2, objectData.distance / 2) -- this might need to be size
|
||||
Target.AddBoxZone(objectData.id, objectData.coords, size, objectData.rotation.z, targetOptions, true)
|
||||
end
|
||||
end
|
||||
objectData.OnRemove = function(pointData)
|
||||
Shells.Event.Trigger('OnRemove', objectData, pointData.spawned)
|
||||
Target.RemoveZone(objectData.id)
|
||||
end
|
||||
return ClientEntity.Register(objectData)
|
||||
end
|
||||
|
||||
function Shells.SetupInterior(shell)
|
||||
if not shell or not shell.interior then return end
|
||||
for _, v in pairs(shell.interior) do
|
||||
local pointData = Shells.AddInteriorObject(shell, v)
|
||||
shell.interiorSpawned[pointData.id] = pointData
|
||||
end
|
||||
end
|
||||
|
||||
function Shells.SetupExterior(shell)
|
||||
if not shell or not shell.exterior then return end
|
||||
for k, v in pairs(shell.exterior) do
|
||||
local pointData = Shells.AddInteriorObject(shell, v)
|
||||
shell.exteriorSpawned[pointData.id] = pointData
|
||||
end
|
||||
end
|
||||
|
||||
function Shells.ClearInterior(shell)
|
||||
if not shell or not shell.interiorSpawned then return end
|
||||
for _, v in pairs(shell.interiorSpawned) do
|
||||
ClientEntity.Unregister(v.id)
|
||||
Target.RemoveZone(v.id)
|
||||
end
|
||||
shell.interiorSpawned = {}
|
||||
end
|
||||
|
||||
function Shells.ClearExterior(shell)
|
||||
if not shell or not shell.exteriorSpawned then return end
|
||||
for _, v in pairs(shell.exteriorSpawned) do
|
||||
ClientEntity.Unregister(v.id)
|
||||
Target.RemoveZone(v.id)
|
||||
end
|
||||
shell.exteriorSpawned = {}
|
||||
end
|
||||
|
||||
|
||||
function Shells.New(data)
|
||||
assert(data.id, "Shells.Create: 'id' is required")
|
||||
assert(data.model, "Shells.Create: 'shellModel' is required")
|
||||
assert(data.coords, "Shells.Create: 'coords' is required")
|
||||
local exterior = data.exterior or {}
|
||||
local exteriorSpawned = {}
|
||||
for k, v in pairs(exterior or {}) do
|
||||
v.OnSpawn = function(pointData)
|
||||
Shells.Event.Trigger('OnSpawn', v, pointData.spawned)
|
||||
local targetOptions = Shells.Target.Get(v.type, data.id, v.id)
|
||||
if targetOptions then
|
||||
local size = vector3(v.distance / 2, v.distance / 2, v.distance / 2)
|
||||
Target.AddBoxZone(v.id, v.coords, size, v.rotation.z, targetOptions, true)
|
||||
end
|
||||
end
|
||||
v.OnRemove = function(pointData)
|
||||
Shells.Event.Trigger('OnRemove', v, pointData.spawned)
|
||||
Target.RemoveZone(v.id)
|
||||
end
|
||||
local pointData = ClientEntity.Register(v)
|
||||
exteriorSpawned[pointData.id] = pointData
|
||||
end
|
||||
data.interiorSpawned = {}
|
||||
data.exteriorSpawned = exteriorSpawned
|
||||
Shells.All[data.id] = data
|
||||
return data
|
||||
end
|
||||
|
||||
local returnPoint = nil
|
||||
function Shells.Enter(id, entranceId)
|
||||
local shell = Shells.All[id]
|
||||
if not shell then
|
||||
print(string.format("Shells.Spawn: Shell with ID '%s' not found", id))
|
||||
return
|
||||
end
|
||||
local entrance = shell.interior[entranceId]
|
||||
if not entrance then
|
||||
print(string.format("Shells.Enter: Entrance with ID '%s' not found in shell '%s'", entranceId, id))
|
||||
return
|
||||
end
|
||||
local ped = PlayerPedId()
|
||||
returnPoint = GetEntityCoords(ped)
|
||||
DoScreenFadeOut(1000)
|
||||
Wait(1000)
|
||||
local entranceCoords = entrance.coords
|
||||
SetEntityCoords(ped, entranceCoords.x, entranceCoords.y, entranceCoords.z, false, false, false, true)
|
||||
FreezeEntityPosition(ped, true)
|
||||
local oldShell = insideShell and Shells.All[insideShell]
|
||||
if oldShell?.id ~= id then
|
||||
Shells.ClearExterior(oldShell)
|
||||
Shells.ClearInterior(oldShell)
|
||||
end
|
||||
Shells.ClearExterior(shell)
|
||||
Shells.SetupInterior(shell)
|
||||
ClientEntity.Register(shell)
|
||||
Wait(1000) -- Wait for the fade out to complete
|
||||
FreezeEntityPosition(ped, false)
|
||||
DoScreenFadeIn(1000)
|
||||
insideShell = shell.id
|
||||
end
|
||||
|
||||
function Shells.Exit(id, exitId)
|
||||
local shell = Shells.All[id]
|
||||
if not shell then
|
||||
print(string.format("Shells.Exit: Shell with ID '%s' not found", id))
|
||||
return
|
||||
end
|
||||
local oldCoords = GetEntityCoords(PlayerPedId())
|
||||
local oldPoint = shell.exterior[exitId]
|
||||
if not oldPoint then
|
||||
print(string.format("Shells.Exit: Old point with ID '%s' not found in shell '%s'", exitId, id))
|
||||
return
|
||||
end
|
||||
DoScreenFadeOut(1000)
|
||||
Wait(1000)
|
||||
SetEntityCoords(PlayerPedId(), oldPoint.coords.x, oldPoint.coords.y, oldPoint.coords.z, false, false, false, true)
|
||||
FreezeEntityPosition(PlayerPedId(), true)
|
||||
Shells.ClearInterior(shell)
|
||||
ClientEntity.Unregister(shell.id)
|
||||
Shells.SetupExterior(shell)
|
||||
shell.interiorSpawned = {}
|
||||
FreezeEntityPosition(PlayerPedId(), false)
|
||||
DoScreenFadeIn(1000)
|
||||
insideShell = false
|
||||
end
|
||||
|
||||
function Shells.Inside()
|
||||
return insideShell
|
||||
end
|
||||
|
||||
RegisterNetEvent('community_bridge:client:CreateShell', function(shell)
|
||||
Shells.New(shell)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('community_bridge:client:EnterShell', function(shellId, entranceId, oldId)
|
||||
local shell = Shells.All[shellId]
|
||||
if not shell then
|
||||
print(string.format("Shells.EnterShell: Shell with ID '%s' not found", shellId))
|
||||
return
|
||||
end
|
||||
|
||||
Shells.Enter(shellId, entranceId, oldId)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('community_bridge:client:ExitShell', function(shellId, oldId)
|
||||
local shell = Shells.All[shellId]
|
||||
print(string.format("Shells.ExitShell: Exiting shell '%s'", shellId))
|
||||
if not shell then
|
||||
print(string.format("Shells.ExitShell: Shell with ID '%s' not found", shellId))
|
||||
return
|
||||
end
|
||||
Shells.Exit(shellId, oldId)
|
||||
|
||||
end)
|
||||
|
||||
RegisterNetEvent('community_bridge:client:AddObjectsToShell', function (shellId, interiorObjects, exteriorObjects)
|
||||
local shell = Shells.All[shellId]
|
||||
print(string.format("Shells.AddObjectsToShell: Adding objects to shell '%s'", shellId),
|
||||
json.encode({interiorObjects = interiorObjects, exteriorObjects = exteriorObjects}, { indent = true }))
|
||||
if not shell then
|
||||
print(string.format("Shells.AddObjectsToShell: Shell with ID '%s' not found", shellId))
|
||||
return
|
||||
end
|
||||
local insideShell = Shells.Inside()
|
||||
if interiorObjects then
|
||||
for _, obj in pairs(interiorObjects) do
|
||||
if not shell.interior[obj.id] then
|
||||
shell.interior[obj.id] = obj
|
||||
if insideShell and insideShell == shellId then
|
||||
local pointData = Shells.AddInteriorObject(shell, obj)
|
||||
shell.interiorSpawned[pointData.id] = pointData
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if exteriorObjects then
|
||||
for _, obj in pairs(exteriorObjects) do
|
||||
if not shell.exterior[obj.id] then
|
||||
shell.exterior[obj.id] = obj
|
||||
if not insideShell then
|
||||
local pointData = Shells.AddInteriorObject(shell, obj)
|
||||
shell.exteriorSpawned[pointData.id] = pointData
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
RegisterNetEvent('community_bridge:client:CreateShells', function(shells)
|
||||
print("Shells.CreateShells: Creating shells")
|
||||
for _, shell in pairs(shells) do
|
||||
Shells.New(shell)
|
||||
end
|
||||
end)
|
||||
-- TriggerClientEvent('community_bridge:client:CreateShells', -1, toClient)
|
||||
-- TriggerClientEvent('community_bridge:client:ExitShell', src, oldId)
|
||||
|
||||
|
||||
AddEventHandler('onResourceStart', function(resource)
|
||||
if resource == GetCurrentResourceName() then
|
||||
DoScreenFadeIn(1000) -- Fade in when resource stops
|
||||
if not returnPoint then return end
|
||||
SetEntityCoords(PlayerPedId(), returnPoint.x, returnPoint.y, returnPoint.z, false, false, false, true)
|
||||
end
|
||||
end)
|
|
@ -0,0 +1,379 @@
|
|||
Ids = Ids or Require("lib/utility/shared/ids.lua")
|
||||
Shells = Shells or {}
|
||||
Shells.All = Shells.All or {}
|
||||
Shells.ActivePlayers = Shells.ActivePlayers or {} -- Track players in shells
|
||||
|
||||
Shells.Interactable = Shells.Interactable or {}
|
||||
Shells.BucketsInUse = Shells.BucketsInUse or {} -- Track buckets in use
|
||||
|
||||
function Shells.Interactable.New(_type, id, model, coords, rotation, entityType, distance, meta)
|
||||
assert(_type, "Shells.Interactable.Create: 'type' is required")
|
||||
assert(id, "Shells.Interactable.Create: 'name' is required")
|
||||
assert(coords, "Shells.Interactable.Create: 'coords' is required")
|
||||
return {
|
||||
type = _type,
|
||||
id = id,
|
||||
model = model,
|
||||
coords = coords,
|
||||
rotation = rotation or vector3(0.0, 0.0, 0.0),
|
||||
distance = distance or 2.0,
|
||||
entityType = entityType or "object", -- Default entity type
|
||||
meta = meta or {},
|
||||
}
|
||||
end
|
||||
|
||||
function Shells.New(data)
|
||||
local id = data.id or Ids.CreateUniqueId(Shells.All)
|
||||
local _type = data.type or "none"
|
||||
local model = data.model
|
||||
local size = data.size or vector3(10.0, 10.0, 10.0) -- Default size if not provided
|
||||
local coords = data.coords or vector3(0.0, 0.0, 0.0) -- Default coordinates if not provided
|
||||
local rotation = data.rotation or vector3(0.0, 0.0, 0.0) -- Default rotation if not provided
|
||||
local interior = data.interior or {}
|
||||
local exterior = data.exterior or {}
|
||||
local bucket = data.bucket or Ids.RandomNumber(Shells.BucketsInUse, 4)
|
||||
assert(id, "Shells.Create: 'id' is required")
|
||||
assert(model, "Shells.Create: 'shellModel' is required")
|
||||
assert(coords, "Shells.Create: 'coords' is required")
|
||||
|
||||
local interiorInteractions = {}
|
||||
for k, v in pairs(interior or {}) do
|
||||
local interiorCoords = coords + (v.offset or vector3(0.0, 0.0, 0.0))
|
||||
local interaction = Shells.Interactable.New(
|
||||
v.type or "none",
|
||||
v.id or Ids.CreateUniqueId(interiorInteractions),
|
||||
v.model,
|
||||
interiorCoords,
|
||||
v.rotation or vector3(0.0, 0.0, 0.0),
|
||||
v.entityType or "object", -- Default entity type for interior interactions
|
||||
v.distance or 2.0,
|
||||
v.meta
|
||||
)
|
||||
interiorInteractions[interaction.id] = interaction
|
||||
end
|
||||
|
||||
local exteriorInteractions = {}
|
||||
for k, v in pairs(exterior or {}) do
|
||||
local interaction = Shells.Interactable.New(
|
||||
v.type or "none",
|
||||
v.id or Ids.CreateUniqueId(exteriorInteractions),
|
||||
v.model,
|
||||
v.coords,
|
||||
v.rotation or vector3(0.0, 0.0, 0.0),
|
||||
v.entityType or "object", -- Default entity type for exterior interactions
|
||||
v.distance or 2.0,
|
||||
v.meta
|
||||
)
|
||||
exteriorInteractions[interaction.id] = interaction
|
||||
end
|
||||
|
||||
local shellData = {
|
||||
id = id,
|
||||
type = _type,
|
||||
entityType = "object", -- Default entity type for shells
|
||||
model = model,
|
||||
coords = coords,
|
||||
size = size or vector3(10.0, 10.0, 10.0), -- Default size if not provided
|
||||
rotation = rotation or vector3(0.0, 0.0, 0.0),
|
||||
interior = interiorInteractions,
|
||||
exterior = exteriorInteractions,
|
||||
}
|
||||
|
||||
Shells.All[id] = shellData
|
||||
return shellData
|
||||
end
|
||||
|
||||
function Shells.Create(data)
|
||||
local shell = Shells.New(data)
|
||||
assert(shell, "Shells.Create: 'shell' is required")
|
||||
TriggerClientEvent('community_bridge:client:CreateShell', -1, shell)
|
||||
return shell
|
||||
end
|
||||
|
||||
function Shells.CreateBulk(shells)
|
||||
assert(shells, "Shells.CreateBulk: 'shells' is required")
|
||||
assert(type(shells) == "table", "Shells.CreateBulk: 'shells' must be a table")
|
||||
local toClient = {}
|
||||
for _, shellData in pairs(shells) do
|
||||
local shell = Shells.New(shellData)
|
||||
toClient[shell.id] = shell
|
||||
end
|
||||
TriggerClientEvent('community_bridge:client:CreateShells', -1, toClient)
|
||||
end
|
||||
|
||||
function Shells.Enter(src, shellId, entranceId)
|
||||
src = tonumber(src)
|
||||
assert(src, "Shells.EnterShell: 'src' is required")
|
||||
assert(shellId, "Shells.EnterShell: 'shellId' is required")
|
||||
print(shellId)
|
||||
local shell = Shells.All[shellId]
|
||||
assert(shell, "Shell not found: " .. tostring(shellId))
|
||||
if shell.onEnter then
|
||||
local canEnter = shell.onEnter(src, shellId)
|
||||
if not canEnter then return false end
|
||||
end
|
||||
if not shell.bucket then
|
||||
local randNum = Ids.RandomNumber(Shells.BucketsInUse, 4)
|
||||
shell.bucket = tonumber(randNum)
|
||||
Shells.BucketsInUse[tostring(randNum)] = true
|
||||
end
|
||||
print(shell.bucket)
|
||||
SetPlayerRoutingBucket(src, shell.bucket)
|
||||
local exit = shell.exterior[entranceId]?.meta?.link
|
||||
TriggerClientEvent('community_bridge:client:EnterShell', src, shellId, exit, Shells.ActivePlayers[tostring(src)])
|
||||
Shells.ActivePlayers[tostring(src)] = shellId
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function Shells.Exit(src, shellId, oldId)
|
||||
|
||||
print(oldId)
|
||||
src = tonumber(src)
|
||||
assert(src, "Shells.ExitShell: 'src' is required")
|
||||
assert(shellId, "Player is not in a shell")
|
||||
|
||||
local shell = Shells.All[shellId]
|
||||
assert(shell, "Shell not found: " .. tostring(shellId))
|
||||
|
||||
-- Restore original routing bucket
|
||||
SetPlayerRoutingBucket(src, 0)
|
||||
local exit = shell.interior[oldId]?.meta?.link
|
||||
-- Clear player's shell data
|
||||
Shells.ActivePlayers[tostring(src)] = nil
|
||||
if shell.onExit then
|
||||
shell.onExit(src, shellId)
|
||||
end
|
||||
TriggerClientEvent('community_bridge:client:ExitShell', src, shellId, exit)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function Shells.Get(shellId)
|
||||
assert(shellId, "Shells.GetShellById: 'shellId' is required")
|
||||
return Shells.All[shellId]
|
||||
end
|
||||
|
||||
function Shells.Inside(src)
|
||||
src = tonumber(src)
|
||||
assert(src, "Shells.IsInside: 'src' is required")
|
||||
|
||||
local shellId = Shells.ActivePlayers[tostring(src)]
|
||||
if not shellId then
|
||||
return false
|
||||
end
|
||||
|
||||
local shell = Shells.All[shellId]
|
||||
if not shell then
|
||||
return false
|
||||
end
|
||||
|
||||
return shell
|
||||
end
|
||||
|
||||
function Shells.AddObjects(shellId, objects)
|
||||
assert(shellId, "Shells.AddObjects: 'shellId' is required")
|
||||
assert(objects, "Shells.AddObjects: 'objects' is required")
|
||||
assert(type(objects) == "table", "Shells.AddObjects: 'objects' must be a table")
|
||||
|
||||
local shell = Shells.All[shellId]
|
||||
assert(shell, "Shell not found: " .. tostring(shellId))
|
||||
|
||||
local interiors = objects.interior or {}
|
||||
local exteriors = objects.exterior or {}
|
||||
for _, objData in pairs(interiors) do
|
||||
local obj = Shells.Interactable.New(
|
||||
objData.type,
|
||||
objData.id,
|
||||
objData.model,
|
||||
objData.coords,
|
||||
objData.rotation,
|
||||
objData.entityType,
|
||||
objData.distance,
|
||||
objData.meta
|
||||
)
|
||||
shell.interior[obj.id] = obj -- Update the shell's interior with the new object
|
||||
end
|
||||
for _, objData in pairs(exteriors) do
|
||||
local obj = Shells.Interactable.New(
|
||||
objData.type,
|
||||
objData.id,
|
||||
objData.model,
|
||||
objData.coords,
|
||||
objData.rotation,
|
||||
objData.entityType,
|
||||
objData.distance,
|
||||
objData.meta
|
||||
)
|
||||
shell.exterior[obj.id] = obj -- Update the shell's exterior with the new object
|
||||
end
|
||||
|
||||
TriggerClientEvent('community_bridge:client:AddObjectsToShell', -1, shellId, shell.interior, shell.exterior)
|
||||
return shell
|
||||
end
|
||||
|
||||
function Shells.RemoveObjects(shellId, objectIds)
|
||||
assert(shellId, "Shells.RemoveObjects: 'shellId' is required")
|
||||
assert(objectIds, "Shells.RemoveObjects: 'objects' is required")
|
||||
if type(objectIds) ~= "table" then
|
||||
objectIds = {objectIds} -- Ensure it's a table
|
||||
end
|
||||
|
||||
local shell = Shells.All[shellId]
|
||||
assert(shell, "Shell not found: " .. tostring(shellId))
|
||||
|
||||
for _, objId in pairs(objectIds) do
|
||||
shell.interior[objId] = nil
|
||||
shell.exterior[objId] = nil
|
||||
end
|
||||
|
||||
TriggerClientEvent('community_bridge:client:RemoveObjectsFromShell', -1, shellId, objectIds)
|
||||
return shell
|
||||
end
|
||||
|
||||
RegisterNetEvent('community_bridge:server:EnterShell', function(shellId, entranceId)
|
||||
local src = source
|
||||
Shells.Enter(src, shellId, entranceId)
|
||||
end)
|
||||
|
||||
RegisterNetEvent('community_bridge:server:ExitShell', function(shellId, oldId)
|
||||
local src = source
|
||||
Shells.Exit(src, shellId, oldId)
|
||||
end)
|
||||
|
||||
AddEventHandler('onPlayerJoining', function(playerId)
|
||||
local src = source
|
||||
TriggerClientEvent('community_bridge:client:CreateShells', src, Shells.All)
|
||||
end)
|
||||
|
||||
function Shells.GetInteractable(shellId, id)
|
||||
assert(shellId, "Shells.GetInteractable: 'shellId' is required")
|
||||
assert(id, "Shells.GetInteractable: 'id' is required")
|
||||
|
||||
local shell = Shells.All[shellId]
|
||||
if not shell then
|
||||
return nil, "Shell not found: " .. tostring(shellId)
|
||||
end
|
||||
|
||||
local interactable = shell.interior[id] or shell.exterior[id]
|
||||
if not interactable then
|
||||
return nil, "Interactable not found: " .. tostring(id)
|
||||
end
|
||||
|
||||
return interactable
|
||||
end
|
||||
|
||||
function Shells.GetClosestInteractable(shellId, coords, exterior)
|
||||
assert(shellId, "Shells.GetClosestInteriorInteractable: 'shellId' is required")
|
||||
assert(coords, "Shells.GetClosestInteriorInteractable: 'coords' is required")
|
||||
|
||||
local shell = Shells.All[shellId]
|
||||
if not shell then
|
||||
return nil, "Shell not found: " .. tostring(shellId)
|
||||
end
|
||||
|
||||
local closest = nil
|
||||
local closestDistance = math.huge
|
||||
if exterior then
|
||||
for _, interactable in pairs(shell.exterior) do
|
||||
local distance = #(coords - interactable.coords)
|
||||
if distance < closestDistance then
|
||||
closestDistance = distance
|
||||
closest = interactable
|
||||
end
|
||||
end
|
||||
return closest, closestDistance
|
||||
end
|
||||
|
||||
for _, interactable in pairs(shell.interior) do
|
||||
local distance = #(coords - interactable.coords)
|
||||
if distance < closestDistance then
|
||||
closestDistance = distance
|
||||
closest = interactable
|
||||
end
|
||||
end
|
||||
return closest, closestDistance
|
||||
end
|
||||
|
||||
local testShell = nil
|
||||
RegisterCommand('shells:create', function(source, args, rawCommand)
|
||||
local coords = GetEntityCoords(GetPlayerPed(source))
|
||||
if testShell then
|
||||
Shells.Exit(source, testShell.id, 'exit1') -- Exit previous shell if it exists
|
||||
end
|
||||
testShell = Shells.Create({
|
||||
id = Ids.CreateUniqueId(Shells.All),
|
||||
type = "shell",
|
||||
model = "shell_garagem",
|
||||
coords = coords + vector3(0.0, 0.0, 100.0), -- Adjusted to place shell slightly below player
|
||||
rotation = vector3(0.0, 0.0, 0.0),
|
||||
size = vector3(10.0, 10.0, 10.0),
|
||||
interior = {
|
||||
{
|
||||
id = 'exit1',
|
||||
type = 'exit',
|
||||
coords = coords + vector3(0.0, 0.0, 1.0),
|
||||
rotation = vector3(0.0, 0.0, 0.0),
|
||||
distance = 2.0,
|
||||
meta = {
|
||||
link = 'entrance1',
|
||||
}
|
||||
}
|
||||
},
|
||||
exterior = {
|
||||
{
|
||||
id = 'entrance1',
|
||||
type = 'entrance',
|
||||
-- entityType = "object",
|
||||
-- model = "xm_int_lev_sub_chair_02",
|
||||
coords = coords - vector3(0.0, 0.0, 0.5),
|
||||
rotation = vector3(0.0, 0.0, 0.0),
|
||||
distance = 2.0,
|
||||
meta = {
|
||||
link = 'exit1',
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
end, true)
|
||||
|
||||
RegisterCommand('shells:addobject', function(source, args, rawCommand)
|
||||
if not testShell then
|
||||
print("No shell created. Use /shells:create first.")
|
||||
return
|
||||
end
|
||||
local model = args[1]
|
||||
if not model then
|
||||
print("Usage: /shells:addobject <shellId> <model>")
|
||||
return
|
||||
end
|
||||
|
||||
local shellId = testShell.id
|
||||
local coords = GetEntityCoords(GetPlayerPed(source))
|
||||
local objectData = {
|
||||
type = "none",
|
||||
entityType = "ped",
|
||||
id = Ids.CreateUniqueId(Shells.All[shellId].interior),
|
||||
model = model,
|
||||
coords = coords - vector3(0.0, 0.0, 0.5), -- Adjusted to place object slightly above player
|
||||
rotation = vector3(0.0, 0.0, 0.0),
|
||||
distance = 2.0,
|
||||
meta = {}
|
||||
}
|
||||
Shells.AddObjects(shellId, {interior = {objectData}})
|
||||
end, true)
|
||||
|
||||
AddEventHandler('onResourceStop', function(resource)
|
||||
if resource == GetCurrentResourceName() then
|
||||
for src, shellId in pairs(Shells.ActivePlayers) do
|
||||
SetPlayerRoutingBucket(tonumber(src), 0) -- Reset routing bucket for all players
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('community_bridge:Server:OnPlayerUnload', function(src)
|
||||
if not Shells.ActivePlayers[tostring(src)] then return end
|
||||
print(string.format("Player %d is exiting shell %s", src, Shells.ActivePlayers[tostring(src)]))
|
||||
Shells.Exit(src, Shells.ActivePlayers[tostring(src)])
|
||||
Shells.ActivePlayers[tostring(src)] = nil
|
||||
end)
|
Loading…
Add table
Add a link
Reference in a new issue