LUADOC - Farming Simulator 19

AnimatedObject

Description
Class for animated objects
Parent
Object
Functions

delete

Description
Delete animated object
Definition
delete()
Code
230function AnimatedObject:delete()
231 self:removeActionEvents()
232
233 if self.controls.triggerId ~= nil then
234 removeTrigger(self.controls.triggerId)
235 for i=0, getNumOfChildren(self.controls.triggerId)-1 do
236 removeTrigger(getChildAt(self.controls.triggerId, i))
237 end
238 self.controls.triggerId = nil
239 end
240
241 if self.sampleMoving ~= nil then
242 g_soundManager:deleteSample(self.sampleMoving)
243 self.sampleMoving = nil
244 end
245 if self.samplePosEnd ~= nil then
246 g_soundManager:deleteSample(self.samplePosEnd)
247 self.samplePosEnd = nil
248 end
249 if self.sampleNegEnd ~= nil then
250 g_soundManager:deleteSample(self.sampleNegEnd)
251 self.sampleNegEnd = nil
252 end
253
254 g_currentMission.environment:removeHourChangeListener(self)
255
256 AnimatedObject:superClass().delete(self)
257end

hourChanged

Description
Called on hour change
Definition
hourChanged()
Code
586function AnimatedObject:hourChanged()
587 if self.isServer then
588 local currentHour = g_currentMission.environment.currentHour
589 if self.openingHours ~= nil then
590 if currentHour >= self.openingHours.startTime and currentHour < self.openingHours.endTime then
591 if not self.openingHours.isOpen then
592 if self.isServer then
593 self.animation.direction = 1
594 self:raiseActive()
595 end
596 self.openingHours.isOpen = true
597 end
598 if self.openingHours.disableIfClosed then
599 self.isEnabled = true
600 end
601 else
602 if self.openingHours.isOpen then
603 if self.isServer then
604 self.animation.direction = -1
605 self:raiseActive()
606 end
607 self.openingHours.isOpen = false
608 end
609 if self.openingHours.disableIfClosed then
610 self.isEnabled = false
611 end
612 end
613 end
614 end
615end

load

