LUADOC - Farming Simulator 19

BunkerSilo

Description
Class for bunker silo
Parent
Object
Functions

clearSiloArea

Description
Clear the silo area
Definition
clearSiloArea()
Code
780function BunkerSilo:clearSiloArea()
781 local xs, _, zs = getWorldTranslation(self.bunkerSiloArea.start)
782 local xw, _, zw = getWorldTranslation(self.bunkerSiloArea.width)
783 local xh, _, zh = getWorldTranslation(self.bunkerSiloArea.height)
784 DensityMapHeightUtil.clearArea(xs,zs, xw,zw, xh,zh)
785end

delete

Description
Deleting bunker silo object
Definition
delete()
Code
161function BunkerSilo:delete()
162 g_currentMission:removeOnCreateLoadedObjectToSave(self)
163 if self.interactionTriggerNode ~= nil then
164 removeTrigger(self.interactionTriggerNode)
165 end
166
167 g_densityMapHeightManager:removeFixedFillTypesArea(self.bunkerSiloArea)
168 g_densityMapHeightManager:removeConvertingFillTypeAreas(self.bunkerSiloArea)
169
170 g_currentMission:removeActivatableObject(self.activatable)
171 BunkerSilo:superClass().delete(self)
172end

getBunkerAreaOffset

Description
Get bunker area offset
Definition
getBunkerAreaOffset(boolean updateAtFront, float offset, integer fillType)
Arguments
booleanupdateAtFrontupdate at front
floatoffsetoffset
integerfillTypefill type
Return Values
floatoffsetoffset
Code
645function BunkerSilo:getBunkerAreaOffset(updateAtFront, offset, fillType)
646 local area = self.bunkerSiloArea
647
648 local hx, hz = area.dhx_norm, area.dhz_norm
649 local hl = MathUtil.vector3Length(area.dhx, area.dhy, area.dhz)
650
651 while offset <= (hl - 1) do
652 local pos = offset
653 if not updateAtFront then
654 pos = hl - offset - 1
655 end
656 local d1x,d1z = pos*hx, pos*hz
657 local d2x,d2z = (pos+1)*hx, (pos+1)*hz
658
659 local a0x, a0z = area.sx + d1x, area.sz + d1z
660 local a1x, a1z = area.wx + d1x, area.wz + d1z
661 local a2x, a2z = area.sx + d2x, area.sz + d2z
662
663 local fillLevel = DensityMapHeightUtil.getFillLevelAtArea(fillType, a0x,a0z, a1x,a1z, a2x,a2z)
664 if fillLevel > 0 then
665 return offset
666 end
667 offset = offset + 1
668 end
669
670 return math.max(hl - 1, 0)
671end

getCanCloseSilo

Description
Get can close silo
Definition
getCanCloseSilo()
Return Values
booleancanClosecan close silo
Code
754function BunkerSilo:getCanCloseSilo()
755 return self.state == BunkerSilo.STATE_FILL and self.fillLevel > 0 and self.compactedPercent >= 100
756end

getCanInteract

Description
Get can interact with silo
Definition
getCanInteract(boolean showInformationOnly)
Arguments
booleanshowInformationOnlyshow information only
Return Values
booleancanInteractcan interact
Code
729function BunkerSilo:getCanInteract(showInformationOnly)
730 if showInformationOnly then
731 if (g_currentMission.controlPlayer and self.playerInRange) then
732 return true
733 end
734 if not g_currentMission.controlPlayer then
735 for vehicle in pairs(self.vehiclesInRange) do
736 if vehicle:getIsActiveForInput(true) then
737 return true
738 end
739 end
740 end
741 else
742 if (g_currentMission.controlPlayer and self.playerInRange) then
743 --if next(self.vehiclesInRange) == nil then
744 return true
745 --end
746 end
747 end
748 return false
749end

getCanOpenSilo

Description
Get can open silo
Definition
getCanOpenSilo()
Return Values
booleancanOpencan open silo
Code
761function BunkerSilo:getCanOpenSilo()
762 if not (self.state == BunkerSilo.STATE_FERMENTED or self.state == BunkerSilo.STATE_DRAIN) then
763 return false
764 end
765 local ix,iy,iz = self:getInteractionPosition()
766 if ix ~= nil then
767 local closerToFront = self:getIsCloserToFront(ix,iy,iz)
768 if closerToFront and not self.isOpenedAtFront then
769 return true
770 end
771 if not closerToFront and not self.isOpenedAtBack then
772 return true
773 end
774 end
775 return false
776end

getInteractionPosition

Description
Get interact position
Definition
getInteractionPosition()
Return Values
floatxx world position
floatyy world position
floatzz world position
Code
792function BunkerSilo:getInteractionPosition()
793 if g_currentMission.controlPlayer and self.playerInRange then
794 return getWorldTranslation(g_currentMission.player.rootNode)
795 else
796 if self.vehiclesInRange[g_currentMission.currentVehicle] ~= nil then
797 return getWorldTranslation(self.vehiclesInRange[g_currentMission.currentVehicle].components[1].node)
798 end
799 end
800 return nil
801end

