NQ-Wanderer Posted January 17, 2022 Share Posted January 17, 2022 As announced last week, the Panacea update is now in development. Today, we’re going to tell you more about the camera Lua API that’s among the many new features and improvements. This addition has been a longtime request from the community. The time for it seemed ripe since the removal of quaternions and the standardization of orientation methods to have a coherent and consistent whole. THE BIG PICTURE This API will allow you to get much more information about the game's camera and the status of the player linked to it. You will be able to get the position and orientation of the camera in the world coordinate system, but it'll also be expressed in the construct local coordinate system. You will find at the end of the devblog the example corresponding to the image. For these changes, we have added under unit: [int] unit.isMasterPlayerSeated(): Checks if the player currently running the control unit is seated. [int] unit.getMasterPlayerSeatId(): Returns the UID of the seat on which the player currently running the control unit is sitting. And so under system: [event] system.cameraChanged([int] mode): Emitted when the player changes the camera mode. [number] system.getCameraHorizontalFov(): Return the current value of the player's horizontal field of view [number] system.getCameraVerticalFov(): Return the current value of the player's vertical field of view [int] system.getCameraMode(): Returns the active camera mode. [int] system.isFirstPerson(): Checks if the active camera is in first person view. [vec3] system.getCameraPos(): Returns the position of the camera in the construct’s local coordinates. [vec3] system.getCameraWorldPos(): Returns the position of the camera in world coordinates. [vec3] system.getCameraWorldForward(): Returns the forward direction vector of the active camera in world coordinates. [vec3] system.getCameraWorldRight(): Returns the right direction vector of the active camera in world coordinates. [vec3] system.getCameraWorldUp(): Returns the up direction vector of the active camera in world coordinates. [vec3] system.getCameraForward(): Returns the forward direction vector of the active camera in the construct’s local coordinates. [vec3] system.getCameraRight(): Returns the right direction vector of the active camera in the construct’s local coordinates. [vec3] system.getCameraUp(): Returns the up direction vector of the active camera in the construct’s local coordinates. We took advantage of these changes to fix an inconsistency between the positions returned by unit.getMasterPlayerWorldPosition and system.getPlayerWorldPosition. These two functions were not returning the same position; they will now return the position of the player's feet. Note: As you may have guessed, the system.getFov function will be deprecated in favor of the consistency of getCameraHorizontalFov. REMOVAL OF WRITING TO THE CLIENT LOG, BUT …. We have decided to remove the ability to write lines directly to the clients log files using Lua. Following a long review, the decision has been made with security concerns in mind as it allowed some nefarious players, for example, to automate mechanics that are not intended to be automated, allowed the creation of bots, and left a door open for players to maliciously inflate the players log files. The following functions are now completely removed: system.logInfo() system.logWarning() system.logError() This feature was never really supported (and notably absent in the codex); however, it is unfortunate that it also impacts less malicious creations. I'm thinking in particular of the audio framework created by the player ZarTaen, used in the popular Arch Orbital HUD flight system, created by the players Dimencia and Archaegeo. For that reason and as a first iteration, we are integrating an API that will allow you to play sounds from Lua. It’s got a very basic functionality now that allows for growth in the future. system.playSound([string] filePath) : Play a sound file from inside the audio folder in your user folder. Only one sound at the same time. system.stopSound(): Stop the playing sound. For obvious reasons, the playing of sounds is restricted to control units that are run explicitly by pressing F on them. You will find the user folder in the same folder where you will find the holograms or screenshots folder. Said folder can be found by navigating to “My Documents/NQ/DualUniverse/audio”, and sub folders can be used to organize and bundle audio files. CONCLUSION As always, we hope you like these new features. Please feel free to come and share your thoughts and ideas, and let us know what Lua-related improvements you would like to see in the future. NQ-Ligo looks forward to chatting with you in this forum thread! THE CAMERA API EXAMPLE Below is an example of Lua code using the new API for the camera. This example allows you to parse the element you are looking at and get Lua information such as the element name, class, methods and fields. To use this example, you will need to link to a controller (e.g. a programming board) and name two slots ‘core’ (for the core unit) and ‘slotIndustry’ (for an industrial unit in this example). Under unit.start --Declaration of globals tooltip = {name="",class="", dist=0, methods={}, fields={}} target = nil slotIndustry.size = 1.25 --Setup the size of the linked industrie element, with the slot named slotIndustry --Custom function declaration function isLinked(id) for k,s in pairs(unit) do if type(s) == 'table' and s.getId and s.getId() == id then return true, s end end return false end --Initial setup system.showScreen(1) unit.hide() unit.setTimer('compute',0.02) Under unit.tick(‘compute’) --Declaration of local math functions local acos, tan, sqrt, deg = math.acos, math.tan, math.sqrt, math.deg --Get elements on the construct and useful positions local ids = core.getElementIdList() local ppos = vec3(unit.getMasterPlayerPosition()) local cpos = vec3(system.getCameraPos()) local cFwd = vec3(system.getCameraForward()) --Set tooltip info by defaults tooltip = {name="",class="", dist=0} target = nil --Iterate on all elements ids for k,id in pairs(ids) do local pos = vec3(core.getElementPositionById(id)) local dir = pos-cpos local dist = dir:len() local angle = dir:angle_between(cFwd) local r, el = isLinked(id) --Check if the player is looking at the element if el and angle < tan((el.size or 0)/dist) or angle < tan(1/dist) then --Register default data info tooltip.name = core.getElementNameById(id) tooltip.class = core.getElementTypeById(id) tooltip.dist = dist tooltip.methods = {} tooltip.fields = {} --If the element is linked scan the methods and fields of the element if r then local km, kf = 1,1 for key,p in pairs(el) do if type(p) == 'function' then tooltip.methods[km] = {name = key, value = ''} km = km+1 else tooltip.fields[kf] = {name = key, value = p} kf = kf+1 end end --Sort the methods and field by alphabetically table.sort(tooltip.methods, function(a,b) return a.name < b.name end) table.sort(tooltip.fields, function(a,b) return a.name < b.name end) end end end Under update: --If not looking at any element, do not draw on update if tooltip.name=="" then return end --Compute the tooltip frame height local height = 90+ (#tooltip.methods + #tooltip.fields)*14 --Build the interface in SVG local svg = { [[<style>* {border:1px solid red} #node{ transform: translate(50%, 50%);} svg {position: absolute; left:0px; top:0px;}]], [[text {font-size:1vh; text-anchor:start; fill:#ccc}]], [[text#eName {font-size:1.25vh; fill:#fff}]], [[text#eClass {fill:#ccc; }]], [[text.pName {fill:#fff; }]], [[text.pValue {text-anchor:end; fill:#ccc; }]], [[</style>]], [[<svg width=100% height=100% viewBox="0 0 1920 1080"> <g id="node">]], string.format([[<rect x=150 y=%.2f fill=rgba(0,0,0,0.5) width=300 height=%.2f />]], -height/2, height), string.format([[<text id="eName" x=160 y=%.2f >%s</text>]], -height/2 +20, tooltip.name), string.format([[<text id="eClass" font-style="italic" x=170 y=%.2f >%s</text>]], -height/2 + 40, tooltip.class), string.format([[<text id="eName" x=160 y=%.2f >Methods</text>]], -height/2 + 60) } --Compose the list of methods of the element local cSVG, yMethods = #svg, 0 if tooltip.methods then for k,m in pairs(tooltip.methods) do yMethods = -height/2 + 60 + k*14 svg[cSVG+k] = string.format('<text class="pName" x=170 y=%.2f >%s</text>', yMethods, m.name ) end end cSVG = #svg+1 yMethods = yMethods +20 svg[cSVG] = string.format([[<text id="eName" x=160 y=%.2f >Fields</text>]], yMethods) --Compose the list of fields of the element if tooltip.fields then for k,f in pairs(tooltip.fields) do local sValue = "" local yFields = yMethods + k*14 if type(f.value) == 'number' then sValue = string.format('%.4f', f.value) elseif type(f.value) == 'boolean' then sValue = string.format('%s', f.value and 'true' or 'false') elseif type(f.value) == 'string' then sValue = f.value else sValue = tostring(f.value) end svg[cSVG+k] = string.format('<text class="pName" x=170 y=%.2f >%s</text><text class="pValue" x=440 y=%.2f >%s</text>', yFields, f.name, yFields, sValue ) end end svg[#svg+1] = [[</g></svg>]] --Concat and display the SVG system.setScreen(table.concat(svg)) Davemane42 1 Link to comment Share on other sites More sharing options...
Recommended Posts