LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

PlaceableGreenhouse

Description
Specialization for placeables
Functions

addPlantPlace

Description
Definition
addPlantPlace()
Code
173function PlaceableGreenhouse:addPlantPlace(node, useRandomYRot)
174 local spec = self.spec_greenhouse
175
176 useRandomYRot = Utils.getNoNil(useRandomYRot, true)
177 if useRandomYRot then
178 setRotation(node, 0, math.random() * math.pi * 2, 0)
179 end
180 table.insert(spec.plantPlaces, {node = node, fillType = nil, stage = nil})
181end

getRandomGrowthInterval

Description
Definition
getRandomGrowthInterval()
Code
22function PlaceableGreenhouse.getRandomGrowthInterval()
23 return math.random(PlaceableGreenhouse.GROWTH_INTERVAL_SECONDS_MIN, PlaceableGreenhouse.GROWTH_INTERVAL_SECONDS_MAX) * (1000 + math.random(50))
24end

getRandomWateringInterval

Description
Definition
getRandomWateringInterval()
Code
28function PlaceableGreenhouse.getRandomWateringInterval()
29 return math.random(PlaceableGreenhouse.WATERING_INTERVAL_SECONDS_MIN, PlaceableGreenhouse.WATERING_INTERVAL_SECONDS_MAX) * (1000 + math.random(50))
30end

initSpecialization

Description
Definition
initSpecialization()
Code
44function PlaceableGreenhouse.initSpecialization()
45 local plantXmlSchema = XMLSchema.new("greenhousePlant")
46 plantXmlSchema:register(XMLValueType.STRING, "greenhousePlant.i3dFilename", "i3d file of plant")
47 plantXmlSchema:register(XMLValueType.NODE_INDEX, "greenhousePlant.stages.growing(?)#node", "Growing mesh")
48 plantXmlSchema:register(XMLValueType.NODE_INDEX, "greenhousePlant.stages.withered#node", "Withered mesh")
49
50 PlaceableGreenhouse.plantXmlSchema = plantXmlSchema
51end

loadPlantFromXml

Description
Definition
loadPlantFromXml()
Code
185function PlaceableGreenhouse:loadPlantFromXml(xmlFilename)
186 local plant = {
187 i3dFilename = "",
188 i3dNode = nil,
189 stages = { -- stagse are stored as child indices of meshes -> allows working on cloned nodes without managing node ids
190 growing = {}, -- growing stages from small to big
191 first = nil,
192 last = nil,
193 withered = nil,
194 }
195 }
196
197 local plantXmlFile = XMLFile.load("plantXml", xmlFilename, PlaceableGreenhouse.plantXmlSchema)
198 if plantXmlFile ~= nil then
199 local i3dFilename = plantXmlFile:getValue("greenhousePlant.i3dFilename")
200 if i3dFilename ~= nil then
201 plant.i3dFilename = Utils.getFilename(i3dFilename, self.baseDirectory)
202
203 local loadingTask = self:createLoadingTask()
204
205 local arguments = {
206 plant = plant,
207 plantXmlFile = plantXmlFile,
208 loadingTask = loadingTask
209 }
210 plant.sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(plant.i3dFilename, false, false, self.plantI3DLoadedCallback, self, arguments)
211 end
212 end
213
214 return plant
215end

onDelete

Description
Definition
onDelete()
Code
256function PlaceableGreenhouse:onDelete()
257 local spec = self.spec_greenhouse
258
259 if spec.growthTimer ~= nil then
260 spec.growthTimer:delete()
261 end
262 if spec.wateringTimer ~= nil then
263 spec.wateringTimer:delete()
264 end
265
266 if spec.filltypeIdToPlant ~= nil then
267 for _, plant in pairs(spec.filltypeIdToPlant) do
268 if plant.sharedLoadRequestId ~= nil then
269 g_i3DManager:releaseSharedI3DFile(plant.sharedLoadRequestId)
270 end
271
272 if plant.i3dNode ~= nil then
273 delete(plant.i3dNode)
274 plant.i3dNode = nil
275 end
276 end
277 end
278
279 g_effectManager:deleteEffects(spec.effects)
280 g_soundManager:deleteSamples(spec.samples)
281end

onFinalizePlacement

Description
Definition
onFinalizePlacement()
Code
285function PlaceableGreenhouse:onFinalizePlacement()
286 self.plantDistributionDirty = true
287 self.spec_greenhouse.wateringTimer:start()
288end

onLoad