getIsCloserToFront

Description
Get is closer to front
Definition
getIsCloserToFront(float ix, float iy, float iz)
Arguments
floatixx position
floatiyy position
floatizz position
Return Values
booleanisCloserToFrontis closer to front
Code
709function BunkerSilo:getIsCloserToFront(ix,iy,iz)
710 local area = self.bunkerSiloArea
711
712 local x = area.sx + (0.5*area.dwx) + (area.offsetFront * area.dhx_norm)
713 local y = area.sy + (0.5*area.dwy) + (area.offsetFront * area.dhy_norm)
714 local z = area.sz + (0.5*area.dwz) + (area.offsetFront * area.dhz_norm)
715 local distFront = MathUtil.vector3Length(x-ix, y-iy, z-iz)
716
717 local x = area.sx + (0.5*area.dwx) + area.dhx - (area.offsetBack * area.dhx_norm)
718 local y = area.sy + (0.5*area.dwy) + area.dhy - (area.offsetBack * area.dhy_norm)
719 local z = area.sz + (0.5*area.dwz) + area.dhz - (area.offsetBack * area.dhz_norm)
720 local distBack = MathUtil.vector3Length(x-ix, y-iy, z-iz)
721
722 return distFront < distBack
723end

interactionTriggerCallback

Description
interactionTriggerCallback
Definition
interactionTriggerCallback(integer triggerId, integer otherId, boolean onEnter, boolean onLeave, boolean onStay, integer otherId)
Arguments
integertriggerIdid of trigger
integerotherIdid of actor
booleanonEnteron enter
booleanonLeaveon leave
booleanonStayon stay
integerotherIdid of other actor
Code
811function BunkerSilo:interactionTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
812 if onEnter or onLeave then
813 if g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then
814 if onEnter then
815 self.playerInRange = true
816 g_currentMission:removeActivatableObject(self.activatable) -- make sure it is not added twice
817 g_currentMission:addActivatableObject(self.activatable)
818 else
819 self.playerInRange = false
820 if self.numVehiclesInRange == 0 then
821 g_currentMission:removeActivatableObject(self.activatable)
822 end
823 end
824 else
825 --local vehicle = g_currentMission.nodeToObject[otherId]
826 local vehicle = g_currentMission.nodeToObject[otherShapeId]
827 if vehicle ~= nil then
828 if onEnter then
829 if self.vehiclesInRange[vehicle] == nil then
830 self.vehiclesInRange[vehicle] = true
831 self.numVehiclesInRange = self.numVehiclesInRange + 1
832
833 g_currentMission:removeActivatableObject(self.activatable) -- make sure it is not added twice
834 g_currentMission:addActivatableObject(self.activatable)
835
836 -- add callback if shovel
837 if vehicle.setBunkerSiloInteractorCallback ~= nil then
838 vehicle:setBunkerSiloInteractorCallback(BunkerSilo.onChangedFillLevelCallback, self)
839 end
840 end
841 else
842 if self.vehiclesInRange[vehicle] then
843 self.vehiclesInRange[vehicle] = nil
844 self.numVehiclesInRange = self.numVehiclesInRange - 1
845
846 if self.numVehiclesInRange == 0 and not self.playerInRange then
847 g_currentMission:removeActivatableObject(self.activatable)
848 end
849
850 -- remove callback if shovel
851 if vehicle.setBunkerSiloInteractorCallback ~= nil then
852 vehicle:setBunkerSiloInteractorCallback(nil)
853 end
854 end
855 end
856 end
857 end
858 end
859end

load

