forked from Simnation/Main
ed
This commit is contained in:
parent
97d1f6a2f2
commit
f8eb493530
31 changed files with 7767 additions and 15 deletions
|
@ -225,8 +225,8 @@ CodeStudio.Products = {
|
||||||
itemPrice = 2,
|
itemPrice = 2,
|
||||||
itemInfo = "Mehr Fleisch als Worte – des is koa Semmel, des is a Lebensgefühl!",
|
itemInfo = "Mehr Fleisch als Worte – des is koa Semmel, des is a Lebensgefühl!",
|
||||||
},
|
},
|
||||||
['tims_instant_nudeln'] = {
|
['mimis_instant_nudeln'] = {
|
||||||
itemName = "Tim's Instant Nudeln",
|
itemName = "Mimis Instant Nudeln",
|
||||||
itemStock = 50,
|
itemStock = 50,
|
||||||
itemPrice = 2,
|
itemPrice = 2,
|
||||||
itemInfo = "der Kulinarische Blitzbesuch in Fernost",
|
itemInfo = "der Kulinarische Blitzbesuch in Fernost",
|
||||||
|
@ -405,7 +405,12 @@ CodeStudio.Products = {
|
||||||
itemPrice = 6,
|
itemPrice = 6,
|
||||||
itemInfo = "",
|
itemInfo = "",
|
||||||
},
|
},
|
||||||
|
['food_bag'] = {
|
||||||
|
itemName = "Papiertüte",
|
||||||
|
itemStock = 5000,
|
||||||
|
itemPrice = 4,
|
||||||
|
itemInfo = "",
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
BIN
resources/[inventory]/inventory_images/images/food_bag.png
Normal file
BIN
resources/[inventory]/inventory_images/images/food_bag.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 131 KiB |
BIN
resources/[inventory]/inventory_images/images/pack_ecola.png
Normal file
BIN
resources/[inventory]/inventory_images/images/pack_ecola.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 541 KiB |
|
@ -28,7 +28,7 @@ config.disableClientOpenInventory = {
|
||||||
glovebox = true, -- Don't remove this
|
glovebox = true, -- Don't remove this
|
||||||
trunk = true, -- Don't remove this
|
trunk = true, -- Don't remove this
|
||||||
drop = true, -- Don't remove this
|
drop = true, -- Don't remove this
|
||||||
--crafting = true,
|
crafting = true,
|
||||||
--shop = true
|
--shop = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +82,7 @@ config.searchPlayer = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
animation = {
|
animation = {
|
||||||
active = false, -- If true, the target player should play one of the following animations. if it's not playing one of the animations, it can't be searched.
|
active = true, -- If true, the target player should play one of the following animations. if it's not playing one of the animations, it can't be searched.
|
||||||
list = { -- animation list
|
list = { -- animation list
|
||||||
{ name = "missminuteman_1ig_2", anim = "handsup_base", },
|
{ name = "missminuteman_1ig_2", anim = "handsup_base", },
|
||||||
{ name = "mp_arresting", anim = "idle", },
|
{ name = "mp_arresting", anim = "idle", },
|
||||||
|
|
|
@ -16,7 +16,7 @@ config.carryItmes = {
|
||||||
},
|
},
|
||||||
moveRate = 0.5, -- https://docs.fivem.net/natives/?_0x085BF80FA50A39D1 (1.0 Default)
|
moveRate = 0.5, -- https://docs.fivem.net/natives/?_0x085BF80FA50A39D1 (1.0 Default)
|
||||||
},
|
},
|
||||||
present = {
|
pdbag = {
|
||||||
model = `xm_prop_x17_bag_01d`,
|
model = `xm_prop_x17_bag_01d`,
|
||||||
bone = 28422,
|
bone = 28422,
|
||||||
offset = vector3(0.15, -0.05, -0.10),
|
offset = vector3(0.15, -0.05, -0.10),
|
||||||
|
@ -24,10 +24,27 @@ config.carryItmes = {
|
||||||
anim = {
|
anim = {
|
||||||
dict = "missfbi4prepp1",
|
dict = "missfbi4prepp1",
|
||||||
name = "idle" -- Neutrale Stehanimation
|
name = "idle" -- Neutrale Stehanimation
|
||||||
}
|
},
|
||||||
disableKeys = {
|
disableKeys = {
|
||||||
21, -- INPUT_SPRINT
|
21, -- INPUT_SPRINT
|
||||||
},
|
},
|
||||||
moveRate = 1.0
|
moveRate = 1.0
|
||||||
}
|
},
|
||||||
|
food_bag = {
|
||||||
|
model = `prop_food_bag1`,
|
||||||
|
bone = 28422,
|
||||||
|
offset = vector3(0.15, -0.05, -0.10),
|
||||||
|
rot = vector3(100.0, -50.0, 220.0),
|
||||||
|
anim = {
|
||||||
|
dict = "missfbi4prepp1",
|
||||||
|
name = "idle" -- Neutrale Stehanimation
|
||||||
|
},
|
||||||
|
disableKeys = {
|
||||||
|
21, -- INPUT_SPRINT
|
||||||
|
},
|
||||||
|
moveRate = 1.0
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,6 @@ config.decayableItems = {
|
||||||
key: item name
|
key: item name
|
||||||
value: second
|
value: second
|
||||||
]]
|
]]
|
||||||
tosti = 172800,
|
food_bag = 864000,
|
||||||
kurkakola = 30,
|
kurkakola = 30,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,6 @@
|
||||||
-- example use: if you set the max usage of a repair kit to 5. after repairing the vehicle 5 times the repair kit will be deleted
|
-- example use: if you set the max usage of a repair kit to 5. after repairing the vehicle 5 times the repair kit will be deleted
|
||||||
-- Added items need to be set to 'uniq = true' in item list
|
-- Added items need to be set to 'uniq = true' in item list
|
||||||
config.maxUseAmount = {
|
config.maxUseAmount = {
|
||||||
binoculars = {
|
|
||||||
amount = 5,
|
|
||||||
autoDecreases = true -- When set to true, the number decreases by one when you use the item.
|
|
||||||
--if it is set to false, you need to trigger x event after using the item "TriggerServerEvent("tgiann-inventory:decreaseMaxUseAmount", itemSlot)"
|
|
||||||
},
|
|
||||||
testitemuniq = {
|
testitemuniq = {
|
||||||
amount = 5,
|
amount = 5,
|
||||||
autoDecreases = true -- When set to true, the number decreases by one when you use the item.
|
autoDecreases = true -- When set to true, the number decreases by one when you use the item.
|
||||||
|
|
|
@ -10204,7 +10204,17 @@ QBShared.Items = {
|
||||||
image = 'pack_ecola.png',
|
image = 'pack_ecola.png',
|
||||||
name = 'pack_ecola',
|
name = 'pack_ecola',
|
||||||
},
|
},
|
||||||
|
food_bag = {
|
||||||
|
shouldClose = true,
|
||||||
|
type = 'item',
|
||||||
|
description = 'Transportiert dein Essen und deinen Alc, egal in welcher Form ^^',
|
||||||
|
weight = 1000,
|
||||||
|
label = 'Papiertüte',
|
||||||
|
unique = true,
|
||||||
|
useable = true,
|
||||||
|
image = 'food_bag.png',
|
||||||
|
name = 'food_bag',
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
2
resources/[tools]/tgiann-attachproptoplayereditor/.gitattributes
vendored
Normal file
2
resources/[tools]/tgiann-attachproptoplayereditor/.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
10
resources/[tools]/tgiann-attachproptoplayereditor/README.md
Normal file
10
resources/[tools]/tgiann-attachproptoplayereditor/README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
I tried to make prop attaching easier with gizmo. While it doesn’t work exactly right, it’s much better than most old methods
|
||||||
|
|
||||||
|
Credit: https://github.com/Demigod916/object_gizmo & https://github.com/dolutattoo/dolu_tool
|
||||||
|
|
||||||
|
**How to use**
|
||||||
|
`/prop <model*> <boneID*> <animDictionary?> <animationName?>`
|
||||||
|
|
||||||
|
https://www.youtube.com/watch?v=LsRLwj2pAS0
|
||||||
|
|
||||||
|
For more fivem scripts; https://tgiann.tebex.io/category/1768400
|
|
@ -0,0 +1,171 @@
|
||||||
|
local usingGizmo = false
|
||||||
|
local mode = "Translate"
|
||||||
|
local extraZ = 1000.0
|
||||||
|
local spawnedProp, pedBoneId = 0, 0
|
||||||
|
local lastCoord = nil
|
||||||
|
local position, rotation = vector3(0.0, 0.0, 0.0), vector3(0.0, 0.0, 0.0)
|
||||||
|
|
||||||
|
local function toggleNuiFrame(bool)
|
||||||
|
usingGizmo = bool
|
||||||
|
SetNuiFocus(bool, bool)
|
||||||
|
end
|
||||||
|
|
||||||
|
function useGizmo(handle, boneid, dict, anim)
|
||||||
|
spawnedProp = handle
|
||||||
|
pedBoneId = boneid
|
||||||
|
|
||||||
|
local playerPed = PlayerPedId()
|
||||||
|
lastCoord = GetEntityCoords(playerPed)
|
||||||
|
|
||||||
|
FreezeEntityPosition(playerPed, true)
|
||||||
|
SetEntityCoords(playerPed, 0.0, 0.0, extraZ-1)
|
||||||
|
SetEntityHeading(playerPed, 0.0)
|
||||||
|
SetEntityRotation(pedBoneId, 0.0, 0.0, 0.0)
|
||||||
|
position, rotation = vector3(0.0, 0.0, 0.0), vector3(0.0, 0.0, 0.0)
|
||||||
|
AttachEntityToEntity(spawnedProp, playerPed, pedBoneId, position, rotation, true, true, false, true, 1, true)
|
||||||
|
|
||||||
|
SendNUIMessage({
|
||||||
|
action = 'setGizmoEntity',
|
||||||
|
data = {
|
||||||
|
handle = spawnedProp,
|
||||||
|
position = vector3(0.0, 0.0, extraZ),
|
||||||
|
rotation = vector3(0.0, 0.0, 0.0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
toggleNuiFrame(true)
|
||||||
|
|
||||||
|
if dict and anim then taskPlayAnim(playerPed, dict, anim) end
|
||||||
|
|
||||||
|
while usingGizmo do
|
||||||
|
DrawScaleformMovieFullscreen(CreateInstuctionScaleform(), 255, 255, 255, 255, 0)
|
||||||
|
SendNUIMessage({
|
||||||
|
action = 'setCameraPosition',
|
||||||
|
data = {
|
||||||
|
position = GetFinalRenderedCamCoord(),
|
||||||
|
rotation = GetFinalRenderedCamRot()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if IsControlJustReleased(0, 44) then
|
||||||
|
SetNuiFocus(true, true)
|
||||||
|
end
|
||||||
|
DisableIdleCamera(true)
|
||||||
|
Wait(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
finish()
|
||||||
|
return {
|
||||||
|
"AttachEntityToEntity(entity, PlayerPedId(), "..pedBoneId..", "..(extraZ-position.z)..", "..position.y..", "..position.x..", "..rotation.x..", "..rotation.y..", "..rotation.z..", true, true, false, true, 1, true)",
|
||||||
|
(extraZ-position.z)..", "..position.y..", "..position.x..", "..rotation.x..", "..rotation.y..", "..rotation.z
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNUICallback('moveEntity', function(data, cb)
|
||||||
|
local entity = data.handle
|
||||||
|
position = data.position
|
||||||
|
rotation = data.rotation
|
||||||
|
AttachEntityToEntity(entity, PlayerPedId(), pedBoneId, extraZ-position.z, position.y, position.x, rotation.x, rotation.y, rotation.z, true, true, false, true, 1, true) --Same attach settings as dp emote and rp emotes
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('finishEdit', function(data, cb)
|
||||||
|
toggleNuiFrame(false)
|
||||||
|
SendNUIMessage({
|
||||||
|
action = 'setGizmoEntity',
|
||||||
|
data = {
|
||||||
|
handle = nil,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('swapMode', function(data, cb)
|
||||||
|
mode = data.mode
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNUICallback('cam', function(data, cb)
|
||||||
|
SetNuiFocus(false, false)
|
||||||
|
cb('ok')
|
||||||
|
end)
|
||||||
|
|
||||||
|
function CreateInstuctionScaleform()
|
||||||
|
local scaleform = RequestScaleformMovie("instructional_buttons")
|
||||||
|
while not HasScaleformMovieLoaded(scaleform) do Wait(10) end
|
||||||
|
|
||||||
|
PushScaleformMovieFunction(scaleform, "CLEAR_ALL")
|
||||||
|
PopScaleformMovieFunctionVoid()
|
||||||
|
|
||||||
|
PushScaleformMovieFunction(scaleform, "SET_CLEAR_SPACE")
|
||||||
|
PushScaleformMovieFunctionParameterInt(200)
|
||||||
|
PopScaleformMovieFunctionVoid()
|
||||||
|
|
||||||
|
InstructionButtonCreate(scaleform, 200, "Done Editing", 1)
|
||||||
|
InstructionButtonCreate(scaleform, 44, "NUI Focus", 2)
|
||||||
|
|
||||||
|
if mode == "Translate" then
|
||||||
|
InstructionButtonCreate(scaleform, 45, "Rotate Mode", 3)
|
||||||
|
else
|
||||||
|
InstructionButtonCreate(scaleform, 32, "Translate Mode", 4)
|
||||||
|
end
|
||||||
|
|
||||||
|
PushScaleformMovieFunction(scaleform, "DRAW_INSTRUCTIONAL_BUTTONS")
|
||||||
|
PopScaleformMovieFunctionVoid()
|
||||||
|
|
||||||
|
PushScaleformMovieFunction(scaleform, "SET_BACKGROUND_COLOUR")
|
||||||
|
PushScaleformMovieFunctionParameterInt(0)
|
||||||
|
PushScaleformMovieFunctionParameterInt(0)
|
||||||
|
PushScaleformMovieFunctionParameterInt(0)
|
||||||
|
PushScaleformMovieFunctionParameterInt(80)
|
||||||
|
PopScaleformMovieFunctionVoid()
|
||||||
|
|
||||||
|
return scaleform
|
||||||
|
end
|
||||||
|
|
||||||
|
function InstructionButtonCreate(scaleform, key, text, number)
|
||||||
|
PushScaleformMovieFunction(scaleform, "SET_DATA_SLOT")
|
||||||
|
PushScaleformMovieFunctionParameterInt(number)
|
||||||
|
PushScaleformMovieMethodParameterButtonName(GetControlInstructionalButton(0, key, true))
|
||||||
|
InstructionButtonMessage(text)
|
||||||
|
PopScaleformMovieFunctionVoid()
|
||||||
|
end
|
||||||
|
|
||||||
|
function InstructionButtonMessage(text)
|
||||||
|
BeginTextCommandScaleformString("STRING")
|
||||||
|
AddTextComponentScaleform(text)
|
||||||
|
EndTextCommandScaleformString()
|
||||||
|
end
|
||||||
|
|
||||||
|
function finish()
|
||||||
|
if DoesEntityExist(spawnedProp) then
|
||||||
|
DeleteEntity(spawnedProp)
|
||||||
|
end
|
||||||
|
local playerPed = PlayerPedId()
|
||||||
|
FreezeEntityPosition(playerPed, false)
|
||||||
|
ClearPedTasks(playerPed)
|
||||||
|
if lastCoord then
|
||||||
|
SetEntityCoords(playerPed, lastCoord)
|
||||||
|
lastCoord = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function taskPlayAnim(ped, dict, anim, flag)
|
||||||
|
CreateThread(function()
|
||||||
|
while usingGizmo do
|
||||||
|
if not IsEntityPlayingAnim(ped, dict, anim, 1) then
|
||||||
|
while not HasAnimDictLoaded(dict) do
|
||||||
|
RequestAnimDict(dict)
|
||||||
|
Wait(10)
|
||||||
|
end
|
||||||
|
TaskPlayAnim(ped, dict, anim, 5.0, 5.0, -1, (flag or 15), 0, false, false, false)
|
||||||
|
RemoveAnimDict(dict)
|
||||||
|
end
|
||||||
|
Wait(1000)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
AddEventHandler('onResourceStop', function(resourceName)
|
||||||
|
if GetCurrentResourceName() == resourceName then
|
||||||
|
finish()
|
||||||
|
end
|
||||||
|
end)
|
|
@ -0,0 +1,14 @@
|
||||||
|
--Example: /prop prop_sandwich_01 18905 mp_player_inteat@burger mp_player_int_eat_burger
|
||||||
|
RegisterCommand('prop',function(source, args, rawCommand)
|
||||||
|
local model = joaat(args[1] or "prop_cs_burger_01")
|
||||||
|
if not HasModelLoaded(model) then RequestModel(model) while not HasModelLoaded(model) do Wait(1) end end
|
||||||
|
local playerPed = PlayerPedId()
|
||||||
|
local playerCoords = GetEntityCoords(playerPed)
|
||||||
|
local object = CreateObject(model, playerCoords.x, playerCoords.y, playerCoords.z, false, false, false)
|
||||||
|
local boneArg = args[2]
|
||||||
|
local boneToNumber = tonumber(boneArg)
|
||||||
|
local bone = (boneArg and boneToNumber) and GetPedBoneIndex(playerPed, boneToNumber) or boneArg and GetEntityBoneIndexByName(playerPed, boneArg) or 18905
|
||||||
|
local objectPositionData = useGizmo(object, bone, args[3], args[4])
|
||||||
|
print(objectPositionData[1])
|
||||||
|
print(objectPositionData[2])
|
||||||
|
end)
|
|
@ -0,0 +1,14 @@
|
||||||
|
fx_version 'cerulean'
|
||||||
|
game 'gta5'
|
||||||
|
lua54 'yes'
|
||||||
|
|
||||||
|
ui_page 'web/dist/index.html'
|
||||||
|
|
||||||
|
client_scripts {
|
||||||
|
"client/*.lua"
|
||||||
|
}
|
||||||
|
|
||||||
|
files {
|
||||||
|
'web/dist/index.html',
|
||||||
|
'web/dist/**/*',
|
||||||
|
}
|
23
resources/[tools]/tgiann-attachproptoplayereditor/tgiann-attachproptoplayereditor/web/.gitignore
vendored
Normal file
23
resources/[tools]/tgiann-attachproptoplayereditor/tgiann-attachproptoplayereditor/web/.gitignore
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist-ssr
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
|
@ -0,0 +1 @@
|
||||||
|
body{overflow:hidden}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Vite + React + TS</title>
|
||||||
|
<script type="module" crossorigin src="./assets/index.4b31427f.js"></script>
|
||||||
|
<link rel="stylesheet" href="./assets/index.09731cda.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Vite + React + TS</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
3685
resources/[tools]/tgiann-attachproptoplayereditor/tgiann-attachproptoplayereditor/web/package-lock.json
generated
Normal file
3685
resources/[tools]/tgiann-attachproptoplayereditor/tgiann-attachproptoplayereditor/web/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"name": "gizmo",
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@react-three/drei": "^9.65.5",
|
||||||
|
"@react-three/fiber": "^8.12.2",
|
||||||
|
"axios": "^1.3.6",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"three": "^0.151.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.0.22",
|
||||||
|
"@types/react-dom": "^18.0.7",
|
||||||
|
"@vitejs/plugin-react": "^2.2.0",
|
||||||
|
"typescript": "^4.6.4",
|
||||||
|
"vite": "^3.2.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { ThreeComponent } from "./components/ThreeComponent";
|
||||||
|
|
||||||
|
function App() {
|
||||||
|
return (
|
||||||
|
<div style={{ width: "100vw", height: "100vh" }}>
|
||||||
|
<ThreeComponent />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { PerspectiveCamera } from "@react-three/drei";
|
||||||
|
import { useNuiEvent } from "../nui-events";
|
||||||
|
import { useThree } from "@react-three/fiber";
|
||||||
|
import { MathUtils } from "three";
|
||||||
|
|
||||||
|
export const CameraComponent = () => {
|
||||||
|
const { camera } = useThree();
|
||||||
|
|
||||||
|
const zRotationHandler = (t: number, e: number) => {
|
||||||
|
return t > 0 && t < 90 ? e : (t > -180 && t < -90) || t > 0 ? -e : e;
|
||||||
|
};
|
||||||
|
|
||||||
|
useNuiEvent("setCameraPosition", ({ position, rotation }: any) => {
|
||||||
|
camera.position.set(position.x, position.z, -position.y);
|
||||||
|
camera.rotation.order = "YZX";
|
||||||
|
|
||||||
|
rotation &&
|
||||||
|
camera.rotation.set(
|
||||||
|
MathUtils.degToRad(rotation.x),
|
||||||
|
MathUtils.degToRad(zRotationHandler(rotation.x, rotation.z)),
|
||||||
|
MathUtils.degToRad(rotation.y)
|
||||||
|
);
|
||||||
|
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PerspectiveCamera
|
||||||
|
position={[0, 0, 10]}
|
||||||
|
makeDefault
|
||||||
|
onUpdate={(self: any) => self.updateProjectionMatrix()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Canvas } from "@react-three/fiber";
|
||||||
|
import { CameraComponent } from "./CameraComponent";
|
||||||
|
import { TransformComponent } from "./TransformComponent";
|
||||||
|
|
||||||
|
export const ThreeComponent = () => {
|
||||||
|
return (
|
||||||
|
<Canvas style={{ zIndex: 1 }}>
|
||||||
|
<CameraComponent />
|
||||||
|
<TransformComponent />
|
||||||
|
</Canvas>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,91 @@
|
||||||
|
import { Suspense, useRef, useState, useEffect } from "react";
|
||||||
|
import { TransformControls } from "@react-three/drei";
|
||||||
|
import { useNuiEvent, fetchNui } from "../nui-events";
|
||||||
|
import { Mesh, MathUtils } from "three";
|
||||||
|
|
||||||
|
export const TransformComponent = () => {
|
||||||
|
const mesh = useRef<Mesh>(null!);
|
||||||
|
const [currentEntity, setCurrentEntity] = useState<number>();
|
||||||
|
const [editorMode, setEditorMode] = useState<
|
||||||
|
"translate" | "rotate" | undefined
|
||||||
|
>("translate");
|
||||||
|
|
||||||
|
const handleObjectDataUpdate = () => {
|
||||||
|
const entity = {
|
||||||
|
handle: currentEntity,
|
||||||
|
position: {
|
||||||
|
x: mesh.current.position.x,
|
||||||
|
y: -mesh.current.position.z,
|
||||||
|
z: mesh.current.position.y,
|
||||||
|
},
|
||||||
|
rotation: {
|
||||||
|
x: MathUtils.radToDeg(mesh.current.rotation.x),
|
||||||
|
y: MathUtils.radToDeg(-mesh.current.rotation.z),
|
||||||
|
z: MathUtils.radToDeg(mesh.current.rotation.y),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
fetchNui("moveEntity", entity);
|
||||||
|
};
|
||||||
|
|
||||||
|
useNuiEvent("setGizmoEntity", (entity: any) => {
|
||||||
|
setCurrentEntity(entity.handle);
|
||||||
|
if (!entity.handle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh.current.position.set(
|
||||||
|
entity.position.x,
|
||||||
|
entity.position.z,
|
||||||
|
-entity.position.y
|
||||||
|
);
|
||||||
|
mesh.current.rotation.order = "YZX";
|
||||||
|
mesh.current.rotation.set(
|
||||||
|
MathUtils.degToRad(entity.rotation.x),
|
||||||
|
MathUtils.degToRad(entity.rotation.z),
|
||||||
|
MathUtils.degToRad(entity.rotation.y)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const keyHandler = (e: KeyboardEvent) => {
|
||||||
|
switch (e.code) {
|
||||||
|
case "KeyR":
|
||||||
|
if (editorMode == "rotate") return;
|
||||||
|
setEditorMode("rotate");
|
||||||
|
fetchNui("swapMode", { mode: "Rotate" });
|
||||||
|
break;
|
||||||
|
case "KeyW":
|
||||||
|
if (editorMode == "translate") return;
|
||||||
|
setEditorMode("translate");
|
||||||
|
fetchNui("swapMode", { mode: "Translate" });
|
||||||
|
break;
|
||||||
|
case "Escape":
|
||||||
|
fetchNui("finishEdit");
|
||||||
|
break;
|
||||||
|
case "KeyQ":
|
||||||
|
fetchNui("cam");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener("keyup", keyHandler);
|
||||||
|
return () => window.removeEventListener("keyup", keyHandler);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Suspense fallback={<p>Loading Gizmo</p>}>
|
||||||
|
{currentEntity != null && (
|
||||||
|
<TransformControls
|
||||||
|
size={0.5}
|
||||||
|
object={mesh}
|
||||||
|
mode={editorMode}
|
||||||
|
onObjectChange={handleObjectDataUpdate}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<mesh ref={mesh} />
|
||||||
|
</Suspense>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,3 @@
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import ReactDOM from "react-dom/client";
|
||||||
|
import App from "./App";
|
||||||
|
import "./index.css";
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
|
<App />
|
||||||
|
);
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { MutableRefObject, useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
const isEnvBrowser = (): boolean => !(window as any).invokeNative
|
||||||
|
|
||||||
|
interface NuiMessageData<T = unknown> {
|
||||||
|
action: string;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
type NuiHandlerSignature<T> = (data: T) => void;
|
||||||
|
|
||||||
|
export const useNuiEvent = <T = any>(
|
||||||
|
action: string,
|
||||||
|
handler: (data: T) => void
|
||||||
|
) => {
|
||||||
|
const savedHandler: MutableRefObject<NuiHandlerSignature<T>> = useRef(() => {});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
savedHandler.current = handler;
|
||||||
|
}, [handler]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const eventListener = (event: MessageEvent<NuiMessageData<T>>) => {
|
||||||
|
const { action: eventAction, data } = event.data;
|
||||||
|
|
||||||
|
if (savedHandler.current) {
|
||||||
|
if (eventAction === action) {
|
||||||
|
savedHandler.current(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener("message", eventListener);
|
||||||
|
|
||||||
|
return () => window.removeEventListener("message", eventListener);
|
||||||
|
}, [action]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function fetchNui<T = any>(eventName: string, data?: any, mockData?: T): Promise<T> {
|
||||||
|
const options = {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isEnvBrowser() && mockData) return mockData;
|
||||||
|
|
||||||
|
const resourceName = (window as any).GetParentResourceName ? (window as any).GetParentResourceName() : 'nui-frame-app';
|
||||||
|
|
||||||
|
const resp = await fetch(`https://${resourceName}/${eventName}`, options);
|
||||||
|
|
||||||
|
const respFormatted = await resp.json()
|
||||||
|
|
||||||
|
return respFormatted
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="vite/client" />
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ESNext",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
|
"allowJs": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": false,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
// https://vitejs.dev/config/
|
||||||
|
export default defineConfig({
|
||||||
|
base: "./",
|
||||||
|
plugins: [react()]
|
||||||
|
})
|
Loading…
Add table
Add a link
Reference in a new issue