LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

SlopeCompensation

Description
Specialization for automatic slope compensation in vehicles based on the angle between two wheel nodes
Functions

getCompensationAngleScale

Description
Definition
getCompensationAngleScale()
Code
172function SlopeCompensation:getCompensationAngleScale(compensationNode)
173 return 1
174end

getCompensationGroundPosition

Description
Definition
getCompensationGroundPosition()
Code
178function SlopeCompensation:getCompensationGroundPosition(compensationNode, wheelId)
179 local spec = self.spec_slopeCompensation
180 local x, y, z = getWorldTranslation(compensationNode["wheel"..wheelId.."Node"])
181
182 spec.lastRaycastDistance = 0
183 raycastAll(x, y, z, 0, -1, 0, "slopeDetectionCallback", compensationNode.raycastDistance, self, SlopeCompensation.SLOPE_COLLISION_MASK)
184 local distance = spec.lastRaycastDistance
185 if distance == 0 then
186 distance = compensationNode["lastDistance"..wheelId]
187 else
188 compensationNode["lastDistance"..wheelId] = spec.lastRaycastDistance
189 end
190
191 return x, y - distance, z, distance ~= 0
192end

initSpecialization

Description
Definition
initSpecialization()
Code
22function SlopeCompensation.initSpecialization()
23 local schema = Vehicle.xmlSchema
24 schema:setXMLSpecializationType("SlopeCompensation")
25
26 schema:register(XMLValueType.FLOAT, "vehicle.slopeCompensation#threshold", "Update threshold for animation", 0.002)
27 schema:register(XMLValueType.BOOL, "vehicle.slopeCompensation#highUpdateFrequency", "Defines if the angle is updated every frame or every seconds frame", false)
28
29 schema:register(XMLValueType.INT, SlopeCompensation.COMPENSATION_NODE_XML_KEY .. "#wheel1", "Wheel index 1")
30 schema:register(XMLValueType.INT, SlopeCompensation.COMPENSATION_NODE_XML_KEY .. "#wheel2", "Wheel index 2")
31 schema:register(XMLValueType.ANGLE, SlopeCompensation.COMPENSATION_NODE_XML_KEY .. "#maxAngle", "Max. angle", 5)
32 schema:register(XMLValueType.ANGLE, SlopeCompensation.COMPENSATION_NODE_XML_KEY .. "#minAngle", "Min. angle", "Negative #maxAngle")
33 schema:register(XMLValueType.FLOAT, SlopeCompensation.COMPENSATION_NODE_XML_KEY .. "#speed", "Move speed", 1)
34 schema:register(XMLValueType.STRING, SlopeCompensation.COMPENSATION_NODE_XML_KEY .. "#animationName", "Animation name")
35
36 schema:setXMLSpecializationType()
37end

loadCompensationNodeFromXML

Description
Definition
loadCompensationNodeFromXML()
Code
131function SlopeCompensation:loadCompensationNodeFromXML(compensationNode, xmlFile, key)
132 compensationNode.raycastDistance = 0
133 compensationNode.lastDistance1 = 0
134 compensationNode.lastDistance2 = 0
135 for _, name in ipairs({"wheel1", "wheel2"}) do
136 local wheelId = self.xmlFile:getValue(key.."#"..name)
137 if wheelId == nil then
138 Logging.xmlWarning(self.xmlFile, "Missing %s for compensation node '%s'", name, key)
139 return false
140 end
141
142 local wheel = self:getWheels()[wheelId]
143 if wheel ~= nil then
144 compensationNode[name.."Node"] = wheel.driveNode
145 compensationNode.raycastDistance = math.max(compensationNode.raycastDistance, wheel.radius+1)
146 else
147 Logging.xmlWarning(self.xmlFile, "Unable to find wheel index '%d' for compensation node '%s'", wheelId, key)
148 return false
149 end
150 end
151
152 compensationNode.maxAngle = self.xmlFile:getValue(key.."#maxAngle", 5)
153 compensationNode.minAngle = self.xmlFile:getValue(key.."#minAngle", -math.deg(compensationNode.maxAngle))
154
155 compensationNode.speed = self.xmlFile:getValue(key.."#speed", 1) / 1000
156
157 compensationNode.lastPos = 0.5
158
159 compensationNode.animationName = self.xmlFile:getValue(key.."#animationName")
160 if compensationNode.animationName ~= nil then
161 local updateAnimation = self:getCompensationAngleScale(compensationNode) > 0
162 self:setAnimationTime(compensationNode.animationName, 0, updateAnimation)
163 self:setAnimationTime(compensationNode.animationName, 1, updateAnimation)
164 self:setAnimationTime(compensationNode.animationName, 0.5, updateAnimation)
165 end
166
167 return true
168end