Description
Load bunker silo
Definition
load(integer nodeId)
Arguments
integernodeIdnode id
Return Values
booleansuccesssuccess
Code
84function BunkerSilo:load(id, xmlFile, key)
85
86 self.nodeId = id
87
88 self.bunkerSiloArea.start = I3DUtil.indexToObject(id, getXMLString(xmlFile, key..".area#startNode"))
89 self.bunkerSiloArea.width = I3DUtil.indexToObject(id, getXMLString(xmlFile, key..".area#widthNode"))
90 self.bunkerSiloArea.height = I3DUtil.indexToObject(id, getXMLString(xmlFile, key..".area#heightNode"))
91
92 self.bunkerSiloArea.sx, self.bunkerSiloArea.sy, self.bunkerSiloArea.sz = getWorldTranslation(self.bunkerSiloArea.start)
93 self.bunkerSiloArea.wx, self.bunkerSiloArea.wy, self.bunkerSiloArea.wz = getWorldTranslation(self.bunkerSiloArea.width)
94 self.bunkerSiloArea.hx, self.bunkerSiloArea.hy, self.bunkerSiloArea.hz = getWorldTranslation(self.bunkerSiloArea.height)
95
96 self.bunkerSiloArea.dhx = self.bunkerSiloArea.hx - self.bunkerSiloArea.sx
97 self.bunkerSiloArea.dhy = self.bunkerSiloArea.hy - self.bunkerSiloArea.sy
98 self.bunkerSiloArea.dhz = self.bunkerSiloArea.hz - self.bunkerSiloArea.sz
99 self.bunkerSiloArea.dhx_norm, self.bunkerSiloArea.dhy_norm, self.bunkerSiloArea.dhz_norm = MathUtil.vector3Normalize(self.bunkerSiloArea.dhx, self.bunkerSiloArea.dhy, self.bunkerSiloArea.dhz)
100
101 self.bunkerSiloArea.dwx = self.bunkerSiloArea.wx - self.bunkerSiloArea.sx
102 self.bunkerSiloArea.dwy = self.bunkerSiloArea.wy - self.bunkerSiloArea.sy
103 self.bunkerSiloArea.dwz = self.bunkerSiloArea.wz - self.bunkerSiloArea.sz
104 self.bunkerSiloArea.dwx_norm, self.bunkerSiloArea.dwy_norm, self.bunkerSiloArea.dwz_norm = MathUtil.vector3Normalize(self.bunkerSiloArea.dwx, self.bunkerSiloArea.dwy, self.bunkerSiloArea.dwz)
105
106 self.interactionTriggerNode = I3DUtil.indexToObject(id, getXMLString(xmlFile, key..".interactionTrigger#node"))
107 if self.interactionTriggerNode ~= nil then
108 addTrigger(self.interactionTriggerNode, "interactionTriggerCallback", self)
109 end
110
111 self.acceptedFillTypes = {}
112 local data = StringUtil.splitString(" ", getXMLString(xmlFile, key.."#acceptedFillTypes") or "chaff grass_windrow dryGrass_windrow")
113 for i=1, table.getn(data) do
114 local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(data[i])
115 if fillTypeIndex ~= nil then
116 self.acceptedFillTypes[fillTypeIndex] = true
117 else
118 g_logManager:warning("'%s' is an invalid fillType for bunkerSilo '%s'!", tostring(data[i]), key.."#acceptedFillTypes")
119 end
120 end
121
122 local inputFillTypeName = getXMLString(xmlFile, key.."#inputFillType") or "chaff"
123 local inputFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(inputFillTypeName)
124 if inputFillTypeIndex ~= nil then
125 self.inputFillType = inputFillTypeIndex
126 else
127 g_logManager:warning("'%s' is an invalid input fillType for bunkerSilo '%s'!", tostring(inputFillTypeName), key.."#inputFillType")
128 end
129
130 local outputFillTypeName = getXMLString(xmlFile, key.."#outputFillType") or "silage"
131 local outputFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(outputFillTypeName)
132 if outputFillTypeIndex ~= nil then
133 self.outputFillType = outputFillTypeIndex
134 else
135 g_logManager:warning("'%s' is an invalid output fillType for bunkerSilo '%s'!", tostring(outputFillTypeName), key.."#outputFillType")
136 end
137
138 g_densityMapHeightManager:setConvertingFillTypeAreas(self.bunkerSiloArea, self.acceptedFillTypes, self.inputFillType)
139
140 self.distanceToCompactedFillLevel = getXMLFloat(xmlFile, key.."#distanceToCompactedFillLevel") or self.distanceToCompactedFillLevel
141 self.fermentingDuration = (getXMLFloat(xmlFile, key.."#fermentingHours") or 6) * 1000 * 60 * 60
142 self.openingLength = getXMLFloat(xmlFile, key.."#openingLength") or 5
143
144 self.fillLevel = 0
145
146 -- adjust timings to difficulty
147 local difficultyMultiplier = g_currentMission.missionInfo.economicDifficulty
148 self.fermentingDuration = self.fermentingDuration*difficultyMultiplier
149 self.distanceToCompactedFillLevel = self.distanceToCompactedFillLevel/difficultyMultiplier
150
151 -- just for tutorial 12 (feeder)
152 self.isTutorialSilo = Utils.getNoNil(getXMLBool(xmlFile, key.."#isTutorialSilo"), false )
153
154 self:setState(BunkerSilo.STATE_FILL)
155
156 return true
157end

loadFromXMLFile

