LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

PlaceableHusbandryFence

Description
Specialization for placeables
Functions

createHusbandryFence

Description
Definition
createHusbandryFence()
Code
329function PlaceableHusbandryFence:createHusbandryFence(fence, poleRoot, panelRoot, panelLength)
330
331 local numPoleVariations = 0
332 if poleRoot ~= nil then
333 numPoleVariations = getNumOfChildren(poleRoot)
334 end
335 local numPanelVariations = 0
336 if panelRoot ~= nil then
337 numPanelVariations = getNumOfChildren(panelRoot)
338 end
339
340 for k, node in ipairs(fence.nodes) do
341 local sx, sy, sz = localToLocal(node, fence.rootNode, 0, 0, 0)
342 local posX, posY, posZ = sx, sy, sz
343 local rotY = 0
344 local nextNode = fence.nodes[k+1]
345 if nextNode ~= nil then
346 local ex, _, ez = localToLocal(nextNode, fence.rootNode, 0, 0, 0)
347 local distance = MathUtil.vector2Length(ex-sx, ez-sz)
348 local dirX, dirZ = MathUtil.vector2Normalize(ex-sx, ez-sz)
349 rotY = math.atan2(dirX, dirZ) + math.pi
350
351 local usedNumPanels = math.floor(distance / panelLength)
352 if distance % panelLength > (panelLength * 0.5) then
353 usedNumPanels = usedNumPanels + 1
354 end
355
356 local usedPanelLength = distance / usedNumPanels
357
358 while distance > 0.001 do
359 local part = {}
360
361 local pole
362 if poleRoot ~= nil and (#fence.parts > 0 or fence.hasStartPole) then
363 pole = clone(getChildAt(poleRoot, math.random(0, numPoleVariations-1)), false, false, false)
364 else
365 pole = createTransformGroup("startPole")
366 end
367 part.pole = pole
368 link(fence.rootNode, pole)
369 setRotation(pole, 0, rotY, 0)
370 setTranslation(pole, posX, posY, posZ)
371
372 if panelRoot ~= nil then
373 local panel = clone(getChildAt(panelRoot, math.random(0, numPanelVariations-1)), false, false, false)
374 link(fence.rootNode, panel)
375 setTranslation(panel, posX, posY, posZ)
376 setDirection(panel, dirX, 0, dirZ, 0, 1, 0)
377 setScale(panel, 1, 1, usedPanelLength / panelLength)
378 part.collision = getChildAt(panel, 0)
379 part.visual = getChildAt(panel, 1)
380 part.panel = panel
381 end
382
383 posX = posX + dirX * usedPanelLength
384 posZ = posZ + dirZ * usedPanelLength
385 distance = distance - usedPanelLength
386 part.length = usedPanelLength
387
388 table.insert(fence.parts, part)
389 end
390 else
391 local pole
392 if poleRoot ~= nil and fence.hasEndPole then
393 pole = clone(getChildAt(poleRoot, math.random(0, numPoleVariations-1)), false, false, false)
394 else
395 pole = createTransformGroup("endPole")
396 end
397
398 link(fence.rootNode, pole)
399 setRotation(pole, 0, rotY, 0)
400 setTranslation(pole, posX, posY, posZ)
401 table.insert(fence.parts, {pole=pole})
402 end
403 end
404
405 self:updateHusbandryFence(fence, false)
406end

getCanBePlacedAt

Description
Definition
getCanBePlacedAt()
Code
471function PlaceableHusbandryFence:getCanBePlacedAt(superFunc, x, y, z, farmId)
472 if not self.spec_husbandryFence.canBePlaced then
473 return false, g_i18n:getText("warning_canNotPlaceFence")
474 end
475
476 return superFunc(self, x, y, z, farmId)
477end

onDelete

Description
Definition
onDelete()
Code
265function PlaceableHusbandryFence:onDelete()
266 local spec = self.spec_husbandryFence
267 if spec.fences ~= nil then
268 for _, fence in ipairs(spec.fences) do
269 if fence.sharedLoadRequestId ~= nil then
270 g_i3DManager:releaseSharedI3DFile(fence.sharedLoadRequestId)
271 end
272 if fence.rootNode ~= nil then
273 delete(fence.rootNode)
274 fence.rootNode = nil
275 end
276 end
277 end
278
279 if spec.gates ~= nil then
280 for _, gate in ipairs(spec.gates) do
281 if gate.sharedLoadRequestId ~= nil then
282 g_i3DManager:releaseSharedI3DFile(gate.sharedLoadRequestId)
283 end
284 if gate.animatedObject ~= nil then
285 gate.animatedObject:delete()
286 gate.animatedObject = nil
287 end
288 end
289 end
290end

onFenceI3DLoaded

Description
Definition
onFenceI3DLoaded()
Code
172function PlaceableHusbandryFence:onFenceI3DLoaded(i3dNode, failedReason, args)
173 local fence = args.fence
174 local fenceXmlFile = args.fenceXmlFile
175 local loadingTask = args.loadingTask
176
177 if i3dNode ~= 0 then
178 local components = {}
179 local i3dMappings = {}
180 I3DUtil.loadI3DComponents(i3dNode, components)
181 I3DUtil.loadI3DMapping(fenceXmlFile, i3dNode, components, i3dMappings)
182
183 local polesRootNode = I3DUtil.indexToObject(components, fenceXmlFile:getString("placeable.fence.poles#node"), i3dMappings)
184 local panelsRootNode = I3DUtil.indexToObject(components, fenceXmlFile:getString("placeable.fence.panels#node"), i3dMappings)
185 local panelLength = fenceXmlFile:getFloat("placable.fence.panels#length", 2)
186 fence.maxAngle = math.rad(fenceXmlFile:getFloat("placeable.fence#maxVerticalAngle", 45))
187
188 self:createHusbandryFence(fence, polesRootNode, panelsRootNode, panelLength)
189
190 delete(i3dNode)
191 end
192
193 fenceXmlFile:delete()
194
195 self:finishLoadingTask(loadingTask)
196end

onGateI3DLoaded

Description
Definition
onGateI3DLoaded()
Code
200function PlaceableHusbandryFence:onGateI3DLoaded(i3dNode, failedReason, args)
201 local gate = args.gate
202 local gateXmlFile = args.gateXmlFile
203 local loadingTask = args.loadingTask
204
205 if i3dNode ~= 0 then
206 local components = {}
207 local i3dMappings = {}
208 I3DUtil.loadI3DComponents(i3dNode, components)
209 I3DUtil.loadI3DMapping(gateXmlFile, i3dNode, components, i3dMappings)
210
211 local gateKey = string.format("placeable.fence.gate(%d)", gate.gateIndex-1)
212
213 local gateRootNode = I3DUtil.indexToObject(components, gateXmlFile:getString(gateKey .. "#node"), i3dMappings)
214
215 if gateRootNode ~= nil then
216
217 local animatedObject = AnimatedObject.new(self.isServer, self.isClient)
218 animatedObject:setOwnerFarmId(self:getOwnerFarmId(), false)
219
220 local saveId = "test" --string.format("AnimatedObject_%s_gate_%d_%d_%d_%d", self.configFileName, segment.x1, segment.z1, segment.x2, segment.x2)
221 local builder = animatedObject:builder(gate.filename, saveId)
222
223 gateXmlFile:iterate(gateKey .. ".door", function(_, doorKey)
224 local doorNode = I3DUtil.indexToObject(gateRootNode, gateXmlFile:getString(doorKey .. "#node"), i3dMappings)
225 if doorNode ~= nil then
226 local rotation = gateXmlFile:getValue(doorKey .. "#openRotation", nil, true)
227 local translation = gateXmlFile:getValue(doorKey .. "#openTranslation", nil, true)
228
229 builder:addSimplePart(doorNode, rotation, translation)
230 end
231 end)
232
233 local duration = gateXmlFile:getValue(gateKey .. "#openDuration") * 1000
234 builder:setDuration(duration)
235
236 local triggerNode = I3DUtil.indexToObject(gateRootNode, gateXmlFile:getString(gateKey .. "#triggerNode"), i3dMappings)
237 builder:setTrigger(triggerNode)
238
239 builder:setSounds(gateXmlFile.handle, gateKey ..".sounds", gateRootNode)
240
241 local openText = gateXmlFile:getString(gateKey .. "#openText", "action_openGate")
242 local closeText = gateXmlFile:getString(gateKey .. "#closeText", "action_closeGate")
243 builder:setActions("ACTIVATE_HANDTOOL", openText, nil, closeText)
244
245 if builder:build() then
246 animatedObject:register(true)
247 gate.animatedObject = animatedObject
248 else
249 animatedObject:delete()
250 end
251
252 link(gate.node, gateRootNode)
253 end
254
255 delete(i3dNode)
256 end
257
258 gateXmlFile:delete()
259
260 self:finishLoadingTask(loadingTask)
261end

onLoad

Description
Definition
onLoad()
Code
65function PlaceableHusbandryFence:onLoad(savegame)
66 local spec = self.spec_husbandryFence
67 spec.fences = {}
68 spec.canBePlaced = true
69
70 self.xmlFile:iterate("placeable.husbandry.fences.fence", function(_, key)
71 local filename = self.xmlFile:getValue(key .. "#filename")
72 if filename == nil then
73 Logging.xmlWarning(self.xmlFile, "Missing segment filename for '%s'", key)
74 return
75 end
76
77 local fence = {}
78 fence.filename = Utils.getFilename(filename, self.baseDirectory)
79 fence.nodes = {}
80 fence.parts = {}
81 fence.rootNode = createTransformGroup("fence")
82 link(self.rootNode, fence.rootNode)
83
84 fence.hasStartPole = self.xmlFile:getValue(key .. "#hasStartPole", true)
85 fence.hasEndPole = self.xmlFile:getValue(key .. "#hasEndPole", true)
86
87 self.xmlFile:iterate(key .. ".node", function(_, segmentKey)
88 local node = self.xmlFile:getValue(segmentKey .. "#node", nil, self.components, self.i3dMappings)
89
90 if node == nil then
91 Logging.xmlWarning(self.xmlFile, "Missing fence node for '%s'", segmentKey)
92 return false
93 end
94
95 table.insert(fence.nodes, node)
96
97 return true
98 end)
99
100 if #fence.nodes > 0 then
101 local fenceXmlFile = XMLFile.load("fence", fence.filename)
102 if fenceXmlFile == nil then
103 Logging.xmlWarning(self.xmlFile, "Could not load fence xml file for '%s'", key)
104 return
105 end
106
107 local fenceFilename = fenceXmlFile:getString("placeable.base.filename")
108 if fenceFilename == nil then
109 Logging.xmlWarning(fenceXmlFile, "Missing fence filename.")
110 return
111 end
112
113 fence.i3dFilename = Utils.getFilename(fenceFilename, self.baseDirectory)
114
115 local loadingTask = self:createLoadingTask()
116 local arguments = {
117 fence = fence,
118 fenceXmlFile = fenceXmlFile,
119 loadingTask = loadingTask
120 }
121 fence.sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(fence.i3dFilename, false, false, self.onFenceI3DLoaded, self, arguments)
122 end
123
124 table.insert(spec.fences, fence)
125 end)
126
127 spec.gates = {}
128 self.xmlFile:iterate("placeable.husbandry.fences.gate", function(_, key)
129 local filename = self.xmlFile:getValue(key .. "#filename")
130 if filename == nil then
131 Logging.xmlWarning(self.xmlFile, "Missing gate filename for '%s'", key)
132 return
133 end
134
135 local gate = {}
136 gate.filename = Utils.getFilename(filename, self.baseDirectory)
137 gate.node = self.xmlFile:getValue(key .. "#node", nil, self.components, self.i3dMappings)
138 if gate.node == nil then
139 Logging.xmlWarning(self.xmlFile, "No gate node defined for '%s'", key)
140 return
141 end
142 gate.gateIndex = self.xmlFile:getValue(key .. "#gateIndex") or 1
143
144 local gateXmlFile = XMLFile.load("gate", gate.filename, Placeable.xmlSchema)
145 if gateXmlFile == nil then
146 Logging.xmlWarning(self.xmlFile, "Could not load gate xml file for '%s'", key)
147 return
148 end
149
150 local gateFilename = gateXmlFile:getString("placeable.base.filename")
151 if gateFilename == nil then
152 Logging.xmlWarning(gateXmlFile, "Missing gate filename.")
153 return
154 end
155
156 gate.i3dFilename = Utils.getFilename(gateFilename, self.baseDirectory)
157
158 local loadingTask = self:createLoadingTask()
159 local arguments = {
160 gate = gate,
161 gateXmlFile = gateXmlFile,
162 loadingTask = loadingTask
163 }
164 gate.sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(gate.i3dFilename, false, false, self.onGateI3DLoaded, self, arguments)
165
166 table.insert(spec.gates, gate)
167 end)
168end

onPreFinalizePlacement

Description
Definition
onPreFinalizePlacement()
Code
294function PlaceableHusbandryFence:onPreFinalizePlacement()
295 local spec = self.spec_husbandryFence
296 for _, fence in ipairs(spec.fences) do
297 self:updateHusbandryFence(fence, true)
298 end
299end

onReadStream

Description
Definition
onReadStream()
Code
303function PlaceableHusbandryFence:onReadStream(streamId, connection)
304 local spec = self.spec_husbandryFence
305 for _, gate in ipairs(spec.gates) do
306 if gate.animatedObject ~= nil then
307 local animatedObjectId = NetworkUtil.readNodeObjectId(streamId)
308 gate.animatedObject:readStream(streamId, connection)
309 g_client:finishRegisterObject(gate.animatedObject, animatedObjectId)
310 end
311 end
312end

onWriteStream

Description
Definition
onWriteStream()
Code
316function PlaceableHusbandryFence:onWriteStream(streamId, connection)
317 local spec = self.spec_husbandryFence
318 for _, gate in ipairs(spec.gates) do
319 if gate.animatedObject ~= nil then
320 NetworkUtil.writeNodeObjectId(streamId, NetworkUtil.getObjectId(gate.animatedObject))
321 gate.animatedObject:writeStream(streamId, connection)
322 g_server:registerObjectInStream(connection, gate.animatedObject)
323 end
324 end
325end

prerequisitesPresent

Description
Checks if all prerequisite specializations are loaded
Definition
prerequisitesPresent(table specializations)
Arguments
tablespecializationsspecializations
Return Values
booleanhasPrerequisitetrue if all prerequisite specializations are loaded
Code
18function PlaceableHusbandryFence.prerequisitesPresent(specializations)
19 return true
20end

registerEventListeners

Description
Definition
registerEventListeners()
Code
33function PlaceableHusbandryFence.registerEventListeners(placeableType)
34 SpecializationUtil.registerEventListener(placeableType, "onLoad", PlaceableHusbandryFence)
35 SpecializationUtil.registerEventListener(placeableType, "onDelete", PlaceableHusbandryFence)
36 SpecializationUtil.registerEventListener(placeableType, "onPreFinalizePlacement", PlaceableHusbandryFence)
37 SpecializationUtil.registerEventListener(placeableType, "onReadStream", PlaceableHusbandryFence)
38 SpecializationUtil.registerEventListener(placeableType, "onWriteStream", PlaceableHusbandryFence)
39end

registerFunctions

Description
Definition
registerFunctions()
Code
24function PlaceableHusbandryFence.registerFunctions(placeableType)
25 SpecializationUtil.registerFunction(placeableType, "updateHusbandryFence", PlaceableHusbandryFence.updateHusbandryFence)
26 SpecializationUtil.registerFunction(placeableType, "createHusbandryFence", PlaceableHusbandryFence.createHusbandryFence)
27 SpecializationUtil.registerFunction(placeableType, "onFenceI3DLoaded", PlaceableHusbandryFence.onFenceI3DLoaded)
28 SpecializationUtil.registerFunction(placeableType, "onGateI3DLoaded", PlaceableHusbandryFence.onGateI3DLoaded)
29end

registerOverwrittenFunctions

Description
Definition
registerOverwrittenFunctions()
Code
43function PlaceableHusbandryFence.registerOverwrittenFunctions(placeableType)
44 SpecializationUtil.registerOverwrittenFunction(placeableType, "setPreviewPosition", PlaceableHusbandryFence.setPreviewPosition)
45 SpecializationUtil.registerOverwrittenFunction(placeableType, "getCanBePlacedAt", PlaceableHusbandryFence.getCanBePlacedAt)
46end

registerXMLPaths

Description
Definition
registerXMLPaths()
Code
50function PlaceableHusbandryFence.registerXMLPaths(schema, basePath)
51 schema:setXMLSpecializationType("Husbandry")
52 basePath = basePath .. ".husbandry.fences"
53 schema:register(XMLValueType.STRING, basePath .. ".fence(?)#filename", "Fence filename")
54 schema:register(XMLValueType.BOOL, basePath .. ".fence(?)#hasStartPole", "Has start pole")
55 schema:register(XMLValueType.BOOL, basePath .. ".fence(?)#hasEndPole", "Has end pole")
56 schema:register(XMLValueType.NODE_INDEX, basePath .. ".fence(?).node(?)#node", "Fence node")
57 schema:register(XMLValueType.NODE_INDEX, basePath .. ".gate(?)#node", "Gate node")
58 schema:register(XMLValueType.STRING, basePath .. ".gate(?)#filename", "Gate filename")
59 schema:register(XMLValueType.INT, basePath .. ".gate(?)#gateIndex", "Gate index")
60 schema:setXMLSpecializationType()
61end

setPreviewPosition

Description
Definition
setPreviewPosition()
Code
458function PlaceableHusbandryFence:setPreviewPosition(superFunc, x, y, z, rotX, rotY, rotZ)
459 superFunc(self, x, y, z, rotX, rotY, rotZ)
460
461 local spec = self.spec_husbandryFence
462 spec.canBePlaced = true
463 for _, fence in ipairs(spec.fences) do
464 local canBePlaced = self:updateHusbandryFence(fence, false)
465 spec.canBePlaced = spec.canBePlaced and canBePlaced
466 end
467end

updateHusbandryFence

Description
Definition
updateHusbandryFence()
Code
410function PlaceableHusbandryFence:updateHusbandryFence(fence, updateCollision)
411 local success = true
412 for index, part in ipairs(fence.parts) do
413 local pole = part.pole
414 local x, y, z = getWorldTranslation(pole)
415 y = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, y, z)
416 setWorldTranslation(pole, x, y, z)
417
418 local panel = part.panel
419 if panel ~= nil then
420 setWorldTranslation(panel, x, y, z)
421 end
422
423 local lastPart = fence.parts[index - 1]
424 if lastPart ~= nil then
425 if lastPart.panel ~= nil then
426 local _, yDif, zDif = localToLocal(pole, lastPart.pole, 0, 0, 0)
427 local angle = math.atan2(math.abs(yDif), math.abs(zDif))
428
429 if angle > fence.maxAngle then
430 success = false
431 end
432
433 I3DUtil.setShaderParameterRec(lastPart.visual, "yOffset", yDif, 0, 0, 0, false, nil)
434
435 if updateCollision then
436 x, y, z = getTranslation(lastPart.collision)
437 local xDir, yDir, zDir = 0, yDif, lastPart.length
438 local length = MathUtil.vector3Length(xDir, yDir, zDir)
439 xDir, yDir, zDir = MathUtil.vector3Normalize(xDir, yDir, zDir)
440
441 local offset = (length-lastPart.length) * 0.5
442 x = x + xDir*offset
443 y = y + yDir*offset
444 z = z + zDir*offset
445
446 setDirection(lastPart.collision, xDir, yDir, zDir, 0, 1, 0)
447 setTranslation(lastPart.collision, x, y, z)
448 end
449 end
450 end
451 end
452
453 return success
454end