Description
Definition
onLoad()
Code
94function PlaceableGreenhouse:onLoad(savegame)
95 local spec = self.spec_greenhouse
96 local xmlFile = self.xmlFile
97 local key = "placeable.greenhouse"
98
99 spec.filltypeIdToPlant = {}
100 spec.plantPlaces = {}
101
102 spec.activeFilltypes = {}
103 spec.hasWater = true
104
105 xmlFile:iterate(key .. ".plants.plant", function(index, plantKey)
106 local fillTypeName = xmlFile:getValue(plantKey .. "#fillType")
107 local fillType = g_fillTypeManager:getFillTypeIndexByName(fillTypeName)
108 if fillType ~= nil then
109 local plantXmlFilename = xmlFile:getValue(plantKey .. "#xmlFilename")
110 if plantXmlFilename ~= nil then
111 plantXmlFilename = Utils.getFilename(plantXmlFilename, self.baseDirectory)
112 local plant = self:loadPlantFromXml(plantXmlFilename)
113 if plant ~= nil then
114 spec.filltypeIdToPlant[fillType] = plant
115 end
116 end
117 else
118 Logging.xmlWarning(xmlFile, "Unknown fillType '%s' for plant '%s'", fillTypeName, plantKey)
119 end
120 end)
121
122 xmlFile:iterate(key .. ".plantSpaces.space", function(index, plantSpaceKey)
123 local plantPlaceNode = self.xmlFile:getValue(plantSpaceKey .. "#node", nil, self.components, self.i3dMappings)
124 local useRandomYRot = self.xmlFile:getValue(plantSpaceKey .. "#useRandomYRot", true)
125 if plantPlaceNode ~= nil then
126 self:addPlantPlace(plantPlaceNode, useRandomYRot)
127 end
128 end)
129
130 xmlFile:iterate(key .. ".plantSpaces.spacesParent", function(index, plantParentKey)
131 local parentNode = self.xmlFile:getValue(plantParentKey .. "#node", nil, self.components, self.i3dMappings)
132 local useRandomYRot = self.xmlFile:getValue(plantParentKey .. "#useRandomYRot", true)
133 local numChildren = getNumOfChildren(parentNode)
134 if numChildren > 0 then
135 for i=0, numChildren-1 do
136 self:addPlantPlace(getChildAt(parentNode, i), useRandomYRot)
137 end
138 else
139 Logging.xmlWarning(xmlFile, "No i3d child nodes for '%s'", plantParentKey)
140 end
141 end)
142
143 if self.isClient then
144 spec.samples = {}
145 spec.samples.watering = g_soundManager:loadSampleFromXML(xmlFile, key .. ".sounds", "watering", self.baseDirectory, self.components, 1, AudioGroup.ENVIRONMENT, self.i3dMappings, nil)
146
147 spec.effects = g_effectManager:loadEffect(xmlFile, key .. ".effectNodes", self.components, self, self.i3dMappings)
148 end
149
150 spec.growthTimer = Timer.new(PlaceableGreenhouse.getRandomGrowthInterval())
151 spec.growthTimer:setFinishCallback(function(timerInstance)
152 timerInstance:setDuration(PlaceableGreenhouse.getRandomGrowthInterval())
153 self:updatePlantsStage() -- restarts timer if reasonable
154 end)
155
156 spec.wateringTimer = Timer.new(PlaceableGreenhouse.getRandomWateringInterval())
157 spec.wateringTimer:setFinishCallback(function(timerInstance)
158 if spec.hasWater then
159 g_effectManager:startEffects(spec.effects)
160 g_soundManager:playSample(spec.samples.watering)
161
162 Timer.createOneshot(PlaceableGreenhouse.WATERING_DURATION_SECONDS * 1000, function()
163 g_effectManager:stopEffects(spec.effects)
164 g_soundManager:stopSample(spec.samples.watering)
165 end)
166 timerInstance:start() -- restart for next watering
167 end
168 end)
169end

onOutputFillTypesChanged

Description
Definition
onOutputFillTypesChanged()
Code
301function PlaceableGreenhouse:onOutputFillTypesChanged(outputs, state)
302 local spec = self.spec_greenhouse
303
304 for _, output in pairs(outputs) do
305 local fillType = output.type
306 if state then
307 if spec.filltypeIdToPlant[fillType] ~= nil then
308 spec.activeFilltypes[fillType] = true
309 end
310 else
311 spec.activeFilltypes[fillType] = nil
312 end
313 end
314
315 -- only directly updated visuals if during gameplay -> plants are updated expliclitly once after load onFinalizePlacement
316 if self:getIsSynchronized() then
317 self.plantDistributionDirty = true
318 end
319
320 self:raiseActive()
321end