Description
Loading from attributes and nodes
Definition
loadFromXMLFile(integer xmlFile, string key)
Arguments
integerxmlFileid of xml object
stringkeykey
Return Values
booleansuccesssuccess
Code
264function BunkerSilo:loadFromXMLFile(xmlFile, key)
265
266 local state = getXMLInt(xmlFile, key.."#state")
267 if state ~= nil then
268 if state >= 0 and state < BunkerSilo.NUM_STATES then
269 self:setState(state)
270 end
271 end
272
273 local fillLevel = getXMLFloat(xmlFile, key.."#fillLevel")
274 if fillLevel ~= nil then
275 self.fillLevel = fillLevel
276 end
277 local compactedFillLevel = getXMLFloat(xmlFile, key.."#compactedFillLevel")
278 if compactedFillLevel ~= nil then
279 self.compactedFillLevel = MathUtil.clamp(compactedFillLevel, 0, self.fillLevel)
280 end
281 self.compactedPercent = MathUtil.getFlooredPercent(math.min(self.compactedFillLevel, self.fillLevel), self.fillLevel)
282
283 local fermentingTime = getXMLFloat(xmlFile, key.."#fermentingTime")
284 if fermentingTime ~= nil then
285 self.fermentingTime = MathUtil.clamp(fermentingTime, 0, self.fermentingDuration)
286 self.fermentingPercent = MathUtil.getFlooredPercent(self.fermentingTime, self.fermentingDuration)
287 end
288
289 self.isOpenedAtFront = Utils.getNoNil(getXMLBool(xmlFile, key.."#openedAtFront"), false)
290 self.isOpenedAtBack = Utils.getNoNil(getXMLBool(xmlFile, key.."#openedAtBack"), false)
291
292 if self.isOpenedAtFront then
293 self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.outputFillType)
294 else
295 self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.fermentingFillType)
296 end
297 if self.isOpenedAtBack then
298 self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.outputFillType)
299 else
300 self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.fermentingFillType)
301 end
302
303 if self.fillLevel > 0 and self.state == BunkerSilo.STATE_DRAIN then
304 local area = self.bunkerSiloArea
305 local offWx = area.wx - area.sx
306 local offWz = area.wz - area.sz
307 local offW = math.sqrt(offWx*offWx + offWz*offWz)
308
309 local offHx = area.hx - area.sx
310 local offHz = area.hz - area.sz
311 local offH = math.sqrt(offHx*offHx + offHz*offHz)
312
313 if offW > 0.001 and offH > 0.001 then
314 -- offset by 0.9m in each direction (and max 45%)
315 local offWScale = math.min(0.45, 0.9 / offW)
316 offWx = offWx * offWScale
317 offWz = offWz * offWScale
318
319 local offHScale = math.min(0.45, 0.9 / offH)
320 offHx = offHx * offHScale
321 offHz = offHz * offHScale
322
323 local innerFillLevel1 = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx+offWx+offHx,area.sz+offWz+offHz, area.wx-offWx+offHx,area.wz-offWz+offHz, area.hx+offWx-offHx,area.hz+offWz-offHz)
324 local innerFillLevel2 = DensityMapHeightUtil.getFillLevelAtArea(self.outputFillType, area.sx+offWx+offHx,area.sz+offWz+offHz, area.wx-offWx+offHx,area.wz-offWz+offHz, area.hx+offWx-offHx,area.hz+offWz-offHz)
325 local innerFillLevel = innerFillLevel1 + innerFillLevel2
326 if innerFillLevel < self.emptyThreshold*0.5 then
327 DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.fermentingFillType)
328 DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.outputFillType)
329 self:setState(BunkerSilo.STATE_FILL, false)
330 end
331 end
332 elseif self.state == BunkerSilo.STATE_FILL then
333 local area = self.bunkerSiloArea
334 local fermentingFillLevel, fermentingPixels, totalFermentingPixels = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
335 -- Set to fermented state if more than 50% of the area is filled with fermenting fill type
336 if fermentingFillLevel > self.emptyThreshold and fermentingPixels > 0.5 * totalFermentingPixels then
337 local inputFillLevel, inputPixels, totalInputPixels = DensityMapHeightUtil.getFillLevelAtArea(self.inputFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
338 -- Only change if less than 10% is filled with input type (chaff) (ie. the silo is not being filled)
339 if inputPixels < 0.1*totalInputPixels then
340 self:setState(BunkerSilo.STATE_FERMENTED, false)
341 end
342 end
343 end
344
345 return true
346end

new

Description
Creating bunker silo object
Definition
new(boolean isServer, boolean isClient, table customMt)
Arguments
booleanisServeris server
booleanisClientis client
tablecustomMtcustomMt
Return Values
tableinstanceInstance of object
Code
32function BunkerSilo:new(isServer, isClient, customMt)
33
34 local self = Object:new(isServer, isClient, customMt or BunkerSilo_mt)
35
36 self.nodeId = 0
37 self.interactionTriggerNode = nil
38
39 self.bunkerSiloArea = {}
40 self.bunkerSiloArea.offsetFront = 0
41 self.bunkerSiloArea.offsetBack = 0
42
43 self.acceptedFillTypes = {}
44
45 self.inputFillType = FillType.CHAFF
46 self.outputFillType = FillType.SILAGE
47 self.fermentingFillType = FillType.TARP
48
49 self.isOpenedAtFront = false
50 self.isOpenedAtBack = false
51 self.distanceToCompactedFillLevel = 100
52
53 self.fermentingTime = 0
54 self.fermentingDuration = 6*60*60*1000 -- 6hours (ingame)
55 self.fermentingPercent = 0
56
57 self.fillLevel = 0
58 self.compactedFillLevel = 0
59 self.compactedPercent = 0
60 self.emptyThreshold = 100
61
62 self.playerInRange = false
63 self.vehiclesInRange = {}
64 self.numVehiclesInRange = 0
65
66 self.siloIsFullWarningTimer = 0
67 self.siloIsFullWarningDuration = 2000
68
69 self.updateTimer = 0
70
71 self.activatable = BunkerSiloActivatable:new(self)
72
73 self.state = BunkerSilo.STATE_FILL
74
75 self.bunkerSiloDirtyFlag = self:getNextDirtyFlag()
76
77 return self
78end

onChangedFillLevelCallback

Description
Called if fill level changed
Definition
onChangedFillLevelCallback(table vehicle, integer fillDelta, integer fillType)
Arguments
tablevehiclevehicle
integerfillDeltafill delta
integerfillTypefill type
Code
866function BunkerSilo.onChangedFillLevelCallback(self, vehicle, fillDelta, fillType)
867 if fillDelta >= 0 then
868 return
869 end
870
871 local area = self.bunkerSiloArea
872
873 local x,y,z = getWorldTranslation(vehicle.components[1].node)
874 local closerToFront = self:getIsCloserToFront(x,y,z)
875
876 local shovelSpec = vehicle.spec_shovel
877 if shovelSpec ~= nil then
878 if #shovelSpec.shovelNodes > 0 then
879 self.shovelNodeIndex = (self.shovelNodeIndex or 0) + 1
880 if self.shovelNodeIndex > #shovelSpec.shovelNodes then
881 self.shovelNodeIndex = 1
882 end
883
884 local shovelNode = shovelSpec.shovelNodes[self.shovelNodeIndex]
885 if shovelNode ~= nil then
886 x, y, z = localToWorld(shovelNode.node, 0, 0, shovelNode.zOffset+shovelNode.length)
887 end
888 end
889 end
890
891 local length = self.openingLength
892
893 if closerToFront then
894 if self.isOpenedAtFront then
895 local p1 = MathUtil.getProjectOnLineParameter(x,z, area.sx,area.sz, area.dhx_norm,area.dhz_norm)
896 if p1 > area.offsetFront - length then
897 local offset = self:getBunkerAreaOffset(true, area.offsetFront, self.fermentingFillType)
898 local targetOffset = math.max(p1, offset) + length
899
900 self:switchFillTypeAtOffset(true, area.offsetFront, targetOffset - area.offsetFront)
901 area.offsetFront = targetOffset
902 end
903 end
904 else
905 if self.isOpenedAtBack then
906 local p1 = MathUtil.getProjectOnLineParameter(x,z, area.hx,area.hz, -area.dhx_norm,-area.dhz_norm)
907 if p1 > area.offsetBack - length then
908 local offset = self:getBunkerAreaOffset(true, area.offsetBack, self.fermentingFillType)
909 local targetOffset = math.max(p1, offset) + length
910
911 self:switchFillTypeAtOffset(false, area.offsetBack, targetOffset - area.offsetBack)
912 area.offsetBack = targetOffset
913 end
914 end
915 end
916end

onCreate

Description
Creating bunker silo object
Definition
onCreate(integer id)
Arguments
integeridnode id
Code
22function BunkerSilo:onCreate(id)
23 g_logManager:error("BunkerSilo.onCreate is deprecated!")
24end

openSilo

Description
Open silo
Definition
openSilo(float px, float py, float pz)
Arguments
floatpxx player position
floatpyy player position
floatpzz player position
Code
620function BunkerSilo:openSilo(px,py,pz)
621 self:setState(BunkerSilo.STATE_DRAIN, true)
622
623 self.bunkerSiloArea.offsetFront = self:getBunkerAreaOffset(true, 0, self.fermentingFillType)
624 self.bunkerSiloArea.offsetBack = self:getBunkerAreaOffset(false, 0, self.fermentingFillType)
625
626 -- check which side is closer to player
627 local openAtFront = self:getIsCloserToFront(px,py,pz)
628 if openAtFront and not self.isOpenedAtFront then
629 self:switchFillTypeAtOffset(true, self.bunkerSiloArea.offsetFront, self.openingLength)
630 self.isOpenedAtFront = true
631 self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)
632 elseif not self.isOpenedAtBack then
633 self:switchFillTypeAtOffset(false, self.bunkerSiloArea.offsetBack, self.openingLength)
634 self.isOpenedAtBack = true
635 self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)
636 end
637end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
178function BunkerSilo:readStream(streamId, connection)
179 BunkerSilo:superClass().readStream(self, streamId, connection)
180 if connection:getIsServer() then
181 local state = streamReadUIntN(streamId, 3)
182 self:setState(state)
183 self.isOpenedAtFront = streamReadBool(streamId)
184 self.isOpenedAtBack = streamReadBool(streamId)
185 self.fillLevel = streamReadFloat32(streamId)
186 self.compactedPercent = math.floor( (streamReadUIntN(streamId, 8) / 2.55) + 0.5)
187 self.fermentingPercent = math.floor( (streamReadUIntN(streamId, 8) / 2.55) + 0.5)
188 end
189end

