LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

BaleManager

Description
This class handles all bales
Parent
AbstractManager
Functions

baleLoaded

Description
Bale i3d file loaded
Definition
baleLoaded()
Code
79function BaleManager:baleLoaded(i3dNode, failedReason, bale)
80 if i3dNode ~= 0 then
81 bale.sharedRoot = i3dNode
82 removeFromPhysics(i3dNode)
83 end
84end

consoleCommandAddBale

Description
Definition
consoleCommandAddBale()
Code
420function BaleManager:consoleCommandAddBale(fillTypeName, isRoundbale, width, height, length, wrapState, modName)
421 local usage = "gsBaleAdd fillTypeName isRoundBale [width] [height/diameter] [length] [wrapState] [modName]"
422
423 if not g_currentMission:getIsServer() then
424 Logging.error("Command only allowed on server!")
425 return
426 end
427
428 fillTypeName = Utils.getNoNil(fillTypeName, "STRAW")
429 isRoundbale = Utils.stringToBoolean(isRoundbale)
430
431 width = width ~= nil and tonumber(width) or nil
432 height = height ~= nil and tonumber(height) or nil
433 length = length ~= nil and tonumber(length) or nil
434 if wrapState ~= nil and tonumber(wrapState) == nil then
435 Logging.error("Invalid wrapState '%s'. Number expected", wrapState, usage)
436 return
437 end
438 wrapState = tonumber(wrapState or 0)
439
440 local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeName)
441 if fillTypeIndex == nil then
442 Logging.error("Invalid fillTypeName '%s' (e.g. STRAW). Use %s" ,fillTypeName, usage)
443 return
444 end
445
446 local baleXMLFilename, _ = self:getBaleXMLFilename(fillTypeIndex, isRoundbale, width, height, length, height, modName)
447 if baleXMLFilename == nil then
448 Logging.error("Could not find bale for given size attributes! (%s)", usage)
449 self:consoleCommandListBales()
450 return
451 end
452
453 local x, y, z = 0, 0, 0
454 local dirX, dirZ, _ = 1, 0
455
456 if g_currentMission.controlPlayer then
457 local player = g_currentMission.player
458 if player ~= nil and player.isControlled and player.rootNode ~= nil and player.rootNode ~= 0 then
459 x, y, z = getWorldTranslation(player.rootNode)
460 dirX, dirZ = -math.sin(player.rotY), -math.cos(player.rotY)
461 end
462 elseif g_currentMission.controlledVehicle ~= nil then
463 x, y, z = getWorldTranslation(g_currentMission.controlledVehicle.rootNode)
464 dirX, _, dirZ = localDirectionToWorld(g_currentMission.controlledVehicle.rootNode, 0, 0, 1)
465 else
466 x, y, z = getWorldTranslation(getCamera())
467 dirX, _, dirZ = localDirectionToWorld(getCamera(), 0, 0, -1)
468 end
469
470 x, z = x + dirX * 4, z + dirZ * 4
471 y = y + 5
472 local ry = MathUtil.getYRotationFromDirection(dirX, dirZ)
473
474 local farmId = g_currentMission:getFarmId()
475 farmId = ((farmId ~= FarmManager.SPECTATOR_FARM_ID) and farmId) or 1 -- don't spawn bales with spectator farm
476
477 local baleObject = Bale.new(g_currentMission:getIsServer(), g_currentMission:getIsClient())
478 if baleObject:loadFromConfigXML(baleXMLFilename, x, y, z, 0, ry, 0) then
479 baleObject:setFillType(fillTypeIndex, true)
480 baleObject:setWrappingState(wrapState)
481 baleObject:setOwnerFarmId(farmId, true)
482 baleObject:register()
483 end
484
485 return string.format("Created bale at (%.2f, %.2f, %.2f). For specific bales use: %s", x, y, z, usage)
486end

consoleCommandListBales