Description
Load animated object from object with given configuration file
Definition
load(integer nodeId, xmlFilename string, index integer)
Arguments
integernodeIdid of object
xmlFilenamestringPath of the xml configuration
indexintegerConfiguration index within the xml file
Return Values
booleansuccesssuccess
Code
48function AnimatedObject:load(nodeId, xmlFile, key, xmlFilename)
49 local modName, baseDirectory = Utils.getModNameAndBaseDirectory(xmlFilename)
50 self.baseDirectory = baseDirectory
51 self.customEnvironment = modName
52
53 self.nodeId = nodeId
54
55 self.samples = {}
56
57 local success = true
58 self.saveId = getXMLString(xmlFile, key.."#saveId")
59 if self.saveId == nil then
60 self.saveId = "AnimatedObject_"..getName(nodeId)
61 end
62
63 local animKey = key .. ".animation"
64
65 self.animation = {}
66 self.animation.parts = {}
67 self.animation.duration = Utils.getNoNil(getXMLFloat(xmlFile, animKey.."#duration"), 3) * 1000
68 if self.animation.duration == 0 then
69 self.animation.duration = 1000
70 end
71 self.animation.time = 0
72 self.animation.direction = 0
73
74 local i = 0
75 while true do
76 local partKey = string.format("%s.part(%d)", animKey, i)
77 if not hasXMLProperty(xmlFile, partKey) then
78 break
79 end
80
81 local node = I3DUtil.indexToObject(self.nodeId, getXMLString(xmlFile, partKey.."#node"))
82 if node ~= nil then
83 local part = {}
84 part.node = node
85 part.animCurve = AnimCurve:new(linearInterpolatorN)
86 local hasFrames = false
87 local j = 0
88 while true do
89 local frameKey = string.format("%s.keyFrame(%d)", partKey, j)
90 if not hasXMLProperty(xmlFile, frameKey) then
91 break
92 end
93
94 local keyTime = getXMLFloat(xmlFile, frameKey.."#time")
95 local keyframe = {self:loadFrameValues(xmlFile, frameKey, node)}
96 keyframe.time = keyTime
97 part.animCurve:addKeyframe(keyframe)
98 hasFrames = true
99
100 j = j + 1
101 end
102
103 if hasFrames then
104 table.insert(self.animation.parts, part)
105 end
106 end
107 i = i + 1
108 end
109
110 local initialTime = Utils.getNoNil(getXMLFloat(xmlFile, animKey.."#initialTime"), 0)*1000
111 self:setAnimTime(initialTime / self.animation.duration, true)
112
113 local startTime = getXMLFloat(xmlFile, key..".openingHours#startTime")
114 local endTime = getXMLFloat(xmlFile, key..".openingHours#endTime")
115 if startTime ~= nil and endTime ~= nil then
116 local disableIfClosed = Utils.getNoNil(getXMLBool(xmlFile, key..".openingHours#disableIfClosed"), false)
117 local closedText = getXMLString(xmlFile, key..".openingHours#closedText")
118 if closedText ~= nil then
119 if g_i18n:hasText(closedText, self.customEnvironment) then
120 closedText = g_i18n:getText(closedText, self.customEnvironment)
121 end
122 end
123 self.openingHours = {startTime=startTime, endTime=endTime, disableIfClosed=disableIfClosed, closedText=closedText}
124 g_currentMission.environment:addHourChangeListener(self)
125 end
126
127 self.isEnabled = true
128
129
130 local triggerId = I3DUtil.indexToObject(self.nodeId, getXMLString(xmlFile, key..".controls#triggerNode"))
131 if triggerId ~= nil then
132 self.controls.triggerId = triggerId
133
134 addTrigger(self.controls.triggerId, "triggerCallback", self)
135 for i=0, getNumOfChildren(self.controls.triggerId)-1 do
136 addTrigger(getChildAt(self.controls.triggerId, i), "triggerCallback", self)
137 end
138
139 local posAction = getXMLString(xmlFile, key..".controls#posAction")
140 if posAction ~= nil then
141 if InputAction[posAction] then
142 self.controls.posAction = posAction
143
144 local posText = getXMLString(xmlFile, key..".controls#posText")
145 if posText ~= nil then
146 if g_i18n:hasText(posText, self.customEnvironment) then
147 posText = g_i18n:getText(posText, self.customEnvironment)
148 end
149 self.controls.posActionText = posText
150 end
151
152 local negText = getXMLString(xmlFile, key..".controls#negText")
153 if negText ~= nil then
154 if g_i18n:hasText(negText, self.customEnvironment) then
155 negText = g_i18n:getText(negText, self.customEnvironment)
156 end
157 self.controls.negActionText = negText
158 end
159
160 local negAction = getXMLString(xmlFile, key..".controls#negAction")
161 if negAction ~= nil then
162 if InputAction[negAction] then
163 self.controls.negAction = negAction
164 else
165 print("Warning: Negative direction action '"..negAction.."' not defined!")
166 end
167 end
168 else
169 print("Warning: Positive direction action '"..posAction.."' not defined!")
170 end
171 end
172 end
173
174 if g_client ~= nil then
175 local soundsKey = key .. ".sounds"
176 self.sampleMoving = g_soundManager:loadSampleFromXML(xmlFile, soundsKey, "moving", self.baseDirectory, self.nodeId, 1, AudioGroup.ENVIRONMENT, nil, nil)
177 self.samplePosEnd = g_soundManager:loadSampleFromXML(xmlFile, soundsKey, "posEnd", self.baseDirectory, self.nodeId, 1, AudioGroup.ENVIRONMENT, nil, nil)
178 self.sampleNegEnd = g_soundManager:loadSampleFromXML(xmlFile, soundsKey, "negEnd", self.baseDirectory, self.nodeId, 1, AudioGroup.ENVIRONMENT, nil, nil)
179 end
180
181 self.animatedObjectDirtyFlag = self:getNextDirtyFlag()
182
183 return success
184end

loadFrameValues

Description
Load frame values from xml
Definition
loadFrameValues(integer fileId, string key, integer node)
Arguments
integerfileIdxml file id
stringkeykey
integernodenode id
Return Values
floatxx translation
floatyy translation
floatzz translation
floatrxx rotation
floatryy rotation
floatrzz rotation
floatsxx scale
floatsyy scale
floatszz scale
integervisibilityvisibility
Code
201function AnimatedObject:loadFrameValues(xmlFile, key, node)
202 local rx,ry,rz = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#rotation"))
203 local x,y,z = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#translation"))
204 local sx,sy,sz = StringUtil.getVectorFromString(getXMLString(xmlFile, key.."#scale"))
205 local isVisible = Utils.getNoNil(getXMLBool(xmlFile, key.."#visibility"), true)
206
207 local drx,dry,drz = getRotation(node)
208 rx = Utils.getNoNilRad(rx, drx)
209 ry = Utils.getNoNilRad(ry, dry)
210 rz = Utils.getNoNilRad(rz, drz)
211 local dx,dy,dz = getTranslation(node)
212 x = Utils.getNoNil(x, dx)
213 y = Utils.getNoNil(y, dy)
214 z = Utils.getNoNil(z, dz)
215 local dsx,dsy,dsz = getScale(node)
216 sx = Utils.getNoNil(sx, dsx)
217 sy = Utils.getNoNil(sy, dsy)
218 sz = Utils.getNoNil(sz, dsz)
219
220 local visibility = 1
221 if not isVisible then
222 visibility = 0
223 end
224
225 return x, y, z, rx, ry, rz, sx, sy, sz, visibility
226end