readUpdateStream

Description
Called on client side on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
212function BunkerSilo:readUpdateStream(streamId, timestamp, connection)
213 BunkerSilo:superClass().readUpdateStream(self, streamId, timestamp, connection)
214 if connection:getIsServer() then
215 if streamReadBool(streamId) then
216 local state = streamReadUIntN(streamId, 3)
217 if state ~= self.state then
218 self:setState(state, true)
219 end
220
221 self.fillLevel = streamReadFloat32(streamId)
222 self.isOpenedAtFront = streamReadBool(streamId)
223 self.isOpenedAtBack = streamReadBool(streamId)
224
225 if self.state == BunkerSilo.STATE_FILL then
226 self.compactedPercent = math.floor( (streamReadUIntN(streamId, 8) / 2.55) + 0.5)
227 elseif self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED then
228 self.fermentingPercent = math.floor( (streamReadUIntN(streamId, 8) / 2.55) + 0.5)
229 end
230 end
231 end
232end

saveToXMLFile

Description
Save to XML file
Definition
saveToXMLFile(integer xmlFile, string key, table usedModNames)
Arguments
integerxmlFileid of xml object
stringkeykey
tableusedModNameslist of use dmod names
Code
353function BunkerSilo:saveToXMLFile(xmlFile, key, usedModNames)
354 setXMLInt(xmlFile, key.."#state", self.state)
355 setXMLFloat(xmlFile, key.."#fillLevel", self.fillLevel)
356 setXMLFloat(xmlFile, key.."#compactedFillLevel", self.compactedFillLevel)
357 setXMLFloat(xmlFile, key.."#fermentingTime", self.fermentingTime)
358 setXMLBool(xmlFile, key.."#openedAtFront", self.isOpenedAtFront)
359 setXMLBool(xmlFile, key.."#openedAtBack", self.isOpenedAtBack)
360end