Description
Definition
consoleCommandListBales()
Code
490function BaleManager:consoleCommandListBales()
491 print("Available bale types:")
492 for _, bale in ipairs(self.bales) do
493 local attributes = {bale.xmlFilename}
494 table.insert(attributes, string.format("isRoundbale=%s", bale.isRoundbale))
495 for _, sizeProperty in ipairs({"width", "height", "length", "diameter"}) do
496 if bale[sizeProperty] ~= nil and bale[sizeProperty] ~= 0 then
497 table.insert(attributes, string.format("%s=%s", sizeProperty, bale[sizeProperty]))
498 end
499 end
500 log(table.concat(attributes, " "))
501
502 local fillTypeNames = {}
503 for _, fillTypeData in ipairs(bale.fillTypes) do
504 table.insert(fillTypeNames, g_fillTypeManager:getFillTypeNameByIndex(fillTypeData.fillTypeIndex))
505 end
506 log(" fillTypes: ", table.concat(fillTypeNames, " "))
507 end
508end

getBaleCapacityByBaleIndex

Description
Returns capacity for specific fill type by given bale index
Definition
getBaleCapacityByBaleIndex(integer baleIndex, integer fillTypeIndex)
Arguments
integerbaleIndexfill type index
integerfillTypeIndexfill type index
Return Values
floatcapacity
Code
387function BaleManager:getBaleCapacityByBaleIndex(baleIndex, fillTypeIndex)
388 if baleIndex ~= nil then
389 local bale = self.bales[baleIndex]
390 if bale ~= nil then
391 for j=1, #bale.fillTypes do
392 if bale.fillTypes[j].fillTypeIndex == fillTypeIndex then
393 return bale.fillTypes[j].capacity
394 end
395 end
396 end
397 end
398
399 return 0
400end

getBaleIndex

Description
Get index of bale that matches given specs
Definition
getBaleIndex(Integer fillTypeIndex, boolean isRoundbale, float width, float height, float length, float diameter, float diameter, string customEnvironment)
Arguments
IntegerfillTypeIndexfill type index
booleanisRoundbaleis roundbale
floatwidthbale width
floatheightbale height
floatlengthbale length
floatdiameterbale diameter
floatdiameterbale diameter
stringcustomEnvironmentseach bales from this custom environment
Return Values
integerindexindex
Code
302function BaleManager:getBaleIndex(fillTypeIndex, isRoundbale, width, height, length, diameter, customEnvironment)
303 -- for mods we search first in it's own custom environment for a matching bale
304 if customEnvironment ~= nil then
305 for baleIndex=1, #self.bales do
306 local bale = self.bales[baleIndex]
307 if bale.isAvailable then
308 if customEnvironment == bale.customEnvironment then
309 if self:getIsBaleMatching(bale, fillTypeIndex, isRoundbale, width, height, length, diameter) then
310 return baleIndex
311 end
312 end
313 end
314 end
315 end
316
317 -- now search all bales without custom environment
318 for baleIndex=1, #self.bales do
319 local bale = self.bales[baleIndex]
320 if bale.isAvailable then
321 if bale.customEnvironment == nil then
322 if self:getIsBaleMatching(bale, fillTypeIndex, isRoundbale, width, height, length, diameter) then
323 return baleIndex
324 end
325 end
326 end
327 end
328
329 return nil
330end

getBaleXMLFilename

Description
Get xml file bale that matches given specs
Definition
getBaleXMLFilename(Integer fillTypeIndex, boolean isRoundbale, float width, float height, float length, float diameter)
Arguments
IntegerfillTypeIndexfill type index
booleanisRoundbaleis roundbale
floatwidthbale width
floatheightbale height
floatlengthbale length
floatdiameterbale diameter
Return Values
integerindexindex
Code
373function BaleManager:getBaleXMLFilename(fillTypeIndex, isRoundbale, width, height, length, diameter, customEnvironment)
374 local baleIndex = self:getBaleIndex(fillTypeIndex, isRoundbale, width, height, length, diameter, customEnvironment)
375 if baleIndex ~= nil then
376 return self.bales[baleIndex].xmlFilename, baleIndex
377 end
378
379 return nil
380end

getFermentationTime

Description
Returns fermentation time for given bale
Definition
getFermentationTime(table bale)
Arguments
tablebalebale object
Return Values
floattimecurrent fermentation time in ms
Code
270function BaleManager:getFermentationTime(bale)
271 for i=1, #self.fermentations do
272 if self.fermentations[i].bale == bale then
273 return self.fermentations[i].time
274 end
275 end
276
277 return 0
278end