onProductionStatusChanged

Description
Definition
onProductionStatusChanged()
Code
325function PlaceableGreenhouse:onProductionStatusChanged(production, status)
326 local spec = self.spec_greenhouse
327
328 local hasWater = not (status == ProductionPoint.PROD_STATUS.MISSING_INPUTS)
329
330 if spec.hasWater ~= hasWater then
331 spec.hasWater = hasWater
332 self:updatePlantsStage()
333 end
334
335 if hasWater and next(spec.activeFilltypes) ~= nil then
336 spec.wateringTimer:startIfNotRunning()
337 else
338 spec.wateringTimer:stop()
339 end
340end

onUpdate

Description
Definition
onUpdate()
Code
293function PlaceableGreenhouse:onUpdate()
294 if self.plantDistributionDirty then
295 self:updatePlantDistribution()
296 end
297end

plantI3DLoadedCallback

Description
Definition
plantI3DLoadedCallback()
Code
219function PlaceableGreenhouse:plantI3DLoadedCallback(i3dNode, failedReason, args)
220 local plant = args.plant
221 local plantXmlFile = args.plantXmlFile
222 local loadingTask = args.loadingTask
223
224 if i3dNode ~= 0 then
225 local components = {}
226 local i3dMappings = {}
227 I3DUtil.loadI3DComponents(i3dNode, components)
228 I3DUtil.loadI3DMapping(plantXmlFile, i3dNode, components, i3dMappings)
229
230 plant.i3dNode = i3dNode
231
232 plantXmlFile:iterate("greenhousePlant.stages.growing", function(index, key)
233 local growingNode = plantXmlFile:getValue(key .. "#node", nil, i3dNode)
234 if growingNode ~= nil then
235 local childIndex = getChildIndex(growingNode)
236 table.insert(plant.stages.growing, childIndex)
237 end
238 end)
239
240 plant.stages.first = plant.stages.growing[1]
241 plant.stages.last = plant.stages.growing[#plant.stages.growing]
242
243 local witheredNode = plantXmlFile:getValue("greenhousePlant.stages.withered#node", nil, plant.i3dNode)
244 if witheredNode ~= nil then
245 plant.stages.withered = getChildIndex(witheredNode)
246 end
247 end
248
249 plantXmlFile:delete()
250
251 self:finishLoadingTask(loadingTask)
252end

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
38function PlaceableGreenhouse.prerequisitesPresent(specializations)
39 return true
40end

registerEventListeners

Description
Definition
registerEventListeners()
Code
66function PlaceableGreenhouse.registerEventListeners(placeableType)
67 SpecializationUtil.registerEventListener(placeableType, "onLoad", PlaceableGreenhouse)
68 SpecializationUtil.registerEventListener(placeableType, "onDelete", PlaceableGreenhouse)
69 SpecializationUtil.registerEventListener(placeableType, "onFinalizePlacement", PlaceableGreenhouse)
70 SpecializationUtil.registerEventListener(placeableType, "onOutputFillTypesChanged", PlaceableGreenhouse)
71 SpecializationUtil.registerEventListener(placeableType, "onProductionStatusChanged", PlaceableGreenhouse)
72 SpecializationUtil.registerEventListener(placeableType, "onUpdate", PlaceableGreenhouse)
73end

registerFunctions

Description
Definition
registerFunctions()
Code
55function PlaceableGreenhouse.registerFunctions(placeableType)
56 SpecializationUtil.registerFunction(placeableType, "loadPlantFromXml", PlaceableGreenhouse.loadPlantFromXml)
57 SpecializationUtil.registerFunction(placeableType, "plantI3DLoadedCallback", PlaceableGreenhouse.plantI3DLoadedCallback)
58 SpecializationUtil.registerFunction(placeableType, "addPlantPlace", PlaceableGreenhouse.addPlantPlace)
59 SpecializationUtil.registerFunction(placeableType, "updatePlantDistribution", PlaceableGreenhouse.updatePlantDistribution)
60 SpecializationUtil.registerFunction(placeableType, "setPlantAtPlace", PlaceableGreenhouse.setPlantAtPlace)
61 SpecializationUtil.registerFunction(placeableType, "updatePlantsStage", PlaceableGreenhouse.updatePlantsStage)
62end

registerXMLPaths

Description
Definition
registerXMLPaths()
Code
77function PlaceableGreenhouse.registerXMLPaths(schema, basePath)
78 schema:setXMLSpecializationType("Greenhouse")
79 schema:register(XMLValueType.STRING, basePath .. ".greenhouse.plants.plant(?)#fillType", "FillType of plant")
80 schema:register(XMLValueType.STRING, basePath .. ".greenhouse.plants.plant(?)#xmlFilename", "xml file of greenhouse plant")
81
82 schema:register(XMLValueType.NODE_INDEX, basePath .. ".greenhouse.plantSpaces.space(?)#node", "node where plant is placed")
83 schema:register(XMLValueType.BOOL, basePath .. ".greenhouse.plantSpaces.space(?)#useRandomYRot", "node is randomly rotated on the y axis", true)
84 schema:register(XMLValueType.NODE_INDEX, basePath .. ".greenhouse.plantSpaces.spacesParent(?)#node", "parent node of nodes where plants are placed")
85 schema:register(XMLValueType.BOOL, basePath .. ".greenhouse.plantSpaces.spacesParent(?)#useRandomYRot", "node is randomly rotated on the y axis", true)
86
87 SoundManager.registerSampleXMLPaths(schema, basePath .. ".greenhouse.sounds", "watering")
88 EffectManager.registerEffectXMLPaths(schema, basePath .. ".greenhouse.effectNodes")
89 schema:setXMLSpecializationType()
90end

setPlantAtPlace

Description
Definition
setPlantAtPlace()
Code
366function PlaceableGreenhouse:setPlantAtPlace(fillType, plantPlace)
367 local spec = self.spec_greenhouse
368
369 -- only update if required fillType differs from current one
370 if plantPlace.fillType ~= fillType then
371 if plantPlace.fillType ~= nil then
372 -- remove existing stages from other plant
373 for i=getNumOfChildren(plantPlace.node)-1, 0, -1 do
374 local plantStage = getChildAt(plantPlace.node, i)
375 delete(plantStage)
376 end
377 plantPlace.fillType = nil
378 end
379
380 local plant = spec.filltypeIdToPlant[fillType]
381 if plant ~= nil then
382 local plantClone = clone(getChildAt(plant.i3dNode, 0), false, false, false)
383
384 for n=getNumOfChildren(plantClone)-1, 0, -1 do
385 local plantStage = getChildAt(plantClone, n)
386 link(plantPlace.node, plantStage, 0)
387 end
388 plantPlace.fillType = fillType
389 plantPlace.stage = nil
390
391 delete(plantClone)
392 end
393 end
394end

updatePlantDistribution

Description
populates the plant nodes with cloned plants set in activeFilltypes
Definition
updatePlantDistribution()
Code
344function PlaceableGreenhouse:updatePlantDistribution()
345 local spec = self.spec_greenhouse
346
347 local numActiveFilltypes = table.size(spec.activeFilltypes)
348 local numPlaces = #spec.plantPlaces
349
350 local fillTypesList = table.toList(spec.activeFilltypes)
351
352 for i=1, numPlaces do
353 -- rotate active fillTypes through places
354 local fillType = fillTypesList[(i % numActiveFilltypes) + 1]
355 local plantPlace = spec.plantPlaces[i]
356
357 self:setPlantAtPlace(fillType, plantPlace)
358 end
359
360 self.plantDistributionDirty = false
361 self:updatePlantsStage()
362end

updatePlantsStage

Description
cycles throufh plants growth stages or sets plants to withered if no water is available
Definition
updatePlantsStage()
Code
398function PlaceableGreenhouse:updatePlantsStage()
399 local spec = self.spec_greenhouse
400
401 if table.size(spec.activeFilltypes) == 0 then
402 return
403 end
404
405 if not spec.hasWater then
406 spec.growthTimer:stop()
407 else
408 spec.growthTimer:start()
409 end
410
411 for i=1, #spec.plantPlaces do
412 local plantPlace = spec.plantPlaces[i]
413
414 local plant = spec.filltypeIdToPlant[plantPlace.fillType]
415
416 local newStage
417 if not spec.hasWater then
418 newStage = plant.stages.withered
419 else
420 newStage = (plantPlace.stage and (plantPlace.stage + 1)) or plant.stages.first
421 if newStage > plant.stages.last then
422 newStage = plant.stages.first
423 end
424 end
425
426 if plantPlace.stage ~= newStage then
427 for n=0, getNumOfChildren(plantPlace.node)-1 do
428 local plantStage = getChildAt(plantPlace.node, n)
429 setVisibility(plantStage, n == newStage)
430 end
431 plantPlace.stage = newStage
432 end
433 end
434end