setState

Description
Set state
Definition
setState(boolean state, boolean showNotification)
Arguments
booleanstatenew state
booleanshowNotificationshow notification
Code
530function BunkerSilo:setState(state, showNotification)
531
532 if state ~= self.state then
533
534 if state == BunkerSilo.STATE_FILL then
535
536 self.fermentingTime = 0
537 self.fermentingPercent = 0
538 self.compactedFillLevel = 0
539 self.isOpenedAtFront = false
540 self.isOpenedAtBack = false
541 self.bunkerSiloArea.offsetFront = 0
542 self.bunkerSiloArea.offsetBack = 0
543
544 if showNotification then
545 self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloIsEmpty"))
546 end
547
548 if self.isServer then
549 g_densityMapHeightManager:removeFixedFillTypesArea(self.bunkerSiloArea)
550 g_densityMapHeightManager:setConvertingFillTypeAreas(self.bunkerSiloArea, self.acceptedFillTypes, self.inputFillType)
551 end
552
553 elseif state == BunkerSilo.STATE_CLOSED then
554
555 if self.isServer then
556 -- change fillType
557 local area = self.bunkerSiloArea
558 local offsetFront = self:getBunkerAreaOffset(true, 0, self.inputFillType)
559 local offsetBack = self:getBunkerAreaOffset(false, 0, self.inputFillType)
560
561 local x0 = area.sx + (offsetFront * area.dhx_norm)
562 local z0 = area.sz + (offsetFront * area.dhz_norm)
563 local x1 = x0 + area.dwx
564 local z1 = z0 + area.dwz
565 local x2 = area.sx + area.dhx - (offsetBack * area.dhx_norm)
566 local z2 = area.sz + area.dhz - (offsetBack * area.dhz_norm)
567
568 local changed = DensityMapHeightUtil.changeFillTypeAtArea(x0,z0, x1,z1, x2,z2, self.inputFillType, self.fermentingFillType)
569
570 g_densityMapHeightManager:removeFixedFillTypesArea(self.bunkerSiloArea)
571 g_densityMapHeightManager:removeConvertingFillTypeAreas(self.bunkerSiloArea)
572 end
573
574 if showNotification then
575 self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloCovered"))
576 end
577
578 elseif state == BunkerSilo.STATE_FERMENTED then
579
580 if showNotification then
581 self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloDoneFermenting"))
582 end
583
584 elseif state == BunkerSilo.STATE_DRAIN then
585
586 self.bunkerSiloArea.offsetFront = 0
587 self.bunkerSiloArea.offsetBack = 0
588
589 if showNotification then
590 self:showBunkerMessage(g_i18n:getText("ingameNotification_bunkerSiloOpened"))
591 end
592
593 if self.isServer then
594 g_densityMapHeightManager:removeConvertingFillTypeAreas(self.bunkerSiloArea)
595 local fillTypes = {}
596 fillTypes[self.outputFillType] = true
597 g_densityMapHeightManager:setFixedFillTypesArea(self.bunkerSiloArea, fillTypes)
598 end
599
600 end
601
602 self.state = state
603 if self.isServer then
604 self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)
605 end
606 end
607end

switchFillTypeAtOffset