getIsBaleMatching

Description
Definition
getIsBaleMatching()
Code
334function BaleManager:getIsBaleMatching(bale, fillTypeIndex, isRoundbale, width, height, length, diameter)
335 if bale.isRoundbale == isRoundbale then
336 local fillTypeMatch = false
337 for j=1, #bale.fillTypes do
338 if bale.fillTypes[j].fillTypeIndex == fillTypeIndex then
339 fillTypeMatch = true
340 break
341 end
342 end
343
344 if fillTypeMatch then
345 local sizeMatch
346 if isRoundbale then
347 sizeMatch = (width == nil or MathUtil.round(width, 2) == bale.width)
348 and (diameter == nil or MathUtil.round(diameter, 2) == bale.diameter)
349 else
350 sizeMatch = (width == nil or MathUtil.round(width, 2) == bale.width)
351 and (height == nil or MathUtil.round(height, 2) == bale.height)
352 and (length == nil or MathUtil.round(length, 2) == bale.length)
353 end
354
355 if sizeMatch then
356 return true
357 end
358 end
359 end
360
361 return false
362end

getPossibleCapacitiesForFillType

Description
Definition
getPossibleCapacitiesForFillType()
Code
404function BaleManager:getPossibleCapacitiesForFillType(fillTypeIndex)
405 local capacities = {}
406
407 for _, bale in ipairs(self.bales) do
408 for _, fillTypeData in ipairs(bale.fillTypes) do
409 if fillTypeData.fillTypeIndex == fillTypeIndex then
410 table.insert(capacities, fillTypeData.capacity)
411 end
412 end
413 end
414
415 return capacities
416end

initDataStructures

Description
Initialize data structures
Definition
initDataStructures()
Code
33function BaleManager:initDataStructures()
34 self.bales = {}
35 self.modBalesToLoad = {}
36 self.fermentations = {}
37end

loadBaleDataFromXML

Description
Loads and adds bale type from xml
Definition
loadBaleDataFromXML(integer xmlFile, float key)
Arguments
integerxmlFilexml file id
floatkeyxmlKey
Return Values
tablebaleTypebaleType object
Code
177function BaleManager:loadBaleDataFromXML(bale, xmlFile, baseDirectory)
178 local i3dFilename = xmlFile:getValue("bale.filename")
179 if i3dFilename ~= nil then
180 bale.i3dFilename = Utils.getFilename(i3dFilename, baseDirectory)
181 if not fileExists(bale.i3dFilename) then
182 Logging.xmlError(xmlFile, "Bale i3d file could not be found '%s'", bale.i3dFilename)
183 return false
184 end
185
186 bale.isRoundbale = xmlFile:getValue("bale.size#isRoundbale", true)
187 bale.width = MathUtil.round(xmlFile:getValue("bale.size#width", 0), 2)
188 bale.height = MathUtil.round(xmlFile:getValue("bale.size#height", 0), 2)
189 bale.length = MathUtil.round(xmlFile:getValue("bale.size#length", 0), 2)
190 bale.diameter = MathUtil.round(xmlFile:getValue("bale.size#diameter", 0), 2)
191
192 if bale.isRoundbale and (bale.diameter == 0 or bale.width == 0) then
193 Logging.xmlError(xmlFile, "Missing size attributes for round bale. Requires width and diameter.")
194 return false
195 elseif not bale.isRoundbale and (bale.width == 0 or bale.height == 0 or bale.length == 0) then
196 Logging.xmlError(xmlFile, "Missing size attributes for square bale. Requires width, height and length.")
197 return false
198 end
199
200 bale.fillTypes = {}
201 xmlFile:iterate("bale.fillTypes.fillType", function(index, key)
202 local fillTypeName = xmlFile:getValue(key .. "#name")
203 local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeName)
204 if fillTypeIndex ~= nil then
205 local fillTypeData = {}
206 fillTypeData.fillTypeIndex = fillTypeIndex
207 fillTypeData.capacity = xmlFile:getValue(key .. "#capacity", 0)
208 table.insert(bale.fillTypes, fillTypeData)
209 else
210 Logging.xmlWarning(xmlFile, "Unknown fill type '%s' for bale in '%s'", fillTypeName, key)
211 end
212 end)
213 else
214 Logging.xmlError(xmlFile, "No i3D file defined in bale xml.")
215 return false
216 end
217
218 return true
219end

