Script v1.7.1.0
- AI
- Animals
- Contracts
- Debug
- Economy
- Effects
- Events
- Farms
- GUI
- Handtools
- I3d
- Materials
- Misc
- Objects
- Placeables
- Player
- Shop
- Sounds
- Specializations
- AIConveyorBelt
- AIImplement
- AIVehicle
- AnimatedVehicle
- ArticulatedAxis
- Attachable
- AttacherJointControl
- AttacherJoints
- BaleGrab
- BaleLoader
- Baler
- BaleWrapper
- BaseMaterial
- BunkerSiloCompacter
- BunkerSiloInteractor
- BuyableBale
- CCTDrivable
- Combine
- ConnectionHoses
- ConveyorBelt
- Cover
- CrabSteering
- Crawlers
- Cultivator
- Cutter
- Cylindered
- CylinderedFoldable
- Dashboard
- Dischargeable
- Drivable
- DynamicallyLoadedParts
- DynamicMountAttacher
- Enterable
- FertilizingCultivator
- FertilizingSowingMachine
- FillTriggerVehicle
- FillUnit
- FillVolume
- Foldable
- FoliageBending
- ForageWagon
- FrontloaderAttacher
- FruitPreparer
- GroundAdjustedNodes
- GroundReference
- Honk
- HookLiftContainer
- HookLiftTrailer
- IKChains
- JigglingParts
- Leveler
- Lights
- LivestockTrailer
- Locomotive
- LogGrab
- ManureBarrel
- MixerWagon
- Motorized
- Mountable
- Mower
- Pickup
- Pipe
- Plow
- PowerConsumer
- PowerTakeOffs
- RandomlyMovingParts
- ReceivingHopper
- ReverseDriving
- Rideable
- RidgeMarker
- Roller
- Ropes
- SemiTrailerFront
- Shovel
- SlopeCompensation
- SmartAttach
- SowingMachine
- SpeedRotatingParts
- SplineVehicle
- Sprayer
- StrawBlower
- StumpCutter
- Suspensions
- Tedder
- TensionBeltObject
- TensionBelts
- TipOccluder
- Trailer
- TreePlanter
- TreeSaw
- TurnOnVehicle
- Washable
- WaterTrailer
- Wearable
- Weeder
- Wheels
- Windrower
- Wipers
- WoodCrusher
- WoodHarvester
- WorkArea
- WorkMode
- WorkParticles
- Triggers
- Utils
- Vehicles
- Weather
Engine v1.7.1.0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- XML
- general
Foundation Reference
Cylindered
DescriptionSpecialization for vehicles with dependent movable parts (e.g. cylinders)Functions
- actionEventInput
- allowLoadMovingToolStates
- getAdditionalSchemaText
- getDischargeNodeEmptyFactor
- getIsDynamicMountGrabOpened
- getIsMovingToolActive
- getMovingPartByNode
- getMovingToolByNode
- getMovingToolDashboardState
- getMovingToolState
- getShovelNodeIsActive
- getWearMultiplier
- isDetachAllowed
- limitInterpolator
- loadCopyLocalDirectionParts
- loadDependentAnimations
- loadDependentAttacherJoints
- loadDependentComponentJoints
- loadDependentMovingTools
- loadDependentParts
- loadDependentTranslatingParts
- loadDependentWheels
- loadDischargeNode
- loadDynamicMountGrabFromXML
- loadExtraDependentParts
- loadMovingPartFromXML
- loadMovingToolFromXML
- loadObjectChangeValuesFromXML
- loadRotationBasedLimits
- loadShovelNode
- movingToolDashboardAttributes
- onDeactivate
- onDelete
- onDraw
- onLoad
- onLoadFinished
- onPostAttach
- onPostLoad
- onPostUpdate
- onReadStream
- onReadUpdateStream
- onRegisterActionEvents
- onSelect
- onUnselect
- onUpdate
- onUpdateTick
- onWriteStream
- onWriteUpdateStream
- prerequisitesPresent
- registerEventListeners
- registerEvents
- registerFunctions
- registerOverwrittenFunctions
- saveToXMLFile
- setComponentJointFrame
- setDelayedData
- setDirty
- setIsEasyControlActive
- setMovingToolDirty
- setObjectChangeValues
- setToolAnimation
- setToolRotation
- setToolTranslation
- updateAttacherJoints
- updateComponentJoints
- updateCylinderedInitial
- updateDelayedTool
- updateDependentAnimations
- updateDependentToolLimits
- updateEasyControl
- updateExtraDependentParts
- updateMovingPart
- updateRotationBasedLimits
- updateWheels
actionEventInput
DescriptionDefinitionactionEventInput()Code
2962 | function Cylindered.actionEventInput(self, actionName, inputValue, callbackState, isAnalog, isMouse) |
2963 | local spec = self.spec_cylindered |
2964 | local tool = spec.movingTools[callbackState] |
2965 | |
2966 | if tool ~= nil then |
2967 | local move |
2968 | if tool.invertAxis then |
2969 | move = -inputValue |
2970 | else |
2971 | move = inputValue |
2972 | end |
2973 | |
2974 | move = move * g_gameSettings:getValue(GameSettings.SETTING.VEHICLE_ARM_SENSITIVITY) |
2975 | if isMouse then |
2976 | -- revert dt scaling for mouse input |
2977 | move = move * 16.666 / g_currentDt * tool.mouseSpeedFactor; |
2978 | |
2979 | -- allow only the input of the highest mouse axis value |
2980 | -- lock the move of the lower mouse axis value until it is higher than 0.75 or the value is higher than the doubled value of the other tool |
2981 | if tool.moveLocked then |
2982 | if math.abs(inputValue) < 0.75 then |
2983 | if math.abs(move) > math.abs(tool.lockTool.move) * 2 then |
2984 | tool.moveLocked = false |
2985 | else |
2986 | move = 0 |
2987 | end |
2988 | else |
2989 | tool.moveLocked = false |
2990 | end |
2991 | else |
2992 | local checkOtherTools = function(tools) |
2993 | for tool2Index, tool2 in ipairs(tools) do |
2994 | if tool2Index ~= callbackState then |
2995 | if tool2.move ~= nil and tool2.move ~= 0 then |
2996 | if math.abs(move) > math.abs(tool2.move) then |
2997 | tool2.move = 0 |
2998 | tool2.moveToSend = 0 |
2999 | tool2.moveLocked = true |
3000 | tool2.lockTool = tool |
3001 | else |
3002 | move = 0 |
3003 | tool.moveLocked = true |
3004 | tool.lockTool = tool2 |
3005 | end |
3006 | end |
3007 | end |
3008 | end |
3009 | end |
3010 | |
3011 | checkOtherTools(spec.movingTools) |
3012 | |
3013 | if self.getAttachedImplements ~= nil then |
3014 | for _, implement in pairs(self:getAttachedImplements()) do |
3015 | local vehicle = implement.object |
3016 | if vehicle.spec_cylindered ~= nil then |
3017 | checkOtherTools(vehicle.spec_cylindered.movingTools) |
3018 | end |
3019 | end |
3020 | end |
3021 | end |
3022 | end |
3023 | |
3024 | if move ~= tool.move then |
3025 | tool.move = move |
3026 | end |
3027 | |
3028 | if tool.move ~= tool.moveToSend then |
3029 | tool.moveToSend = tool.move |
3030 | self:raiseDirtyFlags(spec.cylinderedInputDirtyFlag) |
3031 | end |
3032 | end |
3033 | end |
allowLoadMovingToolStates
DescriptionReturns if loading of moving tool stats from savegame is allowedDefinition
allowLoadMovingToolStates()Return Values
boolean | isAllowed | is allowed |
2012 | function Cylindered:allowLoadMovingToolStates(superFunc) |
2013 | return true |
2014 | end |
getAdditionalSchemaText
DescriptionDefinitiongetAdditionalSchemaText()Code
2256 | function Cylindered:getAdditionalSchemaText(superFunc) |
2257 | local t = superFunc(self) |
2258 | if self.isClient then |
2259 | if self:getIsActiveForInput(true) then |
2260 | local spec = self.spec_cylindered |
2261 | if #spec.controlGroupNames > 1 then |
2262 | if t ~= nil then |
2263 | t = t .. " " |
2264 | end |
2265 | |
2266 | t = tostring(spec.currentControlGroupIndex) |
2267 | end |
2268 | end |
2269 | end |
2270 | |
2271 | return t |
2272 | end |
getDischargeNodeEmptyFactor
DescriptionDefinitiongetDischargeNodeEmptyFactor()Code
2128 | function Cylindered:getDischargeNodeEmptyFactor(superFunc, dischargeNode) |
2129 | if dischargeNode.movingToolActivation == nil then |
2130 | return superFunc(self, dischargeNode) |
2131 | else |
2132 | local spec = self.spec_cylindered |
2133 | local movingToolActivation = dischargeNode.movingToolActivation |
2134 | |
2135 | local currentSpeed = superFunc(self, dischargeNode) |
2136 | |
2137 | local movingTool = spec.nodesToMovingTools[movingToolActivation.node] |
2138 | local state = Cylindered.getMovingToolState(self, movingTool) |
2139 | if movingToolActivation.isInverted then |
2140 | state = math.abs(state-1) |
2141 | end |
2142 | |
2143 | state = math.max(state-movingToolActivation.openOffset, 0) / movingToolActivation.openOffsetInv |
2144 | local speedFactor = MathUtil.clamp(state/movingToolActivation.openFactor, 0, 1) |
2145 | |
2146 | return currentSpeed * speedFactor |
2147 | end |
2148 | end |
getIsDynamicMountGrabOpened
DescriptionDefinitiongetIsDynamicMountGrabOpened()Code
2212 | function Cylindered:getIsDynamicMountGrabOpened(superFunc, grab) |
2213 | local isActive = superFunc(self, grab) |
2214 | if not isActive or grab.movingToolActivation == nil then |
2215 | return isActive |
2216 | end |
2217 | |
2218 | |
2219 | local spec = self.spec_cylindered |
2220 | local movingToolActivation = grab.movingToolActivation |
2221 | local movingTool = spec.nodesToMovingTools[movingToolActivation.node] |
2222 | local state = Cylindered.getMovingToolState(self, movingTool) |
2223 | if movingToolActivation.isInverted then |
2224 | state = math.abs(state-1) |
2225 | end |
2226 | |
2227 | return state > movingToolActivation.openFactor |
2228 | end |
getIsMovingToolActive
DescriptionDefinitiongetIsMovingToolActive()Code
2030 | function Cylindered:getIsMovingToolActive(movingTool) |
2031 | return movingTool.isActive |
2032 | end |
getMovingPartByNode
DescriptionDefinitiongetMovingPartByNode()Code
2024 | function Cylindered:getMovingPartByNode(node) |
2025 | return self.spec_cylindered.nodesToMovingParts[node] |
2026 | end |
getMovingToolByNode
DescriptionDefinitiongetMovingToolByNode()Code
2018 | function Cylindered:getMovingToolByNode(node) |
2019 | return self.spec_cylindered.nodesToMovingTools[node] |
2020 | end |
getMovingToolDashboardState
DescriptionDefinitiongetMovingToolDashboardState()Code
3037 | function Cylindered.getMovingToolDashboardState(self, dashboard) |
3038 | local vehicle = self |
3039 | if dashboard.attacherJointIndex ~= nil then |
3040 | local implement = self:getImplementFromAttacherJointIndex(dashboard.attacherJointIndex) |
3041 | if implement ~= nil then |
3042 | vehicle = implement.object |
3043 | else |
3044 | vehicle = nil |
3045 | end |
3046 | end |
3047 | |
3048 | if vehicle ~= nil then |
3049 | local spec = vehicle.spec_cylindered |
3050 | if spec ~= nil then |
3051 | for _, movingTool in ipairs(spec.movingTools) do |
3052 | if movingTool.axis == dashboard.axis then |
3053 | return (movingTool.move + 1) / 2 |
3054 | end |
3055 | end |
3056 | end |
3057 | end |
3058 | |
3059 | return 0.5 |
3060 | end |
getMovingToolState
DescriptionReturns moving tool stateDefinition
getMovingToolState(table tool)Arguments
table | tool | tool |
float | state | state of moving tool [0..1] |
2511 | function Cylindered.getMovingToolState(self, tool) |
2512 | local state = 0 |
2513 | if tool.rotMax ~= nil and tool.rotMin ~= nil then |
2514 | state = (tool.curRot[tool.rotationAxis]-tool.rotMin) / (tool.rotMax-tool.rotMin) |
2515 | else |
2516 | if tool.transMax ~= nil and tool.transMin ~= nil then |
2517 | state = (tool.curTrans[tool.translationAxis]-tool.transMin) / (tool.transMax-tool.transMin) |
2518 | end |
2519 | end |
2520 | |
2521 | return state |
2522 | end |
getShovelNodeIsActive
DescriptionDefinitiongetShovelNodeIsActive()Code
2172 | function Cylindered:getShovelNodeIsActive(superFunc, shovelNode) |
2173 | local isActive = superFunc(self, shovelNode) |
2174 | if not isActive or shovelNode.movingToolActivation == nil then |
2175 | return isActive |
2176 | end |
2177 | |
2178 | |
2179 | local spec = self.spec_cylindered |
2180 | local movingToolActivation = shovelNode.movingToolActivation |
2181 | local movingTool = spec.nodesToMovingTools[movingToolActivation.node] |
2182 | local state = Cylindered.getMovingToolState(self, movingTool) |
2183 | if movingToolActivation.isInverted then |
2184 | state = math.abs(state-1) |
2185 | end |
2186 | |
2187 | return state > movingToolActivation.openFactor |
2188 | end |
getWearMultiplier
DescriptionReturns current wear multiplierDefinition
getWearMultiplier()Return Values
float | wearMultiplier | current wear multiplier |
2277 | function Cylindered:getWearMultiplier(superFunc) |
2278 | local spec = self.spec_cylindered |
2279 | local multiplier = superFunc(self) |
2280 | |
2281 | if spec.isHydraulicSamplePlaying then |
2282 | multiplier = multiplier + self:getWorkWearMultiplier() |
2283 | end |
2284 | |
2285 | return multiplier |
2286 | end |
isDetachAllowed
DescriptionReturns true if detach is allowedDefinition
isDetachAllowed()Return Values
boolean | detachAllowed | detach is allowed |
2037 | function Cylindered:isDetachAllowed(superFunc) |
2038 | local spec = self.spec_cylindered |
2039 | if spec.detachLockNodes ~= nil then |
2040 | for entry, data in pairs(spec.detachLockNodes) do |
2041 | local node = entry.node |
2042 | local rot = {getRotation(node)} |
2043 | |
2044 | if data.detachingRotMinLimit ~= nil and rot[entry.rotationAxis] < data.detachingRotMinLimit then |
2045 | return false, nil |
2046 | end |
2047 | if data.detachingRotMaxLimit ~= nil and rot[entry.rotationAxis] > data.detachingRotMaxLimit then |
2048 | return false, nil |
2049 | end |
2050 | |
2051 | local trans = {getTranslation(node)} |
2052 | if data.detachingTransMinLimit ~= nil and trans[entry.translationAxis] < data.detachingTransMinLimit then |
2053 | return false, nil |
2054 | end |
2055 | if data.detachingTransMaxLimit ~= nil and trans[entry.translationAxis] > data.detachingTransMaxLimit then |
2056 | return false, nil |
2057 | end |
2058 | end |
2059 | end |
2060 | |
2061 | return superFunc(self) |
2062 | end |
limitInterpolator
DescriptionDefinitionlimitInterpolator()Code
2896 | function Cylindered.limitInterpolator(first, second, alpha) |
2897 | local oneMinusAlpha = 1-alpha |
2898 | |
2899 | local rotMin = nil |
2900 | local rotMax = nil |
2901 | local transMin = nil |
2902 | local transMax = nil |
2903 | |
2904 | if first.rotMin ~= nil and second.rotMin ~= nil then |
2905 | rotMin = first.rotMin*alpha + second.rotMin*oneMinusAlpha |
2906 | end |
2907 | if first.rotMax ~= nil and second.rotMax ~= nil then |
2908 | rotMax = first.rotMax*alpha + second.rotMax*oneMinusAlpha |
2909 | end |
2910 | if first.transMin ~= nil and second.transMin ~= nil then |
2911 | transMin = first.minTrans*alpha + second.transMin*oneMinusAlpha |
2912 | end |
2913 | if first.transMax ~= nil and second.transMax ~= nil then |
2914 | transMax = first.transMax*alpha + second.transMax*oneMinusAlpha |
2915 | end |
2916 | |
2917 | return rotMin, rotMax, transMin, transMax |
2918 | end |
loadCopyLocalDirectionParts
DescriptionLoad copy local direction parts from xmlDefinition
loadCopyLocalDirectionParts(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
1900 | function Cylindered:loadCopyLocalDirectionParts(xmlFile, baseName, entry) |
1901 | entry.copyLocalDirectionParts = {} |
1902 | local j = 0 |
1903 | while true do |
1904 | local refBaseName = baseName..string.format(".copyLocalDirectionPart(%d)", j) |
1905 | if not hasXMLProperty(xmlFile, refBaseName) then |
1906 | break |
1907 | end |
1908 | |
1909 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, refBaseName.."#index", refBaseName.."#node") --FS15 to FS17 |
1910 | |
1911 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#node"), self.i3dMappings) |
1912 | if node ~= nil then |
1913 | local copyLocalDirectionPart = {} |
1914 | copyLocalDirectionPart.node = node |
1915 | copyLocalDirectionPart.dirScale = StringUtil.getVectorNFromString(getXMLString(xmlFile, refBaseName.."#dirScale"), 3) |
1916 | copyLocalDirectionPart.upScale = StringUtil.getVectorNFromString(getXMLString(xmlFile, refBaseName.."#upScale"), 3) |
1917 | |
1918 | self:loadDependentComponentJoints(xmlFile, refBaseName, copyLocalDirectionPart) |
1919 | |
1920 | table.insert(entry.copyLocalDirectionParts, copyLocalDirectionPart) |
1921 | end |
1922 | j = j + 1 |
1923 | end |
1924 | end |
loadDependentAnimations
DescriptionDefinitionloadDependentAnimations()Code
1852 | function Cylindered:loadDependentAnimations(xmlFile, baseName, entry) |
1853 | entry.dependentAnimations = {} |
1854 | |
1855 | local i = 0 |
1856 | while true do |
1857 | local baseKey = string.format("%s.dependentAnimation(%d)", baseName, i) |
1858 | if not hasXMLProperty(xmlFile, baseKey) then |
1859 | break |
1860 | end |
1861 | |
1862 | local animationName = getXMLString(self.xmlFile, baseKey.."#name") |
1863 | if animationName ~= nil then |
1864 | local dependentAnimation = {} |
1865 | dependentAnimation.name = animationName |
1866 | dependentAnimation.lastPos = 0 |
1867 | |
1868 | dependentAnimation.translationAxis = getXMLInt(self.xmlFile, baseKey.."#translationAxis") |
1869 | dependentAnimation.rotationAxis = getXMLInt(self.xmlFile, baseKey.."#rotationAxis") |
1870 | |
1871 | dependentAnimation.node = entry.node |
1872 | local useTranslatingPartIndex = getXMLInt(self.xmlFile, baseKey.."#useTranslatingPartIndex") |
1873 | if useTranslatingPartIndex ~= nil then |
1874 | if entry.translatingParts[useTranslatingPartIndex] ~= nil then |
1875 | dependentAnimation.node = entry.translatingParts[useTranslatingPartIndex].node |
1876 | end |
1877 | end |
1878 | |
1879 | dependentAnimation.minValue = getXMLFloat(self.xmlFile, baseKey.."#minValue") |
1880 | dependentAnimation.maxValue = getXMLFloat(self.xmlFile, baseKey.."#maxValue") |
1881 | if dependentAnimation.rotationAxis ~= nil then |
1882 | dependentAnimation.minValue = MathUtil.degToRad(dependentAnimation.minValue) |
1883 | dependentAnimation.maxValue = MathUtil.degToRad(dependentAnimation.maxValue) |
1884 | end |
1885 | |
1886 | dependentAnimation.invert = Utils.getNoNil(getXMLBool(self.xmlFile, baseKey.."#invert"), false) |
1887 | |
1888 | table.insert(entry.dependentAnimations, dependentAnimation) |
1889 | end |
1890 | |
1891 | i = i + 1 |
1892 | end |
1893 | end |
loadDependentAttacherJoints
DescriptionLoad attacher joints from xmlDefinition
loadDependentAttacherJoints(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
1760 | function Cylindered:loadDependentAttacherJoints(xmlFile, baseName, entry) |
1761 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#jointIndices", baseName..".attacherJoint#jointIndices") --FS15 to FS17 |
1762 | |
1763 | local indices = StringUtil.getVectorNFromString(getXMLString(xmlFile, baseName.. ".attacherJoint#jointIndices")) |
1764 | if indices ~= nil then |
1765 | entry.attacherJoints = {} |
1766 | |
1767 | local availableAttacherJoints |
1768 | if self.getAttacherJoints ~= nil then |
1769 | availableAttacherJoints = self:getAttacherJoints() |
1770 | end |
1771 | if availableAttacherJoints ~= nil then |
1772 | for i=1, table.getn(indices) do |
1773 | if availableAttacherJoints[indices[i]] ~= nil then |
1774 | table.insert(entry.attacherJoints, availableAttacherJoints[indices[i]]) |
1775 | end |
1776 | end |
1777 | end |
1778 | end |
1779 | |
1780 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#inputAttacherJoint", baseName..".inputAttacherJoint#value") --FS15 to FS17 |
1781 | |
1782 | entry.inputAttacherJoint = Utils.getNoNil(getXMLBool(xmlFile, baseName.. ".inputAttacherJoint#value"), false) |
1783 | end |
loadDependentComponentJoints
DescriptionLoad component joints from xmlDefinition
loadDependentComponentJoints(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
1709 | function Cylindered:loadDependentComponentJoints(xmlFile, baseName, entry) |
1710 | if not self.isServer then |
1711 | return |
1712 | end |
1713 | |
1714 | entry.componentJoints = {} |
1715 | |
1716 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#componentJointIndex", baseName..".componentJoint#index") --FS15 to FS17 |
1717 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, baseName.."#anchorActor", baseName..".componentJoint#anchorActor") --FS15 to FS17 |
1718 | |
1719 | local i = 0 |
1720 | while true do |
1721 | local key = baseName .. string.format(".componentJoint(%d)", i) |
1722 | if not hasXMLProperty(xmlFile, key) then |
1723 | break |
1724 | end |
1725 | local index = getXMLInt(xmlFile, key .. "#index") |
1726 | if index ~= nil and self.componentJoints[index] ~= nil then |
1727 | local anchorActor = Utils.getNoNil(getXMLInt(xmlFile, key.."#anchorActor"), 0) |
1728 | |
1729 | local componentJoint = self.componentJoints[index] |
1730 | |
1731 | local jointEntry = {} |
1732 | jointEntry.componentJoint = componentJoint |
1733 | jointEntry.anchorActor = anchorActor |
1734 | jointEntry.index = index |
1735 | |
1736 | local jointNode = componentJoint.jointNode |
1737 | if jointEntry.anchorActor == 1 then |
1738 | jointNode = componentJoint.jointNodeActor1 |
1739 | end |
1740 | |
1741 | local node = self.components[componentJoint.componentIndices[2]].node |
1742 | jointEntry.x, jointEntry.y, jointEntry.z = localToLocal(node, jointNode, 0,0,0) |
1743 | jointEntry.upX, jointEntry.upY, jointEntry.upZ = localDirectionToLocal(node, jointNode, 0,1,0) |
1744 | jointEntry.dirX, jointEntry.dirY, jointEntry.dirZ = localDirectionToLocal(node, jointNode, 0,0,1) |
1745 | |
1746 | table.insert(entry.componentJoints, jointEntry) |
1747 | else |
1748 | g_logManager:xmlWarning(self.configFileName, "Invalid index for '%s'", key) |
1749 | end |
1750 | |
1751 | i = i + 1 |
1752 | end |
1753 | end |
loadDependentMovingTools
DescriptionLoad dependent moving tools from xmlDefinition
loadDependentMovingTools(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
1621 | function Cylindered:loadDependentMovingTools(xmlFile, baseName, entry) |
1622 | entry.dependentMovingTools = {} |
1623 | |
1624 | local j = 0 |
1625 | while true do |
1626 | local refBaseName = baseName..string.format(".dependentMovingTool(%d)", j) |
1627 | if not hasXMLProperty(xmlFile, refBaseName) then |
1628 | break |
1629 | end |
1630 | |
1631 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, refBaseName.."#index", refBaseName.."#index") --FS17 to FS19 |
1632 | |
1633 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#node"), self.i3dMappings) |
1634 | local speedScale = getXMLFloat(xmlFile, refBaseName.."#speedScale") |
1635 | local requiresMovement = Utils.getNoNil(getXMLBool(xmlFile, refBaseName.."#requiresMovement"), false) |
1636 | |
1637 | local rotationBasedLimits = AnimCurve:new(Cylindered.limitInterpolator) |
1638 | local found = false |
1639 | local i = 0 |
1640 | while true do |
1641 | local key = string.format("%s.limit(%d)", refBaseName..".rotationBasedLimits", i) |
1642 | if not hasXMLProperty(xmlFile, key) then |
1643 | break |
1644 | end |
1645 | |
1646 | local keyFrame = self:loadRotationBasedLimits(xmlFile, key, entry) |
1647 | if keyFrame ~= nil then |
1648 | rotationBasedLimits:addKeyframe(keyFrame) |
1649 | found = true |
1650 | end |
1651 | i = i + 1 |
1652 | end |
1653 | if not found then |
1654 | rotationBasedLimits = nil |
1655 | end |
1656 | |
1657 | local minTransLimits = getXMLString(xmlFile, refBaseName.."#minTransLimits") |
1658 | local maxTransLimits = getXMLString(xmlFile, refBaseName.."#maxTransLimits") |
1659 | local minRotLimits = getXMLString(xmlFile, refBaseName.."#minRotLimits") |
1660 | local maxRotLimits = getXMLString(xmlFile, refBaseName.."#maxRotLimits") |
1661 | if node ~= nil and (rotationBasedLimits ~= nil or speedScale ~= nil or minTransLimits ~= nil or maxTransLimits ~= nil or minRotLimits ~= nil or maxRotLimits ~= nil) then |
1662 | local dependentTool = {} |
1663 | dependentTool.node = node |
1664 | dependentTool.rotationBasedLimits = rotationBasedLimits |
1665 | dependentTool.speedScale = speedScale |
1666 | dependentTool.requiresMovement = requiresMovement |
1667 | dependentTool.minTransLimits = StringUtil.getVectorNFromString(minTransLimits, 2) |
1668 | dependentTool.maxTransLimits = StringUtil.getVectorNFromString(maxTransLimits, 2) |
1669 | dependentTool.minRotLimits = StringUtil.getRadiansFromString(minRotLimits, 2) |
1670 | dependentTool.maxRotLimits = StringUtil.getRadiansFromString(maxRotLimits, 2) |
1671 | table.insert(entry.dependentMovingTools, dependentTool) |
1672 | end |
1673 | |
1674 | j = j + 1 |
1675 | end |
1676 | end |
loadDependentParts
DescriptionLoad dependent parts from xmlDefinition
loadDependentParts(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
1683 | function Cylindered:loadDependentParts(xmlFile, baseName, entry) |
1684 | entry.dependentPartNodes = {} |
1685 | |
1686 | local j = 0 |
1687 | while true do |
1688 | local refBaseName = baseName..string.format(".dependentPart(%d)", j) |
1689 | if not hasXMLProperty(xmlFile, refBaseName) then |
1690 | break |
1691 | end |
1692 | |
1693 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, refBaseName.."#index", refBaseName.."#index") --FS17 to FS19 |
1694 | |
1695 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#node"), self.i3dMappings) |
1696 | if node ~= nil then |
1697 | table.insert(entry.dependentPartNodes, node) |
1698 | end |
1699 | |
1700 | j = j + 1 |
1701 | end |
1702 | end |
loadDependentTranslatingParts
DescriptionLoad translating partsDefinition
loadDependentTranslatingParts(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
1812 | function Cylindered:loadDependentTranslatingParts(xmlFile, baseName, entry) |
1813 | entry.translatingParts = {} |
1814 | if entry.referencePoint ~= nil then |
1815 | local j = 0 |
1816 | while true do |
1817 | local refBaseName = baseName..string.format(".translatingPart(%d)", j) |
1818 | if not hasXMLProperty(xmlFile, refBaseName) then |
1819 | break |
1820 | end |
1821 | |
1822 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, refBaseName.."#index", refBaseName.."#node") --FS15 to FS17 |
1823 | |
1824 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#node"), self.i3dMappings) |
1825 | if node ~= nil then |
1826 | local transEntry = {} |
1827 | transEntry.node = node |
1828 | local x, y, z = getTranslation(node) |
1829 | transEntry.startPos = {x, y, z} |
1830 | local _, _, refZ = worldToLocal(node, getWorldTranslation(entry.referencePoint)) |
1831 | transEntry.referenceDistance = refZ |
1832 | transEntry.referenceDistancePoint = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, refBaseName.."#referenceDistancePoint"), self.i3dMappings) |
1833 | |
1834 | transEntry.minZTrans = getXMLFloat(xmlFile, refBaseName.."#minZTrans") |
1835 | transEntry.maxZTrans = getXMLFloat(xmlFile, refBaseName.."#maxZTrans") |
1836 | |
1837 | table.insert(entry.translatingParts, transEntry) |
1838 | end |
1839 | j = j + 1 |
1840 | end |
1841 | end |
1842 | end |
loadDependentWheels
DescriptionLoad wheels from xmlDefinition
loadDependentWheels(integer xmlFile, string baseName, table entry)Arguments
integer | xmlFile | id of xml object |
string | baseName | base name |
table | entry | entry to add |
1790 | function Cylindered:loadDependentWheels(xmlFile, baseName, entry) |
1791 | if SpecializationUtil.hasSpecialization(Wheels, self.specializations) then |
1792 | local indices = StringUtil.getVectorNFromString(getXMLString(xmlFile, baseName.. "#wheelIndices")) |
1793 | if indices ~= nil then |
1794 | entry.wheels = {} |
1795 | for _,wheelIndex in pairs(indices) do |
1796 | local wheel = self:getWheelFromWheelIndex(wheelIndex) |
1797 | if wheel ~= nil then |
1798 | table.insert(entry.wheels, wheel) |
1799 | else |
1800 | g_logManager:xmlWarning(self.configFileName, "Invalid wheelIndex '%s' for '%s'!", wheelIndex, baseName) |
1801 | end |
1802 | end |
1803 | end |
1804 | end |
1805 | end |
loadDischargeNode
DescriptionDefinitionloadDischargeNode()Code
2107 | function Cylindered:loadDischargeNode(superFunc, xmlFile, key, entry) |
2108 | if not superFunc(self, xmlFile, key, entry) then |
2109 | return false |
2110 | end |
2111 | |
2112 | local baseKey = key .. ".movingToolActivation" |
2113 | |
2114 | if hasXMLProperty(xmlFile, baseKey) then |
2115 | entry.movingToolActivation = {} |
2116 | entry.movingToolActivation.node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, baseKey.."#node"), self.i3dMappings) |
2117 | entry.movingToolActivation.isInverted = Utils.getNoNil(getXMLBool(xmlFile, baseKey.."#isInverted"), false) |
2118 | entry.movingToolActivation.openFactor = Utils.getNoNil(getXMLFloat(xmlFile, baseKey.."#openFactor"), 1) |
2119 | entry.movingToolActivation.openOffset = Utils.getNoNil(getXMLFloat(xmlFile, baseKey.."#openOffset"), 0) |
2120 | entry.movingToolActivation.openOffsetInv = 1-entry.movingToolActivation.openOffset |
2121 | end |
2122 | |
2123 | return true |
2124 | end |
loadDynamicMountGrabFromXML
DescriptionDefinitionloadDynamicMountGrabFromXML()Code
2192 | function Cylindered:loadDynamicMountGrabFromXML(superFunc, xmlFile, key, entry) |
2193 | if not superFunc(self, xmlFile, key, entry) then |
2194 | return false |
2195 | end |
2196 | |
2197 | local baseKey = key .. ".movingToolActivation" |
2198 | if not hasXMLProperty(xmlFile, baseKey) then |
2199 | return true |
2200 | end |
2201 | |
2202 | entry.movingToolActivation = {} |
2203 | entry.movingToolActivation.node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, baseKey.."#node"), self.i3dMappings) |
2204 | entry.movingToolActivation.isInverted = Utils.getNoNil(getXMLBool(xmlFile, baseKey.."#isInverted"), false) |
2205 | entry.movingToolActivation.openFactor = Utils.getNoNil(getXMLFloat(xmlFile, baseKey.."#openFactor"), 1) |
2206 | |
2207 | return true |
2208 | end |
loadExtraDependentParts
DescriptionDefinitionloadExtraDependentParts()Code
1846 | function Cylindered:loadExtraDependentParts(xmlFile, baseName, entry) |
1847 | return true |
1848 | end |
loadMovingPartFromXML
DescriptionDefinitionloadMovingPartFromXML()Code
1321 | function Cylindered:loadMovingPartFromXML(xmlFile, key, entry) |
1322 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key.."#index", key.."#node") --FS17 to FS19 |
1323 | |
1324 | local node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#node"), self.i3dMappings) |
1325 | local referenceFrame = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#referenceFrame"), self.i3dMappings) |
1326 | if node ~= nil and referenceFrame ~= nil then |
1327 | entry.referencePoint = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#referencePoint"), self.i3dMappings) |
1328 | entry.node = node |
1329 | entry.referenceFrame = referenceFrame |
1330 | entry.invertZ = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#invertZ"), false) |
1331 | entry.scaleZ = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#scaleZ"), false) |
1332 | entry.limitedAxis = getXMLInt(self.xmlFile, key.."#limitedAxis") |
1333 | entry.isActiveDirty = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#isActiveDirty"), false) |
1334 | entry.playSound = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#playSound"), false) |
1335 | |
1336 | entry.moveToReferenceFrame = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#moveToReferenceFrame"), false) |
1337 | if entry.moveToReferenceFrame then |
1338 | local x,y,z = worldToLocal(referenceFrame, getWorldTranslation(node)) |
1339 | entry.referenceFrameOffset = {x,y,z} |
1340 | end |
1341 | |
1342 | entry.doLineAlignment = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#doLineAlignment"), false) |
1343 | entry.partLength = Utils.getNoNil(getXMLFloat(self.xmlFile, key..".orientationLine#partLength"), 0.5) |
1344 | entry.orientationLineNodes = {} |
1345 | local i = 0 |
1346 | while true do |
1347 | local pointKey = string.format("%s.orientationLine.lineNode(%d)", key, i) |
1348 | if not hasXMLProperty(xmlFile, pointKey) then |
1349 | break |
1350 | end |
1351 | |
1352 | local lineNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, pointKey.."#node"), self.i3dMappings) |
1353 | table.insert(entry.orientationLineNodes, lineNode) |
1354 | |
1355 | i = i + 1 |
1356 | end |
1357 | |
1358 | entry.doDirectionAlignment = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#doDirectionAlignment"), true) |
1359 | entry.doRotationAlignment = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#doRotationAlignment"), false) |
1360 | entry.rotMultiplier = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#rotMultiplier"), 0) |
1361 | |
1362 | local minRot = getXMLFloat(self.xmlFile, key.."#minRot") |
1363 | local maxRot = getXMLFloat(self.xmlFile, key.."#maxRot") |
1364 | if minRot ~= nil and maxRot ~= nil then |
1365 | if entry.limitedAxis ~= nil then |
1366 | entry.minRot = MathUtil.getValidLimit(math.rad(minRot)) |
1367 | entry.maxRot = MathUtil.getValidLimit(math.rad(maxRot)) |
1368 | else |
1369 | print("Warning: minRot/maxRot requires the use of limitedAxis in '"..self.configFileName.."'") |
1370 | end |
1371 | end |
1372 | entry.alignToWorldY = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#alignToWorldY"), false) |
1373 | |
1374 | if entry.referencePoint ~= nil then |
1375 | local localReferencePoint = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, key.."#localReferencePoint"), self.i3dMappings) |
1376 | local refX, refY, refZ = worldToLocal(node, getWorldTranslation(entry.referencePoint)) |
1377 | if localReferencePoint ~= nil then |
1378 | local x,y,z = worldToLocal(node, getWorldTranslation(localReferencePoint)) |
1379 | |
1380 | entry.referenceDistance = MathUtil.vector3Length(refX-x, refY-y, refZ-z) |
1381 | entry.lastReferenceDistance = entry.referenceDistance |
1382 | entry.localReferencePoint = {x, y, z} |
1383 | |
1384 | local side = y*(refZ-z) - z*(refY-y) |
1385 | entry.localReferenceAngleSide = side |
1386 | entry.localReferencePointNode = localReferencePoint |
1387 | entry.updateLocalReferenceDistance = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#updateLocalReferenceDistance"), false) |
1388 | entry.localReferenceTranslate = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#localReferenceTranslate"), false) |
1389 | if entry.localReferenceTranslate then |
1390 | entry.localReferenceTranslation = { getTranslation(entry.node) } |
1391 | end |
1392 | else |
1393 | entry.referenceDistance = 0 |
1394 | entry.localReferencePoint = {refX, refY, refZ} |
1395 | end |
1396 | entry.referenceDistanceThreshold = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#referenceDistanceThreshold"), 0) |
1397 | |
1398 | entry.useLocalOffset = Utils.getNoNil(getXMLBool(self.xmlFile, key.."#useLocalOffset"), false) |
1399 | |
1400 | entry.localReferenceDistance = MathUtil.vector2Length(entry.localReferencePoint[2], entry.localReferencePoint[3]) |
1401 | |
1402 | self:loadDependentTranslatingParts(self.xmlFile, key, entry) |
1403 | end |
1404 | |
1405 | -- direction threshold for updateing the moving tools of the vehicle is entered/active |
1406 | entry.directionThreshold = Utils.getNoNil(getXMLFloat(self.xmlFile, key.."#directionThreshold"), 0.0001) |
1407 | entry.lastDirection = {0, 0, 0} |
1408 | entry.lastUpVector = {0, 0, 0} |
1409 | |
1410 | entry.isDirty = false |
1411 | entry.isPart = true |
1412 | |
1413 | return true |
1414 | end |
1415 | |
1416 | return false |
1417 | end |
loadMovingToolFromXML
DescriptionDefinitionloadMovingToolFromXML()Code
1421 | function Cylindered:loadMovingToolFromXML(xmlFile, key, entry) |
1422 | local spec = self.spec_cylindered |
1423 | |
1424 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key.."#index", key.."#node") --FS17 to FS19 |
1425 | |
1426 | local node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#node"), self.i3dMappings) |
1427 | if node ~= nil then |
1428 | entry.node = node |
1429 | |
1430 | entry.externalMove = 0 |
1431 | entry.easyArmControlActive = true |
1432 | entry.isEasyControlTarget = Utils.getNoNil(getXMLBool(xmlFile, key.."#isEasyControlTarget"), false) |
1433 | |
1434 | entry.networkInterpolators = {} |
1435 | |
1436 | -- rotation |
1437 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key.."#rotSpeed", key..".rotation#rotSpeed") --FS15 to FS17 |
1438 | |
1439 | local rotSpeed = getXMLFloat(xmlFile, key..".rotation#rotSpeed") |
1440 | if rotSpeed ~= nil then |
1441 | entry.rotSpeed = math.rad(rotSpeed)/1000 |
1442 | end |
1443 | local rotAcceleration = getXMLFloat(xmlFile, key..".rotation#rotAcceleration") |
1444 | if rotAcceleration ~= nil then |
1445 | entry.rotAcceleration = math.rad(rotAcceleration)/(1000*1000) |
1446 | end |
1447 | entry.lastRotSpeed = 0 |
1448 | local rotMax = getXMLFloat(xmlFile, key..".rotation#rotMax") |
1449 | if rotMax ~= nil then |
1450 | entry.rotMax = math.rad(rotMax) |
1451 | end |
1452 | local rotMin = getXMLFloat(xmlFile, key..".rotation#rotMin") |
1453 | if rotMin ~= nil then |
1454 | entry.rotMin = math.rad(rotMin) |
1455 | end |
1456 | entry.syncMaxRotLimits = Utils.getNoNil(getXMLBool(xmlFile, key..".rotation#syncMaxRotLimits"), false) |
1457 | entry.syncMinRotLimits = Utils.getNoNil(getXMLBool(xmlFile, key..".rotation#syncMinRotLimits"), false) |
1458 | entry.rotSendNumBits = Utils.getNoNil(getXMLInt(xmlFile, key..".rotation#rotSendNumBits"), 8) |
1459 | local attachRotMax = getXMLFloat(xmlFile, key..".rotation#attachRotMax") |
1460 | if attachRotMax ~= nil then |
1461 | entry.attachRotMax = math.rad(attachRotMax) |
1462 | end |
1463 | local attachRotMin = getXMLFloat(xmlFile, key..".rotation#attachRotMin") |
1464 | if attachRotMin ~= nil then |
1465 | entry.attachRotMin = math.rad(attachRotMin) |
1466 | end |
1467 | |
1468 | -- translation |
1469 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key.."#transSpeed", key..".rotation#transSpeed") --FS15 to FS17 |
1470 | |
1471 | local transSpeed = getXMLFloat(xmlFile, key..".translation#transSpeed") |
1472 | if transSpeed ~= nil then |
1473 | entry.transSpeed = transSpeed/1000 |
1474 | end |
1475 | local transAcceleration = getXMLFloat(xmlFile, key..".translation#transAcceleration") |
1476 | if transAcceleration ~= nil then |
1477 | entry.transAcceleration = transAcceleration/(1000*1000) |
1478 | end |
1479 | entry.lastTransSpeed = 0 |
1480 | entry.transMax = getXMLFloat(xmlFile, key..".translation#transMax") |
1481 | entry.transMin = getXMLFloat(xmlFile, key..".translation#transMin") |
1482 | entry.attachTransMax = getXMLFloat(xmlFile, key..".translation#attachTransMax") |
1483 | entry.attachTransMin = getXMLFloat(xmlFile, key..".translation#attachTransMin") |
1484 | entry.playSound = Utils.getNoNil(getXMLBool(xmlFile, key.."#playSound"), false) |
1485 | |
1486 | -- animation |
1487 | if SpecializationUtil.hasSpecialization(AnimatedVehicle, self.specializations) then |
1488 | local animSpeed = getXMLFloat(xmlFile, key..".animation#animSpeed") |
1489 | if animSpeed ~= nil then |
1490 | entry.animSpeed = animSpeed / 1000 |
1491 | end |
1492 | local animAcceleration = getXMLFloat(xmlFile, key..".animation#animAcceleration") |
1493 | if animAcceleration ~= nil then |
1494 | entry.animAcceleration = animAcceleration / (1000*1000) |
1495 | end |
1496 | entry.curAnimTime = 0 |
1497 | entry.lastAnimSpeed = 0 |
1498 | entry.animName = getXMLString(xmlFile, key..".animation#animName") |
1499 | entry.animSendNumBits = Utils.getNoNil(getXMLInt(xmlFile, key..".animation#animSendNumBits"), 8) |
1500 | entry.animMaxTime = math.min(Utils.getNoNil(getXMLFloat(xmlFile, key..".animation#animMaxTime"), 1.0), 1.0) |
1501 | entry.animMinTime = math.max(Utils.getNoNil(getXMLFloat(xmlFile, key..".animation#animMinTime"), 0.0), 0.0) |
1502 | |
1503 | local animStartTime = getXMLFloat(xmlFile, key..".animation#animStartTime") |
1504 | if animStartTime ~= nil then |
1505 | entry.curAnimTime = animStartTime |
1506 | self:setAnimationTime(entry.animName, animStartTime) |
1507 | end |
1508 | |
1509 | entry.networkInterpolators.animation = InterpolatorValue:new(entry.curAnimTime) |
1510 | entry.networkInterpolators.animation:setMinMax(0, 1) |
1511 | end |
1512 | |
1513 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key..".controls#iconFilename", key..".controls#iconName") --FS17 to FS19 |
1514 | |
1515 | local iconName = getXMLString(xmlFile, key .. ".controls#iconName") |
1516 | if iconName ~= nil then |
1517 | if InputHelpElement.AXIS_ICON[iconName] == nil then |
1518 | -- add the mod name as a prefix to match axis icon loading name collision avoidance |
1519 | iconName = (self.customEnvironment or "") .. iconName |
1520 | end |
1521 | |
1522 | entry.axisActionIcon = iconName |
1523 | end |
1524 | |
1525 | entry.controlGroupIndex = getXMLInt(xmlFile, key .. ".controls#groupIndex") or 0 |
1526 | if entry.controlGroupIndex ~= 0 then |
1527 | if spec.controlGroupNames[entry.controlGroupIndex] ~= nil then |
1528 | ListUtil.addElementToList(spec.controlGroups, entry.controlGroupIndex) |
1529 | else |
1530 | g_logManager:xmlWarning(self.configFileName, "ControlGroup '%d' not defined for '%s'!", entry.controlGroupIndex, key) |
1531 | end |
1532 | end |
1533 | |
1534 | entry.axis = getXMLString(xmlFile, key..".controls#axis") |
1535 | if entry.axis ~= nil then |
1536 | entry.axisActionIndex = InputAction[entry.axis] |
1537 | end |
1538 | entry.invertAxis = Utils.getNoNil(getXMLBool(xmlFile, key..".controls#invertAxis"), false) |
1539 | entry.mouseSpeedFactor = Utils.getNoNil(getXMLFloat(xmlFile, key..".controls#mouseSpeedFactor"), 1.0) |
1540 | |
1541 | if (entry.rotSpeed ~= nil or entry.transSpeed ~= nil or entry.animSpeed ~= nil) then |
1542 | entry.dirtyFlag = self:getNextDirtyFlag() |
1543 | entry.saving = Utils.getNoNil(getXMLBool(xmlFile, key.."#allowSaving"), true) |
1544 | end |
1545 | |
1546 | entry.isDirty = false |
1547 | entry.isIntitialDirty = Utils.getNoNil(getXMLBool(xmlFile, key.."#isIntitialDirty"), true) |
1548 | |
1549 | entry.rotationAxis = Utils.getNoNil(getXMLInt(xmlFile, key..".rotation#rotationAxis"), 1) |
1550 | entry.translationAxis = Utils.getNoNil(getXMLInt(xmlFile, key..".translation#translationAxis"), 3) |
1551 | |
1552 | local detachingRotMaxLimit = getXMLFloat(xmlFile, key..".rotation#detachingRotMaxLimit") |
1553 | local detachingRotMinLimit = getXMLFloat(xmlFile, key..".rotation#detachingRotMinLimit") |
1554 | local detachingTransMaxLimit = getXMLFloat(xmlFile, key..".translation#detachingTransMaxLimit") |
1555 | local detachingTransMinLimit = getXMLFloat(xmlFile, key..".translation#detachingTransMinLimit") |
1556 | if detachingRotMaxLimit ~= nil or detachingRotMinLimit ~= nil or detachingTransMaxLimit ~= nil or detachingTransMinLimit ~= nil then |
1557 | if spec.detachLockNodes == nil then |
1558 | spec.detachLockNodes = {} |
1559 | end |
1560 | |
1561 | local detachLock = {} |
1562 | if detachingRotMaxLimit ~= nil then |
1563 | detachLock.detachingRotMaxLimit = math.rad(detachingRotMaxLimit) |
1564 | end |
1565 | if detachingRotMinLimit ~= nil then |
1566 | detachLock.detachingRotMinLimit = math.rad(detachingRotMinLimit) |
1567 | end |
1568 | detachLock.detachingTransMinLimit = detachingTransMinLimit |
1569 | detachLock.detachingTransMaxLimit = detachingTransMaxLimit |
1570 | |
1571 | spec.detachLockNodes[entry] = detachLock |
1572 | end |
1573 | |
1574 | |
1575 | local rx,ry,rz = getRotation(node) |
1576 | entry.curRot = {rx,ry,rz} |
1577 | local x,y,z = getTranslation(node) |
1578 | entry.curTrans = {x,y,z} |
1579 | |
1580 | entry.startRot = getXMLFloat(xmlFile, key..".rotation#startRot") |
1581 | if entry.startRot ~= nil then |
1582 | entry.startRot = math.rad(entry.startRot) |
1583 | end |
1584 | entry.startTrans = getXMLFloat(xmlFile, key..".translation#startTrans") |
1585 | |
1586 | entry.move = 0 |
1587 | entry.moveToSend = 0 |
1588 | |
1589 | -- delayed node |
1590 | XMLUtil.checkDeprecatedXMLElements(xmlFile, self.configFileName, key.."#delayedIndex", key.."#delayedNode") --FS17 to FS19 |
1591 | |
1592 | entry.delayedNode = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, key.."#delayedNode"), self.i3dMappings) |
1593 | if entry.delayedNode ~= nil then |
1594 | entry.currentDelayedData = {rot = {rx, ry, rz}, trans = {x, y, z}} |
1595 | entry.delayedHistroyData = {} |
1596 | entry.delayedHistroyData[1] = {rot = {rx, ry, rz}, trans = {x, y, z}} |
1597 | entry.delayedHistroyData[2] = {rot = {rx, ry, rz}, trans = {x, y, z}} |
1598 | entry.delayedHistroyData[3] = {rot = {rx, ry, rz}, trans = {x, y, z}} |
1599 | entry.delayedHistoryIndex = 0 |
1600 | end |
1601 | |
1602 | entry.networkInterpolators.translation = InterpolatorValue:new(entry.curTrans[entry.translationAxis]) |
1603 | entry.networkInterpolators.translation:setMinMax(entry.transMin, entry.transMax) |
1604 | entry.networkInterpolators.rotation = InterpolatorAngle:new(entry.curRot[entry.rotationAxis]) |
1605 | entry.networkInterpolators.rotation:setMinMax(entry.rotMin, entry.rotMax) |
1606 | entry.networkTimeInterpolator = InterpolationTime:new(1.2) |
1607 | |
1608 | entry.isTool = true |
1609 | |
1610 | return true |
1611 | end |
1612 | |
1613 | return false |
1614 | end |
loadObjectChangeValuesFromXML
DescriptionLoad object change from xmlDefinition
loadObjectChangeValuesFromXML(integer xmlFile, string key, integer node, table object)Arguments
integer | xmlFile | id of xml object |
string | key | key |
integer | node | node id |
table | object | object |
2070 | function Cylindered:loadObjectChangeValuesFromXML(superFunc, xmlFile, key, node, object) |
2071 | superFunc(self, xmlFile, key, node, object) |
2072 | |
2073 | local spec = self.spec_cylindered |
2074 | |
2075 | if spec.nodesToMovingTools ~= nil and spec.nodesToMovingTools[node] ~= nil then |
2076 | local movingTool = spec.nodesToMovingTools[node] |
2077 | object.movingToolRotMaxActive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMaxActive"), movingTool.rotMax) |
2078 | object.movingToolRotMaxInactive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMaxInactive"), movingTool.rotMax) |
2079 | object.movingToolRotMinActive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMinActive"), movingTool.rotMin) |
2080 | object.movingToolRotMinInactive = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#movingToolRotMinInactive"), movingTool.rotMin) |
2081 | end |
2082 | end |
loadRotationBasedLimits
DescriptionDefinitionloadRotationBasedLimits()Code
1928 | function Cylindered:loadRotationBasedLimits(xmlFile, key, tool) |
1929 | local rotation = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#rotation"), nil) |
1930 | local rotMin = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#rotMin"), nil) |
1931 | local rotMax = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#rotMax"), nil) |
1932 | local transMin = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#transMin"), nil) |
1933 | local transMax = Utils.getNoNilRad(getXMLFloat(xmlFile, key.."#transMax"), nil) |
1934 | |
1935 | if rotation ~= nil and (rotMin ~= nil or rotMax ~= nil or transMin ~= nil or transMax ~= nil) then |
1936 | local time = (rotation-tool.rotMin) / (tool.rotMax-tool.rotMin) |
1937 | return {rotMin=rotMin, rotMax=rotMax, transMin=transMin, transMax=transMax, time=time} |
1938 | end |
1939 | |
1940 | return nil |
1941 | end |
loadShovelNode
DescriptionDefinitionloadShovelNode()Code
2152 | function Cylindered:loadShovelNode(superFunc, xmlFile, key, entry) |
2153 | if not superFunc(self, xmlFile, key, entry) then |
2154 | return false |
2155 | end |
2156 | |
2157 | local baseKey = key .. ".movingToolActivation" |
2158 | if not hasXMLProperty(xmlFile, baseKey) then |
2159 | return true |
2160 | end |
2161 | |
2162 | entry.movingToolActivation = {} |
2163 | entry.movingToolActivation.node = I3DUtil.indexToObject(self.components, getXMLString(xmlFile, baseKey.."#node"), self.i3dMappings) |
2164 | entry.movingToolActivation.isInverted = Utils.getNoNil(getXMLBool(xmlFile, baseKey.."#isInverted"), false) |
2165 | entry.movingToolActivation.openFactor = Utils.getNoNil(getXMLFloat(xmlFile, baseKey.."#openFactor"), 1) |
2166 | |
2167 | return true |
2168 | end |
movingToolDashboardAttributes
DescriptionDefinitionmovingToolDashboardAttributes()Code
3064 | function Cylindered.movingToolDashboardAttributes(self, xmlFile, key, dashboard) |
3065 | dashboard.axis = getXMLString(xmlFile, key.."#axis") |
3066 | |
3067 | if dashboard.axis == nil then |
3068 | g_logManager:xmlWarning(self.configFileName, "Misssing axis attribute for dashboard '%s'", key) |
3069 | return false |
3070 | end |
3071 | |
3072 | dashboard.attacherJointIndex = getXMLInt(xmlFile, key.."#attacherJointIndex") |
3073 | |
3074 | return true |
3075 | end |
onDeactivate
DescriptionCalled on deactivateDefinition
onDeactivate()Code
2382 | function Cylindered:onDeactivate() |
2383 | if self.isClient then |
2384 | local spec = self.spec_cylindered |
2385 | g_soundManager:stopSample(spec.samples.hydraulic) |
2386 | spec.isHydraulicSamplePlaying = false |
2387 | end |
2388 | end |
onDelete
DescriptionCalled on deletingDefinition
onDelete()Code
516 | function Cylindered:onDelete() |
517 | local spec = self.spec_cylindered |
518 | |
519 | if self.isClient then |
520 | g_soundManager:deleteSamples(spec.samples) |
521 | end |
522 | |
523 | for _,movingTool in pairs(spec.movingTools) do |
524 | if movingTool.icon ~= nil then |
525 | movingTool.icon:delete() |
526 | movingTool.icon = nil |
527 | end |
528 | end |
529 | end |
onDraw
DescriptionDefinitiononDraw()Code
1310 | function Cylindered:onDraw(isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
1311 | local spec = self.spec_cylindered |
1312 | if #spec.controlGroupNames > 1 then |
1313 | if isActiveForInputIgnoreSelection then |
1314 | g_currentMission:addExtraPrintText(string.format(g_i18n:getText("action_selectedControlGroup"), spec.controlGroupNames[spec.currentControlGroupIndex], spec.currentControlGroupIndex)) |
1315 | end |
1316 | end |
1317 | end |
onLoad
DescriptionCalled on loadingDefinition
onLoad(table savegame)Arguments
table | savegame | savegame |
101 | function Cylindered:onLoad(savegame) |
102 | local spec = self.spec_cylindered |
103 | |
104 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.movingParts", "vehicle.cylindered.movingParts") --FS17 to FS19 |
105 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.movingTools", "vehicle.cylindered.movingTools") --FS17 to FS19 |
106 | XMLUtil.checkDeprecatedXMLElements(self.xmlFile, self.configFileName, "vehicle.cylinderedHydraulicSound", "vehicle.cylindered.sounds.hydraulic") --FS17 to FS19 |
107 | |
108 | spec.samples = {} |
109 | if self.isClient then |
110 | spec.samples.hydraulic = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.cylindered.sounds", "hydraulic", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self) |
111 | spec.isHydraulicSamplePlaying = false |
112 | end |
113 | |
114 | spec.activeDirtyMovingParts = {} |
115 | |
116 | local referenceNodes = {} |
117 | spec.nodesToMovingParts = {} |
118 | spec.movingParts = {} |
119 | self.anyMovingPartsDirty = false |
120 | spec.detachLockNodes = nil |
121 | local i = 0 |
122 | while true do |
123 | local partKey = string.format("vehicle.cylindered.movingParts.movingPart(%d)", i) |
124 | if not hasXMLProperty(self.xmlFile, partKey) then |
125 | break |
126 | end |
127 | |
128 | local entry = {} |
129 | if self:loadMovingPartFromXML(self.xmlFile, partKey, entry) then |
130 | if referenceNodes[entry.node] == nil then |
131 | referenceNodes[entry.node] = {} |
132 | end |
133 | if spec.nodesToMovingParts[entry.node] == nil then |
134 | table.insert(referenceNodes[entry.node], entry) |
135 | |
136 | self:loadDependentParts(self.xmlFile, partKey, entry) |
137 | self:loadDependentComponentJoints(self.xmlFile, partKey, entry) |
138 | self:loadCopyLocalDirectionParts(self.xmlFile, partKey, entry) |
139 | self:loadExtraDependentParts(self.xmlFile, partKey, entry) |
140 | self:loadDependentAnimations(self.xmlFile, partKey, entry) |
141 | |
142 | entry.key = partKey |
143 | table.insert(spec.movingParts, entry) |
144 | |
145 | if entry.isActiveDirty then |
146 | table.insert(spec.activeDirtyMovingParts, entry) |
147 | end |
148 | |
149 | spec.nodesToMovingParts[entry.node] = entry |
150 | else |
151 | g_logManager:xmlWarning(self.configFileName, "Moving part with node '%s' already exists!", getName(entry.node)) |
152 | end |
153 | end |
154 | |
155 | i = i + 1 |
156 | end |
157 | |
158 | spec.isActiveDirtyTimeOffset = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.cylindered.movingParts#isActiveDirtyTimeOffset"), 0) * 1000 |
159 | spec.isActiveDirtyTime = g_currentMission.time |
160 | |
161 | -- find dependencies |
162 | for _, part in pairs(spec.movingParts) do |
163 | part.dependentParts = {} |
164 | for _, ref in pairs(part.dependentPartNodes) do |
165 | if referenceNodes[ref] ~= nil then |
166 | for _, p in pairs(referenceNodes[ref]) do |
167 | part.dependentParts[p] = p |
168 | p.isDependentPart = true |
169 | end |
170 | end |
171 | end |
172 | end |
173 | |
174 | local function addMovingPart(part, newTable, allowDependentParts) |
175 | for _, addedPart in ipairs(newTable) do |
176 | if addedPart == part then |
177 | return |
178 | end |
179 | end |
180 | |
181 | if part.isDependentPart == true then |
182 | if allowDependentParts ~= true then |
183 | return |
184 | end |
185 | end |
186 | |
187 | table.insert(newTable, part) |
188 | |
189 | for _, depPart in pairs(part.dependentParts) do |
190 | addMovingPart(depPart, newTable, true) |
191 | end |
192 | end |
193 | |
194 | local newParts = {} |
195 | for _, part in ipairs(spec.movingParts) do |
196 | addMovingPart(part, newParts) |
197 | end |
198 | spec.movingParts = newParts |
199 | |
200 | spec.controlGroups = {} |
201 | spec.controlGroupMapping = {} |
202 | spec.currentControlGroupIndex = 1 |
203 | spec.controlGroupNames = {} |
204 | local i = 0 |
205 | while true do |
206 | local groupKey = string.format("vehicle.cylindered.movingTools.controlGroups.controlGroup(%d)", i) |
207 | if not hasXMLProperty(self.xmlFile, groupKey) then |
208 | break |
209 | end |
210 | |
211 | local name = getXMLString(self.xmlFile, groupKey.."#name") |
212 | if name ~= nil then |
213 | table.insert(spec.controlGroupNames, g_i18n:convertText(name, self.customEnvironment)) |
214 | end |
215 | |
216 | i = i + 1 |
217 | end |
218 | |
219 | spec.nodesToMovingTools = {} |
220 | spec.movingTools = {} |
221 | local i = 0 |
222 | while true do |
223 | local toolKey = string.format("vehicle.cylindered.movingTools.movingTool(%d)", i) |
224 | if not hasXMLProperty(self.xmlFile, toolKey) then |
225 | break |
226 | end |
227 | |
228 | local entry = {} |
229 | if self:loadMovingToolFromXML(self.xmlFile, toolKey, entry) then |
230 | if referenceNodes[entry.node] == nil then |
231 | referenceNodes[entry.node] = {} |
232 | end |
233 | |
234 | if spec.nodesToMovingTools[entry.node] == nil then |
235 | table.insert(referenceNodes[entry.node], entry) |
236 | |
237 | self:loadDependentMovingTools(self.xmlFile, toolKey, entry) |
238 | self:loadDependentParts(self.xmlFile, toolKey, entry) |
239 | self:loadDependentComponentJoints(self.xmlFile, toolKey, entry) |
240 | self:loadExtraDependentParts(self.xmlFile, toolKey, entry) |
241 | self:loadDependentAnimations(self.xmlFile, toolKey, entry) |
242 | |
243 | entry.isActive = true |
244 | entry.key = toolKey |
245 | table.insert(spec.movingTools, entry) |
246 | spec.nodesToMovingTools[entry.node] = entry |
247 | else |
248 | g_logManager:xmlWarning(self.configFileName, "Moving tool with node '%s' already exists!", getName(entry.node)) |
249 | end |
250 | end |
251 | i = i + 1 |
252 | end |
253 | |
254 | for _, groupIndex in ipairs(spec.controlGroups) do |
255 | local subSelectionIndex = self:addSubselection(groupIndex) |
256 | spec.controlGroupMapping[subSelectionIndex] = groupIndex |
257 | end |
258 | |
259 | for _, part in pairs(spec.movingTools) do |
260 | part.dependentParts = {} |
261 | for _, ref in pairs(part.dependentPartNodes) do |
262 | if referenceNodes[ref] ~= nil then |
263 | for _, p in pairs(referenceNodes[ref]) do |
264 | part.dependentParts[p] = p |
265 | end |
266 | end |
267 | end |
268 | for i=#part.dependentMovingTools, 1, -1 do |
269 | local dependentTool = part.dependentMovingTools[i] |
270 | local tool = spec.nodesToMovingTools[dependentTool.node] |
271 | if tool ~= nil then |
272 | dependentTool.movingTool = tool |
273 | else |
274 | g_logManager:xmlWarning(self.configFileName, "Dependent moving tool '%s' not defined. Ignoring it!", getName(dependentTool.node)) |
275 | table.remove(part.dependentMovingTools, i) |
276 | end |
277 | end |
278 | end |
279 | |
280 | |
281 | local simpleKey = "vehicle.cylindered.movingTools.easyArmControl" |
282 | if hasXMLProperty(self.xmlFile, simpleKey) then |
283 | spec.easyArmControl = {} |
284 | spec.easyArmControl.rootNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, simpleKey.."#rootNode"), self.i3dMappings) |
285 | spec.easyArmControl.targetNodeY = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, simpleKey.."#node"), self.i3dMappings) |
286 | spec.easyArmControl.targetNodeZ = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, simpleKey.."#targetNodeZ"), self.i3dMappings) or spec.easyArmControl.targetNodeY |
287 | |
288 | if spec.easyArmControl.targetNodeZ ~= nil and spec.easyArmControl.targetNodeY ~= nil then |
289 | local targetYTool = self:getMovingToolByNode(spec.easyArmControl.targetNodeY) |
290 | local targetZTool = self:getMovingToolByNode(spec.easyArmControl.targetNodeZ) |
291 | if targetYTool ~= nil and targetZTool ~= nil then |
292 | spec.easyArmControl.targetNode = spec.easyArmControl.targetNodeZ |
293 | if getParent(spec.easyArmControl.targetNodeY) == spec.easyArmControl.targetNodeZ then |
294 | spec.easyArmControl.targetNode = spec.easyArmControl.targetNodeY |
295 | end |
296 | spec.easyArmControl.targetRefNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, simpleKey.."#refNode"), self.i3dMappings) |
297 | spec.easyArmControl.lastValidPositionY = {getTranslation(spec.easyArmControl.targetNodeY)} |
298 | spec.easyArmControl.lastValidPositionZ = {getTranslation(spec.easyArmControl.targetNodeZ)} |
299 | spec.easyArmControl.xRotationMaxDistance = getXMLFloat(self.xmlFile, simpleKey..".xRotationNodes#maxDistance") or 0 |
300 | spec.easyArmControl.xRotationNodes = {} |
301 | spec.easyArmControl.zTranslationNodes = {} |
302 | |
303 | i = 0 |
304 | local maxTrans = 0 |
305 | while true do |
306 | local transKey = string.format("%s.zTranslationNodes.zTranslationNode(%d)", simpleKey, i) |
307 | if not hasXMLProperty(self.xmlFile, transKey) then |
308 | break |
309 | end |
310 | |
311 | local node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, transKey.."#node"), self.i3dMappings) |
312 | if node ~= nil then |
313 | local movingTool = self:getMovingToolByNode(node) |
314 | if movingTool ~= nil then |
315 | local maxDistance = math.abs(movingTool.transMin - movingTool.transMax) |
316 | maxTrans = maxTrans + maxDistance |
317 | movingTool.easyArmControlActive = false |
318 | table.insert(spec.easyArmControl.zTranslationNodes, {node=node, movingTool=movingTool, maxDistance=maxDistance, transFactor=0}) |
319 | end |
320 | end |
321 | |
322 | i = i + 1 |
323 | end |
324 | |
325 | for _, translationNode in ipairs(spec.easyArmControl.zTranslationNodes) do |
326 | translationNode.transFactor = translationNode.maxDistance / maxTrans |
327 | end |
328 | |
329 | for i=1, 2 do |
330 | local xRotKey = string.format("%s.xRotationNodes.xRotationNode%d", simpleKey, i) |
331 | if not hasXMLProperty(self.xmlFile, xRotKey) then |
332 | g_logManager:xmlWarning(self.configFileName, "Missing second xRotation node for easy control!") |
333 | spec.easyArmControl = nil |
334 | break |
335 | end |
336 | |
337 | local node = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, xRotKey.."#node"), self.i3dMappings) |
338 | local refNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, xRotKey.."#refNode"), self.i3dMappings) |
339 | if node ~= nil and refNode ~= nil then |
340 | local movingTool = self:getMovingToolByNode(node) |
341 | if movingTool ~= nil then |
342 | movingTool.easyArmControlActive = false |
343 | table.insert(spec.easyArmControl.xRotationNodes, {node=node, refNode=refNode, movingTool=movingTool}) |
344 | end |
345 | end |
346 | end |
347 | else |
348 | g_logManager:xmlError(self.configFileName, "Missing moving tools for easy control targets!") |
349 | spec.easyArmControl = nil |
350 | end |
351 | else |
352 | g_logManager:xmlError(self.configFileName, "Missing easy control targets!") |
353 | spec.easyArmControl = nil |
354 | end |
355 | end |
356 | |
357 | if self.loadDashboardsFromXML ~= nil then |
358 | local dashboardData = {valueTypeToLoad = "movingTool", |
359 | valueObject = self, |
360 | valueFunc = Cylindered.getMovingToolDashboardState, |
361 | minFunc = 0, |
362 | maxFunc = 1, |
363 | additionalAttributesFunc = Cylindered.movingToolDashboardAttributes, |
364 | idleValue = 0.5} |
365 | |
366 | self:loadDashboardsFromXML(self.xmlFile, "vehicle.cylindered.dashboards", dashboardData) |
367 | end |
368 | |
369 | if self.isClient and g_isDevelopmentVersion then |
370 | if (#spec.movingParts > 0 or #spec.movingTools > 0) and spec.samples.hydraulic == nil then |
371 | g_logManager:xmlDevWarning(self.configFileName, "Missing cylindered hydraulic sound") |
372 | end |
373 | end |
374 | |
375 | spec.cylinderedDirtyFlag = self:getNextDirtyFlag() |
376 | spec.cylinderedInputDirtyFlag = self:getNextDirtyFlag() |
377 | |
378 | spec.isLoading = true |
379 | end |
onLoadFinished
DescriptionCalled after loadingDefinition
onLoadFinished(table savegame)Arguments
table | savegame | savegame |
502 | function Cylindered:onLoadFinished(savegame) |
503 | local spec = self.spec_cylindered |
504 | spec.isLoading = false |
505 | |
506 | for i=1, table.getn(spec.movingTools) do |
507 | local tool = spec.movingTools[i] |
508 | if tool.delayedHistoryIndex ~= nil and tool.delayedHistoryIndex > 0 then |
509 | self:updateDelayedTool(tool, true) |
510 | end |
511 | end |
512 | end |
onPostAttach
DescriptionCalled if vehicle gets attachedDefinition
onPostAttach(table attacherVehicle, integer inputJointDescIndex, integer jointDescIndex)Arguments
table | attacherVehicle | attacher vehicle |
integer | inputJointDescIndex | index of input attacher joint |
integer | jointDescIndex | index of attacher joint it gets attached to |
2316 | function Cylindered:onPostAttach(attacherVehicle, inputJointDescIndex, jointDescIndex) |
2317 | local spec = self.spec_cylindered |
2318 | |
2319 | for _, tool in ipairs(spec.movingTools) do |
2320 | local changed = false |
2321 | if tool.transSpeed ~= nil then |
2322 | local trans = tool.curTrans[tool.translationAxis] |
2323 | |
2324 | local changedTrans = false |
2325 | if tool.attachTransMax ~= nil and trans > tool.attachTransMax then |
2326 | trans = tool.attachTransMax |
2327 | changedTrans = true |
2328 | elseif tool.attachTransMin ~= nil and trans < tool.attachTransMin then |
2329 | trans = tool.attachTransMin |
2330 | changedTrans = true |
2331 | end |
2332 | if changedTrans then |
2333 | tool.curTrans[tool.translationAxis] = trans |
2334 | setTranslation(tool.node, unpack(tool.curTrans)) |
2335 | changed = true |
2336 | end |
2337 | end |
2338 | if tool.rotSpeed ~= nil then |
2339 | local rot = tool.curRot[tool.rotationAxis] |
2340 | |
2341 | local changedRot = false |
2342 | if tool.attachRotMax ~= nil and rot > tool.attachRotMax then |
2343 | rot = tool.attachRotMax |
2344 | changedRot = true |
2345 | elseif tool.attachRotMin ~= nil and rot < tool.attachRotMin then |
2346 | rot = tool.attachRotMin |
2347 | changedRot = true |
2348 | end |
2349 | if changedRot then |
2350 | tool.curRot[tool.rotationAxis] = rot |
2351 | setRotation(tool.node, unpack(tool.curRot)) |
2352 | changed = true |
2353 | end |
2354 | end |
2355 | if changed then |
2356 | Cylindered.setDirty(self, tool) |
2357 | end |
2358 | end |
2359 | end |
onPostLoad
DescriptionCalled after loadingDefinition
onPostLoad(table savegame)Arguments
table | savegame | savegame |
384 | function Cylindered:onPostLoad(savegame) |
385 | local spec = self.spec_cylindered |
386 | |
387 | for _, tool in pairs(spec.movingTools) do |
388 | if self:getIsMovingToolActive(tool) then |
389 | if tool.startRot ~= nil then |
390 | tool.curRot[tool.rotationAxis] = tool.startRot |
391 | setRotation(tool.node, unpack(tool.curRot)) |
392 | end |
393 | if tool.startTrans ~= nil then |
394 | tool.curTrans[tool.translationAxis] = tool.startTrans |
395 | setTranslation(tool.node, unpack(tool.curTrans)) |
396 | end |
397 | |
398 | if tool.delayedNode ~= nil then |
399 | self:setDelayedData(tool, true) |
400 | end |
401 | |
402 | if tool.isIntitialDirty then |
403 | Cylindered.setDirty(self, tool) |
404 | end |
405 | end |
406 | end |
407 | |
408 | for _, part in pairs(spec.movingParts) do |
409 | self:loadDependentAttacherJoints(self.xmlFile, part.key, part) |
410 | self:loadDependentWheels(self.xmlFile, part.key, part) |
411 | end |
412 | |
413 | for _, tool in pairs(spec.movingTools) do |
414 | self:loadDependentAttacherJoints(self.xmlFile, tool.key, tool) |
415 | self:loadDependentWheels(self.xmlFile, tool.key, tool) |
416 | end |
417 | |
418 | if self:allowLoadMovingToolStates() then |
419 | if savegame ~= nil and not savegame.resetVehicles then |
420 | local i = 0 |
421 | for _, tool in ipairs(spec.movingTools) do |
422 | if tool.saving then |
423 | if self:getIsMovingToolActive(tool) then |
424 | local toolKey = string.format("%s.cylindered.movingTool(%d)", savegame.key, i) |
425 | local changed = false |
426 | if tool.transSpeed ~= nil then |
427 | local newTrans = getXMLFloat(savegame.xmlFile, toolKey.."#translation") |
428 | if newTrans ~= nil then |
429 | if tool.transMax ~= nil then |
430 | newTrans = math.min(newTrans, tool.transMax) |
431 | end |
432 | if tool.transMin ~= nil then |
433 | newTrans = math.max(newTrans, tool.transMin) |
434 | end |
435 | end |
436 | if newTrans ~= nil and math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then |
437 | tool.curTrans = {getTranslation(tool.node)} |
438 | tool.curTrans[tool.translationAxis] = newTrans |
439 | setTranslation(tool.node, unpack(tool.curTrans)) |
440 | changed = true |
441 | end |
442 | end |
443 | if tool.rotSpeed ~= nil then |
444 | local newRot = getXMLFloat(savegame.xmlFile, toolKey.."#rotation") |
445 | if newRot ~= nil then |
446 | if tool.rotMax ~= nil then |
447 | newRot = math.min(newRot, tool.rotMax) |
448 | end |
449 | if tool.rotMin ~= nil then |
450 | newRot = math.max(newRot, tool.rotMin) |
451 | end |
452 | end |
453 | if newRot ~= nil and math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then |
454 | tool.curRot = {getRotation(tool.node)} |
455 | tool.curRot[tool.rotationAxis] = newRot |
456 | setRotation(tool.node, unpack(tool.curRot)) |
457 | changed = true |
458 | end |
459 | end |
460 | if tool.animSpeed ~= nil then |
461 | local animTime = getXMLFloat(savegame.xmlFile, toolKey.."#animationTime") |
462 | if animTime ~= nil then |
463 | if tool.animMinTime ~= nil then |
464 | animTime = math.max(animTime, tool.animMinTime) |
465 | end |
466 | if tool.animMaxTime ~= nil then |
467 | animTime = math.min(animTime, tool.animMaxTime) |
468 | end |
469 | |
470 | tool.curAnimTime = animTime |
471 | self:setAnimationTime(tool.animName, animTime, true) |
472 | end |
473 | end |
474 | if changed then |
475 | Cylindered.setDirty(self, tool) |
476 | end |
477 | |
478 | if tool.delayedNode ~= nil then |
479 | self:setDelayedData(tool, true) |
480 | end |
481 | end |
482 | i = i + 1 |
483 | end |
484 | |
485 | for _, dependentTool in pairs(tool.dependentMovingTools) do |
486 | Cylindered.updateRotationBasedLimits(self, tool, dependentTool) |
487 | end |
488 | end |
489 | end |
490 | end |
491 | |
492 | self:updateEasyControl(9999, true) |
493 | self:updateCylinderedInitial(false) |
494 | |
495 | -- force update after loading, e.g. savegame |
496 | spec.isActiveDirtyTime = g_currentMission.time + math.max(spec.isActiveDirtyTimeOffset, 1000) |
497 | end |
onPostUpdate
DescriptionDefinitiononPostUpdate()Code
1247 | function Cylindered:onPostUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
1248 | local spec = self.spec_cylindered |
1249 | |
1250 | spec.isActiveDirtyTime = g_currentMission.time + spec.isActiveDirtyTimeOffset |
1251 | |
1252 | if spec.isActiveDirtyTime >= g_currentMission.time then |
1253 | for _, part in pairs(spec.activeDirtyMovingParts) do |
1254 | Cylindered.setDirty(self, part) |
1255 | end |
1256 | end |
1257 | |
1258 | for _, tool in pairs(spec.movingTools) do |
1259 | if tool.isDirty then |
1260 | if tool.playSound then |
1261 | spec.movingToolNeedsSound = true |
1262 | end |
1263 | if self.isServer then |
1264 | -- update component joint |
1265 | Cylindered.updateComponentJoints(self, tool, false) |
1266 | end |
1267 | self:updateExtraDependentParts(tool, dt) |
1268 | self:updateDependentAnimations(tool, dt) |
1269 | tool.isDirty = false |
1270 | end |
1271 | end |
1272 | |
1273 | if self.anyMovingPartsDirty then |
1274 | for i, part in ipairs(spec.movingParts) do |
1275 | if part.isDirty then |
1276 | Cylindered.updateMovingPart(self, part, false) |
1277 | self:updateExtraDependentParts(part, dt) |
1278 | self:updateDependentAnimations(part, dt) |
1279 | if part.playSound then |
1280 | spec.cylinderedHydraulicSoundPartNumber = i |
1281 | spec.movingPartNeedsSound = true |
1282 | end |
1283 | else |
1284 | if spec.isClient and spec.cylinderedHydraulicSoundPartNumber == i then |
1285 | spec.movingPartNeedsSound = false |
1286 | end |
1287 | end |
1288 | end |
1289 | self.anyMovingPartsDirty = false |
1290 | end |
1291 | |
1292 | if self.isClient then |
1293 | if spec.movingToolNeedsSound or spec.movingPartNeedsSound then |
1294 | if not spec.isHydraulicSamplePlaying then |
1295 | g_soundManager:playSample(spec.samples.hydraulic) |
1296 | spec.isHydraulicSamplePlaying = true |
1297 | end |
1298 | self:raiseActive() |
1299 | else |
1300 | if spec.isHydraulicSamplePlaying then |
1301 | g_soundManager:stopSample(spec.samples.hydraulic) |
1302 | spec.isHydraulicSamplePlaying = false |
1303 | end |
1304 | end |
1305 | end |
1306 | end |
onReadStream
DescriptionCalled on client side on joinDefinition
onReadStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
560 | function Cylindered:onReadStream(streamId, connection) |
561 | local spec = self.spec_cylindered |
562 | |
563 | if streamReadBool(streamId) then |
564 | if connection:getIsServer() then |
565 | for i=1, table.getn(spec.movingTools) do |
566 | local tool = spec.movingTools[i] |
567 | if tool.dirtyFlag ~= nil then |
568 | tool.networkTimeInterpolator:reset() |
569 | if tool.transSpeed ~= nil then |
570 | local newTrans = streamReadFloat32(streamId) |
571 | tool.curTrans[tool.translationAxis] = newTrans |
572 | setTranslation(tool.node, unpack(tool.curTrans)) |
573 | tool.networkInterpolators.translation:setValue(tool.curTrans[tool.translationAxis]) |
574 | end |
575 | if tool.rotSpeed ~= nil then |
576 | local newRot = streamReadFloat32(streamId) |
577 | tool.curRot[tool.rotationAxis] = newRot |
578 | setRotation(tool.node, unpack(tool.curRot)) |
579 | tool.networkInterpolators.rotation:setAngle(newRot) |
580 | end |
581 | if tool.animSpeed ~= nil then |
582 | local newAnimTime = streamReadFloat32(streamId) |
583 | tool.curAnimTime = newAnimTime |
584 | self:setAnimationTime(tool.animName, tool.curAnimTime) |
585 | tool.networkInterpolators.animation:setValue(newAnimTime) |
586 | end |
587 | if tool.delayedNode ~= nil then |
588 | self:setDelayedData(tool, true) |
589 | end |
590 | Cylindered.setDirty(self, tool) |
591 | end |
592 | end |
593 | end |
594 | end |
595 | end |
onReadUpdateStream
DescriptionCalled on on updateDefinition
onReadUpdateStream(integer streamId, integer timestamp, table connection)Arguments
integer | streamId | stream ID |
integer | timestamp | timestamp |
table | connection | connection |
629 | function Cylindered:onReadUpdateStream(streamId, timestamp, connection) |
630 | local spec = self.spec_cylindered |
631 | |
632 | -- if server, read input from client |
633 | if not connection:getIsServer() then |
634 | if streamReadBool(streamId) then |
635 | for _, tool in ipairs(spec.movingTools) do |
636 | if tool.axisActionIndex ~= nil then |
637 | tool.move = (streamReadUIntN(streamId, 12) / 4095 * 2 - 1) * 5 |
638 | if math.abs(tool.move) < 0.01 then |
639 | tool.move = 0 |
640 | end |
641 | end |
642 | end |
643 | end |
644 | else |
645 | -- if client, read updated attributes |
646 | if streamReadBool(streamId) then |
647 | for _, tool in ipairs(spec.movingTools) do |
648 | if tool.dirtyFlag ~= nil then |
649 | if streamReadBool(streamId) then |
650 | tool.networkTimeInterpolator:startNewPhaseNetwork() |
651 | |
652 | if tool.transSpeed ~= nil then |
653 | local newTrans = streamReadFloat32(streamId) |
654 | if math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then |
655 | tool.networkInterpolators.translation:setTargetValue(newTrans) |
656 | end |
657 | end |
658 | if tool.rotSpeed ~= nil then |
659 | local newRot |
660 | if tool.rotMin == nil or tool.rotMax == nil then |
661 | newRot = NetworkUtil.readCompressedAngle(streamId) |
662 | else |
663 | if tool.syncMinRotLimits then |
664 | tool.rotMin = streamReadFloat32(streamId) |
665 | end |
666 | if tool.syncMaxRotLimits then |
667 | tool.rotMax = streamReadFloat32(streamId) |
668 | end |
669 | |
670 | tool.networkInterpolators.rotation:setMinMax(tool.rotMin, tool.rotMax) |
671 | newRot = NetworkUtil.readCompressedRange(streamId, tool.rotMin, tool.rotMax, tool.rotSendNumBits) |
672 | end |
673 | if math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then |
674 | tool.networkInterpolators.rotation:setTargetAngle(newRot) |
675 | end |
676 | end |
677 | if tool.animSpeed ~= nil then |
678 | local newAnimTime = NetworkUtil.readCompressedRange(streamId, tool.animMinTime, tool.animMaxTime, tool.animSendNumBits) |
679 | if math.abs(newAnimTime - tool.curAnimTime) > 0.0001 then |
680 | tool.networkInterpolators.animation:setTargetValue(newAnimTime) |
681 | end |
682 | end |
683 | end |
684 | end |
685 | end |
686 | end |
687 | end |
688 | end |
onRegisterActionEvents
DescriptionDefinitiononRegisterActionEvents()Code
2290 | function Cylindered:onRegisterActionEvents(isActiveForInput, isActiveForInputIgnoreSelection) |
2291 | if self.isClient then |
2292 | local spec = self.spec_cylindered |
2293 | self:clearActionEventsTable(spec.actionEvents) |
2294 | |
2295 | -- no check for selection since movingTools can be controlled globally |
2296 | -- sub selection moving tools always require the selection of the sub index |
2297 | if isActiveForInputIgnoreSelection then |
2298 | for i=1, table.getn(spec.movingTools) do |
2299 | local movingTool = spec.movingTools[i] |
2300 | local isSelectedGroup = movingTool.controlGroupIndex == 0 or movingTool.controlGroupIndex == spec.currentControlGroupIndex |
2301 | local canBeControlled = (not g_gameSettings:getValue("easyArmControl") and not movingTool.isEasyControlTarget) or movingTool.easyArmControlActive |
2302 | if movingTool.axisActionIndex ~= nil and isSelectedGroup and canBeControlled then |
2303 | local _, actionEventId = self:addActionEvent(spec.actionEvents, movingTool.axisActionIndex, self, Cylindered.actionEventInput, false, false, true, true, i, movingTool.axisActionIcon) |
2304 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_NORMAL) |
2305 | end |
2306 | end |
2307 | end |
2308 | end |
2309 | end |
onSelect
DescriptionDefinitiononSelect()Code
2363 | function Cylindered:onSelect(subSelectionIndex) |
2364 | local spec = self.spec_cylindered |
2365 | local controlGroupIndex = spec.controlGroupMapping[subSelectionIndex] |
2366 | if controlGroupIndex ~= nil then |
2367 | spec.currentControlGroupIndex = controlGroupIndex |
2368 | else |
2369 | spec.currentControlGroupIndex = 0 |
2370 | end |
2371 | end |
onUnselect
DescriptionDefinitiononUnselect()Code
2375 | function Cylindered:onUnselect() |
2376 | local spec = self.spec_cylindered |
2377 | spec.currentControlGroupIndex = 0 |
2378 | end |
onUpdate
DescriptionCalled on updateDefinition
onUpdate(float dt, boolean isActive, boolean isActiveForInput, boolean isSelected)Arguments
float | dt | time since last call in ms |
boolean | isActive | true if vehicle is active |
boolean | isActiveForInput | true if vehicle is active for input |
boolean | isSelected | true if vehicle is selected |
747 | function Cylindered:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
748 | local spec = self.spec_cylindered |
749 | |
750 | spec.movingToolNeedsSound = false |
751 | spec.movingPartNeedsSound = false |
752 | |
753 | self:updateEasyControl(dt) |
754 | |
755 | if self.isServer then |
756 | for i=1,table.getn(spec.movingTools) do |
757 | local tool = spec.movingTools[i] |
758 | |
759 | local rotSpeed = 0 |
760 | local transSpeed = 0 |
761 | local animSpeed = 0 |
762 | |
763 | local move = tool.move + tool.externalMove |
764 | if math.abs(move) > 0 then |
765 | tool.externalMove = 0 |
766 | |
767 | if tool.rotSpeed ~= nil then |
768 | rotSpeed = move*tool.rotSpeed |
769 | if tool.rotAcceleration ~= nil and math.abs(rotSpeed - tool.lastRotSpeed) >= tool.rotAcceleration*dt then |
770 | if rotSpeed > tool.lastRotSpeed then |
771 | rotSpeed = tool.lastRotSpeed + tool.rotAcceleration*dt |
772 | else |
773 | rotSpeed = tool.lastRotSpeed - tool.rotAcceleration*dt |
774 | end |
775 | end |
776 | end |
777 | if tool.transSpeed ~= nil then |
778 | transSpeed = move*tool.transSpeed |
779 | if tool.transAcceleration ~= nil and math.abs(transSpeed - tool.lastTransSpeed) >= tool.transAcceleration*dt then |
780 | if transSpeed > tool.lastTransSpeed then |
781 | transSpeed = tool.lastTransSpeed + tool.transAcceleration*dt |
782 | else |
783 | transSpeed = tool.lastTransSpeed - tool.transAcceleration*dt |
784 | end |
785 | end |
786 | end |
787 | if tool.animSpeed ~= nil then |
788 | animSpeed = move*tool.animSpeed |
789 | if tool.animAcceleration ~= nil and math.abs(animSpeed - tool.lastAnimSpeed) >= tool.animAcceleration*dt then |
790 | if animSpeed > tool.lastAnimSpeed then |
791 | animSpeed = tool.lastAnimSpeed + tool.animAcceleration*dt |
792 | else |
793 | animSpeed = tool.lastAnimSpeed - tool.animAcceleration*dt |
794 | end |
795 | end |
796 | end |
797 | else |
798 | -- decelerate |
799 | if tool.rotAcceleration ~= nil then |
800 | if tool.lastRotSpeed < 0 then |
801 | rotSpeed = math.min(tool.lastRotSpeed + tool.rotAcceleration*dt, 0) |
802 | else |
803 | rotSpeed = math.max(tool.lastRotSpeed - tool.rotAcceleration*dt, 0) |
804 | end |
805 | end |
806 | if tool.transAcceleration ~= nil then |
807 | if tool.lastTransSpeed < 0 then |
808 | transSpeed = math.min(tool.lastTransSpeed + tool.transAcceleration*dt, 0) |
809 | else |
810 | transSpeed = math.max(tool.lastTransSpeed - tool.transAcceleration*dt, 0) |
811 | end |
812 | end |
813 | if tool.animAcceleration ~= nil then |
814 | if tool.lastAnimSpeed < 0 then |
815 | animSpeed = math.min(tool.lastAnimSpeed + tool.animAcceleration*dt, 0) |
816 | else |
817 | animSpeed = math.max(tool.lastAnimSpeed - tool.animAcceleration*dt, 0) |
818 | end |
819 | end |
820 | end |
821 | |
822 | local changed = false |
823 | if rotSpeed ~= nil and rotSpeed ~= 0 then |
824 | changed = changed or Cylindered.setToolRotation(self, tool, rotSpeed, dt) |
825 | else |
826 | tool.lastRotSpeed = 0 |
827 | end |
828 | if transSpeed ~= nil and transSpeed ~= 0 then |
829 | changed = changed or Cylindered.setToolTranslation(self, tool, transSpeed, dt) |
830 | else |
831 | tool.lastTransSpeed = 0 |
832 | end |
833 | if animSpeed ~= nil and animSpeed ~= 0 then |
834 | changed = changed or Cylindered.setToolAnimation(self, tool, animSpeed, dt) |
835 | else |
836 | tool.lastAnimSpeed = 0 |
837 | end |
838 | |
839 | for _, dependentTool in pairs(tool.dependentMovingTools) do |
840 | if dependentTool.speedScale ~= nil then |
841 | local isAllowed = true |
842 | if dependentTool.requiresMovement then |
843 | if not changed then |
844 | isAllowed = false |
845 | end |
846 | end |
847 | |
848 | if isAllowed then |
849 | dependentTool.movingTool.externalMove = dependentTool.speedScale * tool.move |
850 | end |
851 | end |
852 | |
853 | Cylindered.updateRotationBasedLimits(self, tool, dependentTool) |
854 | |
855 | self:updateDependentToolLimits(tool, dependentTool) |
856 | end |
857 | |
858 | if changed then |
859 | if tool.playSound then |
860 | spec.movingToolNeedsSound = true |
861 | end |
862 | Cylindered.setDirty(self, tool) |
863 | tool.networkPositionIsDirty = true |
864 | self:raiseDirtyFlags(tool.dirtyFlag) |
865 | self:raiseDirtyFlags(spec.cylinderedDirtyFlag) |
866 | |
867 | -- keep moving tool at least 2 frames in a row network dirty, so the client will always recieve and set the final position of the tool |
868 | tool.networkDirtyNextFrame = true |
869 | else |
870 | if tool.networkDirtyNextFrame then |
871 | self:raiseDirtyFlags(tool.dirtyFlag) |
872 | self:raiseDirtyFlags(spec.cylinderedDirtyFlag) |
873 | tool.networkDirtyNextFrame = nil |
874 | end |
875 | end |
876 | end |
877 | else |
878 | -- client side |
879 | for i=1,table.getn(spec.movingTools) do |
880 | local tool = spec.movingTools[i] |
881 | |
882 | tool.networkTimeInterpolator:update(dt) |
883 | local interpolationAlpha = tool.networkTimeInterpolator:getAlpha() |
884 | local changed = false |
885 | |
886 | if self:getIsMovingToolActive(tool) then |
887 | if tool.rotSpeed ~= nil then |
888 | local newRot = tool.networkInterpolators.rotation:getInterpolatedValue(interpolationAlpha) |
889 | if math.abs(newRot - tool.curRot[tool.rotationAxis]) > 0.0001 then |
890 | changed = true |
891 | tool.curRot[tool.rotationAxis] = newRot |
892 | setRotation(tool.node, tool.curRot[1], tool.curRot[2], tool.curRot[3]) |
893 | end |
894 | end |
895 | |
896 | if tool.transSpeed ~= nil then |
897 | local newTrans = tool.networkInterpolators.translation:getInterpolatedValue(interpolationAlpha) |
898 | if math.abs(newTrans - tool.curTrans[tool.translationAxis]) > 0.0001 then |
899 | changed = true |
900 | tool.curTrans[tool.translationAxis] = newTrans |
901 | setTranslation(tool.node, tool.curTrans[1], tool.curTrans[2], tool.curTrans[3]) |
902 | end |
903 | end |
904 | |
905 | if tool.animSpeed ~= nil then |
906 | local newAnimTime = tool.networkInterpolators.animation:getInterpolatedValue(interpolationAlpha) |
907 | if math.abs(newAnimTime - tool.curAnimTime) > 0.0001 then |
908 | changed = true |
909 | tool.curAnimTime = newAnimTime |
910 | self:setAnimationTime(tool.animName, newAnimTime) |
911 | end |
912 | end |
913 | |
914 | if changed then |
915 | Cylindered.setDirty(self, tool) |
916 | end |
917 | end |
918 | |
919 | for _, dependentTool in pairs(tool.dependentMovingTools) do |
920 | if not dependentTool.movingTool.syncMinRotLimits or not dependentTool.movingTool.syncMaxRotLimits then |
921 | self:updateDependentToolLimits(tool, dependentTool) |
922 | end |
923 | end |
924 | |
925 | if tool.networkTimeInterpolator:isInterpolating() then |
926 | self:raiseActive() |
927 | end |
928 | end |
929 | end |
930 | |
931 | for i=1, table.getn(spec.movingTools) do |
932 | local tool = spec.movingTools[i] |
933 | if tool.delayedHistoryIndex ~= nil and tool.delayedHistoryIndex > 0 then |
934 | self:updateDelayedTool(tool) |
935 | end |
936 | end |
937 | end |
onUpdateTick
DescriptionDefinitiononUpdateTick()Code
1228 | function Cylindered:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected) |
1229 | if self.isClient then |
1230 | local spec = self.spec_cylindered |
1231 | for _,movingTool in pairs(spec.movingTools) do |
1232 | if movingTool.axisActionIndex ~= nil then |
1233 | -- check only movingTools from selected control group since the other movingTools action events are not registered |
1234 | if spec.currentControlGroupIndex == movingTool.controlGroupIndex then |
1235 | local actionEvent = spec.actionEvents[movingTool.axisActionIndex] |
1236 | if actionEvent ~= nil then |
1237 | g_inputBinding:setActionEventActive(actionEvent.actionEventId, self:getIsMovingToolActive(movingTool)) |
1238 | end |
1239 | end |
1240 | end |
1241 | end |
1242 | end |
1243 | end |
onWriteStream
DescriptionCalled on server side on joinDefinition
onWriteStream(integer streamId, integer connection)Arguments
integer | streamId | streamId |
integer | connection | connection |
601 | function Cylindered:onWriteStream(streamId, connection) |
602 | local spec = self.spec_cylindered |
603 | |
604 | if streamWriteBool(streamId, self:allowLoadMovingToolStates()) then |
605 | if not connection:getIsServer() then |
606 | for i=1, table.getn(spec.movingTools) do |
607 | local tool = spec.movingTools[i] |
608 | if tool.dirtyFlag ~= nil then |
609 | if tool.transSpeed ~= nil then |
610 | streamWriteFloat32(streamId, tool.curTrans[tool.translationAxis]) |
611 | end |
612 | if tool.rotSpeed ~= nil then |
613 | streamWriteFloat32(streamId, tool.curRot[tool.rotationAxis]) |
614 | end |
615 | if tool.animSpeed ~= nil then |
616 | streamWriteFloat32(streamId, tool.curAnimTime) |
617 | end |
618 | end |
619 | end |
620 | end |
621 | end |
622 | end |
onWriteUpdateStream
DescriptionCalled on on updateDefinition
onWriteUpdateStream(integer streamId, table connection, integer dirtyMask)Arguments
integer | streamId | stream ID |
table | connection | connection |
integer | dirtyMask | dirty mask |
695 | function Cylindered:onWriteUpdateStream(streamId, connection, dirtyMask) |
696 | local spec = self.spec_cylindered |
697 | |
698 | -- if client, send input to server |
699 | if connection:getIsServer() then |
700 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.cylinderedInputDirtyFlag) ~= 0) then |
701 | for _, tool in ipairs(spec.movingTools) do |
702 | if tool.axisActionIndex ~= nil then |
703 | local value = (MathUtil.clamp(tool.moveToSend / 5, -1, 1) + 1) / 2 * 4095 |
704 | streamWriteUIntN(streamId, value, 12) |
705 | end |
706 | end |
707 | end |
708 | else |
709 | -- if server, send updated attributes |
710 | if streamWriteBool(streamId, bitAND(dirtyMask, spec.cylinderedDirtyFlag) ~= 0) then |
711 | for _, tool in ipairs(spec.movingTools) do |
712 | if tool.dirtyFlag ~= nil then |
713 | if streamWriteBool(streamId, bitAND(dirtyMask, tool.dirtyFlag) ~= 0 and self:getIsMovingToolActive(tool)) then |
714 | if tool.transSpeed ~= nil then |
715 | streamWriteFloat32(streamId, tool.curTrans[tool.translationAxis]) |
716 | end |
717 | if tool.rotSpeed ~= nil then |
718 | local rot = tool.curRot[tool.rotationAxis] |
719 | if tool.rotMin == nil or tool.rotMax == nil then |
720 | NetworkUtil.writeCompressedAngle(streamId, rot) |
721 | else |
722 | if tool.syncMinRotLimits then |
723 | streamWriteFloat32(streamId, tool.rotMin) |
724 | end |
725 | if tool.syncMaxRotLimits then |
726 | streamWriteFloat32(streamId, tool.rotMax) |
727 | end |
728 | NetworkUtil.writeCompressedRange(streamId, rot, tool.rotMin, tool.rotMax, tool.rotSendNumBits) |
729 | end |
730 | end |
731 | if tool.animSpeed ~= nil then |
732 | NetworkUtil.writeCompressedRange(streamId, tool.curAnimTime, tool.animMinTime, tool.animMaxTime, tool.animSendNumBits) |
733 | end |
734 | end |
735 | end |
736 | end |
737 | end |
738 | end |
739 | end |
prerequisitesPresent
DescriptionChecks if all prerequisite specializations are loadedDefinition
prerequisitesPresent(table specializations)Arguments
table | specializations | specializations |
boolean | hasPrerequisite | true if all prerequisite specializations are loaded |
19 | function Cylindered.prerequisitesPresent(specializations) |
20 | return true |
21 | end |
registerEventListeners
DescriptionDefinitionregisterEventListeners()Code
78 | function Cylindered.registerEventListeners(vehicleType) |
79 | SpecializationUtil.registerEventListener(vehicleType, "onLoad", Cylindered) |
80 | SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", Cylindered) |
81 | SpecializationUtil.registerEventListener(vehicleType, "onLoadFinished", Cylindered) |
82 | SpecializationUtil.registerEventListener(vehicleType, "onDelete", Cylindered) |
83 | SpecializationUtil.registerEventListener(vehicleType, "onReadStream", Cylindered) |
84 | SpecializationUtil.registerEventListener(vehicleType, "onWriteStream", Cylindered) |
85 | SpecializationUtil.registerEventListener(vehicleType, "onReadUpdateStream", Cylindered) |
86 | SpecializationUtil.registerEventListener(vehicleType, "onWriteUpdateStream", Cylindered) |
87 | SpecializationUtil.registerEventListener(vehicleType, "onUpdate", Cylindered) |
88 | SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", Cylindered) |
89 | SpecializationUtil.registerEventListener(vehicleType, "onPostUpdate", Cylindered) |
90 | SpecializationUtil.registerEventListener(vehicleType, "onDraw", Cylindered) |
91 | SpecializationUtil.registerEventListener(vehicleType, "onRegisterActionEvents", Cylindered) |
92 | SpecializationUtil.registerEventListener(vehicleType, "onPostAttach", Cylindered) |
93 | SpecializationUtil.registerEventListener(vehicleType, "onSelect", Cylindered) |
94 | SpecializationUtil.registerEventListener(vehicleType, "onUnselect", Cylindered) |
95 | SpecializationUtil.registerEventListener(vehicleType, "onDeactivate", Cylindered) |
96 | end |
registerEvents
DescriptionDefinitionregisterEvents()Code
25 | function Cylindered.registerEvents(vehicleType) |
26 | SpecializationUtil.registerEvent(vehicleType, "onMovingToolChanged") |
27 | end |
registerFunctions
DescriptionDefinitionregisterFunctions()Code
31 | function Cylindered.registerFunctions(vehicleType) |
32 | SpecializationUtil.registerFunction(vehicleType, "loadMovingPartFromXML", Cylindered.loadMovingPartFromXML) |
33 | SpecializationUtil.registerFunction(vehicleType, "loadMovingToolFromXML", Cylindered.loadMovingToolFromXML) |
34 | SpecializationUtil.registerFunction(vehicleType, "loadDependentMovingTools", Cylindered.loadDependentMovingTools) |
35 | SpecializationUtil.registerFunction(vehicleType, "loadDependentParts", Cylindered.loadDependentParts) |
36 | SpecializationUtil.registerFunction(vehicleType, "loadDependentComponentJoints", Cylindered.loadDependentComponentJoints) |
37 | SpecializationUtil.registerFunction(vehicleType, "loadDependentAttacherJoints", Cylindered.loadDependentAttacherJoints) |
38 | SpecializationUtil.registerFunction(vehicleType, "loadDependentWheels", Cylindered.loadDependentWheels) |
39 | SpecializationUtil.registerFunction(vehicleType, "loadDependentTranslatingParts", Cylindered.loadDependentTranslatingParts) |
40 | SpecializationUtil.registerFunction(vehicleType, "loadExtraDependentParts", Cylindered.loadExtraDependentParts) |
41 | SpecializationUtil.registerFunction(vehicleType, "loadDependentAnimations", Cylindered.loadDependentAnimations) |
42 | SpecializationUtil.registerFunction(vehicleType, "loadCopyLocalDirectionParts", Cylindered.loadCopyLocalDirectionParts) |
43 | SpecializationUtil.registerFunction(vehicleType, "loadRotationBasedLimits", Cylindered.loadRotationBasedLimits) |
44 | SpecializationUtil.registerFunction(vehicleType, "setMovingToolDirty", Cylindered.setMovingToolDirty) |
45 | SpecializationUtil.registerFunction(vehicleType, "updateCylinderedInitial", Cylindered.updateCylinderedInitial) |
46 | SpecializationUtil.registerFunction(vehicleType, "allowLoadMovingToolStates", Cylindered.allowLoadMovingToolStates) |
47 | SpecializationUtil.registerFunction(vehicleType, "getMovingToolByNode", Cylindered.getMovingToolByNode) |
48 | SpecializationUtil.registerFunction(vehicleType, "getMovingPartByNode", Cylindered.getMovingPartByNode) |
49 | SpecializationUtil.registerFunction(vehicleType, "getIsMovingToolActive", Cylindered.getIsMovingToolActive) |
50 | SpecializationUtil.registerFunction(vehicleType, "setDelayedData", Cylindered.setDelayedData) |
51 | SpecializationUtil.registerFunction(vehicleType, "updateDelayedTool", Cylindered.updateDelayedTool) |
52 | SpecializationUtil.registerFunction(vehicleType, "updateEasyControl", Cylindered.updateEasyControl) |
53 | SpecializationUtil.registerFunction(vehicleType, "setIsEasyControlActive", Cylindered.setIsEasyControlActive) |
54 | SpecializationUtil.registerFunction(vehicleType, "updateExtraDependentParts", Cylindered.updateExtraDependentParts) |
55 | SpecializationUtil.registerFunction(vehicleType, "updateDependentAnimations", Cylindered.updateDependentAnimations) |
56 | SpecializationUtil.registerFunction(vehicleType, "updateDependentToolLimits", Cylindered.updateDependentToolLimits) |
57 | end |
registerOverwrittenFunctions
DescriptionDefinitionregisterOverwrittenFunctions()Code
61 | function Cylindered.registerOverwrittenFunctions(vehicleType) |
62 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "isDetachAllowed", Cylindered.isDetachAllowed) |
63 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadObjectChangeValuesFromXML", Cylindered.loadObjectChangeValuesFromXML) |
64 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "setObjectChangeValues", Cylindered.setObjectChangeValues) |
65 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadDischargeNode", Cylindered.loadDischargeNode) |
66 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getDischargeNodeEmptyFactor", Cylindered.getDischargeNodeEmptyFactor) |
67 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadShovelNode", Cylindered.loadShovelNode) |
68 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getShovelNodeIsActive", Cylindered.getShovelNodeIsActive) |
69 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadDynamicMountGrabFromXML", Cylindered.loadDynamicMountGrabFromXML) |
70 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getIsDynamicMountGrabOpened", Cylindered.getIsDynamicMountGrabOpened) |
71 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "setComponentJointFrame", Cylindered.setComponentJointFrame) |
72 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getAdditionalSchemaText", Cylindered.getAdditionalSchemaText) |
73 | SpecializationUtil.registerOverwrittenFunction(vehicleType, "getWearMultiplier", Cylindered.getWearMultiplier) |
74 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
533 | function Cylindered:saveToXMLFile(xmlFile, key, usedModNames) |
534 | local spec = self.spec_cylindered |
535 | |
536 | local index = 0 |
537 | for _, tool in ipairs(spec.movingTools) do |
538 | if tool.saving then |
539 | local toolKey = string.format("%s.movingTool(%d)", key, index) |
540 | |
541 | if tool.transSpeed ~= nil then |
542 | setXMLFloat(xmlFile, toolKey.."#translation", tool.curTrans[tool.translationAxis]) |
543 | end |
544 | if tool.rotSpeed ~= nil then |
545 | setXMLFloat(xmlFile, toolKey.."#rotation", tool.curRot[tool.rotationAxis]) |
546 | end |
547 | if tool.animSpeed ~= nil then |
548 | setXMLFloat(xmlFile, toolKey.."#animationTime", tool.curAnimTime) |
549 | end |
550 | |
551 | index = index + 1 |
552 | end |
553 | end |
554 | end |
setComponentJointFrame
DescriptionDefinitionsetComponentJointFrame()Code
2232 | function Cylindered:setComponentJointFrame(superFunc, jointDesc, anchorActor) |
2233 | superFunc(self, jointDesc, anchorActor) |
2234 | |
2235 | -- update the joint to component offset |
2236 | local spec = self.spec_cylindered |
2237 | for _, movingTool in ipairs(spec.movingTools) do |
2238 | for _, componentJoint in ipairs(movingTool.componentJoints) do |
2239 | local componentJointDesc = self.componentJoints[componentJoint.index] |
2240 | |
2241 | local jointNode = componentJointDesc.jointNode |
2242 | if componentJoint.anchorActor == 1 then |
2243 | jointNode = componentJointDesc.jointNodeActor1 |
2244 | end |
2245 | |
2246 | local node = self.components[componentJointDesc.componentIndices[2]].node |
2247 | componentJoint.x, componentJoint.y, componentJoint.z = localToLocal(node, jointNode, 0,0,0) |
2248 | componentJoint.upX, componentJoint.upY, componentJoint.upZ = localDirectionToLocal(node, jointNode, 0,1,0) |
2249 | componentJoint.dirX, componentJoint.dirY, componentJoint.dirZ = localDirectionToLocal(node, jointNode, 0,0,1) |
2250 | end |
2251 | end |
2252 | end |
setDelayedData
DescriptionDefinitionsetDelayedData()Code
942 | function Cylindered:setDelayedData(tool, immediate) |
943 | local x, y, z = getTranslation(tool.node) |
944 | local rx, ry, rz = getRotation(tool.node) |
945 | |
946 | tool.delayedHistroyData[3] = {rot = {rx, ry, rz}, trans = {x, y, z}} |
947 | if immediate then |
948 | tool.delayedHistroyData[2] = tool.delayedHistroyData[3] |
949 | tool.delayedHistroyData[1] = tool.delayedHistroyData[2] |
950 | end |
951 | |
952 | tool.delayedHistoryIndex = 3 |
953 | end |
setDirty
DescriptionSet dirtyDefinition
setDirty(table part)Arguments
table | part | part to set dirty |
2527 | function Cylindered.setDirty(self, part) |
2528 | if not part.isDirty or self.spec_cylindered.isLoading then -- during loading we always allow setting dirty since we do not reset it |
2529 | part.isDirty = true |
2530 | self.anyMovingPartsDirty = true |
2531 | |
2532 | if part.delayedNode ~= nil then |
2533 | self:setDelayedData(part) |
2534 | end |
2535 | |
2536 | -- on moving tools we update the wheels and attacher joints on dirty since the are updated from external influences (e.g. animations) |
2537 | -- on moving parts the part is updated first and then the wheels and attacher joints are updated |
2538 | if part.isTool then |
2539 | Cylindered.updateAttacherJoints(self, part) |
2540 | Cylindered.updateWheels(self, part) |
2541 | end |
2542 | |
2543 | for _, v in pairs(part.dependentParts) do |
2544 | Cylindered.setDirty(self, v) |
2545 | end |
2546 | end |
2547 | end |
setIsEasyControlActive
DescriptionDefinitionsetIsEasyControlActive()Code
1126 | function Cylindered:setIsEasyControlActive(state, noEventSend) |
1127 | if self.isServer then |
1128 | local spec = self.spec_cylindered |
1129 | local easyArmControl = spec.easyArmControl |
1130 | if easyArmControl ~= nil then |
1131 | local targetYTool = self:getMovingToolByNode(easyArmControl.targetNodeY) |
1132 | local targetZTool = self:getMovingToolByNode(easyArmControl.targetNodeZ) |
1133 | |
1134 | if state then |
1135 | local _, y, z = localToLocal(easyArmControl.targetRefNode, getParent(easyArmControl.targetNodeY), 0, 0, 0) |
1136 | local _, oldY, _ = getTranslation(easyArmControl.targetNodeY) |
1137 | if Cylindered.setToolTranslation(self, targetYTool, nil, 0, y-oldY) then |
1138 | Cylindered.setDirty(self, targetYTool) |
1139 | |
1140 | self:raiseDirtyFlags(targetYTool.dirtyFlag) |
1141 | end |
1142 | |
1143 | _, _, z = localToLocal(easyArmControl.targetRefNode, getParent(easyArmControl.targetNodeZ), 0, 0, 0) |
1144 | local _, _, oldZ = getTranslation(easyArmControl.targetNodeZ) |
1145 | if Cylindered.setToolTranslation(self, targetZTool, nil, 0, z-oldZ) then |
1146 | Cylindered.setDirty(self, targetZTool) |
1147 | |
1148 | self:raiseDirtyFlags(targetZTool.dirtyFlag) |
1149 | end |
1150 | |
1151 | self:raiseDirtyFlags(spec.cylinderedDirtyFlag) |
1152 | end |
1153 | end |
1154 | end |
1155 | |
1156 | CylinderedEasyControlChangeEvent.sendEvent(self, state, noEventSend) |
1157 | end |
setMovingToolDirty
DescriptionSet moving tool dirtyDefinition
setMovingToolDirty(integer node)Arguments
integer | node | node id |
1946 | function Cylindered:setMovingToolDirty(node) |
1947 | local spec = self.spec_cylindered |
1948 | |
1949 | local tool = spec.nodesToMovingTools[node] |
1950 | if tool ~= nil then |
1951 | local x,y,z = getRotation(tool.node) |
1952 | tool.curRot[1] = x |
1953 | tool.curRot[2] = y |
1954 | tool.curRot[3] = z |
1955 | local x,y,z = getTranslation(tool.node) |
1956 | tool.curTrans[1] = x |
1957 | tool.curTrans[2] = y |
1958 | tool.curTrans[3] = z |
1959 | Cylindered.setDirty(self, tool) |
1960 | |
1961 | if not self.isServer and self.isClient then |
1962 | tool.networkInterpolators.translation:setValue(tool.curTrans[tool.translationAxis]) |
1963 | tool.networkInterpolators.rotation:setAngle(tool.curRot[tool.rotationAxis]) |
1964 | end |
1965 | end |
1966 | end |
setObjectChangeValues
DescriptionSets object change valuesDefinition
setObjectChangeValues(table object, boolean isActive)Arguments
table | object | object |
boolean | isActive | is active |
2088 | function Cylindered:setObjectChangeValues(superFunc, object, isActive) |
2089 | superFunc(self, object, isActive) |
2090 | |
2091 | local spec = self.spec_cylindered |
2092 | |
2093 | if spec.nodesToMovingTools ~= nil and spec.nodesToMovingTools[object.node] ~= nil then |
2094 | local movingTool = spec.nodesToMovingTools[object.node] |
2095 | if isActive then |
2096 | movingTool.rotMax = object.movingToolRotMaxActive |
2097 | movingTool.rotMin = object.movingToolRotMinActive |
2098 | else |
2099 | movingTool.rotMax = object.movingToolRotMaxInactive |
2100 | movingTool.rotMin = object.movingToolRotMinInactive |
2101 | end |
2102 | end |
2103 | end |
setToolAnimation
DescriptionSet tool animationDefinition
setToolAnimation(table tool, float animSpeed, float dt)Arguments
table | tool | tool |
float | animSpeed | animation speed |
float | dt | time since last call in ms |
boolean | changed | animation changed |
2483 | function Cylindered.setToolAnimation(self, tool, animSpeed, dt) |
2484 | local lastAnimTime = self:getAnimationTime(tool.animName) |
2485 | local newAnimTime = lastAnimTime+animSpeed*dt |
2486 | |
2487 | if tool.animMaxTime ~= nil then |
2488 | newAnimTime = math.min(newAnimTime, tool.animMaxTime) |
2489 | end |
2490 | if tool.animMinTime ~= nil then |
2491 | newAnimTime = math.max(newAnimTime, tool.animMinTime) |
2492 | end |
2493 | local diff = newAnimTime - lastAnimTime |
2494 | if dt ~= 0 then |
2495 | tool.lastAnimSpeed = diff / dt |
2496 | end |
2497 | if math.abs(diff) > 0.0001 then |
2498 | tool.curAnimTime = newAnimTime |
2499 | self:setAnimationTime(tool.animName, newAnimTime) |
2500 | SpecializationUtil.raiseEvent(self, "onMovingToolChanged", tool, animSpeed, dt) |
2501 | return true |
2502 | end |
2503 | |
2504 | return false |
2505 | end |
setToolRotation
DescriptionSet tool rotationDefinition
setToolRotation(table tool, float rotSpeed, float dt, float delta)Arguments
table | tool | tool |
float | rotSpeed | rotation speed |
float | dt | time since last call in ms |
float | delta | delta rotation |
boolean | changed | rotation changed |
2435 | function Cylindered.setToolRotation(self, tool, rotSpeed, dt, delta) |
2436 | local curRot = { getRotation(tool.node) } |
2437 | local newRot = curRot[tool.rotationAxis] |
2438 | if rotSpeed ~= nil then |
2439 | newRot = newRot + rotSpeed*dt |
2440 | else |
2441 | newRot = newRot + delta |
2442 | end |
2443 | if tool.rotMax ~= nil then |
2444 | newRot = math.min(newRot, tool.rotMax) |
2445 | end |
2446 | if tool.rotMin ~= nil then |
2447 | newRot = math.max(newRot, tool.rotMin) |
2448 | end |
2449 | local diff = newRot - curRot[tool.rotationAxis] |
2450 | if rotSpeed ~= nil then |
2451 | if dt ~= 0 then |
2452 | tool.lastRotSpeed = diff/dt |
2453 | end |
2454 | end |
2455 | |
2456 | if math.abs(diff) > 0.0001 then |
2457 | -- wrap if not limited |
2458 | if tool.rotMin == nil and tool.rotMax == nil then |
2459 | if newRot > 2*math.pi then |
2460 | newRot = newRot - 2*math.pi |
2461 | end |
2462 | if newRot < 0 then |
2463 | newRot = newRot + 2*math.pi |
2464 | end |
2465 | end |
2466 | tool.curRot[tool.rotationAxis] = newRot |
2467 | setRotation(tool.node, unpack(tool.curRot)) |
2468 | |
2469 | SpecializationUtil.raiseEvent(self, "onMovingToolChanged", tool, rotSpeed, dt) |
2470 | |
2471 | return true |
2472 | end |
2473 | |
2474 | return false |
2475 | end |
setToolTranslation
DescriptionSet tool translationDefinition
setToolTranslation(table tool, float transSpeed, float dt)Arguments
table | tool | tool |
float | transSpeed | translation speed |
float | dt | time since last call in ms |
boolean | changed | translation changed |
2396 | function Cylindered.setToolTranslation(self, tool, transSpeed, dt, delta) |
2397 | local curTrans = { getTranslation(tool.node) } |
2398 | local newTrans = curTrans[tool.translationAxis] |
2399 | local oldTrans = newTrans |
2400 | if transSpeed ~= nil then |
2401 | newTrans = newTrans + transSpeed*dt |
2402 | else |
2403 | newTrans = newTrans + delta |
2404 | end |
2405 | if tool.transMax ~= nil then |
2406 | newTrans = math.min(newTrans, tool.transMax) |
2407 | end |
2408 | if tool.transMin ~= nil then |
2409 | newTrans = math.max(newTrans, tool.transMin) |
2410 | end |
2411 | local diff = newTrans - oldTrans |
2412 | if dt ~= 0 then |
2413 | tool.lastTransSpeed = diff/dt |
2414 | end |
2415 | if math.abs(diff) > 0.0001 then |
2416 | curTrans[tool.translationAxis] = newTrans |
2417 | tool.curTrans = curTrans |
2418 | setTranslation(tool.node, unpack(tool.curTrans)) |
2419 | |
2420 | SpecializationUtil.raiseEvent(self, "onMovingToolChanged", tool, transSpeed, dt) |
2421 | |
2422 | return true |
2423 | end |
2424 | |
2425 | return false |
2426 | end |
updateAttacherJoints
DescriptionUpdate attacher jointsDefinition
updateAttacherJoints(table entry)Arguments
table | entry | entry |
2860 | function Cylindered.updateAttacherJoints(self, entry) |
2861 | if self.isServer then |
2862 | if entry.attacherJoints ~= nil then |
2863 | for _,joint in ipairs(entry.attacherJoints) do |
2864 | if joint.jointIndex ~= 0 then |
2865 | setJointFrame(joint.jointIndex, 0, joint.jointTransform) |
2866 | end |
2867 | end |
2868 | end |
2869 | |
2870 | if entry.inputAttacherJoint then |
2871 | if self.getAttacherVehicle ~= nil then |
2872 | local attacherVehicle = self:getAttacherVehicle() |
2873 | if attacherVehicle ~= nil then |
2874 | |
2875 | local attacherJoints = attacherVehicle:getAttacherJoints() |
2876 | if attacherJoints ~= nil then |
2877 | |
2878 | local jointDescIndex = attacherVehicle:getAttacherJointIndexFromObject(self) |
2879 | if jointDescIndex ~= nil then |
2880 | local jointDesc = attacherJoints[jointDescIndex] |
2881 | |
2882 | local inputAttacherJoint = self:getActiveInputAttacherJoint() |
2883 | if inputAttacherJoint ~= nil then |
2884 | setJointFrame(jointDesc.jointIndex, 1, inputAttacherJoint.node ) |
2885 | end |
2886 | end |
2887 | end |
2888 | end |
2889 | end |
2890 | end |
2891 | end |
2892 | end |
updateComponentJoints
DescriptionUpdate component jointsDefinition
updateComponentJoints(table entry, boolean placeComponents)Arguments
table | entry | entry |
boolean | placeComponents | place components |
2831 | function Cylindered.updateComponentJoints(self, entry, placeComponents) |
2832 | if self.isServer then |
2833 | if entry.componentJoints ~= nil then |
2834 | for _,joint in ipairs(entry.componentJoints) do |
2835 | local componentJoint = joint.componentJoint |
2836 | |
2837 | local jointNode = componentJoint.jointNode |
2838 | if joint.anchorActor == 1 then |
2839 | jointNode = componentJoint.jointNodeActor1 |
2840 | end |
2841 | |
2842 | if placeComponents then |
2843 | local node = self.components[componentJoint.componentIndices[2]].node |
2844 | local x,y,z = localToWorld(jointNode, joint.x, joint.y, joint.z) |
2845 | local upX,upY,upZ = localDirectionToWorld(jointNode, joint.upX,joint.upY,joint.upZ) |
2846 | local dirX,dirY,dirZ = localDirectionToWorld(jointNode, joint.dirX,joint.dirY,joint.dirZ) |
2847 | setWorldTranslation(node, x,y,z) |
2848 | I3DUtil.setWorldDirection(node, dirX,dirY,dirZ, upX,upY,upZ) |
2849 | end |
2850 | |
2851 | self:setComponentJointFrame(componentJoint, joint.anchorActor) |
2852 | end |
2853 | end |
2854 | end |
2855 | end |
updateCylinderedInitial
DescriptionInitial update of cylinderedDefinition
updateCylinderedInitial(boolean placeComponents)Arguments
boolean | placeComponents | place components |
1971 | function Cylindered:updateCylinderedInitial(placeComponents, keepDirty) |
1972 | if placeComponents == nil then |
1973 | placeComponents = true |
1974 | end |
1975 | |
1976 | if keepDirty == nil then |
1977 | keepDirty = false |
1978 | end |
1979 | |
1980 | local spec = self.spec_cylindered |
1981 | |
1982 | for _, part in pairs(spec.activeDirtyMovingParts) do |
1983 | Cylindered.setDirty(self, part) |
1984 | end |
1985 | |
1986 | for _, tool in ipairs(spec.movingTools) do |
1987 | if tool.isDirty then |
1988 | Cylindered.updateWheels(self, tool) |
1989 | if self.isServer then |
1990 | Cylindered.updateComponentJoints(self, tool, placeComponents) |
1991 | end |
1992 | tool.isDirty = false or keepDirty |
1993 | end |
1994 | |
1995 | self:updateDependentAnimations(tool, 9999) |
1996 | end |
1997 | |
1998 | for _, part in ipairs(spec.movingParts) do |
1999 | if part.isDirty then |
2000 | Cylindered.updateMovingPart(self, part, placeComponents) |
2001 | Cylindered.updateWheels(self, part) |
2002 | part.isDirty = false or keepDirty |
2003 | end |
2004 | |
2005 | self:updateDependentAnimations(part, 9999) |
2006 | end |
2007 | end |
updateDelayedTool
DescriptionDefinitionupdateDelayedTool()Code
957 | function Cylindered:updateDelayedTool(tool, forceLastPosition) |
958 | local spec = self.spec_cylindered |
959 | |
960 | if forceLastPosition ~= nil and forceLastPosition then |
961 | tool.delayedHistroyData[2] = tool.delayedHistroyData[3] |
962 | tool.delayedHistroyData[1] = tool.delayedHistroyData[2] |
963 | end |
964 | |
965 | local currentData = tool.delayedHistroyData[1] |
966 | tool.delayedHistroyData[1] = tool.delayedHistroyData[2] |
967 | tool.delayedHistroyData[2] = tool.delayedHistroyData[3] |
968 | |
969 | setRotation(tool.delayedNode, unpack(currentData.rot)) |
970 | setTranslation(tool.delayedNode, unpack(currentData.trans)) |
971 | |
972 | -- local r, _, _ = getRotation(tool.node) |
973 | -- log(string.format("%s: %.2f | %s: %.2f", getName(tool.node), math.deg(r), getName(tool.delayedNode), math.deg(currentData.rot[1]))) |
974 | |
975 | tool.delayedHistoryIndex = tool.delayedHistoryIndex - 1 |
976 | |
977 | local movingPart = spec.nodesToMovingParts[tool.delayedNode] |
978 | local movingTool = spec.nodesToMovingTools[tool.delayedNode] |
979 | if movingPart ~= nil then |
980 | Cylindered.setDirty(self, movingPart) |
981 | end |
982 | if spec.nodesToMovingTools[tool.delayedNode] ~= nil then |
983 | Cylindered.setDirty(self, movingTool) |
984 | end |
985 | end |
updateDependentAnimations
DescriptionDefinitionupdateDependentAnimations()Code
1166 | function Cylindered:updateDependentAnimations(part, dt) |
1167 | if #part.dependentAnimations > 0 then |
1168 | for _, dependentAnimation in ipairs(part.dependentAnimations) do |
1169 | local pos = 0 |
1170 | if dependentAnimation.translationAxis ~= nil then |
1171 | local retValues = {getTranslation(dependentAnimation.node)} |
1172 | pos = (retValues[dependentAnimation.translationAxis] - dependentAnimation.minValue) / (dependentAnimation.maxValue - dependentAnimation.minValue) |
1173 | end |
1174 | |
1175 | if dependentAnimation.rotationAxis ~= nil then |
1176 | local retValues = {getRotation(dependentAnimation.node)} |
1177 | pos = (retValues[dependentAnimation.rotationAxis] - dependentAnimation.minValue) / (dependentAnimation.maxValue - dependentAnimation.minValue) |
1178 | end |
1179 | |
1180 | pos = MathUtil.clamp(math.abs(pos), 0, 1) |
1181 | if dependentAnimation.invert then |
1182 | pos = 1-pos |
1183 | end |
1184 | dependentAnimation.lastPos = pos |
1185 | |
1186 | self:setAnimationTime(dependentAnimation.name, pos, true) |
1187 | end |
1188 | end |
1189 | end |
updateDependentToolLimits
DescriptionDefinitionupdateDependentToolLimits()Code
1193 | function Cylindered:updateDependentToolLimits(tool, dependentTool) |
1194 | if dependentTool.minTransLimits ~= nil or dependentTool.maxTransLimits ~= nil then |
1195 | local state = Cylindered.getMovingToolState(self, tool) |
1196 | if dependentTool.minTransLimits ~= nil then |
1197 | dependentTool.movingTool.transMin = MathUtil.lerp(dependentTool.minTransLimits[1], dependentTool.minTransLimits[2], 1-state) |
1198 | end |
1199 | if dependentTool.maxTransLimits ~= nil then |
1200 | dependentTool.movingTool.transMax = MathUtil.lerp(dependentTool.maxTransLimits[1], dependentTool.maxTransLimits[2], 1-state) |
1201 | end |
1202 | local transLimitChanged = Cylindered.setToolTranslation(self, dependentTool.movingTool, 0, 0) |
1203 | if transLimitChanged then |
1204 | Cylindered.setDirty(self, dependentTool.movingTool) |
1205 | end |
1206 | end |
1207 | |
1208 | if dependentTool.minRotLimits ~= nil or dependentTool.maxRotLimits ~= nil then |
1209 | local state = Cylindered.getMovingToolState(self, tool) |
1210 | if dependentTool.minRotLimits ~= nil then |
1211 | dependentTool.movingTool.rotMin = MathUtil.lerp(dependentTool.minRotLimits[1], dependentTool.minRotLimits[2], 1-state) |
1212 | end |
1213 | if dependentTool.maxRotLimits ~= nil then |
1214 | dependentTool.movingTool.rotMax = MathUtil.lerp(dependentTool.maxRotLimits[1], dependentTool.maxRotLimits[2], 1-state) |
1215 | end |
1216 | |
1217 | dependentTool.movingTool.networkInterpolators.rotation:setMinMax(dependentTool.movingTool.rotMin, dependentTool.movingTool.rotMax) |
1218 | |
1219 | local rotLimitChanged = Cylindered.setToolRotation(self, dependentTool.movingTool, 0, 0) |
1220 | if rotLimitChanged then |
1221 | Cylindered.setDirty(self, dependentTool.movingTool) |
1222 | end |
1223 | end |
1224 | end |
updateEasyControl
DescriptionDefinitionupdateEasyControl()Code
989 | function Cylindered:updateEasyControl(dt, updateDelayedNodes) |
990 | local spec = self.spec_cylindered |
991 | local easyArmControl = spec.easyArmControl |
992 | if easyArmControl ~= nil then |
993 | local targetYTool = self:getMovingToolByNode(easyArmControl.targetNodeY) |
994 | local targetZTool = self:getMovingToolByNode(easyArmControl.targetNodeZ) |
995 | |
996 | local easyArmControlState = g_gameSettings:getValue("easyArmControl") |
997 | local easyArmControlsActive = true |
998 | easyArmControlsActive = easyArmControlsActive and self:getIsMovingToolActive(targetYTool) |
999 | easyArmControlsActive = easyArmControlsActive and self:getIsMovingToolActive(targetZTool) |
1000 | |
1001 | local hasChanged = false |
1002 | if self.isClient then |
1003 | if spec.lastEasyArmControlState ~= easyArmControlState or spec.lastEasyArmControlsActive ~= easyArmControlsActive then |
1004 | spec.lastEasyArmControlState = easyArmControlState |
1005 | spec.lastEasyArmControlsActive = easyArmControlsActive |
1006 | self:requestActionEventUpdate() |
1007 | |
1008 | local isActive = easyArmControlState and easyArmControlsActive |
1009 | self:setIsEasyControlActive(isActive) |
1010 | hasChanged = isActive |
1011 | end |
1012 | end |
1013 | |
1014 | local tYx, tYy, tYz = getTranslation(easyArmControl.targetNodeY) |
1015 | local tZx, tZy, tZz = getTranslation(easyArmControl.targetNodeZ) |
1016 | if tYx+tYy+tYz ~= easyArmControl.oldTargetNodeYTrans or tZx+tZy+tZz ~= easyArmControl.oldTargetNodeZTrans then |
1017 | hasChanged = true |
1018 | end |
1019 | |
1020 | if self.isServer and easyArmControlState and hasChanged and easyArmControlsActive then |
1021 | easyArmControl.oldTargetNodeYTrans = tYx+tYy+tYz |
1022 | easyArmControl.oldTargetNodeZTrans = tZx+tZy+tZz |
1023 | |
1024 | local xRotNode1 = easyArmControl.xRotationNodes[1].refNode |
1025 | local xRotNode2 = easyArmControl.xRotationNodes[2].refNode |
1026 | |
1027 | local x,y,z = localToLocal(easyArmControl.targetNode, getParent(xRotNode1), 0, 0, 0) |
1028 | local distance = MathUtil.vector3Length(x, y, z) |
1029 | local transDelta = distance - easyArmControl.xRotationMaxDistance |
1030 | |
1031 | for i, translationNode in ipairs(easyArmControl.zTranslationNodes) do |
1032 | local tool = translationNode.movingTool |
1033 | local targetTrans = MathUtil.clamp(transDelta*translationNode.transFactor, tool.transMin, tool.transMax) |
1034 | local _, _, z = getTranslation(translationNode.node) |
1035 | local deltaTrans = targetTrans - z |
1036 | |
1037 | if Cylindered.setToolTranslation(self, tool, nil, 0, deltaTrans) then |
1038 | Cylindered.setDirty(self, tool) |
1039 | |
1040 | self:raiseDirtyFlags(tool.dirtyFlag) |
1041 | self:raiseDirtyFlags(spec.cylinderedDirtyFlag) |
1042 | end |
1043 | end |
1044 | |
1045 | local _,_,node1Length = localToLocal(xRotNode2, xRotNode1, 0, 0, 0) |
1046 | local _, b, c = localToLocal(easyArmControl.targetRefNode, easyArmControl.xRotationNodes[2].node, 0, 0, 0) |
1047 | local node2Length = MathUtil.vector2Length(b, c) |
1048 | local _, ly, lz = localToLocal(easyArmControl.targetNode, getParent(xRotNode1), 0, 0, 0) |
1049 | local _, _, iy, iz = MathUtil.getCircleCircleIntersection(0,0, node1Length, ly, lz, node2Length) |
1050 | local isOutOfRange = true |
1051 | |
1052 | if iy ~= nil and iz ~= nil then |
1053 | local node1Rotation = -math.atan2(iy, iz) |
1054 | local node1Tool = easyArmControl.xRotationNodes[1].movingTool |
1055 | |
1056 | if node1Rotation >= node1Tool.rotMin and node1Rotation <= node1Tool.rotMax then |
1057 | local node2Rotation = math.pi - math.acos((node1Length*node1Length + node2Length*node2Length - distance*distance) / (2*node1Length*node2Length)) |
1058 | local node2Tool = easyArmControl.xRotationNodes[2].movingTool |
1059 | |
1060 | if node2Rotation >= node2Tool.rotMin and node2Rotation <= node2Tool.rotMax then |
1061 | setRotation(xRotNode1, node1Rotation, 0, 0) |
1062 | setRotation(xRotNode2, node2Rotation, 0, 0) |
1063 | |
1064 | for i=1, 2 do |
1065 | local rotationNode = easyArmControl.xRotationNodes[i] |
1066 | local rx,_,_ = getRotation(rotationNode.refNode) |
1067 | local x,_,_ = getRotation(rotationNode.node) |
1068 | |
1069 | if Cylindered.setToolRotation(self, rotationNode.movingTool, nil, 0, rx-x) then |
1070 | Cylindered.setDirty(self, rotationNode.movingTool) |
1071 | |
1072 | if updateDelayedNodes ~= nil and updateDelayedNodes then |
1073 | self:updateDelayedTool(rotationNode.movingTool) |
1074 | end |
1075 | |
1076 | self:raiseDirtyFlags(rotationNode.movingTool.dirtyFlag) |
1077 | self:raiseDirtyFlags(spec.cylinderedDirtyFlag) |
1078 | end |
1079 | end |
1080 | |
1081 | x, y, z = getTranslation(easyArmControl.targetNodeY) |
1082 | easyArmControl.lastValidPositionY[1] = x |
1083 | easyArmControl.lastValidPositionY[2] = y |
1084 | easyArmControl.lastValidPositionY[3] = z |
1085 | |
1086 | x, y, z = getTranslation(easyArmControl.targetNodeZ) |
1087 | easyArmControl.lastValidPositionZ[1] = x |
1088 | easyArmControl.lastValidPositionZ[2] = y |
1089 | easyArmControl.lastValidPositionZ[3] = z |
1090 | |
1091 | isOutOfRange = false |
1092 | end |
1093 | end |
1094 | end |
1095 | |
1096 | if isOutOfRange then |
1097 | setTranslation(easyArmControl.targetNodeY, unpack(easyArmControl.lastValidPositionY)) |
1098 | setTranslation(easyArmControl.targetNodeZ, unpack(easyArmControl.lastValidPositionZ)) |
1099 | end |
1100 | end |
1101 | |
1102 | if VehicleDebug.state == VehicleDebug.DEBUG_ATTRIBUTES then |
1103 | local xRotNode1 = easyArmControl.xRotationNodes[1].refNode |
1104 | local xRotNode2 = easyArmControl.xRotationNodes[2].refNode |
1105 | |
1106 | local _,_,node1Length = localToLocal(xRotNode2, xRotNode1, 0, 0, 0) |
1107 | local _, b, c = localToLocal(easyArmControl.targetRefNode, easyArmControl.xRotationNodes[2].node, 0, 0, 0) |
1108 | local node2Length = MathUtil.vector2Length(b, c) |
1109 | |
1110 | local x1,y1,z1 = localToWorld(xRotNode1, 0, 0, 0) |
1111 | local x2,y2,z2 = localToWorld(xRotNode1, 0, 0, node1Length) |
1112 | drawDebugLine(x1,y1,z1, 0, 1, 0, x2,y2,z2, 0, 1, 0) |
1113 | |
1114 | x1,y1,z1 = localToWorld(xRotNode2, 0, 0, 0) |
1115 | x2,y2,z2 = localToWorld(xRotNode2, 0, 0, node2Length) |
1116 | drawDebugLine(x1,y1,z1, 1, 0, 0, x2,y2,z2, 1, 0, 0) |
1117 | |
1118 | DebugUtil.drawDebugNode(easyArmControl.targetNode, "scTarget") |
1119 | DebugUtil.drawDebugNode(easyArmControl.targetRefNode, "scTargetRef") |
1120 | end |
1121 | end |
1122 | end |
updateExtraDependentParts
DescriptionDefinitionupdateExtraDependentParts()Code
1161 | function Cylindered:updateExtraDependentParts(part, dt) |
1162 | end |
updateMovingPart
DescriptionUpdate moving partDefinition
updateMovingPart(table part, boolean placeComponents, boolean updateDependentParts)Arguments
table | part | part |
boolean | placeComponents | place components |
boolean | updateDependentParts | update dependent parts |
2574 | function Cylindered.updateMovingPart(self, part, placeComponents, updateDependentParts) |
2575 | |
2576 | -- the local reference point must be referenceDistance away from the referencePoint |
2577 | local refX,refY,refZ |
2578 | local dirX, dirY, dirZ = 0,0,0 |
2579 | local changed = false |
2580 | if part.referencePoint ~= nil then |
2581 | if part.moveToReferenceFrame then |
2582 | local x,y,z = localToLocal(part.referenceFrame, getParent(part.node), part.referenceFrameOffset[1], part.referenceFrameOffset[2], part.referenceFrameOffset[3]) |
2583 | setTranslation(part.node, x,y,z) |
2584 | changed = true |
2585 | end |
2586 | refX,refY,refZ = getWorldTranslation(part.referencePoint) |
2587 | if part.referenceDistance == 0 then |
2588 | if part.useLocalOffset then |
2589 | local lx, ly, lz = worldToLocal(part.node, refX, refY, refZ) |
2590 | dirX, dirY, dirZ = localDirectionToWorld(part.node, lx-part.localReferencePoint[1], ly-part.localReferencePoint[2], lz) |
2591 | else |
2592 | local x,y,z = getWorldTranslation(part.node) |
2593 | dirX, dirY, dirZ = refX - x, refY-y, refZ-z |
2594 | end |
2595 | else |
2596 | if part.updateLocalReferenceDistance then |
2597 | local _,y,z = worldToLocal(part.node, getWorldTranslation(part.localReferencePointNode)) |
2598 | part.localReferenceDistance = MathUtil.vector2Length(y, z) |
2599 | end |
2600 | if part.referenceDistancePoint ~= nil then |
2601 | local _,_,z = worldToLocal(part.node, getWorldTranslation(part.referenceDistancePoint)) |
2602 | part.referenceDistance = z |
2603 | end |
2604 | |
2605 | if part.localReferenceTranslate then |
2606 | local _, ly, lz = worldToLocal(part.node, refX, refY, refZ) |
2607 | |
2608 | -- calculate line-circle intersection |
2609 | if math.abs(ly) < part.referenceDistance then |
2610 | local dz = math.sqrt(part.referenceDistance*part.referenceDistance - ly*ly) |
2611 | |
2612 | local z1 = (lz - dz) - part.localReferenceDistance |
2613 | local z2 = (lz + dz) - part.localReferenceDistance |
2614 | if math.abs(z2) < math.abs(z1) then |
2615 | z1 = z2 |
2616 | end |
2617 | local parentNode = getParent(part.node) |
2618 | local tx,ty,tz = unpack(part.localReferenceTranslation) |
2619 | local _, _, coz = localToLocal(parentNode, part.node, tx,ty,tz) |
2620 | local ox,oy,oz = localDirectionToLocal(part.node, parentNode, 0,0,z1-coz) |
2621 | setTranslation(part.node, tx+ox,ty+oy,tz+oz) |
2622 | changed = true |
2623 | end |
2624 | else |
2625 | |
2626 | local r1 = part.localReferenceDistance |
2627 | local r2 = part.referenceDistance |
2628 | local _, ly, lz = worldToLocal(part.node, refX, refY, refZ) |
2629 | --print("intersect: "..ly .. " "..lz) |
2630 | local ix, iy, i2x, i2y = MathUtil.getCircleCircleIntersection(0,0, r1, ly, lz, r2) |
2631 | |
2632 | local allowUpdate = true |
2633 | if part.referenceDistanceThreshold > 0 then |
2634 | local lRefX, lRefY, lRefZ = worldToLocal(part.node, getWorldTranslation(part.referencePoint)) |
2635 | local x,y,z = worldToLocal(part.node, getWorldTranslation(part.localReferencePointNode)) |
2636 | local currentDistance = MathUtil.vector3Length(lRefX-x, lRefY-y, lRefZ-z) |
2637 | |
2638 | if math.abs(currentDistance-part.referenceDistance) < part.referenceDistanceThreshold then |
2639 | allowUpdate = false |
2640 | end |
2641 | end |
2642 | |
2643 | if allowUpdate and ix ~= nil then |
2644 | if i2x ~= nil then |
2645 | -- use the point which as the same angle side as the original configuration |
2646 | local side = ix*(lz-iy) - iy*(ly-ix) |
2647 | if (side < 0) ~= (part.localReferenceAngleSide < 0) then |
2648 | iy = i2y |
2649 | ix = i2x |
2650 | end |
2651 | end |
2652 | dirX, dirY, dirZ = localDirectionToWorld(part.node, 0, ix, iy) |
2653 | changed = true |
2654 | end |
2655 | end |
2656 | end |
2657 | else |
2658 | if part.alignToWorldY then |
2659 | dirX, dirY, dirZ = localDirectionToWorld(getRootNode(), 0, 1, 0) |
2660 | changed = true |
2661 | else |
2662 | dirX, dirY, dirZ = localDirectionToWorld(part.referenceFrame, 0, 0, 1) |
2663 | changed = true |
2664 | end |
2665 | if part.moveToReferenceFrame then |
2666 | local x,y,z = localToLocal(part.referenceFrame, getParent(part.node), part.referenceFrameOffset[1], part.referenceFrameOffset[2], part.referenceFrameOffset[3]) |
2667 | setTranslation(part.node, x,y,z) |
2668 | changed = true |
2669 | end |
2670 | |
2671 | if part.doLineAlignment then |
2672 | local foundPoint = false |
2673 | for i=1, #part.orientationLineNodes-1 do |
2674 | local startNode = part.orientationLineNodes[i] |
2675 | local endNode = part.orientationLineNodes[i+1] |
2676 | |
2677 | local _, sy, sz = localToLocal(startNode, part.referenceFrame, 0, 0, 0) |
2678 | local _, ey, ez = localToLocal(endNode, part.referenceFrame, 0, 0, 0) |
2679 | local _, cy, cz = localToLocal(part.node, part.referenceFrame, 0, 0, 0) |
2680 | |
2681 | local hasIntersection, i1y, i1z, i2y, i2z = MathUtil.getCircleLineIntersection(cy, cz, part.partLength, sy, sz, ey, ez) |
2682 | if hasIntersection then |
2683 | local targetY, targetZ |
2684 | if not MathUtil.getIsOutOfBounds(i1y, sy, ey) and not MathUtil.getIsOutOfBounds(i1z, sz, ez) then |
2685 | targetY, targetZ = i1y, i1z |
2686 | foundPoint = true |
2687 | end |
2688 | if not MathUtil.getIsOutOfBounds(i2y, sy, ey) and not MathUtil.getIsOutOfBounds(i2z, sz, ez) then |
2689 | targetY, targetZ = i2y, i2z |
2690 | foundPoint = true |
2691 | end |
2692 | |
2693 | if foundPoint and not MathUtil.isNan(targetY) and not MathUtil.isNan(targetZ) then |
2694 | dirX, dirY, dirZ = localDirectionToWorld(part.referenceFrame, 0, targetY, targetZ) |
2695 | local upX, upY, upZ = localDirectionToWorld(part.referenceFrame, 0, 1, 0) |
2696 | |
2697 | I3DUtil.setWorldDirection(part.node, dirX, dirY, dirZ, upX, upY, upZ, part.limitedAxis, part.minRot, part.maxRot) |
2698 | changed = true |
2699 | break |
2700 | end |
2701 | end |
2702 | end |
2703 | end |
2704 | end |
2705 | |
2706 | -- if the vehicle is not active we use thresholds to update the moving parts |
2707 | if not self:getIsActive() then |
2708 | if part.directionThreshold ~= nil and part.directionThreshold > 0 then |
2709 | local lDirX, lDirY, lDirZ = worldDirectionToLocal(getParent(part.node), dirX, dirY, dirZ) |
2710 | local upX, upY, upZ = localDirectionToWorld(part.referenceFrame, 0, 1, 0) |
2711 | if math.abs(part.lastDirection[1] - lDirX) > part.directionThreshold or |
2712 | math.abs(part.lastDirection[2] - lDirY) > part.directionThreshold or |
2713 | math.abs(part.lastDirection[3] - lDirZ) > part.directionThreshold or |
2714 | math.abs(part.lastUpVector[1] - upX) > part.directionThreshold or |
2715 | math.abs(part.lastUpVector[2] - upY) > part.directionThreshold or |
2716 | math.abs(part.lastUpVector[3] - upZ) > part.directionThreshold then |
2717 | part.lastDirection = {lDirX, lDirY, lDirZ} |
2718 | part.lastUpVector = {upX, upY, upZ} |
2719 | else |
2720 | dirX, dirY, dirZ = 0, 0, 0 |
2721 | changed = false |
2722 | end |
2723 | end |
2724 | end |
2725 | |
2726 | if (dirX ~= 0 or dirY ~= 0 or dirZ ~= 0) and part.doDirectionAlignment then |
2727 | local upX, upY, upZ = localDirectionToWorld(part.referenceFrame, 0, 1, 0) |
2728 | if part.invertZ then |
2729 | dirX = -dirX |
2730 | dirY = -dirY |
2731 | dirZ = -dirZ |
2732 | end |
2733 | |
2734 | I3DUtil.setWorldDirection(part.node, dirX, dirY, dirZ, upX, upY, upZ, part.limitedAxis, part.minRot, part.maxRot) |
2735 | changed = true |
2736 | |
2737 | if part.scaleZ and part.localReferenceDistance ~= nil then |
2738 | local len = MathUtil.vector3Length(dirX, dirY, dirZ) |
2739 | setScale(part.node, 1, 1, len/part.localReferenceDistance) |
2740 | end |
2741 | end |
2742 | if part.doRotationAlignment then |
2743 | local x,y,z = getRotation(part.referenceFrame) |
2744 | setRotation(part.node, x*part.rotMultiplier, y*part.rotMultiplier, z*part.rotMultiplier) |
2745 | changed = true |
2746 | end |
2747 | |
2748 | if part.referencePoint ~= nil then |
2749 | local numTranslatingParts = table.getn(part.translatingParts) |
2750 | if numTranslatingParts > 0 then |
2751 | local _, _, dist = worldToLocal(part.node, refX, refY, refZ) |
2752 | for i=1,numTranslatingParts do |
2753 | local translatingPart = part.translatingParts[i] |
2754 | local newZ = (dist - translatingPart.referenceDistance)/numTranslatingParts |
2755 | |
2756 | if translatingPart.minZTrans ~= nil then |
2757 | newZ = math.max(translatingPart.minZTrans, newZ) |
2758 | end |
2759 | |
2760 | if translatingPart.maxZTrans ~= nil then |
2761 | newZ = math.min(translatingPart.maxZTrans, newZ) |
2762 | end |
2763 | |
2764 | local allowUpdate = true |
2765 | if part.referenceDistanceThreshold > 0 then |
2766 | local _, _, oldZ = getTranslation(translatingPart.node) |
2767 | if math.abs(oldZ-newZ) < part.referenceDistanceThreshold then |
2768 | allowUpdate = false |
2769 | end |
2770 | end |
2771 | |
2772 | if allowUpdate then |
2773 | setTranslation(translatingPart.node, translatingPart.startPos[1], translatingPart.startPos[2], newZ) |
2774 | changed = true |
2775 | end |
2776 | end |
2777 | end |
2778 | end |
2779 | |
2780 | if changed then |
2781 | if part.copyLocalDirectionParts ~= nil then |
2782 | for _,copyLocalDirectionPart in pairs(part.copyLocalDirectionParts) do |
2783 | local dx,dy,dz = localDirectionToWorld(part.node, 0,0,1) |
2784 | dx,dy,dz = worldDirectionToLocal(getParent(part.node), dx,dy,dz) |
2785 | dx = dx * copyLocalDirectionPart.dirScale[1] |
2786 | dy = dy * copyLocalDirectionPart.dirScale[2] |
2787 | dz = dz * copyLocalDirectionPart.dirScale[3] |
2788 | |
2789 | local ux,uy,uz = localDirectionToWorld(part.node, 0,1,0) |
2790 | ux,uy,uz = worldDirectionToLocal(getParent(part.node), ux,uy,uz) |
2791 | ux = ux * copyLocalDirectionPart.upScale[1] |
2792 | uy = uy * copyLocalDirectionPart.upScale[2] |
2793 | uz = uz * copyLocalDirectionPart.upScale[3] |
2794 | |
2795 | setDirection(copyLocalDirectionPart.node, dx,dy,dz, ux,uy,uz) |
2796 | changed = true |
2797 | |
2798 | if self.isServer then |
2799 | Cylindered.updateComponentJoints(self, copyLocalDirectionPart, placeComponents) |
2800 | end |
2801 | end |
2802 | end |
2803 | end |
2804 | |
2805 | -- update component joint |
2806 | if self.isServer then |
2807 | if changed then |
2808 | Cylindered.updateComponentJoints(self, part, placeComponents) |
2809 | Cylindered.updateAttacherJoints(self, part) |
2810 | Cylindered.updateWheels(self, part) |
2811 | end |
2812 | end |
2813 | |
2814 | if changed then |
2815 | Cylindered.updateWheels(self, part) |
2816 | end |
2817 | |
2818 | if updateDependentParts and part.dependentParts ~= nil then |
2819 | for _,part in pairs(part.dependentParts) do |
2820 | Cylindered.updateMovingPart(self, part, placeComponents, updateDependentParts) |
2821 | end |
2822 | end |
2823 | |
2824 | part.isDirty = false |
2825 | end |
updateRotationBasedLimits
DescriptionDefinitionupdateRotationBasedLimits()Code
2922 | function Cylindered.updateRotationBasedLimits(self, tool, dependentTool) |
2923 | if dependentTool.rotationBasedLimits ~= nil then |
2924 | local state = Cylindered.getMovingToolState(self, tool) |
2925 | if dependentTool.rotationBasedLimits ~= nil then |
2926 | local minRot, maxRot, minTrans, maxTrans = dependentTool.rotationBasedLimits:get(state) |
2927 | |
2928 | if minRot ~= nil then |
2929 | dependentTool.movingTool.rotMin = minRot |
2930 | end |
2931 | if maxRot ~= nil then |
2932 | dependentTool.movingTool.rotMax = maxRot |
2933 | end |
2934 | if minTrans ~= nil then |
2935 | dependentTool.movingTool.transMin = minTrans |
2936 | end |
2937 | if maxTrans ~= nil then |
2938 | dependentTool.movingTool.transMax = maxTrans |
2939 | end |
2940 | |
2941 | local isDirty = false |
2942 | if minRot ~= nil or maxRot ~= nil then |
2943 | isDirty = isDirty or Cylindered.setToolRotation(self, dependentTool.movingTool, 0, 0) |
2944 | end |
2945 | if minTrans ~= nil or maxTrans ~= nil then |
2946 | isDirty = isDirty or Cylindered.setToolTranslation(self, dependentTool.movingTool, 0, 0) |
2947 | end |
2948 | |
2949 | if isDirty then |
2950 | Cylindered.setDirty(self, dependentTool.movingTool) |
2951 | |
2952 | -- sync the new limited rotation values and also the new rotation limits |
2953 | self:raiseDirtyFlags(dependentTool.movingTool.dirtyFlag) |
2954 | self:raiseDirtyFlags(self.spec_cylindered.cylinderedDirtyFlag) |
2955 | end |
2956 | end |
2957 | end |
2958 | end |
updateWheels
DescriptionUpdate wheel of partDefinition
updateWheels(table part)Arguments
table | part | part |
2552 | function Cylindered.updateWheels(self, part) |
2553 | if part.wheels ~= nil then |
2554 | for _, wheel in pairs(part.wheels) do |
2555 | wheel.positionX, wheel.positionY, wheel.positionZ = localToLocal(getParent(wheel.repr), wheel.node, wheel.startPositionX-wheel.steeringCenterOffsetX, wheel.startPositionY-wheel.steeringCenterOffsetY, wheel.startPositionZ-wheel.steeringCenterOffsetZ) |
2556 | if wheel.useReprDirection then |
2557 | wheel.directionX, wheel.directionY, wheel.directionZ = localDirectionToLocal(wheel.repr, wheel.node, 0,-1,0) |
2558 | wheel.axleX, wheel.axleY, wheel.axleZ = localDirectionToLocal(wheel.repr, wheel.node, 1,0,0) |
2559 | elseif wheel.useDriveNodeDirection then |
2560 | wheel.directionX, wheel.directionY, wheel.directionZ = localDirectionToLocal(wheel.driveNodeDirectionNode, wheel.node, 0,-1,0) |
2561 | wheel.axleX, wheel.axleY, wheel.axleZ = localDirectionToLocal(wheel.driveNodeDirectionNode, wheel.node, 1,0,0) |
2562 | end |
2563 | |
2564 | self:updateWheelBase(wheel) |
2565 | end |
2566 | end |
2567 | end |