Description
Switch fill type at offset
Definition
switchFillTypeAtOffset(boolean switchAtFront, float offset, float length)
Arguments
booleanswitchAtFrontswitch at front
floatoffsetoffset
floatlengthlength
Code
678function BunkerSilo:switchFillTypeAtOffset(switchAtFront, offset, length)
679
680 local fillType = self.fermentingFillType
681 local newFillType = self.outputFillType
682
683 local a0x, a0z = nil, nil
684 local a1x, a1z = nil, nil
685 local a2x, a2z = nil, nil
686
687 local area = self.bunkerSiloArea
688
689 if switchAtFront then
690 a0x, a0z = area.sx + (offset * area.dhx_norm), area.sz + (offset * area.dhz_norm)
691 a1x, a1z = a0x + area.dwx, a0z + area.dwz
692 a2x, a2z = area.sx + ((offset + length) * area.dhx_norm), area.sz + ((offset + length) * area.dhz_norm)
693 else
694 a0x, a0z = area.hx - (offset * area.dhx_norm), area.hz - (offset * area.dhz_norm)
695 a1x, a1z = a0x + area.dwx, a0z + area.dwz
696 a2x, a2z = area.hx - ((offset + length) * area.dhx_norm), area.hz - ((offset + length) * area.dhz_norm)
697 end
698
699 DensityMapHeightUtil.changeFillTypeAtArea(a0x,a0z, a1x,a1z, a2x,a2z, fillType, newFillType)
700
701end

update

Description
Update
Definition
update(float dt)
Arguments
floatdttime since last call in ms
Code
365function BunkerSilo:update(dt)
366
367 if self:getCanInteract(true) then
368 local fillTypeIndex = self.inputFillType
369 if self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED or self.state == BunkerSilo.STATE_DRAIN then
370 fillTypeIndex = self.outputFillType
371 end
372 local fillTypeName = ""
373 local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex)
374 if fillType ~= nil then
375 fillTypeName = fillType.title
376 end
377 if self.state == BunkerSilo.STATE_FILL then
378 g_currentMission:addExtraPrintText(g_i18n:getText("info_fillLevel")..string.format(" %s: %d", fillTypeName, self.fillLevel))
379 g_currentMission:addExtraPrintText(g_i18n:getText("info_compacting")..string.format(" %d%%", self.compactedPercent))
380 elseif self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED then
381 g_currentMission:addExtraPrintText(g_i18n:getText("info_fermenting")..string.format(" %s: %d%%", fillTypeName, self.fermentingPercent))
382 elseif self.state == BunkerSilo.STATE_DRAIN then
383 g_currentMission:addExtraPrintText(g_i18n:getText("info_fillLevel")..string.format(" %s: %d", fillTypeName, self.fillLevel))
384 end
385 end
386
387 if self.state == BunkerSilo.STATE_CLOSED then
388 if self.isServer then
389 self.fermentingTime = math.min(self.fermentingDuration, self.fermentingTime + dt*g_currentMission.missionInfo.timeScale)
390 local fermentingPercent = MathUtil.getFlooredPercent(self.fermentingTime, self.fermentingDuration)
391 if fermentingPercent ~= self.fermentingPercent then
392 self.fermentingPercent = fermentingPercent
393 self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)
394 end
395 if self.fermentingTime >= self.fermentingDuration then
396 self:setState(BunkerSilo.STATE_FERMENTED, true)
397 end
398 end
399 end
400
401 if self.isServer then
402 if self.state == BunkerSilo.STATE_FILL then
403 for vehicle,state in pairs(self.vehiclesInRange) do
404 if state then
405 if vehicle:getIsActive() then
406 local distance = vehicle.lastMovedDistance
407 if distance > 0 then
408 local mass = vehicle:getTotalMass(false)
409
410 local refNode = vehicle.components[1].node
411 local scale = (mass / BunkerSilo.COMPACTING_BASE_MASS)
412
413 local bunkerSiloCompacter
414 if vehicle.getBunkerSiloCompacter ~= nil then
415 bunkerSiloCompacter = vehicle:getBunkerSiloCompacter()
416 end
417 if bunkerSiloCompacter ~= nil then
418 if bunkerSiloCompacter.refNode ~= nil then
419 refNode = bunkerSiloCompacter.refNode
420 end
421 if bunkerSiloCompacter.scale ~= nil then
422 scale = (mass / BunkerSilo.COMPACTING_BASE_MASS) * bunkerSiloCompacter.scale
423 end
424 end
425
426 local deltaCompact = distance*scale*self.distanceToCompactedFillLevel
427
428 if vehicle.getWheels ~= nil then
429 local wheels = vehicle:getWheels()
430 local numWheels = #wheels
431 if numWheels > 0 then
432 local wheelsOnSilo = 0
433 local wheelsInAir = 0
434 for _, wheel in ipairs(wheels) do
435 if wheel.contact == Wheels.WHEEL_GROUND_HEIGHT_CONTACT then
436 wheelsOnSilo = wheelsOnSilo + 1
437 elseif wheel.contact == Wheels.WHEEL_NO_CONTACT then
438 wheelsInAir = wheelsInAir + 1
439 end
440 end
441 if wheelsOnSilo > 0 then
442 deltaCompact = deltaCompact * ((wheelsOnSilo + wheelsInAir) / numWheels)
443 else
444 deltaCompact = 0
445 end
446 end
447 end
448
449 if deltaCompact > 0 then
450 local compactedFillLevel = math.min(self.compactedFillLevel + deltaCompact, self.fillLevel)
451 if compactedFillLevel ~= self.compactedFillLevel then
452 self.compactedFillLevel = compactedFillLevel
453 self.compactedPercent = MathUtil.getFlooredPercent(math.min(self.compactedFillLevel, self.fillLevel), self.fillLevel)
454 self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)
455 end
456 end
457 end
458 end
459 end
460 end
461 end
462 end
463
464 -- for chaff tutorial: always take the highest fill level of all bunker silos
465 if g_currentMission ~= nil and g_currentMission.bunkerScore ~= nil then
466 if g_currentMission.bunkerScore < self.fillLevel then
467 g_currentMission.bunkerScore = self.fillLevel
468 end
469 end
470
471 self:raiseActive()
472end