loadBaleFromXML

Description
Definition
loadBaleFromXML()
Code
120function BaleManager:loadBaleFromXML(xmlFile, key, baseDirectory)
121 if type(xmlFile) ~= "table" then
122 xmlFile = XMLFile.wrap(xmlFile)
123 end
124
125 local xmlFilename = xmlFile:getString(key .. "#filename")
126 if xmlFilename ~= nil then
127 local bale = {}
128 bale.xmlFilename = Utils.getFilename(xmlFilename, baseDirectory)
129 bale.isAvailable = xmlFile:getBool(key .. "#isAvailable", true)
130 local baleXmlFile = XMLFile.load("TempBale", bale.xmlFilename, BaleManager.baleXMLSchema)
131 if baleXmlFile ~= nil then
132 local success = self:loadBaleDataFromXML(bale, baleXmlFile, baseDirectory)
133 baleXmlFile:delete()
134 if success then
135 table.insert(self.bales, bale)
136 return true
137 end
138 end
139 end
140
141 Logging.xmlError(xmlFile, "Failed to load bale from xml '%s'", key)
142
143 return false
144end

loadBales

Description
Definition
loadBales()
Code
110function BaleManager:loadBales(xmlFile, baseDirectory)
111 xmlFile:iterate("map.bales.bale", function(index, key)
112 self:loadBaleFromXML(xmlFile, key, baseDirectory)
113 end)
114
115 return true
116end

loadMapData

Description
Load data on map load
Definition
loadMapData()
Return Values
booleantrueif loading was successful else false
Code
42function BaleManager:loadMapData(xmlFile, missionInfo, baseDirectory)
43 BaleManager:superClass().loadMapData(self)
44
45 local filename = getXMLString(xmlFile, "map.bales#filename")
46 local xmlFilename = Utils.getFilename(filename, baseDirectory)
47 local balesXMLFile = XMLFile.load("TempBales", xmlFilename, BaleManager.mapBalesXMLSchema)
48 if balesXMLFile ~= nil then
49 self:loadBales(balesXMLFile, baseDirectory)
50 balesXMLFile:delete()
51 end
52
53 for i=#self.modBalesToLoad, 1, -1 do
54 local bale = self.modBalesToLoad[i]
55 local baleXmlFile = XMLFile.load("TempBale", bale.xmlFilename, BaleManager.baleXMLSchema)
56 if baleXmlFile ~= nil then
57 if self:loadBaleDataFromXML(bale, baleXmlFile, bale.baseDirectory) then
58 table.insert(self.bales, bale)
59 end
60 baleXmlFile:delete()
61 end
62 table.remove(self.modBalesToLoad, i)
63 end
64
65 for _, bale in ipairs(self.bales) do
66 bale.sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(bale.i3dFilename, false, true, self.baleLoaded, self, bale)
67 end
68
69 if g_addCheatCommands then
70 addConsoleCommand("gsBaleAdd", "Adds a bale", "consoleCommandAddBale", self)
71 addConsoleCommand("gsBaleList", "List available bale types", "consoleCommandListBales", self)
72 end
73
74 return true
75end

loadModBaleFromXML

Description
Definition
loadModBaleFromXML()
Code
148function BaleManager:loadModBaleFromXML(xmlFile, key, baseDirectory, customEnvironment)
149 if type(xmlFile) ~= "table" then
150 xmlFile = XMLFile.wrap(xmlFile)
151 end
152
153 local xmlFilename = xmlFile:getString(key .. "#filename")
154 if xmlFilename ~= nil then
155 xmlFilename = Utils.getFilename(xmlFilename, baseDirectory)
156
157 local bale = {}
158 bale.xmlFilename = xmlFilename
159 bale.baseDirectory = baseDirectory
160 bale.customEnvironment = customEnvironment
161 bale.isAvailable = xmlFile:getBool(key .. "#isAvailable", true)
162
163 table.insert(self.modBalesToLoad, bale)
164 return true
165 end
166
167 Logging.xmlError(xmlFile, "Failed to load bale from xml '%s'", key)
168
169 return false
170end

