Script v1_7_1_0
- AI
- Animals
- Collections
- Contracts
- Debug
- Economy
- Elements
- EnvironmentalScore
- Errors
- Events
- GUI
- Handtools
- Hud
- I3d
- Input
- Jobs
- Maps
- Materials
- Misc
- Objects
- Parameters
- Placeables
- Placement
- Player
- Shop
- Sounds
- Specialization
- Specializations
- StateMachine
- Statistics
- Tasks
- Triggers
- Utils
- Vehicles
Engine v1_7_1_0
- AI
- Animation
- Camera
- Entity
- Fillplanes
- general
- General
- I3D
- Input
- Lighting
- Math
- Network
- Node
- NoteNode
- Overlays
- Particle System
- Physics
- Rendering
- Scenegraph
- Shape
- Sound
- Spline
- String
- Terrain Detail
- Text Rendering
- Tire Track
- VoiceChat
- XML
Foundation Reference
FarmlandStatistics
Functions- buildOverlay
- closeStatistics
- delete
- getFarmlandFieldInfo
- getFillLevelPrice
- getFillLevelWeight
- getSelectedFarmland
- loadFromItemsXML
- loadFromXML
- new
- onClickButtonResetStats
- onClickButtonSwitchValues
- onClickMapFarmland
- onClickSwitchMapMode
- onMenuActivate
- onMenuCancel
- openStatistics
- overwriteGameFunctions
- readStatisticFromStream
- resetStatistic
- saveToXMLFile
- setMapFrame
- updateButtonIcons
- updateStatistic
- writeStatisticToStream
buildOverlay
DescriptionDefinitionbuildOverlay()Code
453 | function FarmlandStatistics:buildOverlay(overlay) |
454 | setOverlayColor(overlay, 1, 1, 1, 0.3) |
455 | resetDensityMapVisualizationOverlay(overlay) |
456 | if self.selectedFarmlandId ~= nil then |
457 | local _, fieldArea = self:getFarmlandFieldInfo(self.selectedFarmlandId) |
458 | if fieldArea > 0 then |
459 | local map = g_farmlandManager:getLocalMap() |
460 | |
461 | setDensityMapVisualizationOverlayStateColor(overlay, map, 0, 0, 0, getBitVectorMapNumChannels(map), self.selectedFarmlandId, unpack(MapOverlayGenerator.COLOR.FIELD_SELECTED)) |
462 | end |
463 | end |
464 | end |
closeStatistics
DescriptionDefinitioncloseStatistics()Code
474 | function FarmlandStatistics:closeStatistics() |
475 | local mapFrame = self.mapFrame |
476 | mapFrame.economicAnalysisWindow:setVisible(false) |
477 | mapFrame.laboratoryWindow:setVisible(true) |
478 | mapFrame.envScoreWindow:setVisible(true) |
479 | mapFrame:resetUIDeadzones() |
480 | |
481 | self.pfModule:updatePrecisionFarmingOverlays() |
482 | end |
delete
DescriptionDefinitiondelete()Code
78 | function FarmlandStatistics:delete() |
79 | g_farmlandManager:removeStateChangeListener(self) |
80 | |
81 | self.statistics = {} |
82 | self.statisticsByFarmland = {} |
83 | |
84 | self.selectedFarmlandId = nil |
85 | self.showTotal = false |
86 | end |
getFarmlandFieldInfo
DescriptionDefinitiongetFarmlandFieldInfo()Code
468 | function FarmlandStatistics:getFarmlandFieldInfo(farmlandId) |
469 | return self.pfModule:getFarmlandFieldInfo(farmlandId) |
470 | end |
getFillLevelPrice
DescriptionDefinitiongetFillLevelPrice()Code
521 | function FarmlandStatistics:getFillLevelPrice(fillLevel, fillTypeIndex) |
522 | if fillTypeIndex == "soilSamples" then |
523 | local price = self.pfModule.soilMap.pricePerSample[g_currentMission.missionInfo.economicDifficulty] or 0 |
524 | return fillLevel * price |
525 | end |
526 | |
527 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex) |
528 | if fillType ~= nil then |
529 | return fillLevel * fillType.pricePerLiter |
530 | end |
531 | |
532 | return fillLevel |
533 | end |
getFillLevelWeight
DescriptionDefinitiongetFillLevelWeight()Code
510 | function FarmlandStatistics:getFillLevelWeight(fillLevel, fillTypeIndex) |
511 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex) |
512 | if fillType ~= nil then |
513 | return fillLevel * (fillType.massPerLiter / FillTypeManager.MASS_SCALE) |
514 | end |
515 | |
516 | return fillLevel |
517 | end |
getSelectedFarmland
DescriptionDefinitiongetSelectedFarmland()Code
257 | function FarmlandStatistics:getSelectedFarmland() |
258 | if self.selectedFarmlandId ~= nil then |
259 | return self.selectedFarmlandId |
260 | end |
261 | end |
loadFromItemsXML
DescriptionDefinitionloadFromItemsXML()Code
49 | function FarmlandStatistics:loadFromItemsXML(xmlFile, key) |
50 | key = key .. ".farmlandStatistics" |
51 | |
52 | for i=1, #self.statistics do |
53 | local statistic = self.statistics[i] |
54 | local statKey = string.format("%s.farmlandStatistic(%d)", key, i - 1) |
55 | if not xmlFile:hasProperty(statKey) then |
56 | break |
57 | end |
58 | |
59 | statistic:loadFromItemsXML(xmlFile, statKey) |
60 | end |
61 | end |
loadFromXML
DescriptionDefinitionloadFromXML()Code
41 | function FarmlandStatistics:loadFromXML(xmlFile, key, baseDirectory, configFileName, mapFilename) |
42 | g_farmlandManager:addStateChangeListener(self) |
43 | |
44 | return true |
45 | end |
new
DescriptionDefinitionnew()Code
18 | function FarmlandStatistics.new(pfModule, customMt) |
19 | local self = setmetatable({}, customMt or FarmlandStatistics_mt) |
20 | |
21 | self.statistics = {} |
22 | self.statisticsByFarmland = {} |
23 | self.mapFrame = nil |
24 | |
25 | self.selectedFarmlandId = nil |
26 | self.showTotal = false |
27 | |
28 | self.updateValuesTimer = 0 |
29 | self.updateValuesInterval = 1000 |
30 | self.updateValuesIntervalMultiplayer = 5000 -- reduced interval so we send a update event only every 5 secs |
31 | |
32 | self.pfModule = pfModule |
33 | |
34 | self.lastInputHelpMode = g_inputBinding:getInputHelpMode() |
35 | |
36 | return self |
37 | end |
onClickButtonResetStats
DescriptionDefinitiononClickButtonResetStats()Code
177 | function FarmlandStatistics:onClickButtonResetStats() |
178 | if self.selectedFarmlandId ~= nil then |
179 | self:resetStatistic(self.selectedFarmlandId, false) |
180 | if g_server == nil and g_client ~= nil then |
181 | g_client:getServerConnection():sendEvent(FarmlandStatisticsResetEvent.new(self.selectedFarmlandId)) |
182 | end |
183 | |
184 | self:openStatistics(self.selectedFarmlandId) |
185 | end |
186 | end |
onClickButtonSwitchValues
DescriptionDefinitiononClickButtonSwitchValues()Code
190 | function FarmlandStatistics:onClickButtonSwitchValues() |
191 | self.showTotal = not self.showTotal |
192 | if self.selectedFarmlandId ~= nil then |
193 | self:openStatistics(self.selectedFarmlandId) |
194 | end |
195 | |
196 | if self.mapFrame ~= nil then |
197 | self.mapFrame.buttonResetStats:setDisabled(self.showTotal) |
198 | end |
199 | end |
onClickMapFarmland
DescriptionDefinitiononClickMapFarmland()Code
203 | function FarmlandStatistics:onClickMapFarmland(farmlandId) |
204 | if farmlandId == self.selectedFarmlandId then |
205 | self.selectedFarmlandId = nil |
206 | self:closeStatistics() |
207 | self.pfModule:onFarmlandSelectionChanged(nil, nil) |
208 | return |
209 | else |
210 | local ownerFarmId = g_farmlandManager:getFarmlandOwner(farmlandId) |
211 | if ownerFarmId ~= FarmlandManager.NO_OWNER_FARM_ID and ownerFarmId == g_currentMission:getFarmId() then |
212 | self.selectedFarmlandId = farmlandId |
213 | self.updateValuesTimer = 0 |
214 | self:openStatistics(farmlandId) |
215 | self.pfModule:updatePrecisionFarmingOverlays() |
216 | end |
217 | end |
218 | end |
onClickSwitchMapMode
DescriptionDefinitiononClickSwitchMapMode()Code
244 | function FarmlandStatistics:onClickSwitchMapMode() |
245 | if self.selectedFarmlandId ~= nil then |
246 | if not self.showTotal then |
247 | self:onClickButtonResetStats() |
248 | return true |
249 | end |
250 | end |
251 | |
252 | return false |
253 | end |
onMenuActivate
DescriptionDefinitiononMenuActivate()Code
233 | function FarmlandStatistics:onMenuActivate() |
234 | if self.selectedFarmlandId ~= nil then |
235 | self:onClickButtonSwitchValues() |
236 | return true |
237 | end |
238 | |
239 | return false |
240 | end |
onMenuCancel
DescriptionDefinitiononMenuCancel()Code
222 | function FarmlandStatistics:onMenuCancel() |
223 | if self.selectedFarmlandId ~= nil then |
224 | self:onClickMapFarmland(self.selectedFarmlandId) |
225 | return true |
226 | end |
227 | |
228 | return false |
229 | end |
openStatistics
DescriptionDefinitionopenStatistics()Code
265 | function FarmlandStatistics:openStatistics(farmlandId, noEventSend) |
266 | local mapFrame = self.mapFrame |
267 | |
268 | local statistic = self.statisticsByFarmland[farmlandId] |
269 | if statistic ~= nil then |
270 | local fieldNumber, fieldArea = self:getFarmlandFieldInfo(farmlandId) |
271 | if fieldArea >= 0.01 then |
272 | self:updateButtonIcons() |
273 | mapFrame.economicAnalysisWindow:setVisible(true) |
274 | mapFrame.laboratoryWindow:setVisible(false) |
275 | mapFrame.envScoreWindow:setVisible(false) |
276 | mapFrame:resetUIDeadzones() |
277 | |
278 | local text |
279 | if fieldNumber ~= 0 then |
280 | text = string.format(g_i18n:getText("ui_economicAnalysisHeaderField"), fieldNumber, fieldArea) |
281 | else |
282 | text = string.format(g_i18n:getText("ui_economicAnalysisHeaderAdditionalField"), fieldArea) |
283 | end |
284 | mapFrame.economicAnalysisHeaderField:setText(text) |
285 | |
286 | mapFrame.economicAnalysisHeaderValues:setText(g_i18n:getText(self.showTotal and "ui_economicAnalysisHeaderValuesTotal" or "ui_economicAnalysisHeaderValuesPeriod")) |
287 | mapFrame.buttonSwitchValues:setText(g_i18n:getText(self.showTotal and "ui_economicAnalysisButtonPeriod" or "ui_economicAnalysisButtonTotal")) |
288 | |
289 | local function setChangePercentageElement(element, value, valueRegular, cost, inversePercentageColor) |
290 | local pct = 0 |
291 | if value ~= valueRegular then |
292 | local direction |
293 | local pctText = "" |
294 | if valueRegular ~= 0 then |
295 | pct = math.floor(-100 * (1 - (value / valueRegular))) |
296 | if pct ~= 0 then |
297 | local str = pct <= 0 and "(%d%%)" or "(+%d%%)" |
298 | pctText = string.format(str, pct) |
299 | direction = pct > 0 |
300 | end |
301 | else |
302 | if math.floor(cost or 0) > 0 then |
303 | pctText = string.format("(+%s)", g_i18n:formatMoney(cost)) |
304 | pct = 100 |
305 | direction = true |
306 | else |
307 | pctText = "" |
308 | end |
309 | end |
310 | if inversePercentageColor == true then |
311 | direction = not direction |
312 | end |
313 | |
314 | element:applyProfile(direction and "ingameMenuPrecisionFarmingStatsChangeNeg" or "ingameMenuPrecisionFarmingStatsChangePos", true) |
315 | element:setText(pctText) |
316 | element:applyScreenAlignment() |
317 | else |
318 | element:setText("") |
319 | end |
320 | |
321 | return pct |
322 | end |
323 | |
324 | local function buildValueDisplay(mapFrame, statistic, index, showTotal, name, nameRegular, fillTypeIndex, showWeight, showValue, showCost, showDetailedLiters, unitStr, cost, weight, inversePercentageColor) |
325 | if unitStr == nil then |
326 | unitStr = " l" |
327 | elseif unitStr:len() > 0 then |
328 | unitStr = " " .. unitStr |
329 | end |
330 | |
331 | local value = statistic:getValue(showTotal, name) |
332 | local valueRegular = value |
333 | if nameRegular ~= nil then |
334 | if type(nameRegular) == "string" then |
335 | valueRegular = statistic:getValue(showTotal, nameRegular) |
336 | elseif type(nameRegular) == "number" then |
337 | valueRegular = nameRegular |
338 | end |
339 | end |
340 | |
341 | cost = cost or self:getFillLevelPrice(value, fillTypeIndex) |
342 | weight = weight or self:getFillLevelWeight(value, fillTypeIndex) |
343 | |
344 | if showValue then |
345 | local valueText = "%d" .. unitStr |
346 | if showDetailedLiters then |
347 | valueText = "%.1f" .. unitStr |
348 | else |
349 | value = MathUtil.round(value) |
350 | end |
351 | if showWeight then |
352 | valueText = valueText .. " | %.1f t" |
353 | end |
354 | |
355 | mapFrame.statAmountText[index]:setText(string.format(valueText, value, weight)) |
356 | else |
357 | mapFrame.statAmountText[index]:setText("") |
358 | end |
359 | |
360 | if showCost == nil or showCost then |
361 | mapFrame.statCostText[index]:setText(g_i18n:formatMoney(cost)) |
362 | else |
363 | mapFrame.statCostText[index]:setText("") |
364 | end |
365 | |
366 | local percentageIncrease = setChangePercentageElement(mapFrame.statPercentageText[index], value, valueRegular, cost, inversePercentageColor) |
367 | if showCost == false then |
368 | percentageIncrease = 0 |
369 | end |
370 | |
371 | return math.max(math.floor(cost)), math.max(math.floor(cost * (-percentageIncrease * 0.01 + 1)), 0) |
372 | end |
373 | |
374 | local totalCosts = 0 |
375 | local totalRegularCosts = 0 |
376 | local costs, regularCosts |
377 | |
378 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 1, self.showTotal, "numSoilSamples", 0, "soilSamples", false, true, true, false, "", statistic:getValue(self.showTotal, "soilSampleCosts")) |
379 | totalCosts = totalCosts + costs |
380 | totalRegularCosts = totalRegularCosts + regularCosts |
381 | |
382 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 2, self.showTotal, "usedLime", "usedLimeRegular", FillType.LIME, true, true, true, false) |
383 | totalCosts = totalCosts + costs |
384 | totalRegularCosts = totalRegularCosts + regularCosts |
385 | |
386 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 3, self.showTotal, "usedMineralFertilizer", "usedMineralFertilizerRegular", FillType.FERTILIZER, true, true, true, false) |
387 | totalCosts = totalCosts + costs |
388 | totalRegularCosts = totalRegularCosts + regularCosts |
389 | |
390 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 4, self.showTotal, "usedLiquidFertilizer", "usedLiquidFertilizerRegular", FillType.LIQUIDFERTILIZER, false, true, true, false) |
391 | totalCosts = totalCosts + costs |
392 | totalRegularCosts = totalRegularCosts + regularCosts |
393 | |
394 | buildValueDisplay(mapFrame, statistic, 5, self.showTotal, "usedManure", "usedManureRegular", FillType.MANURE, true, true, false, false) |
395 | buildValueDisplay(mapFrame, statistic, 6, self.showTotal, "usedLiquidManure", "usedLiquidManureRegular", FillType.LIQUIDMANURE, false, true, false, false) |
396 | |
397 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 7, self.showTotal, "usedSeeds", "usedSeedsRegular", FillType.SEEDS, true, true, true, false) |
398 | totalCosts = totalCosts + costs |
399 | totalRegularCosts = totalRegularCosts + regularCosts |
400 | |
401 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 8, self.showTotal, "usedHerbicide", "usedHerbicideRegular", FillType.HERBICIDE, false, true, true, false) |
402 | totalCosts = totalCosts + costs |
403 | totalRegularCosts = totalRegularCosts + regularCosts |
404 | |
405 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 9, self.showTotal, "usedFuel", nil, FillType.DIESEL, false, true, true, true) |
406 | totalCosts = totalCosts + costs |
407 | totalRegularCosts = totalRegularCosts + regularCosts |
408 | |
409 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 10, self.showTotal, "vehicleCosts", nil, 0, false, false, true, false) |
410 | totalCosts = totalCosts + costs |
411 | totalRegularCosts = totalRegularCosts + regularCosts |
412 | |
413 | costs, regularCosts = buildValueDisplay(mapFrame, statistic, 11, self.showTotal, "helperCosts", nil, 0, false, false, true, false) |
414 | totalCosts = totalCosts + costs |
415 | totalRegularCosts = totalRegularCosts + regularCosts |
416 | |
417 | local yieldWeight = statistic:getValue(self.showTotal, "yieldWeight") |
418 | local yieldBestPrice = statistic:getValue(self.showTotal, "yieldBestPrice") |
419 | buildValueDisplay(mapFrame, statistic, 12, self.showTotal, "yield", "yieldRegular", 0, true, true, true, false, nil, yieldBestPrice, yieldWeight, true) |
420 | |
421 | local earningsIncreasePct = statistic:getValue(self.showTotal, "yield") / math.max(statistic:getValue(self.showTotal, "yieldRegular"), 0.01) |
422 | local earningsIncrease = yieldBestPrice - yieldBestPrice / math.max(earningsIncreasePct, 0.01) |
423 | |
424 | local costIncrease = totalRegularCosts - totalCosts |
425 | |
426 | setChangePercentageElement(mapFrame.statTotalCostPercentageText, totalCosts, 0, math.abs(costIncrease), false) |
427 | setChangePercentageElement(mapFrame.statTotalEarningsPercentageText, yieldBestPrice, 0, earningsIncrease, true) |
428 | setChangePercentageElement(mapFrame.statTotalPercentageText, yieldBestPrice, 0, costIncrease - earningsIncrease, false) |
429 | |
430 | local totalEarnings = yieldBestPrice |
431 | local result = totalEarnings - totalCosts |
432 | |
433 | mapFrame.statTotalCostText:setText(g_i18n:formatMoney(totalCosts)) |
434 | mapFrame.statTotalEarningsText:setText(g_i18n:formatMoney(totalEarnings)) |
435 | mapFrame.statTotalText:setText(g_i18n:formatMoney(result)) |
436 | else |
437 | self.selectedFarmlandId = nil |
438 | self:closeStatistics() |
439 | end |
440 | |
441 | self.pfModule:onFarmlandSelectionChanged(farmlandId, fieldNumber, fieldArea) |
442 | end |
443 | |
444 | if not noEventSend then |
445 | if g_server == nil and g_client ~= nil then |
446 | g_client:getServerConnection():sendEvent(RequestFarmlandStatisticsEvent.new(farmlandId)) |
447 | end |
448 | end |
449 | end |
overwriteGameFunctions
DescriptionDefinitionoverwriteGameFunctions()Code
543 | function FarmlandStatistics:overwriteGameFunctions(pfModule) |
544 | pfModule:overwriteGameFunction(FarmlandManager, "loadFarmlandData", function(superFunc, farmlandManager, xmlFile) |
545 | if not superFunc(farmlandManager, xmlFile) then |
546 | return false |
547 | end |
548 | |
549 | local farmlands = g_farmlandManager:getFarmlands() |
550 | if farmlands ~= nil then |
551 | for id, farmland in pairs(farmlands) do |
552 | local statistic = FarmlandStatistic.new(id) |
553 | self.statisticsByFarmland[id] = statistic |
554 | table.insert(self.statistics, statistic) |
555 | end |
556 | end |
557 | |
558 | return true |
559 | end) |
560 | end |
readStatisticFromStream
DescriptionDefinitionreadStatisticFromStream()Code
121 | function FarmlandStatistics:readStatisticFromStream(farmlandId, streamId, connection) |
122 | if streamReadBool(streamId) then |
123 | local totalFieldArea = streamReadFloat32(streamId) |
124 | local farmland = g_farmlandManager.farmlands[farmlandId] |
125 | if farmland ~= nil then |
126 | farmland.totalFieldArea = totalFieldArea |
127 | end |
128 | end |
129 | |
130 | local statistic = self.statisticsByFarmland[farmlandId] |
131 | if statistic ~= nil then |
132 | statistic:onReadStream(streamId, connection) |
133 | end |
134 | |
135 | self.selectedFarmlandId = farmlandId |
136 | self:openStatistics(farmlandId, true) |
137 | self.pfModule:updatePrecisionFarmingOverlays() |
138 | end |
resetStatistic
DescriptionDefinitionresetStatistic()Code
495 | function FarmlandStatistics:resetStatistic(farmlandId, reloadValues, clearTotal) |
496 | local statistic = self.statisticsByFarmland[farmlandId] |
497 | if statistic ~= nil then |
498 | statistic:reset(clearTotal) |
499 | end |
500 | |
501 | if reloadValues then |
502 | if self.selectedFarmlandId ~= nil then |
503 | self:openStatistics(self.selectedFarmlandId) |
504 | end |
505 | end |
506 | end |
saveToXMLFile
DescriptionDefinitionsaveToXMLFile()Code
65 | function FarmlandStatistics:saveToXMLFile(xmlFile, key, usedModNames) |
66 | key = key .. ".farmlandStatistics" |
67 | |
68 | for i=1, #self.statistics do |
69 | local statistic = self.statistics[i] |
70 | local statKey = string.format("%s.farmlandStatistic(%d)", key, i - 1) |
71 | |
72 | statistic:saveToXMLFile(xmlFile, statKey, usedModNames) |
73 | end |
74 | end |
setMapFrame
DescriptionDefinitionsetMapFrame()Code
156 | function FarmlandStatistics:setMapFrame(mapFrame) |
157 | self.mapFrame = mapFrame |
158 | mapFrame.economicAnalysisWindow:setVisible(false) |
159 | |
160 | self:updateButtonIcons() |
161 | end |
updateButtonIcons
DescriptionDefinitionupdateButtonIcons()Code
165 | function FarmlandStatistics:updateButtonIcons() |
166 | PrecisionFarmingGUI.updateButtonOnInputHelpChange(self.mapFrame.buttonSwitchValues, "ingameMenuPrecisionFarmingStatsSwitchButtonConsole", "ingameMenuPrecisionFarmingStatsSwitchButton") |
167 | PrecisionFarmingGUI.updateButtonOnInputHelpChange(self.mapFrame.buttonResetStats, "ingameMenuPrecisionFarmingStatsResetButtonConsole", "ingameMenuPrecisionFarmingStatsResetButton") |
168 | |
169 | if self.mapFrame.buttonSwitchValues.inputActionName == nil then |
170 | local uvs = self.showTotal and FarmlandStatistics.UV.TOTAL or FarmlandStatistics.UV.PERIOD |
171 | self.mapFrame.buttonSwitchValues:setImageUVs(nil, GuiUtils.getUVs(uvs)) |
172 | end |
173 | end |
updateStatistic
DescriptionDefinitionupdateStatistic()Code
486 | function FarmlandStatistics:updateStatistic(farmlandId, name, value) |
487 | local statistic = self.statisticsByFarmland[farmlandId] |
488 | if statistic ~= nil then |
489 | statistic:updateStatistic(name, value) |
490 | end |
491 | end |
writeStatisticToStream
DescriptionDefinitionwriteStatisticToStream()Code
142 | function FarmlandStatistics:writeStatisticToStream(farmlandId, streamId, connection) |
143 | local farmland = g_farmlandManager.farmlands[farmlandId] |
144 | if streamWriteBool(streamId, farmland ~= nil) then |
145 | streamWriteFloat32(streamId, farmland.totalFieldArea or 0) |
146 | end |
147 | |
148 | local statistic = self.statisticsByFarmland[farmlandId] |
149 | if statistic ~= nil then |
150 | statistic:onWriteStream(streamId, connection) |
151 | end |
152 | end |