onPostLoad

Description
Definition
onPostLoad()
Code
58function SlopeCompensation:onPostLoad(savegame)
59 local spec = self.spec_slopeCompensation
60
61 spec.lastRaycastDistance = 0
62 spec.nodes = {}
63 local i = 0
64 while true do
65 local key = string.format("vehicle.slopeCompensation.compensationNode(%d)", i)
66 if not self.xmlFile:hasProperty(key) then
67 break
68 end
69
70 local compensationNode = {}
71 if self:loadCompensationNodeFromXML(compensationNode, self.xmlFile, key) then
72 table.insert(spec.nodes, compensationNode)
73 end
74
75 i = i + 1
76 end
77
78 spec.threshold = self.xmlFile:getValue("vehicle.slopeCompensation#threshold", 0.002)
79
80 if #spec.nodes == 0 then
81 SpecializationUtil.removeEventListener(self, "onUpdate", SlopeCompensation)
82 SpecializationUtil.removeEventListener(self, "onUpdateTick", SlopeCompensation)
83 else
84 if self.xmlFile:getValue("vehicle.slopeCompensation#highUpdateFrequency", false) then
85 SpecializationUtil.removeEventListener(self, "onUpdateTick", SlopeCompensation)
86 else
87 SpecializationUtil.removeEventListener(self, "onUpdate", SlopeCompensation)
88 end
89 end
90end

onUpdate

Description
Definition
onUpdate()
Code
94function SlopeCompensation:onUpdate(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
95 local spec = self.spec_slopeCompensation
96
97 for _, compensationNode in ipairs(spec.nodes) do
98 local x1, y1, z1, valid1 = self:getCompensationGroundPosition(compensationNode, 1)
99 local x2, y2, z2, valid2 = self:getCompensationGroundPosition(compensationNode, 2)
100
101 if valid1 and valid2 then
102 local h = y1 - y2
103 local l = MathUtil.vector2Length(x1-x2, z1-z2)
104 local angle = math.tan(h/l) * self:getCompensationAngleScale(compensationNode)
105 local pos = MathUtil.clamp((angle - compensationNode.minAngle) / (compensationNode.maxAngle - compensationNode.minAngle), 0, 1)
106
107 if math.abs(compensationNode.lastPos - pos) > spec.threshold then
108 local dir = MathUtil.sign(pos - compensationNode.lastPos)
109 local limit = dir > 0 and math.min or math.max
110
111 compensationNode.lastPos = limit(compensationNode.lastPos + compensationNode.speed * dt * dir, pos)
112
113 if self.setAnimationTime ~= nil then
114 if compensationNode.animationName ~= nil then
115 self:setAnimationTime(compensationNode.animationName, compensationNode.lastPos, true)
116 end
117 end
118 end
119 end
120 end
121end

onUpdateTick

Description
Definition
onUpdateTick()
Code
125function SlopeCompensation:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
126 SlopeCompensation.onUpdate(self, dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
127end

prerequisitesPresent

Description
Definition
prerequisitesPresent()
Code
16function SlopeCompensation.prerequisitesPresent(specializations)
17 return SpecializationUtil.hasSpecialization(Wheels, specializations)
18end

registerEventListeners

Description
Definition
registerEventListeners()
Code
50function SlopeCompensation.registerEventListeners(vehicleType)
51 SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", SlopeCompensation)
52 SpecializationUtil.registerEventListener(vehicleType, "onUpdate", SlopeCompensation)
53 SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", SlopeCompensation)
54end

registerFunctions

Description
Definition
registerFunctions()
Code
41function SlopeCompensation.registerFunctions(vehicleType)
42 SpecializationUtil.registerFunction(vehicleType, "loadCompensationNodeFromXML", SlopeCompensation.loadCompensationNodeFromXML)
43 SpecializationUtil.registerFunction(vehicleType, "getCompensationAngleScale", SlopeCompensation.getCompensationAngleScale)
44 SpecializationUtil.registerFunction(vehicleType, "getCompensationGroundPosition", SlopeCompensation.getCompensationGroundPosition)
45 SpecializationUtil.registerFunction(vehicleType, "slopeDetectionCallback", SlopeCompensation.slopeDetectionCallback)
46end

slopeDetectionCallback

Description
Definition
slopeDetectionCallback()
Code
196function SlopeCompensation:slopeDetectionCallback(hitObjectId, x, y, z, distance)
197 if getRigidBodyType(hitObjectId) ~= RigidBodyType.STATIC then
198 return true
199 end
200
201 self.spec_slopeCompensation.lastRaycastDistance = distance
202
203 return false
204end