updateFillLevel

Description
Update fill level
Definition
updateFillLevel()
Code
498function BunkerSilo:updateFillLevel()
499 local area = self.bunkerSiloArea
500 local fillLevel = self.fillLevel
501 local fillType = self.inputFillType
502
503 if fillType ~= FillType.UNKNOWN then
504 if self.state == BunkerSilo.STATE_FILL then
505 fillLevel = DensityMapHeightUtil.getFillLevelAtArea(fillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
506 elseif self.state == BunkerSilo.STATE_CLOSED then
507 fillLevel = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
508 elseif self.state == BunkerSilo.STATE_FERMENTED then
509 local fillLevel1 = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
510 local fillLevel2 = DensityMapHeightUtil.getFillLevelAtArea(self.outputFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
511 fillLevel = fillLevel1 + fillLevel2
512 elseif self.state == BunkerSilo.STATE_DRAIN then
513 local fillLevel1 = DensityMapHeightUtil.getFillLevelAtArea(self.fermentingFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
514 local fillLevel2 = DensityMapHeightUtil.getFillLevelAtArea(self.outputFillType, area.sx,area.sz, area.wx,area.wz, area.hx,area.hz)
515 fillLevel = fillLevel1 + fillLevel2
516 if fillLevel < self.emptyThreshold then
517 DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.fermentingFillType)
518 DensityMapHeightUtil.removeFromGroundByArea(area.sx,area.sz, area.wx,area.wz, area.hx,area.hz, self.outputFillType)
519 self:setState(BunkerSilo.STATE_FILL, true)
520 end
521 end
522 end
523 self.fillLevel = fillLevel
524end

updateTick

Description
UpdateTick
Definition
updateTick(float dt)
Arguments
floatdttime since last call in ms
Code
477function BunkerSilo:updateTick(dt)
478 if self.isServer then
479 self.updateTimer = self.updateTimer - dt
480 if self.updateTimer <= 0 then
481 self.updateTimer = 200 + math.random()*100 -- update every 200 to 300ms
482
483 local oldFillLevel = self.fillLevel
484 self:updateFillLevel()
485 if oldFillLevel ~= self.fillLevel then
486 self:raiseDirtyFlags(self.bunkerSiloDirtyFlag)
487 end
488 end
489 end
490 if not self.adjustedOpeningLength then
491 self.adjustedOpeningLength = true
492 self.openingLength = math.max(self.openingLength, DensityMapHeightUtil.getDefaultMaxRadius(self.outputFillType)+1)
493 end
494end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
195function BunkerSilo:writeStream(streamId, connection)
196 BunkerSilo:superClass().writeStream(self, streamId, connection)
197 if not connection:getIsServer() then
198 streamWriteUIntN(streamId, self.state, 3)
199 streamWriteBool(streamId, self.isOpenedAtFront)
200 streamWriteBool(streamId, self.isOpenedAtBack)
201 streamWriteFloat32(streamId, self.fillLevel)
202 streamWriteUIntN(streamId, 2.55*self.compactedPercent, 8)
203 streamWriteUIntN(streamId, 2.55*self.fermentingPercent, 8)
204 end
205end

writeUpdateStream

Description
Called on server side on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
239function BunkerSilo:writeUpdateStream(streamId, connection, dirtyMask)
240 BunkerSilo:superClass().writeUpdateStream(self, streamId, connection, dirtyMask)
241 if not connection:getIsServer() then
242 if streamWriteBool(streamId, bitAND(dirtyMask, self.bunkerSiloDirtyFlag) ~= 0) then
243 streamWriteUIntN(streamId, self.state, 3)
244
245 streamWriteFloat32(streamId, self.fillLevel)
246 streamWriteBool(streamId, self.isOpenedAtFront)
247 streamWriteBool(streamId, self.isOpenedAtBack)
248
249 if self.state == BunkerSilo.STATE_FILL then
250 streamWriteUIntN(streamId, 2.55*self.compactedPercent, 8)
251 elseif self.state == BunkerSilo.STATE_CLOSED or self.state == BunkerSilo.STATE_FERMENTED then
252 streamWriteUIntN(streamId, 2.55*self.fermentingPercent, 8)
253 end
254 end
255 end
256end