loadFromXMLFile

Description
Loading from attributes and nodes
Definition
loadFromXMLFile(integer xmlFile, string key)
Arguments
integerxmlFileid of xml object
stringkeykey
Return Values
booleansuccesssuccess
Code
321function AnimatedObject:loadFromXMLFile(xmlFile, key)
322 local animTime = getXMLFloat(xmlFile, key .. "#time")
323 if animTime ~= nil then
324 self.animation.direction = Utils.getNoNil(getXMLInt(xmlFile, key.."#direction"), 0)
325 self:setAnimTime(animTime, true)
326 end
327
328 AnimatedObject.hourChanged(self)
329
330 return true
331end

new

Description
Creating new instance of animated object class
Definition
new(boolean isServer, boolean isClient, table customMt)
Arguments
booleanisServeris server
booleanisClientis client
tablecustomMtcustom metatable
Return Values
tableselfnew instance of object
Code
20function AnimatedObject:new(isServer, isClient, customMt)
21 local self = Object:new(isServer, isClient, customMt or AnimatedObject_mt)
22 self.nodeId = 0
23 self.isMoving = false
24 self.wasPressed = false
25
26 -- input controls fields:
27 self.controls = {}
28 self.controls.active = false
29 self.controls.posAction = nil
30 self.controls.negAction = nil
31 self.controls.posText = nil
32 self.controls.negText = nil
33 self.controls.posActionEventId = nil
34 self.controls.negActionEventId = nil
35
36 self.networkTimeInterpolator = InterpolationTime:new(1.2)
37 self.networkAnimTimeInterpolator = InterpolatorValue:new(0)
38
39 return self
40end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
263function AnimatedObject:readStream(streamId, connection)
264 AnimatedObject:superClass().readStream(self, streamId, connection)
265 if connection:getIsServer() then
266 local animTime = streamReadFloat32(streamId)
267 self:setAnimTime(animTime, true)
268
269 self.networkAnimTimeInterpolator:setValue(animTime)
270
271 self.networkTimeInterpolator:reset()
272 end
273end

readUpdateStream

Description
Called on client side on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
291function AnimatedObject:readUpdateStream(streamId, timestamp, connection)
292 AnimatedObject:superClass().readUpdateStream(self, streamId, timestamp, connection)
293 if connection:getIsServer() then
294 if streamReadBool(streamId) then
295 self.networkTimeInterpolator:startNewPhaseNetwork()
296 local animTime = streamReadFloat32(streamId)
297 self.networkAnimTimeInterpolator:setTargetValue(animTime)
298 end
299 end
300end

setAnimTime

Description
Set animation time
Definition
setAnimTime(float t)
Arguments
floatttime
Code
559function AnimatedObject:setAnimTime(t, omitSound)
560 t = MathUtil.clamp(t, 0, 1)
561
562 for _, part in pairs(self.animation.parts) do
563 local v = part.animCurve:get(t)
564 self:setFrameValues(part.node, v)
565 end
566
567 self.animation.time = t
568 self.isMoving = true
569
570 return t
571end

setFrameValues

Description
Set frame values
Definition
setFrameValues(integer node, table v)
Arguments
integernodenode id
tablevvalues
Code
577function AnimatedObject:setFrameValues(node, v)
578 setTranslation(node, v[1], v[2], v[3])
579 setRotation(node, v[4], v[5], v[6])
580 setScale(node, v[7], v[8], v[9])
581 setVisibility(node, v[10] == 1)
582end

triggerCallback