new

Description
Creating manager
Definition
new()
Return Values
tableinstanceinstance of object
Code
19function BaleManager.new(customMt)
20 local self = AbstractManager.new(customMt or BaleManager_mt)
21
22 BaleManager.baleXMLSchema = XMLSchema.new("bale")
23 BaleManager.registerBaleXMLPaths(BaleManager.baleXMLSchema)
24
25 BaleManager.mapBalesXMLSchema = XMLSchema.new("mapBales")
26 BaleManager.registerMapBalesXMLPaths(BaleManager.mapBalesXMLSchema)
27
28 return self
29end

registerBaleXMLPaths

Description
Definition
registerBaleXMLPaths()
Code
512function BaleManager.registerBaleXMLPaths(schema)
513 schema:register(XMLValueType.STRING, "bale.filename", "Path to i3d file")
514
515 schema:register(XMLValueType.BOOL, "bale.size#isRoundbale", "Bale is a roundbale", true)
516 schema:register(XMLValueType.FLOAT, "bale.size#width", "Bale Width", 0)
517 schema:register(XMLValueType.FLOAT, "bale.size#height", "Bale Height", 0)
518 schema:register(XMLValueType.FLOAT, "bale.size#length", "Bale Length", 0)
519 schema:register(XMLValueType.FLOAT, "bale.size#diameter", "Bale Diameter", 0)
520
521 schema:register(XMLValueType.NODE_INDEX, "bale.mountableObject#triggerNode", "Trigger node")
522 schema:register(XMLValueType.FLOAT, "bale.mountableObject#forceAcceleration", "Acceleration force", 4)
523 schema:register(XMLValueType.FLOAT, "bale.mountableObject#forceLimitScale", "Force limit scale", 1)
524 schema:register(XMLValueType.BOOL, "bale.mountableObject#axisFreeY", "Joint is free in Y direction", false)
525 schema:register(XMLValueType.BOOL, "bale.mountableObject#axisFreeX", "Joint is free in X direction", false)
526
527 schema:register(XMLValueType.STRING, "bale.uvId", "Specify that this bale model has a custom UV. This will result in baleWrapper to replace the bale if the UV is different to the defined one in the baleWrapper. So the baleWrapper will always use a bale with a UV that matches the wrapping texture.", "DEFAULT")
528
529 schema:register(XMLValueType.NODE_INDEX, "bale.baleMeshes.baleMesh(?)#node", "Path to mesh node")
530 schema:register(XMLValueType.BOOL, "bale.baleMeshes.baleMesh(?)#supportsWrapping", "Defines if the mesh is hidden while wrapping or not")
531 schema:register(XMLValueType.STRING, "bale.baleMeshes.baleMesh(?)#fillTypes", "If defined this mesh is only visible if any of this fillTypes is set")
532 schema:register(XMLValueType.BOOL, "bale.baleMeshes.baleMesh(?)#isTensionBeltMesh", "Defines if this mesh is detected for tension belt calculation", false)
533
534 schema:register(XMLValueType.STRING, "bale.fillTypes.fillType(?)#name", "Name of fill type")
535 schema:register(XMLValueType.FLOAT, "bale.fillTypes.fillType(?)#capacity", "Fill level of bale with this fill type")
536 schema:register(XMLValueType.FLOAT, "bale.fillTypes.fillType(?)#mass", "Mass of bale with this fill type", 500)
537 schema:register(XMLValueType.FLOAT, "bale.fillTypes.fillType(?)#forceAcceleration", "Force acceleration value of bale with this fill type", "bale.mountableObject#forceAcceleration")
538 schema:register(XMLValueType.BOOL, "bale.fillTypes.fillType(?)#supportsWrapping", "Wrapping is allowed while this type is used")
539
540 schema:register(XMLValueType.STRING, "bale.fillTypes.fillType(?).diffuse#filename", "Diffuse texture to apply to all mesh nodes")
541 schema:register(XMLValueType.STRING, "bale.fillTypes.fillType(?).normal#filename", "Normal texture to apply to all mesh nodes")
542 schema:register(XMLValueType.STRING, "bale.fillTypes.fillType(?).specular#filename", "Specular texture to apply to all mesh nodes")
543 schema:register(XMLValueType.STRING, "bale.fillTypes.fillType(?).alpha#filename", "Alpha texture to apply to all mesh nodes")
544
545 schema:register(XMLValueType.STRING, "bale.fillTypes.fillType(?).fermenting#outputFillType", "Output fill type after fermenting")
546 schema:register(XMLValueType.BOOL, "bale.fillTypes.fillType(?).fermenting#requiresWrapping", "Wrapping is required to start fermenting", true)
547 schema:register(XMLValueType.FLOAT, "bale.fillTypes.fillType(?).fermenting#time", "Fermenting time in ingame days which represent months", 1)
548
549 -- packed bales
550 schema:register(XMLValueType.STRING, "bale.packedBale#singleBale", "Path to single bale xml filename")
551 schema:register(XMLValueType.NODE_INDEX, "bale.packedBale.singleBale(?)#node", "Single bale spawn node")
552end

