647 lines
18 KiB
Lua
647 lines
18 KiB
Lua
local Freecam = exports['fivem-freecam']
|
|
|
|
local function CamThread()
|
|
CreateThread(function()
|
|
local IsDisabledControlJustPressed = IsDisabledControlJustPressed
|
|
local DisableControlAction = DisableControlAction
|
|
while Modeler.IsFreecamMode do
|
|
if IsDisabledControlJustPressed(0, 26) then -- C
|
|
Modeler.IsFreecamMode = false
|
|
Modeler:FreecamMode(false)
|
|
break
|
|
end
|
|
DisableControlAction(0, 199, true) -- P
|
|
DisableControlAction(0, 200, true) -- ESC
|
|
Wait(0)
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function isInside(coords)
|
|
local extent = Modeler.shellMinMax
|
|
|
|
local isX = coords.x >= extent.min.x and coords.x <= extent.max.x
|
|
local isY = coords.y >= extent.min.y and coords.y <= extent.max.y
|
|
local isZ = coords.z >= extent.min.z and coords.z <= extent.max.z
|
|
if isX and isY and isZ then
|
|
return true
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
local function getMinMax(shellPos, shellMin, shellMax)
|
|
local min = vector3(shellPos.x + shellMin.x, shellPos.y + shellMin.y, shellPos.z + shellMin.z)
|
|
local max = vector3(shellPos.x + shellMax.x, shellPos.y + shellMax.y, shellPos.z + shellMax.z)
|
|
|
|
return {min = min, max = max}
|
|
end
|
|
|
|
|
|
AddEventHandler('freecam:onTick', function()
|
|
if not Modeler.IsFreecamMode then return end
|
|
|
|
local update = true
|
|
local lookAt = Freecam:GetTarget(5.0)
|
|
local camPos = Freecam:GetPosition()
|
|
|
|
-- see if camPos is the same as the last one
|
|
if Modeler.CurrentCameraPosition and Modeler.CurrentCameraLookAt then
|
|
local posX = Modeler.CurrentCameraPosition.x == camPos.x
|
|
local posY = Modeler.CurrentCameraPosition.y == camPos.y
|
|
local posZ = Modeler.CurrentCameraPosition.z == camPos.z
|
|
|
|
local lookAtX = Modeler.CurrentCameraLookAt.x == lookAt.x
|
|
local lookAtY = Modeler.CurrentCameraLookAt.y == lookAt.y
|
|
local lookAtZ = Modeler.CurrentCameraLookAt.z == lookAt.z
|
|
|
|
if posX and posY and posZ and lookAtX and lookAtY and lookAtZ then
|
|
return
|
|
end
|
|
end
|
|
|
|
if not isInside(camPos) then
|
|
Freecam:SetPosition(Modeler.CurrentCameraPosition.x, Modeler.CurrentCameraPosition.y, Modeler.CurrentCameraPosition.z)
|
|
update = false
|
|
end
|
|
|
|
if update then
|
|
Modeler.CurrentCameraLookAt = lookAt
|
|
Modeler.CurrentCameraPosition = camPos
|
|
end
|
|
|
|
SendNUIMessage({
|
|
action = "updateCamera",
|
|
data = {
|
|
cameraPosition = Modeler.CurrentCameraPosition,
|
|
cameraLookAt = Modeler.CurrentCameraLookAt,
|
|
}
|
|
})
|
|
end)
|
|
|
|
|
|
|
|
|
|
-- WHERE THE ACTUAL CLASS STARTS
|
|
|
|
Modeler = {
|
|
IsMenuActive = false,
|
|
IsFreecamMode = false,
|
|
|
|
property_id = nil,
|
|
|
|
shellPos = nil,
|
|
shellMinMax = nil,
|
|
|
|
CurrentObject = nil,
|
|
CurrentCameraPosition = nil,
|
|
CurrentCameraLookAt = nil,
|
|
CurrentObjectAlpha = 200,
|
|
|
|
Cart = {},
|
|
|
|
-- Hover stuff
|
|
IsHovering = false,
|
|
HoverObject = nil,
|
|
HoverDistance = 5.0,
|
|
|
|
OpenMenu = function(self, property_id)
|
|
|
|
|
|
local property = Property.Get(property_id)
|
|
|
|
if not property then return end
|
|
if not property.owner and not property.has_access then return end
|
|
if property.has_access and not Config.AccessCanEditFurniture then return end
|
|
|
|
self.shellPos = GetEntityCoords(property.shellObj)
|
|
local min, max = GetModelDimensions(property.shellData.hash)
|
|
|
|
self.shellMinMax = getMinMax(self.shellPos, min, max)
|
|
|
|
self.property_id = property_id
|
|
self.IsMenuActive = true
|
|
|
|
self:UpdateFurnitures()
|
|
|
|
SendNUIMessage({
|
|
action = "setVisible",
|
|
data = true
|
|
})
|
|
|
|
SendNUIMessage({
|
|
action = "setFurnituresData",
|
|
data = Config.Furnitures
|
|
})
|
|
|
|
-- Owned furniture is set by the Property class
|
|
SetNuiFocus(true, true)
|
|
self:FreecamActive(true)
|
|
self:FreecamMode(false)
|
|
end,
|
|
|
|
CloseMenu = function(self)
|
|
self.IsMenuActive = false
|
|
self:ClearCart()
|
|
|
|
SendNUIMessage({
|
|
action = "setOwnedItems",
|
|
data = {},
|
|
})
|
|
|
|
SendNUIMessage({
|
|
action = "setVisible",
|
|
data = false
|
|
})
|
|
|
|
SetNuiFocus(false, false)
|
|
|
|
self:HoverOut()
|
|
self:StopPlacement()
|
|
self:FreecamActive(false)
|
|
|
|
Wait(500)
|
|
|
|
self.CurrentCameraPosition = nil
|
|
self.CurrentCameraLookAt = nil
|
|
self.CurrentObject = nil
|
|
self.property_id = nil
|
|
end,
|
|
|
|
FreecamActive = function(self, bool)
|
|
if bool then
|
|
Freecam:SetActive(true)
|
|
Freecam:SetKeyboardSetting('BASE_MOVE_MULTIPLIER', 0.1)
|
|
Freecam:SetKeyboardSetting('FAST_MOVE_MULTIPLIER', 2)
|
|
Freecam:SetKeyboardSetting('SLOW_MOVE_MULTIPLIER', 2)
|
|
Freecam:SetFov(45.0)
|
|
self.IsFreecamMode = true
|
|
else
|
|
Freecam:SetActive(false)
|
|
--reset to default
|
|
Freecam:SetKeyboardSetting('BASE_MOVE_MULTIPLIER', 5)
|
|
Freecam:SetKeyboardSetting('FAST_MOVE_MULTIPLIER', 10)
|
|
Freecam:SetKeyboardSetting('SLOW_MOVE_MULTIPLIER', 10)
|
|
self.IsFreecamMode = false
|
|
end
|
|
end,
|
|
|
|
FreecamMode = function(self, bool)
|
|
if bool then --not in UI
|
|
self.IsFreecamMode = true
|
|
CamThread()
|
|
Freecam:SetFrozen(false)
|
|
SetNuiFocus(false, false)
|
|
else -- in UI
|
|
self.IsFreecamMode = false
|
|
Freecam:SetFrozen(true)
|
|
SetNuiFocus(true, true)
|
|
SendNUIMessage({
|
|
action = "freecamMode",
|
|
data = false
|
|
})
|
|
end
|
|
end,
|
|
|
|
StartPlacement = function(self, data)
|
|
self:HoverOut() -- stops the hover effect on the previous object because sometimes mouseleave doesnt work
|
|
local object = data.object
|
|
local curObject
|
|
local objectRot
|
|
local objectPos
|
|
|
|
Modeler.CurrentCameraLookAt = Freecam:GetTarget(5.0)
|
|
Modeler.CurrentCameraPosition = Freecam:GetPosition()
|
|
|
|
if data.entity then --if the object is already spawned
|
|
curObject = data.entity
|
|
objectPos = GetEntityCoords(curObject)
|
|
objectRot = GetEntityRotation(curObject)
|
|
else
|
|
self:StopPlacement()
|
|
lib.requestModel(object)
|
|
|
|
curObject = CreateObject(GetHashKey(object), 0.0, 0.0, 0.0, false, true, false)
|
|
SetEntityCoords(curObject, self.CurrentCameraLookAt.x, self.CurrentCameraLookAt.y, self.CurrentCameraLookAt.z)
|
|
|
|
objectRot = GetEntityRotation(curObject)
|
|
objectPos = self.CurrentCameraLookAt
|
|
end
|
|
|
|
FreezeEntityPosition(curObject, true)
|
|
SetEntityCollision(curObject, false, false)
|
|
SetEntityAlpha(curObject, self.CurrentObjectAlpha, false)
|
|
SetEntityDrawOutline(curObject, true)
|
|
SetEntityDrawOutlineColor(255, 255, 255, 255)
|
|
SetEntityDrawOutlineShader(0)
|
|
|
|
SendNUIMessage({
|
|
action = "setObjectAlpha",
|
|
data = self.CurrentObjectAlpha
|
|
})
|
|
|
|
SendNUIMessage({
|
|
action = "setupModel",
|
|
data = {
|
|
objectPosition = objectPos,
|
|
objectRotation = objectRot,
|
|
cameraPosition = self.CurrentCameraPosition,
|
|
cameraLookAt = self.CurrentCameraLookAt,
|
|
entity = data.entity,
|
|
}
|
|
})
|
|
|
|
SetNuiFocus(true, true)
|
|
self.CurrentObject = curObject
|
|
end,
|
|
|
|
MoveObject = function (self, data)
|
|
local coords = vec3(data.x + 0.0, data.y + 0.0, data.z + 0.0)
|
|
if not isInside(coords) then
|
|
return
|
|
end
|
|
|
|
SetEntityCoords(self.CurrentObject, coords)
|
|
-- get the current offset of this object in relation to the
|
|
end,
|
|
|
|
RotateObject = function (self, data)
|
|
SetEntityRotation(self.CurrentObject, data.x + 0.0, data.y + 0.0, data.z + 0.0)
|
|
end,
|
|
|
|
StopPlacement = function (self)
|
|
if self.CurrentObject == nil then return end
|
|
|
|
local canDelete = true
|
|
for k, v in pairs(self.Cart) do
|
|
if k == self.CurrentObject then
|
|
canDelete = false
|
|
break
|
|
end
|
|
end
|
|
-- furnitureObjs
|
|
-- see if its an owned object
|
|
local property = PropertiesTable[self.property_id]
|
|
local ownedfurnitures = property.furnitureObjs
|
|
for i = 1, #ownedfurnitures do
|
|
if ownedfurnitures[i].entity == self.CurrentObject then
|
|
self:UpdateFurniture(ownedfurnitures[i])
|
|
canDelete = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if canDelete then
|
|
DeleteEntity(self.CurrentObject)
|
|
end
|
|
|
|
SetEntityDrawOutline(self.CurrentObject, false)
|
|
SetEntityAlpha(self.CurrentObject, 255, false)
|
|
self.CurrentObject = nil
|
|
end,
|
|
|
|
UpdateFurnitures = function(self)
|
|
|
|
if not self.IsMenuActive then
|
|
return
|
|
end
|
|
|
|
if not self.property_id then return end
|
|
|
|
local property = Property.Get(self.property_id)
|
|
|
|
if not property then return end
|
|
if not property.owner and not property.has_access then return end
|
|
if property.has_access and not Config.AccessCanEditFurniture then return end
|
|
|
|
|
|
SendNUIMessage({
|
|
action = "setOwnedItems",
|
|
data = property.furnitureObjs,
|
|
})
|
|
end,
|
|
|
|
-- can be better
|
|
-- everytime "Stop Placement" is pressed on an owned object, it will update the furniture
|
|
-- maybe should do it all at once when the user leaves the menu????
|
|
UpdateFurniture = function (self, item)
|
|
local newPos = GetEntityCoords(item.entity)
|
|
local newRot = GetEntityRotation(item.entity)
|
|
|
|
local offsetPos = {
|
|
x = math.floor((newPos.x - self.shellPos.x) * 10000) / 10000,
|
|
y = math.floor((newPos.y - self.shellPos.y) * 10000) / 10000,
|
|
z = math.floor((newPos.z - self.shellPos.z) * 10000) / 10000,
|
|
}
|
|
|
|
local newFurniture = {
|
|
id = item.id,
|
|
label = item.label,
|
|
object = item.object,
|
|
position = offsetPos,
|
|
rotation = newRot,
|
|
type = item.type,
|
|
}
|
|
|
|
TriggerServerEvent("ps-housing:server:updateFurniture", self.property_id, newFurniture)
|
|
end,
|
|
|
|
SetObjectAlpha = function (self, data)
|
|
self.CurrentObjectAlpha = data.alpha
|
|
SetEntityAlpha(self.CurrentObject, self.CurrentObjectAlpha, false)
|
|
end,
|
|
|
|
PlaceOnGround = function (self)
|
|
local x, y, z = table.unpack(GetEntityCoords(self.CurrentObject))
|
|
local ground, z = GetGroundZFor_3dCoord(x, y, z, 0)
|
|
SetEntityCoords(self.CurrentObject, x, y, z)
|
|
|
|
return {x = x, y = y, z = z}
|
|
end,
|
|
|
|
SelectCartItem = function (self, data)
|
|
self:StopPlacement()
|
|
|
|
if data ~= nil then
|
|
self:StartPlacement(data)
|
|
end
|
|
end,
|
|
|
|
AddToCart = function (self, data)
|
|
local item = {
|
|
label = data.label,
|
|
object = data.object,
|
|
price = data.price,
|
|
entity = self.CurrentObject,
|
|
position = GetEntityCoords(self.CurrentObject),
|
|
rotation = GetEntityRotation(self.CurrentObject),
|
|
type = data.type,
|
|
}
|
|
|
|
self.Cart[self.CurrentObject] = item
|
|
|
|
SendNUIMessage({
|
|
action = "addToCart",
|
|
data = item
|
|
})
|
|
|
|
self:StopPlacement()
|
|
self.CurrentObject = nil
|
|
end,
|
|
|
|
RemoveFromCart = function (self, data)
|
|
local item = data
|
|
|
|
if item ~= nil then
|
|
DeleteEntity(item.entity)
|
|
|
|
SendNUIMessage({
|
|
action = "removeFromCart",
|
|
data = item
|
|
})
|
|
|
|
self.Cart[data.entity] = nil
|
|
end
|
|
end,
|
|
|
|
UpdateCartItem = function (self, data)
|
|
local item = self.Cart[data.entity]
|
|
|
|
if item ~= nil then
|
|
item = data
|
|
end
|
|
end,
|
|
|
|
ClearCart = function (self)
|
|
for _, v in pairs(self.Cart) do
|
|
DeleteEntity(v.entity)
|
|
end
|
|
|
|
self.Cart = {}
|
|
SendNUIMessage({
|
|
action = "clearCart"
|
|
})
|
|
end,
|
|
|
|
BuyCart = function (self)
|
|
local items = {}
|
|
local totalPrice = 0
|
|
|
|
-- If the cart is empty, return notify
|
|
if not next(self.Cart) then
|
|
Framework[Config.Notify].Notify("Din kurv er tom", "error")
|
|
return
|
|
end
|
|
|
|
-- seperate loop to get total price so it doesnt have to do all that math for no reason
|
|
for _, v in pairs(self.Cart) do
|
|
totalPrice = totalPrice + v.price
|
|
end
|
|
|
|
PlayerData = QBCore.Functions.GetPlayerData()
|
|
if PlayerData.money.cash < totalPrice and PlayerData.money.bank < totalPrice then
|
|
Framework[Config.Notify].Notify("Du har ikke nok penge!", "error")
|
|
return
|
|
end
|
|
|
|
for _, v in pairs(self.Cart) do
|
|
|
|
local offsetPos = {
|
|
x = math.floor((v.position.x - self.shellPos.x) * 10000) / 10000,
|
|
y = math.floor((v.position.y - self.shellPos.y) * 10000) / 10000,
|
|
z = math.floor((v.position.z - self.shellPos.z) * 10000) / 10000,
|
|
}
|
|
|
|
local id = tostring(math.random(100000, 999999)..self.property_id)
|
|
|
|
items[#items + 1] = {
|
|
id = id,
|
|
object = v.object,
|
|
label = v.label,
|
|
position = offsetPos,
|
|
rotation = v.rotation,
|
|
type = v.type,
|
|
}
|
|
end
|
|
|
|
TriggerServerEvent("ps-housing:server:buyFurniture", self.property_id, items, totalPrice)
|
|
|
|
self:ClearCart()
|
|
end,
|
|
|
|
SetHoverDistance = function (self, data)
|
|
self.HoverDistance = data + 0.0
|
|
end,
|
|
|
|
HoverIn = function (self, data)
|
|
if self.HoverObject then
|
|
local tries = 0
|
|
while DoesEntityExist(self.HoverObject) do
|
|
SetEntityAsMissionEntity(self.HoverObject, true, true)
|
|
DeleteEntity(self.HoverObject)
|
|
Wait(50)
|
|
tries = tries + 1
|
|
if tries > 25 then
|
|
break
|
|
end
|
|
end
|
|
|
|
self.HoverObject = nil
|
|
end
|
|
|
|
local object = data.object and joaat(data.object) or nil
|
|
if object == nil then return end
|
|
lib.requestModel(object)
|
|
if self.HoverObject then return end
|
|
self.HoverObject = CreateObject(object, 0.0, 0.0, 0.0, false, false, false)
|
|
Modeler.CurrentCameraLookAt = Freecam:GetTarget(self.HoverDistance)
|
|
local camRot = Freecam:GetRotation()
|
|
|
|
SetEntityCoords(self.HoverObject, self.CurrentCameraLookAt.x, self.CurrentCameraLookAt.y, self.CurrentCameraLookAt.z)
|
|
FreezeEntityPosition(self.HoverObject, true)
|
|
SetEntityCollision(self.HoverObject, false, false)
|
|
SetEntityRotation(self.HoverObject, 0.0, 0.0, camRot.z)
|
|
|
|
self.IsHovering = true
|
|
while self.IsHovering do
|
|
local rot = GetEntityRotation(self.HoverObject)
|
|
SetEntityRotation(self.HoverObject, rot.x, rot.y, rot.z + 0.1)
|
|
Wait(0)
|
|
end
|
|
end,
|
|
|
|
HoverOut = function (self)
|
|
if self.HoverObject == nil then return end
|
|
if self.HoverObject and self.HoverObject ~= 0 then
|
|
local tries = 0
|
|
while DoesEntityExist(self.HoverObject) do
|
|
SetEntityAsMissionEntity(self.HoverObject, true, true)
|
|
DeleteEntity(self.HoverObject)
|
|
Wait(50)
|
|
tries = tries + 1
|
|
if tries > 25 then
|
|
break
|
|
end
|
|
end
|
|
self.HoverObject = nil
|
|
end
|
|
self.IsHovering = false
|
|
end,
|
|
|
|
SelectOwnedItem = function (self, data)
|
|
self:StopPlacement()
|
|
if data ~= nil then
|
|
self:StartPlacement(data)
|
|
end
|
|
end,
|
|
|
|
RemoveOwnedItem = function (self, data)
|
|
local item = data
|
|
|
|
if item ~= nil then
|
|
SendNUIMessage({
|
|
action = "removeOwnedItem",
|
|
data = item
|
|
})
|
|
|
|
TriggerServerEvent("ps-housing:server:removeFurniture", self.property_id, item.id)
|
|
end
|
|
end,
|
|
}
|
|
|
|
RegisterNUICallback("previewFurniture", function(data, cb)
|
|
Modeler:StartPlacement(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("moveObject", function(data, cb)
|
|
Modeler:MoveObject(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("rotateObject", function(data, cb)
|
|
Modeler:RotateObject(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("stopPlacement", function(data, cb)
|
|
Modeler:StopPlacement()
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("setObjectAlpha", function(data, cb)
|
|
Modeler:SetObjectAlpha(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("hideUI", function(data, cb)
|
|
Modeler:CloseMenu()
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("freecamMode", function(data, cb)
|
|
Modeler:FreecamMode(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("placeOnGround", function(data, cb)
|
|
local coords = Modeler:PlaceOnGround()
|
|
cb(coords)
|
|
end)
|
|
|
|
RegisterNUICallback("selectCartItem", function(data, cb)
|
|
Modeler:SelectCartItem(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("addToCart", function(data, cb)
|
|
Modeler:AddToCart(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("removeCartItem", function(data, cb)
|
|
Modeler:RemoveFromCart(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("updateCartItem", function(data, cb)
|
|
Modeler:UpdateCartItem(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("buyCartItems", function(data, cb)
|
|
Modeler:BuyCart()
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("hoverIn", function(data, cb)
|
|
Modeler:HoverIn(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("hoverOut", function(data, cb)
|
|
Modeler:HoverOut()
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("setHoverDistance", function(data, cb)
|
|
Modeler:SetHoverDistance(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("selectOwnedItem", function(data, cb)
|
|
Modeler:SelectOwnedItem(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("removeOwnedItem", function(data, cb)
|
|
Modeler:RemoveOwnedItem(data)
|
|
cb("ok")
|
|
end)
|
|
|
|
RegisterNUICallback("showNotification", function(data, cb)
|
|
Framework[Config.Notify].Notify(data.message, data.type)
|
|
cb("ok")
|
|
end)
|