Description
Trigger callback
Definition
triggerCallback(integer triggerId, integer otherId, boolean onEnter, boolean onLeave, boolean onStay)
Arguments
integertriggerIdid of trigger
integerotherIdid of object that calls callback
booleanonEntercalled on enter
booleanonLeavecalled on leave
booleanonStaycalled on stay
Code
624function AnimatedObject:triggerCallback(triggerId, otherId, onEnter, onLeave, onStay)
625 if g_currentMission.missionInfo:isa(FSCareerMissionInfo) then
626 if onEnter or onLeave then
627 if g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then
628 if onEnter then
629 if self.ownerFarmId == nil or self.ownerFarmId == AccessHandler.EVERYONE or g_currentMission.accessHandler:canFarmAccessOtherId(g_currentMission:getFarmId(), self.ownerFarmId) then
630 self.playerInRange = g_currentMission.player
631 end
632 else
633 self.playerInRange = nil
634 end
635 self:raiseActive()
636 end
637 end
638 end
639end

update

Description
Called on update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
459function AnimatedObject:update(dt)
460 AnimatedObject:superClass().update(self, dt)
461
462 -- Update availability of the input actions
463 local deactivateInput = false
464 if self.playerInRange then
465 if self.isEnabled then
466 if not self.controls.active then
467 self:registerActionEventsWhenInRange()
468 end
469 self:updateActionEventTexts()
470 else
471 deactivateInput = true
472 if self.openingHours ~= nil and self.openingHours.closedText ~= nil then
473 g_currentMission:addExtraPrintText(self.openingHours.closedText)
474 end
475 end
476 else
477 deactivateInput = true
478 end
479
480 if deactivateInput and self.controls.active then
481 self:removeActionEvents()
482 end
483
484 local finishedAnimation = false
485
486 -- former updateTick()
487 if self.isServer then
488 if self.animation.direction ~= 0 then
489 local newAnimTime = MathUtil.clamp(self.animation.time + (self.animation.direction*dt)/self.animation.duration, 0, 1)
490
491 self:setAnimTime(newAnimTime)
492 if newAnimTime == 0 or newAnimTime == 1 then
493 self.animation.direction = 0
494 finishedAnimation = true
495 end
496 end
497
498 if self.animation.time ~= self.animation.timeSend then
499 self.animation.timeSend = self.animation.time
500 self:raiseDirtyFlags(self.animatedObjectDirtyFlag)
501 end
502 else
503 self.networkTimeInterpolator:update(dt)
504 local interpolationAlpha = self.networkTimeInterpolator:getAlpha()
505 local animTime = self.networkAnimTimeInterpolator:getInterpolatedValue(interpolationAlpha)
506 local newAnimTime = self:setAnimTime(animTime)
507
508 if self.animation.direction ~= 0 then
509 if self.animation.direction > 0 then
510 if newAnimTime == 1 then
511 self.animation.direction = 0
512 finishedAnimation = true
513 end
514 else
515 if newAnimTime == 0 then
516 self.animation.direction = 0
517 finishedAnimation = true
518 end
519 end
520 end
521
522 if self.networkTimeInterpolator:isInterpolating() then
523 self:raiseActive()
524 end
525 end
526
527 if self.sampleMoving ~= nil then
528 if self.isMoving and self.animation.direction ~= 0 then
529 if not self.sampleMoving.isPlaying then
530 g_soundManager:playSample(self.sampleMoving)
531 self.sampleMoving.isPlaying = true
532 end
533 else
534 if self.sampleMoving.isPlaying then
535 g_soundManager:stopSample(self.sampleMoving)
536 self.sampleMoving.isPlaying = false
537 end
538 end
539 end
540
541 if finishedAnimation and self.animation.direction == 0 then
542 if self.samplePosEnd ~= nil and self.animation.time == 1 then
543 g_soundManager:playSample(self.samplePosEnd)
544 elseif self.sampleNegEnd ~= nil and self.animation.time == 0 then
545 g_soundManager:playSample(self.sampleNegEnd)
546 end
547 end
548
549 self.isMoving = false
550
551 if self.animation.direction ~= 0 then
552 self:raiseActive()
553 end
554end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
279function AnimatedObject:writeStream(streamId, connection)
280 AnimatedObject:superClass().writeStream(self, streamId, connection)
281 if not connection:getIsServer() then
282 streamWriteFloat32(streamId, self.animation.time)
283 end
284end

writeUpdateStream

Description
Called on server side on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
307function AnimatedObject:writeUpdateStream(streamId, connection, dirtyMask)
308 AnimatedObject:superClass().writeUpdateStream(self, streamId, connection, dirtyMask)
309 if not connection:getIsServer() then
310 if streamWriteBool(streamId, bitAND(dirtyMask, self.animatedObjectDirtyFlag) ~= 0) then
311 streamWriteFloat32(streamId, self.animation.timeSend)
312 end
313 end
314end