registerFermentation

Description
Register bale fermentation
Definition
registerFermentation(table bale, float currentTime, float maxTime)
Arguments
tablebalebale object
floatcurrentTimecurrent fermentation time in ms
floatmaxTimemax fermentation time
Code
254function BaleManager:registerFermentation(bale, currentTime, maxTime)
255 maxTime = maxTime * g_currentMission.missionInfo.economicDifficulty
256
257 local fermentation = {}
258 fermentation.bale = bale
259 fermentation.time = currentTime
260 fermentation.percentageSend = 0
261 fermentation.maxTime = maxTime
262
263 table.insert(self.fermentations, fermentation)
264end

registerMapBalesXMLPaths

Description
Definition
registerMapBalesXMLPaths()
Code
556function BaleManager.registerMapBalesXMLPaths(schema)
557 schema:register(XMLValueType.STRING, "map.bales.bale(?)#filename", "Path to bale xml")
558 schema:register(XMLValueType.STRING, "map.bales.bale(?)#isAvailable", "Bale is available for all balers to spawn")
559end

removeFermentation

Description
Removed fermentation of given bale
Definition
removeFermentation(table bale)
Arguments
tablebalebale object
Code
283function BaleManager:removeFermentation(bale)
284 for i=#self.fermentations, 1, -1 do
285 if self.fermentations[i].bale == bale then
286 table.remove(self.fermentations, i)
287 end
288 end
289end

unloadMapData

Description
Unload data on mission delete
Definition
unloadMapData()
Code
88function BaleManager:unloadMapData()
89 for _, bale in ipairs(self.bales) do
90 if bale.sharedLoadRequestId ~= nil then
91 g_i3DManager:releaseSharedI3DFile(bale.sharedLoadRequestId)
92 bale.sharedLoadRequestId = nil
93 end
94 if bale.sharedRoot ~= nil then
95 delete(bale.sharedRoot)
96 bale.sharedRoot = nil
97 end
98 end
99
100 if g_addCheatCommands then
101 removeConsoleCommand("gsBaleAdd")
102 removeConsoleCommand("gsBaleList")
103 end
104
105 BaleManager:superClass().unloadMapData(self)
106end

update

Description
Update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
224function BaleManager:update(dt)
225 if g_server ~= nil then
226 local numFermentations = #self.fermentations
227 if numFermentations > 0 then
228 local timeScale = g_currentMission:getEffectiveTimeScale()
229
230 for i=numFermentations, 1, -1 do
231 local fermentation = self.fermentations[i]
232
233 fermentation.time = fermentation.time + dt * timeScale
234 if fermentation.time >= fermentation.maxTime then
235 fermentation.bale:onFermentationEnd()
236 table.remove(self.fermentations, i)
237 end
238
239 local percentage = fermentation.time / fermentation.maxTime
240 if math.floor(percentage * 100) ~= math.floor(fermentation.percentageSend * 100) then
241 fermentation.bale:onFermentationUpdate(percentage)
242 fermentation.percentageSend = percentage
243 end
244 end
245 end
246 end
247end