From 4295e2d9f49c489795f16cd5b0c1af8af5b79fde Mon Sep 17 00:00:00 2001 From: Jag <77469789+jag3dagster@users.noreply.github.com> Date: Wed, 17 Jan 2024 03:15:24 -0800 Subject: [PATCH] feat: Add entity debug drawing (#4) --- client/classes/entity.lua | 1 + client/debugdraw.lua | 263 ++++++++++++------ client/nui.lua | 6 + locales/en.json | 1 + web/src/App.tsx | 7 +- .../portals/components/EntitySettings.tsx | 30 +- .../views/portals/components/PortalInfo.tsx | 1 + web/src/providers/LocaleProvider.tsx | 1 + web/src/store/portals.tsx | 13 +- web/src/types/EntityDef.tsx | 3 + 10 files changed, 232 insertions(+), 94 deletions(-) diff --git a/client/classes/entity.lua b/client/classes/entity.lua index 6102d46..1519580 100644 --- a/client/classes/entity.lua +++ b/client/classes/entity.lua @@ -3,6 +3,7 @@ Entity = {} function Entity.new(interiorId, mloPortalIndex, entityIndex, mloLocation) local entity = {} + entity.index = entityIndex entity.linkType = 1 entity.maxOcclusion = 0.5 entity.modelHashKey = GetInteriorPortalEntityArchetype(interiorId, mloPortalIndex, entityIndex) diff --git a/client/debugdraw.lua b/client/debugdraw.lua index 11f23ad..d7117b9 100644 --- a/client/debugdraw.lua +++ b/client/debugdraw.lua @@ -2,6 +2,7 @@ local drawPortalInfo = false local drawPortalOutline = false local drawPortalFill = false local drawNavigate = nil +local drawEntities = {} local mloInteriorId = nil local mloPosition = nil @@ -19,10 +20,12 @@ local mloInterval = nil local AddTextComponentSubstringPlayerName = AddTextComponentSubstringPlayerName local BeginTextCommandDisplayText = BeginTextCommandDisplayText +local DoesEntityExist = DoesEntityExist local DrawLine = DrawLine local DrawMarker = DrawMarker local DrawPoly = DrawPoly local EndTextCommandDisplayText = EndTextCommandDisplayText +local GetClosestObjectOfType = GetClosestObjectOfType local GetEntityCoords = GetEntityCoords local GetFinalRenderedCamCoord = GetFinalRenderedCamCoord local GetGameplayCamFov = GetGameplayCamFov @@ -34,6 +37,7 @@ local GetInteriorPortalRoomTo = GetInteriorPortalRoomTo local GetInteriorPosition = GetInteriorPosition local GetInteriorRotation = GetInteriorRotation local GetScreenCoordFromWorldCoord = GetScreenCoordFromWorldCoord +local SetEntityDrawOutline = SetEntityDrawOutline local SetTextCentre = SetTextCentre local SetTextDropShadow = SetTextDropShadow local SetTextOutline = SetTextOutline @@ -41,6 +45,17 @@ local SetTextScale = SetTextScale -- ##### Functions ##### -- +local function anyDebugEntitiesActive() + local anyActive = false + for _,v in pairs(drawEntities) do + if v.debug then + anyActive = true + break + end + end + return anyActive +end + local function draw3dText(coords, text) local onScreen, screenX, screenY = GetScreenCoordFromWorldCoord(coords.x, coords.y, coords.z) @@ -99,133 +114,207 @@ local function resetMLODebugData() mloPortalCorners = nil mloPortalCrossVectors = nil mloPortalConnections = nil + + for _,v in pairs(drawEntities) do + if v.entity and DoesEntityExist(v.entity) then + SetEntityDrawOutline(v.entity, false) + v.entity = nil + end + end end local function updateDebugMLOInfo() local currentInteriorId = GetInteriorFromEntity(cache.ped) - if currentInteriorId > 0 and currentInteriorId ~= mloInteriorId then - if mloPortalNavEnabled ~= nil and mloPortalNavEnabled ~= currentInteriorId then - SendReactMessage('ht_mlotool:cancelNavigation', {}) - mloPortalNavEnabled = nil - drawNavigate = nil - end + if currentInteriorId > 0 then + if currentInteriorId ~= mloInteriorId then + if mloPortalNavEnabled ~= nil and mloPortalNavEnabled ~= currentInteriorId then + SendReactMessage('ht_mlotool:cancelNavigation', {}) + mloPortalNavEnabled = nil + drawNavigate = nil + end - mloInteriorId = currentInteriorId - local rotX, rotY, rotZ, rotW = GetInteriorRotation(mloInteriorId) - mloRotation = quat(rotW, rotX, rotY, rotZ) - mloPosition = vec3(GetInteriorPosition(mloInteriorId)) - mloPortalCount = GetInteriorPortalCount(mloInteriorId) - mloPortalCorners = {} - mloPortalCrossVectors = {} - mloPortalConnections = {} + if mloInteriorId ~= nil then + for _,v in pairs(drawEntities) do + if v.entity and DoesEntityExist(v.entity) then + SetEntityDrawOutline(v.entity, false) + end + end + + table.wipe(drawEntities) + SendReactMessage('ht_mlotool:cancelEntityDebug', {}) + end - for portalId = 0, mloPortalCount - 1 do - local pCorners = {} + mloInteriorId = currentInteriorId + local rotX, rotY, rotZ, rotW = GetInteriorRotation(mloInteriorId) + mloRotation = quat(rotW, rotX, rotY, rotZ) + mloPosition = vec3(GetInteriorPosition(mloInteriorId)) + mloPortalCount = GetInteriorPortalCount(mloInteriorId) + mloPortalCorners = {} + mloPortalCrossVectors = {} + mloPortalConnections = {} - for cornerIndex = 0, 3 do - local cX, cY, cZ = GetInteriorPortalCornerPosition(mloInteriorId, portalId, cornerIndex) - local cPosition = mloPosition + qMult(mloRotation, vec3(cX, cY, cZ)) + for portalId = 0, mloPortalCount - 1 do + local pCorners = {} + + for cornerIndex = 0, 3 do + local cX, cY, cZ = GetInteriorPortalCornerPosition(mloInteriorId, portalId, cornerIndex) + local cPosition = mloPosition + qMult(mloRotation, vec3(cX, cY, cZ)) + + pCorners[cornerIndex] = cPosition + end - pCorners[cornerIndex] = cPosition + mloPortalCorners[portalId] = pCorners + mloPortalCrossVectors[portalId] = lerp(pCorners[0], pCorners[2], 0.5) + + mloPortalConnections[portalId] = { GetInteriorPortalRoomFrom(mloInteriorId, portalId), GetInteriorPortalRoomTo(mloInteriorId, portalId) } end + end + + for _,v in pairs(drawEntities) do + if v.debug then + local entity = GetClosestObjectOfType(v.pos.x, v.pos.y, v.pos.z, 1.0, v.arch, false, false, false) + + if entity and entity ~= v.entity and DoesEntityExist(entity) then + -- This shouldn't ever happen + if DoesEntityExist(v.entity) then + SetEntityDrawOutline(v.entity, false) + end - mloPortalCorners[portalId] = pCorners - mloPortalCrossVectors[portalId] = lerp(pCorners[0], pCorners[2], 0.5) + v.entity = entity + SetEntityDrawOutline(entity, true) + end + elseif v.entity then + if DoesEntityExist(v.entity) then + SetEntityDrawOutline(v.entity, false) + end - mloPortalConnections[portalId] = { GetInteriorPortalRoomFrom(mloInteriorId, portalId), GetInteriorPortalRoomTo(mloInteriorId, portalId) } + v.entity = nil + end end elseif currentInteriorId <= 0 then resetMLODebugData() end end -function UpdateDebugDraw(enablePortalInfo, enablePortalOutline, enablePortalFill, navigatedPortal) - drawPortalInfo = enablePortalInfo - drawPortalOutline = enablePortalOutline - drawPortalFill = enablePortalFill - drawNavigate = navigatedPortal +local function drawDebug() + local pedCoords = GetEntityCoords(cache.ped) - if not drawInterval and (drawPortalInfo or drawPortalOutline or drawPortalFill or drawNavigate) then - updateDebugMLOInfo() + -- Give time for any updates and then end interval iteration to try again + if not mloInteriorId or not mloPosition or not mloRotation or not mloPortalCount + or not mloPortalCorners or not mloPortalCrossVectors or not mloPortalConnections + then + Wait(500) + return + end - mloInterval = SetInterval(updateDebugMLOInfo, 1000) + for portalId = 0, mloPortalCount - 1 do + local corners = mloPortalCorners[portalId] + local crossVector = mloPortalCrossVectors[portalId] - drawInterval = SetInterval(function() - local pedCoords = GetEntityCoords(cache.ped) + if #(pedCoords - crossVector) <= 8.0 then + if drawPortalInfo then + local roomFrom, roomTo = table.unpack(mloPortalConnections[portalId]) - -- Give time for any updates and then end interval iteration to try again - if not mloInteriorId or not mloPosition or not mloRotation or not mloPortalCount - or not mloPortalCorners or not mloPortalCrossVectors or not mloPortalConnections - then - Wait(500) - return + draw3dText(vec3(crossVector.x, crossVector.y, crossVector.z + 0.15), locale('debug_text_portal_id', portalId)) + draw3dText(vec3(crossVector.x, crossVector.y, crossVector.z), locale('debug_text_conn_rooms', roomFrom, roomTo)) end - for portalId = 0, mloPortalCount - 1 do - local corners = mloPortalCorners[portalId] - local crossVector = mloPortalCrossVectors[portalId] + if drawPortalOutline then + -- Borders outline + DrawLine(corners[0].x, corners[0].y, corners[0].z, corners[1].x, corners[1].y, corners[1].z, 0, 255, 0, 255) + DrawLine(corners[1].x, corners[1].y, corners[1].z, corners[2].x, corners[2].y, corners[2].z, 0, 255, 0, 255) + DrawLine(corners[2].x, corners[2].y, corners[2].z, corners[3].x, corners[3].y, corners[3].z, 0, 255, 0, 255) + DrawLine(corners[3].x, corners[3].y, corners[3].z, corners[0].x, corners[0].y, corners[0].z, 0, 255, 0, 255) - if #(pedCoords - crossVector) <= 8.0 then - if drawPortalInfo then - local roomFrom, roomTo = table.unpack(mloPortalConnections[portalId]) + -- Middle cross lines + DrawLine(corners[0].x, corners[0].y, corners[0].z, corners[2].x, corners[2].y, corners[2].z, 0, 255, 0, 255) + DrawLine(corners[1].x, corners[1].y, corners[1].z, corners[3].x, corners[3].y, corners[3].z, 0, 255, 0, 255) + end - draw3dText(vec3(crossVector.x, crossVector.y, crossVector.z + 0.15), locale('debug_text_portal_id', portalId)) - draw3dText(vec3(crossVector.x, crossVector.y, crossVector.z), locale('debug_text_conn_rooms', roomFrom, roomTo)) - end + if drawPortalFill then + -- Both sets are needed so the fill can be seen from both sides of the portal + DrawPoly(corners[0].x, corners[0].y, corners[0].z, corners[1].x, corners[1].y, corners[1].z, corners[2].x, corners[2].y, corners[2].z, 100, 65, 217, 150) + DrawPoly(corners[0].x, corners[0].y, corners[0].z, corners[2].x, corners[2].y, corners[2].z, corners[3].x, corners[3].y, corners[3].z, 100, 65, 217, 150) + DrawPoly(corners[3].x, corners[3].y, corners[3].z, corners[2].x, corners[2].y, corners[2].z, corners[1].x, corners[1].y, corners[1].z, 100, 65, 217, 150) + DrawPoly(corners[3].x, corners[3].y, corners[3].z, corners[1].x, corners[1].y, corners[1].z, corners[0].x, corners[0].y, corners[0].z, 100, 65, 217, 150) + end + end - if drawPortalOutline then - -- Borders outline - DrawLine(corners[0].x, corners[0].y, corners[0].z, corners[1].x, corners[1].y, corners[1].z, 0, 255, 0, 255) - DrawLine(corners[1].x, corners[1].y, corners[1].z, corners[2].x, corners[2].y, corners[2].z, 0, 255, 0, 255) - DrawLine(corners[2].x, corners[2].y, corners[2].z, corners[3].x, corners[3].y, corners[3].z, 0, 255, 0, 255) - DrawLine(corners[3].x, corners[3].y, corners[3].z, corners[0].x, corners[0].y, corners[0].z, 0, 255, 0, 255) + if drawNavigate == portalId then + if not mloPortalNavEnabled then + mloPortalNavEnabled = mloInteriorId + end - -- Middle cross lines - DrawLine(corners[0].x, corners[0].y, corners[0].z, corners[2].x, corners[2].y, corners[2].z, 0, 255, 0, 255) - DrawLine(corners[1].x, corners[1].y, corners[1].z, corners[3].x, corners[3].y, corners[3].z, 0, 255, 0, 255) - end + local dirX = pedCoords.x - crossVector.x + local dirY = pedCoords.y - crossVector.y + local dirZ = pedCoords.z - crossVector.z + 0.75 + + DrawMarker( + 26, -- MarkerTypeHorizontalCircleSkinny_Arrow + pedCoords.x, pedCoords.y, pedCoords.z + 0.75, + dirX, dirY, dirZ, + 0.0, 0.0, 0.0, + 1.0, 1.0, 1.0, + 100, 65, 217, 200, + false, false, 0, false, nil, nil, false) + end + end +end - if drawPortalFill then - -- Both sets are needed so the fill can be seen from both sides of the portal - DrawPoly(corners[0].x, corners[0].y, corners[0].z, corners[1].x, corners[1].y, corners[1].z, corners[2].x, corners[2].y, corners[2].z, 100, 65, 217, 150) - DrawPoly(corners[0].x, corners[0].y, corners[0].z, corners[2].x, corners[2].y, corners[2].z, corners[3].x, corners[3].y, corners[3].z, 100, 65, 217, 150) - DrawPoly(corners[3].x, corners[3].y, corners[3].z, corners[2].x, corners[2].y, corners[2].z, corners[1].x, corners[1].y, corners[1].z, 100, 65, 217, 150) - DrawPoly(corners[3].x, corners[3].y, corners[3].z, corners[1].x, corners[1].y, corners[1].z, corners[0].x, corners[0].y, corners[0].z, 100, 65, 217, 150) - end - end +function UpdateDebugDraw(enablePortalInfo, enablePortalOutline, enablePortalFill, navigatedPortal) + drawPortalInfo = enablePortalInfo + drawPortalOutline = enablePortalOutline + drawPortalFill = enablePortalFill + drawNavigate = navigatedPortal - if drawNavigate == portalId then - if not mloPortalNavEnabled then - mloPortalNavEnabled = mloInteriorId - end + if not drawInterval and (drawPortalInfo or drawPortalOutline or drawPortalFill or drawNavigate) then + if not mloInterval then + updateDebugMLOInfo() + mloInterval = SetInterval(updateDebugMLOInfo, 1000) + end - local dirX = pedCoords.x - crossVector.x - local dirY = pedCoords.y - crossVector.y - local dirZ = pedCoords.z - crossVector.z + 0.75 - - DrawMarker( - 26, -- MarkerTypeHorizontalCircleSkinny_Arrow - pedCoords.x, pedCoords.y, pedCoords.z + 0.75, - dirX, dirY, dirZ, - 0.0, 0.0, 0.0, - 1.0, 1.0, 1.0, - 100, 65, 217, 200, - false, false, 0, false, nil, nil, false) - end - end - end, 0) + drawInterval = SetInterval(drawDebug, 0) elseif not drawPortalInfo and not drawPortalOutline and not drawPortalFill and not drawNavigate then if drawInterval then ClearInterval(drawInterval) drawInterval = nil end - if mloInterval then + if mloInterval and not anyDebugEntitiesActive() then ClearInterval(mloInterval) mloInterval = nil + resetMLODebugData() end - resetMLODebugData() end end + +function UpdateDebugEntities(portalIndex, entityIndex, debug) + local interiorId = mloInteriorId or GetInteriorFromEntity(cache.ped) + + if interiorId > 0 then + local key = ('%s:%s'):format(portalIndex, entityIndex) + + if drawEntities[key] then + drawEntities[key].debug = debug + else + local x,y,z = GetInteriorPortalEntityPosition(interiorId, portalIndex, entityIndex) + local pos = GetOffsetFromInteriorInWorldCoords(interiorId, x, y, z) + local arch = GetInteriorPortalEntityArchetype(interiorId, portalIndex, entityIndex) + drawEntities[key] = { portalIndex = portalIndex, entityIndex = entityIndex, debug = debug, pos = pos, arch = arch } + end + + if debug and not mloInterval then + mloInterval = SetInterval(updateDebugMLOInfo, 1000) + elseif not debug and mloInterval and not anyDebugEntitiesActive() then + ClearInterval(mloInterval) + mloInterval = nil + end + end +end + +CreateThread(function() + SetEntityDrawOutlineColor(255, 137, 0, 200) -- Orange + SetEntityDrawOutlineShader(1) +end) diff --git a/client/nui.lua b/client/nui.lua index 9a178b9..8493a8f 100644 --- a/client/nui.lua +++ b/client/nui.lua @@ -28,6 +28,12 @@ RegisterNUICallback('ht_mlotool:debugDrawToggle', function(data, cb) UpdateDebugDraw(data.info, data.outline, data.fill, data.navigate) end) +RegisterNUICallback('ht_mlotool:debugEntityToggle', function(data, cb) + cb({}) + + UpdateDebugEntities(data.portalIndex, data.entityIndex, data.debug) +end) + RegisterNUICallback('ht_mlotool:fetchLocales', function(_, cb) local lang = GetConvar('ox:locale', 'en') local locales = json.decode(LoadResourceFile(cache.resource, ('locales/%s.json'):format(lang))) diff --git a/locales/en.json b/locales/en.json index 97f2a3a..2ad2642 100644 --- a/locales/en.json +++ b/locales/en.json @@ -28,6 +28,7 @@ "ui_blank": "", "ui_close": "Close", + "ui_debug": "Debug", "ui_debug_comments": "Add Debug Comments", "ui_debug_comments_info": "Whether or not to add debug comments to the output file(s). NOTE: These should be used for debugging only, CodeWalker currently parses the comments incorrectly.", "ui_file_options": "File Generation Options", diff --git a/web/src/App.tsx b/web/src/App.tsx index a11c8b5..b1d63aa 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -61,10 +61,9 @@ const App: React.FC = () => { }); }); - const setNavigatedPortal = usePortalsStore((state) => state.setNavigatedPortal); - useNuiEvent("ht_mlotool:cancelNavigation", (data: any) => { - setNavigatedPortal(null); - }); + const [setNavigatedPortal, resetDebugEntities] = usePortalsStore((state) => [state.setNavigatedPortal, state.resetDebugEntities]); + useNuiEvent("ht_mlotool:cancelNavigation", () => setNavigatedPortal(null)); + useNuiEvent('ht_mlotool:cancelEntityDebug', resetDebugEntities); useHotkeys([ ["Escape", exitUI] diff --git a/web/src/layouts/views/portals/components/EntitySettings.tsx b/web/src/layouts/views/portals/components/EntitySettings.tsx index 9820c94..69cc89d 100644 --- a/web/src/layouts/views/portals/components/EntitySettings.tsx +++ b/web/src/layouts/views/portals/components/EntitySettings.tsx @@ -1,7 +1,11 @@ -import { Center, Checkbox, Text, Tooltip } from "@mantine/core"; +import { Center, Checkbox, Switch, Text, Tooltip } from "@mantine/core"; +import { getHotkeyHandler } from "@mantine/hooks"; import { useEffect, useState } from "react"; import { MemoNumberInput } from "../../../shared/Inputs"; +import { useVisibility } from "../../../../providers/VisibilityProvider"; import { useGeneralStore } from "../../../../store/general"; +import { usePortalsStore } from "../../../../store/portals"; +import { fetchNui } from "../../../../utils/fetchNui"; interface Props { portalIndex: number; @@ -9,8 +13,11 @@ interface Props { } const EntitySettings: React.FC = (props) => { + const exitUi = useVisibility((state) => state.exitUI); const mlo = useGeneralStore((state) => state.mlo); + const [debugEntities, addDebugEntity] = usePortalsStore((state) => [state.debugEntities, state.addDebugEntity]) const [activeEntity, setActiveEntity] = useState(mlo?.portals[props.portalIndex].entities[props.entityIndex]); + let key = `${props.portalIndex}:${props.entityIndex}`; let timer: NodeJS.Timeout; useEffect(() => { @@ -26,6 +33,13 @@ const EntitySettings: React.FC = (props) => { return () => clearTimeout(timer); }, [activeEntity]); + const handleDebugToggle = (e: React.ChangeEvent) => { + if (!debugEntities || !key) return; + + addDebugEntity(key, e.currentTarget.checked); + fetchNui("ht_mlotool:debugEntityToggle", { portalIndex: props.portalIndex, entityIndex: props.entityIndex, debug: e.currentTarget.checked }, "1") + } + return ( @@ -56,6 +70,7 @@ const EntitySettings: React.FC = (props) => { setActiveEntity({ ...activeEntity, isDoor: e.currentTarget.checked }); } }} + onKeyDown={getHotkeyHandler([["Escape", exitUi]])} /> @@ -68,6 +83,17 @@ const EntitySettings: React.FC = (props) => { setActiveEntity({ ...activeEntity, isGlass: e.currentTarget.checked }); } }} + onKeyDown={getHotkeyHandler([["Escape", exitUi]])} + /> + + + +
+
@@ -75,4 +101,4 @@ const EntitySettings: React.FC = (props) => { ); }; -export default EntitySettings; \ No newline at end of file +export default EntitySettings; diff --git a/web/src/layouts/views/portals/components/PortalInfo.tsx b/web/src/layouts/views/portals/components/PortalInfo.tsx index 34f8421..b40ebd7 100644 --- a/web/src/layouts/views/portals/components/PortalInfo.tsx +++ b/web/src/layouts/views/portals/components/PortalInfo.tsx @@ -98,6 +98,7 @@ const PortalInfo: React.FC = (props) => { {locale("ui_portal_entity_max_occl")} {locale("ui_portal_entity_door")} {locale("ui_portal_entity_glass")} + {locale("ui_debug")} diff --git a/web/src/providers/LocaleProvider.tsx b/web/src/providers/LocaleProvider.tsx index e3d0528..35b954e 100644 --- a/web/src/providers/LocaleProvider.tsx +++ b/web/src/providers/LocaleProvider.tsx @@ -8,6 +8,7 @@ interface Locale { const defaultLocale: Locale = { ui_blank: "", ui_close: "Close", + ui_debug: "Debug", ui_debug_comments: "Add Debug Comments", ui_debug_comments_info: "Whether or not to add debug comments to the output file(s). NOTE: These should be used for debugging only, CodeWalker currently parses the comments incorrectly.", ui_file_options: "File Generation Options", diff --git a/web/src/store/portals.tsx b/web/src/store/portals.tsx index a2cf540..832aebf 100644 --- a/web/src/store/portals.tsx +++ b/web/src/store/portals.tsx @@ -10,11 +10,16 @@ export interface PortalsStoreState { // PortalToggles navigatedPortal: NumberField; + // EntityToggles + debugEntities: { [index: string]: boolean } + // Scroll Area State scrollPosition: { x: number, y: number }; // Actions setNavigatedPortal: (portal: NumberField) => void; + addDebugEntity: (key: string, value: boolean) => void; + resetDebugEntities: () => void; toggleSwitch: (t: "enablePortalOutline" | "enablePortalFill" | "enablePortalInfo") => void; setScrollPosition: (pos: { x: number, y: number }) => void; }; @@ -28,11 +33,17 @@ export const usePortalsStore = create((set, get) => ({ // PortalToggles navigatedPortal: null, + // EntityToggles + debugEntities: {}, + // Scroll Area State scrollPosition: { x: 0, y: 0 }, // Actions setNavigatedPortal: (portal) => set({ navigatedPortal: portal }), toggleSwitch: (t) => set((state) => ({ [t]: !state[t] })), - setScrollPosition: (pos) => set({ scrollPosition: pos }) + setScrollPosition: (pos) => set({ scrollPosition: pos }), + + addDebugEntity: (key, value) => set({ debugEntities: { ...get().debugEntities, [key]: value } }), + resetDebugEntities: () => set({ debugEntities: {} }) })); diff --git a/web/src/types/EntityDef.tsx b/web/src/types/EntityDef.tsx index f8f2615..dc31e03 100644 --- a/web/src/types/EntityDef.tsx +++ b/web/src/types/EntityDef.tsx @@ -1,4 +1,5 @@ interface EntityDefConstructor { + index: number; linkType: number; maxOcclusion: number; modelHashKey: number; @@ -8,6 +9,7 @@ interface EntityDefConstructor { } export class EntityDef { + public index: number; public linkType: number; public maxOcclusion: number; public modelHashKey: number; @@ -16,6 +18,7 @@ export class EntityDef { public isGlass: boolean; constructor(data: EntityDefConstructor | EntityDef) { + this.index = data.index; this.linkType = data.linkType; this.maxOcclusion = data.maxOcclusion; this.modelHashKey = data.modelHashKey;