LUADOC - Farming Simulator 22

Placeable

Description
Base Class for placeables Note about terrain modification on placement: If terrain modification is enabled using the placeable.leveling#requireLeveling attribute, the configuration needs at least one leveling area to be defined (ramps are optional). These areas represent parallelograms which are passed to terrain modification functions. They are defined by start, width and height nodes which in this case should be set up to form rectangular shapes. For the best results, create a new transform group for each area at the starting positions and add separate nodes for the three defining points in the placeable object I3D file.
Parent
Object
Functions

addToPhysics

Description
Definition
addToPhysics()
Code
1126function Placeable:addToPhysics()
1127 if self.rootNode ~= nil then
1128 addToPhysics(self.rootNode)
1129 end
1130end

canBeSold

Description
Definition
canBeSold()
Code
918function Placeable:canBeSold()
919 return true, nil
920end

canBuy

Description
Returns true if we can place a building checking item count
Definition
canBuy()
Return Values
bool
Code
896function Placeable:canBuy()
897 local storeItem = self.storeItem
898 local maxItemCount = storeItem.maxItemCount
899 if maxItemCount == nil then
900 return true
901 end
902
903 if g_currentMission:getNumOfItems(storeItem, g_currentMission:getFarmId()) < storeItem.maxItemCount then
904 return true
905 end
906
907 return false
908end

collectPickObjects

Description
Collect shapes that can be used for picking. Adds them to the mission for node -> object reference.
Definition
collectPickObjects(integer node)
Arguments
integernodenode id
Code
1021function Placeable:collectPickObjects(node)
1022 if getRigidBodyType(node) ~= RigidBodyType.NONE then
1023 table.insert(self.pickObjects, node)
1024 end
1025 local numChildren = getNumOfChildren(node)
1026 for i=1, numChildren do
1027 self:collectPickObjects(getChildAt(node, i-1))
1028 end
1029end

createLoadingTask

Description
Definition
createLoadingTask()
Code
449function Placeable:createLoadingTask(target)
450 local task = {target=target}
451 table.insert(self.loadingTasks, task)
452 return task
453end

dayChanged

Description
Definition
dayChanged()
Code
1191function Placeable:dayChanged(day)
1192 SpecializationUtil.raiseEvent(self, "onDayChanged", day)
1193end

delete

Description
Deleting placeable
Definition
delete()
Code
546function Placeable:delete()
547 if self.isDeleted then
548 Logging.devError("Trying to delete a already deleted placeable")
549 printCallstack()
550 return
551 end
552
553 g_messageCenter:unsubscribeAll(self)
554
555 self.isDeleting = true
556 SpecializationUtil.raiseEvent(self, "onPreDelete")
557
558 -- Remove from placeables to delete list, so that base mission doesn't try to double delete
559 g_currentMission:removePlaceableToDelete(self)
560 g_currentMission.placeableSystem:removePlaceable(self)
561 g_currentMission:removeOwnedItem(self)
562
563 if self.sharedLoadRequestId ~= nil then
564 g_i3DManager:releaseSharedI3DFile(self.sharedLoadRequestId)
565 self.sharedLoadRequestId = nil
566 end
567
568 for _, node in pairs(self.pickObjects) do
569 g_currentMission:removeNodeObject(node)
570 end
571
572 SpecializationUtil.raiseEvent(self, "onDelete")
573
574 if self.boughtWithFarmland and self.isServer then
575 g_farmlandManager:removeStateChangeListener(self)
576 end
577
578 if self.rootNode ~= nil then
579 delete(self.rootNode)
580 self.rootNode = nil
581 end
582
583 if self.xmlFile ~= nil then
584 self.xmlFile:delete()
585 self.xmlFile = nil
586 end
587
588 self.isDeleting = false
589 self.isDeleted = true
590
591 Placeable:superClass().delete(self)
592end

draw

Description
Definition
draw()
Code
831function Placeable:draw()
832 SpecializationUtil.raiseEvent(self, "onDraw")
833end

finalizePlacement

Description
Called if placeable is placed
Definition
finalizePlacement()
Code
499function Placeable:finalizePlacement()
500 SpecializationUtil.raiseEvent(self, "onPreFinalizePlacement")
501
502 self:addToPhysics()
503
504 g_currentMission.placeableSystem:addPlaceable(self)
505 g_currentMission:addOwnedItem(self)
506
507 self:collectPickObjects(self.rootNode)
508 for _, node in pairs(self.pickObjects) do
509 g_currentMission:addNodeObject(node, self)
510 end
511
512 local x,_,z = getWorldTranslation(self.rootNode)
513 self.farmlandId = g_farmlandManager:getFarmlandIdAtWorldPosition(x, z)
514
515 if self.boughtWithFarmland then
516 if self.isServer then
517 self:updateOwnership()
518 end
519
520 g_farmlandManager:addStateChangeListener(self)
521 end
522 SpecializationUtil.raiseEvent(self, "onFinalizePlacement")
523
524 SpecializationUtil.raiseEvent(self, "onPostFinalizePlacement")
525
526 if self:getNeedWeatherChanged() then
527 g_messageCenter:subscribe(MessageType.WEATHER_CHANGED, self.weatherChanged, self)
528 end
529 if self:getNeedHourChanged() then
530 g_messageCenter:subscribe(MessageType.HOUR_CHANGED, self.hourChanged, self)
531 end
532 if self:getNeedMinuteChanged() then
533 g_messageCenter:subscribe(MessageType.MINUTE_CHANGED, self.minuteChanged, self)
534 end
535 if self:getNeedDayChanged() then
536 g_messageCenter:subscribe(MessageType.DAY_CHANGED, self.dayChanged, self)
537 end
538 g_messageCenter:subscribe(MessageType.PERIOD_CHANGED, self.periodChanged, self)
539
540 g_messageCenter:publish(MessageType.FARM_PROPERTY_CHANGED, self:getOwnerFarmId())
541end

finishLoadingTask

Description
Definition
finishLoadingTask()
Code
457function Placeable:finishLoadingTask(task)
458 for k, t in ipairs(self.loadingTasks) do
459 if t == task then
460 table.remove(self.loadingTasks, k)
461 break
462 end
463 end
464
465 if self.readyForFinishLoading and #self.loadingTasks == 0 then
466 self:onFinishedLoading()
467 end
468end

getCanBePlacedAt

Description
Definition
getCanBePlacedAt()
Code
912function Placeable:getCanBePlacedAt(x, y, z, farmId)
913 return true, nil
914end

getCanBeRenamedByFarm

Description
Definition
getCanBeRenamedByFarm()
Code
849function Placeable:getCanBeRenamedByFarm(farmId)
850 return self.canBeRenamed and self:getOwnerFarmId() == farmId
851end

getDailyUpkeep

Description
Returns daily up keep
Definition
getDailyUpkeep()
Return Values
integerdailyUpkeepdaily up keep
Code
1080function Placeable:getDailyUpkeep()
1081 local storeItem = self.storeItem
1082
1083 local multiplier = 1
1084 if storeItem.lifetime ~= nil and storeItem.lifetime ~= 0 then
1085 local ageMultiplier = math.min(self.age/storeItem.lifetime, 1)
1086 multiplier = 1 + EconomyManager.MAX_DAILYUPKEEP_MULTIPLIER * ageMultiplier
1087 end
1088 return StoreItemUtil.getDailyUpkeep(storeItem, nil) * multiplier
1089end

getDestructionMethod

Description
Definition
getDestructionMethod()
Code
930function Placeable:getDestructionMethod()
931 return Placeable.DESTRUCTION.SELL
932end

getImageFilename

Description
Definition
getImageFilename()
Code
843function Placeable:getImageFilename()
844 return self.storeItem.imageFilename
845end

getIsSynchronized

Description
Definition
getIsSynchronized()
Code
807function Placeable:getIsSynchronized()
808 return self.loadingStep == Placeable.LOAD_STEP_SYNCHRONIZED
809end

getName

Description
Definition
getName()
Code
837function Placeable:getName()
838 return self.name or (self.storeItem and self.storeItem.name)
839end

getNeedDayChanged

Description
Definition
getNeedDayChanged()
Code
1185function Placeable:getNeedDayChanged()
1186 return false
1187end

getNeedHourChanged

Description
Definition
getNeedHourChanged()
Code
1161function Placeable:getNeedHourChanged()
1162 return false
1163end

getNeedMinuteChanged

Description
Definition
getNeedMinuteChanged()
Code
1173function Placeable:getNeedMinuteChanged()
1174 return false
1175end

getNeedsSaving

Description
Definition
getNeedsSaving()
Code
813function Placeable:getNeedsSaving()
814 return true
815end

getNeedWeatherChanged

Description
Definition
getNeedWeatherChanged()
Code
1149function Placeable:getNeedWeatherChanged()
1150 return false
1151end

getPrice

Description
Definition
getPrice()
Code
888function Placeable:getPrice()
889 return self.price
890end

getPropertyState

Description
Definition
getPropertyState()
Code
793function Placeable:getPropertyState()
794 return self.propertyState
795end

getSellAction

Description
Returns if a placeable should be deleted or moved to farm 0 on sell
Definition
getSellAction()
Return Values
integersellPricePlaceable.SELL_AND_DELETE or Placeable.SELL_AND_SPECTATOR_FARM
Code
1113function Placeable:getSellAction()
1114 local isOnPublicGround = g_farmlandManager:getFarmlandOwner(self.farmlandId) == FarmManager.SPECTATOR_FARM_ID
1115
1116 -- keep placeables on farm 0 if they are on public ground (e.g. prod points) or cannot be deleted and
1117 if self:isMapBound() and (isOnPublicGround or not self.canBeDeleted) then
1118 return Placeable.SELL_AND_SPECTATOR_FARM
1119 end
1120
1121 return Placeable.SELL_AND_DELETE
1122end

getSellPrice

Description
Returns sell price
Definition
getSellPrice()
Return Values
integersellPricesell price
Code
1094function Placeable:getSellPrice()
1095 if self.undoTimer > g_time - Placeable.UNDO_DURATION and self.undoTimer > g_currentMission.lastConstructionScreenOpenTime
1096 and g_currentMission.lastConstructionScreenOpenTime > 0 then
1097 return self.price, true
1098 end
1099
1100 local priceMultiplier = 0.5
1101 local maxAge = self.storeItem.lifetime
1102
1103 if maxAge ~= nil and maxAge ~= 0 then
1104 priceMultiplier = priceMultiplier * math.exp(-3.5 * math.min(self.age/maxAge, 1))
1105 end
1106
1107 return math.floor(self.price * math.max(priceMultiplier, 0.05))
1108end

getSpecValueSlots

Description
Definition
getSpecValueSlots()
Code
1204function Placeable.getSpecValueSlots(storeItem, realItem)
1205 local numOwned = g_currentMission:getNumOfItems(storeItem)
1206 local slotUsage = g_currentMission.slotSystem:getStoreItemSlotUsage(storeItem, numOwned == 0) * -1
1207
1208 return string.format("%0d $SLOTS$", slotUsage)
1209end

hourChanged

Description
Definition
hourChanged()
Code
1167function Placeable:hourChanged(hour)
1168 SpecializationUtil.raiseEvent(self, "onHourChanged", hour)
1169end

init

Description
Definition
init()
Code
133function Placeable.init()
134 local schema = Placeable.xmlSchema
135
136 local basePath = "placeable"
137 schema:register(XMLValueType.STRING, basePath .. "#type", "Placeable type", nil, true)
138 schema:register(XMLValueType.STRING, basePath .. ".annotation", "Annotation", nil, false)
139 schema:register(XMLValueType.STRING, basePath .. ".base.filename", "Placeable i3d file", nil, true)
140 schema:register(XMLValueType.BOOL, basePath .. ".base.canBeRenamed", "Placeable can be renamed by player", false)
141 schema:register(XMLValueType.BOOL, basePath .. ".base.boughtWithFarmland", "Placeable is bough with farmland", false)
142 schema:register(XMLValueType.BOOL, basePath .. ".base.buysFarmland", "Placeable buys farmland it is placed on", false)
143 schema:register(XMLValueType.BOOL, basePath .. ".base.canBeDeleted", "Placeable can be deleted by the player, set to false if it should be set farm 0 on sell instead", true)
144 StoreManager.registerStoreDataXMLPaths(schema, basePath)
145 I3DUtil.registerI3dMappingXMLPaths(schema, basePath)
146
147
148 local savegameSchema = Placeable.xmlSchemaSavegame
149 local basePathSavegame = "placeables.placeable(?)"
150 savegameSchema:register(XMLValueType.BOOL, "placeables#loadAnyFarmInSingleplayer", "Load any farm in singleplayer. Causes any placeable with any farmId to be loaded.", false)
151 savegameSchema:register(XMLValueType.INT, "placeables#version", "Version of map placeables file")
152 savegameSchema:register(XMLValueType.STRING, basePathSavegame .. "#name", "Custom name set by player to be used instead of store item name")
153 savegameSchema:register(XMLValueType.STRING, basePathSavegame .. "#mapBoundId", "Map bound identifier (defines that a placeable is placed on a map directly, and with a unique ID)")
154 savegameSchema:register(XMLValueType.VECTOR_TRANS, basePathSavegame .. "#position", "Position")
155 savegameSchema:register(XMLValueType.VECTOR_ROT, basePathSavegame .. "#rotation", "Rotation")
156 savegameSchema:register(XMLValueType.STRING, basePathSavegame .. "#filename", "Path to xml filename")
157 savegameSchema:register(XMLValueType.FLOAT, basePathSavegame .. "#age", "Age of placeable in months.", 0)
158 savegameSchema:register(XMLValueType.FLOAT, basePathSavegame .. "#price", "Price of placeable")
159 savegameSchema:register(XMLValueType.INT, basePathSavegame .. "#farmId", "Owner farmland", 0)
160 savegameSchema:register(XMLValueType.INT, basePathSavegame .. "#id", "Save id")
161 savegameSchema:register(XMLValueType.BOOL, basePathSavegame .. "#defaultFarmProperty", "Is property of default farm. Causes object to be removed on non-starter games.", false)
162 savegameSchema:register(XMLValueType.STRING, basePathSavegame .. "#modName", "Name of mod")
163 savegameSchema:register(XMLValueType.INT, basePathSavegame .. "#sinceVersion", "Version of xml file when this placeable was added. Will cause placeable to appear on older, existing saves")
164
165 for name, spec in pairs(g_placeableSpecializationManager:getSpecializations()) do
166 local classObj = ClassUtil.getClassObject(spec.className)
167 if classObj ~= nil then
168 if rawget(classObj, "registerXMLPaths") then
169 classObj.registerXMLPaths(schema, basePath)
170 end
171
172 if rawget(classObj, "registerSavegameXMLPaths") then
173 classObj.registerSavegameXMLPaths(savegameSchema, basePathSavegame .. "." .. name)
174 end
175 end
176 end
177
178 g_storeManager:addSpecType("placeableSlots", "shopListAttributeIconSlots", nil, Placeable.getSpecValueSlots, "placeable")
179end

initPose

Description
Initialize pose
Definition
initPose(float x, float y, float z, float rx, float ry, float rz, boolean initRandom)
Arguments
floatxx world position
floatyy world position
floatzz world position
floatrxrx world rotation
floatryry world rotation
floatrzrz world rotation
booleaninitRandominitialize random
Code
492function Placeable:initPose()
493 setTranslation(self.rootNode, self.position.x, self.position.y, self.position.z)
494 setRotation(self.rootNode, self.rotation.x, self.rotation.y, self.rotation.z)
495end

isMapBound

Description
Definition
isMapBound()
Code
924function Placeable:isMapBound()
925 return self.mapBoundId ~= nil
926end

load

Description
Definition
load()
Code
226function Placeable:load(placeableData, asyncCallbackFunction, asyncCallbackObject, asyncCallbackArguments)
227 self.asyncData = {}
228 self.asyncData.callback = asyncCallbackFunction
229 self.asyncData.object = asyncCallbackObject
230 self.asyncData.arguments = asyncCallbackArguments
231
232 if asyncCallbackFunction == nil then
233 self:onLoadingError("Missing asyncCallbackFunction. Placeable only supports async loading!")
234 return
235 end
236
237 local modName, baseDirectory = Utils.getModNameAndBaseDirectory(placeableData.filename)
238
239 self:setLoadingStep(Placeable.LOAD_STEP_PRE_LOAD)
240
241 self.configFileName = placeableData.filename
242
243 self.baseDirectory = baseDirectory
244 self.customEnvironment = modName
245 self.typeName = placeableData.typeName
246
247 local typeDef = g_placeableTypeManager:getTypeByName(self.typeName)
248 if typeDef == nil then
249 self:onLoadingError("Unable to find placeable type '%s'", self.typeName)
250 return
251 end
252
253 self.type = typeDef
254 self.specializations = typeDef.specializations
255 self.specializationNames = typeDef.specializationNames
256 self.specializationsByName = typeDef.specializationsByName
257 self.eventListeners = table.copy(typeDef.eventListeners, 2)
258
259 self.xmlFile = XMLFile.load("placeableXml", placeableData.filename, Placeable.xmlSchema)
260 self.savegame = placeableData.savegame
261
262 self.position = {x=placeableData.posX, y=placeableData.posY, z=placeableData.posZ}
263 self.rotation = {x=placeableData.rotX, y=placeableData.rotY, z=placeableData.rotZ}
264
265 if placeableData.ownerFarmId ~= nil then
266 self:setOwnerFarmId(placeableData.ownerFarmId, true)
267 end
268
269 self.storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
270 if self.storeItem ~= nil then
271 self.brand = g_brandManager:getBrandByIndex(self.storeItem.brandIndex)
272
273 if self.price == 0 or self.price == nil then
274 self.price = StoreItemUtil.getDefaultPrice(self.storeItem)
275 end
276 else
277 self:onLoadingError("Missing storeItem for placable '%s'", self.configFileName)
278 return
279 end
280
281 -- pass function pointers from specializations to 'self'
282 for funcName, func in pairs(typeDef.functions) do
283 self[funcName] = func
284 end
285
286 for i=1, #self.specializations do
287 local specEntryName = "spec_" .. self.specializationNames[i]
288 if self[specEntryName] ~= nil then
289 self:onLoadingError("The placeable specialization '%s' could not be added because variable '%s' already exists!", self.specializationNames[i], specEntryName)
290 return
291 end
292
293 local env = setmetatable({}, { __index = self } )
294 self[specEntryName] = env
295 end
296
297 SpecializationUtil.raiseEvent(self, "onPreLoad", self.savegame)
298 if self.loadingState ~= Placeable.LOADING_STATE_OK then
299 self:onLoadingError("Placeable pre-loading failed!")
300 return
301 end
302
303 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "placeable.filename", "placeable.base.filename")
304 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "placeable.dayNightObjects", "Visiblity Condition-Tab in GIANTS Editor / Exporter")
305
306 self.i3dFilename = self.xmlFile:getValue("placeable.base.filename")
307 if self.i3dFilename == nil then
308 self:onLoadingError("Placeable filename missing!")
309 return
310 end
311
312 self.canBeRenamed = self.xmlFile:getValue("placeable.base.canBeRenamed", false)
313 self.boughtWithFarmland = self.xmlFile:getValue("placeable.base.boughtWithFarmland", false)
314 self.buysFarmland = self.xmlFile:getValue("placeable.base.buysFarmland", false)
315 self.canBeDeleted = self.xmlFile:getValue("placeable.base.canBeDeleted", true)
316
317 if self.storeItem.showInStore and not self.canBeDeleted then
318 self:onLoadingError('Store item can be manually placed (showInStore.showInStore) but not deleted by the player (base.canBeDeleted=false)! Only use this option for preplaced placeables')
319 return
320 end
321
322 self:setLoadingStep(Placeable.LOAD_STEP_AWAIT_I3D)
323
324 self.i3dFilename = Utils.getFilename(self.i3dFilename, baseDirectory)
325 self.sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(self.i3dFilename, true, false, self.loadI3dFinished, self, nil)
326end

loadI3dFinished

Description
Definition
loadI3dFinished()
Code
330function Placeable:loadI3dFinished(i3dNode, failedReason, args)
331 self:setLoadingState(Placeable.LOADING_STATE_OK)
332 self:setLoadingStep(Placeable.LOAD_STEP_LOAD)
333
334 self:removeFromPhysics()
335
336 if i3dNode == 0 then
337 self:onLoadingError("Placeable i3d loading failed!!")
338 return
339 end
340
341 self.rootNode = i3dNode
342
343 link(getRootNode(), i3dNode)
344
345 I3DUtil.loadI3DComponents(i3dNode, self.components)
346
347 if #self.components == 0 then
348 self:onLoadingError("Unable to get placeable components")
349 return
350 end
351
352 I3DUtil.loadI3DMapping(self.xmlFile, "placeable", self.components, self.i3dMappings)
353
354 self:initPose()
355
356 SpecializationUtil.raiseEvent(self, "onLoad", self.savegame)
357 if self.loadingState ~= Placeable.LOADING_STATE_OK then
358 self:onLoadingError("Placeable loading failed!")
359 return
360 end
361
362 self:setLoadingStep(Placeable.LOAD_STEP_POST_LOAD)
363
364 SpecializationUtil.raiseEvent(self, "onPostLoad", self.savegame)
365 if self.loadingState ~= Placeable.LOADING_STATE_OK then
366 self:onLoadingError("Placeable post-loading failed!")
367 return
368 end
369
370 self:setVisibility(false)
371
372 if #self.loadingTasks == 0 then
373 self:onFinishedLoading()
374 else
375 self.readyForFinishLoading = true
376 self:setLoadingStep(Placeable.LOAD_STEP_AWAIT_SUB_I3D)
377 end
378end

minuteChanged

Description
Definition
minuteChanged()
Code
1179function Placeable:minuteChanged(minute)
1180 SpecializationUtil.raiseEvent(self, "onMinuteChanged", minute)
1181end

new

Description
Definition
new()
Code
188function Placeable.new(isServer, isClient, customMt)
189 local self = Object.new(isServer, isClient, customMt or Placeable_mt)
190
191 self.finishedLoading = false
192
193 self.rootNode = nil
194 self.i3dMappings = {}
195 self.components = {}
196
197 self.loadingState = Placeable.LOADING_STATE_OK
198 self.loadingStep = Placeable.LOAD_STEP_CREATED
199
200 self.isDeleting = false
201 self.isDeleted = false
202 self.isLoadedFromSavegame = false
203
204 self.loadingTasks = {}
205 self.readyForFinishLoading = false
206
207 self.propertyState = Placeable.PROPERTY_STATE_OWNED
208
209 self.age = 0
210 self.price = 0
211 self.farmlandId = 0
212 self.pickObjects = {}
213
214 self.undoTimer = 0
215
216 -- defines that a placeable is placed on a map directly, and with a unique ID
217 self.mapBoundId = nil
218
219 self.synchronizedConnections = {} -- start update stream if connection to client was synchronized
220
221 return self
222end

onBuy

Description
Definition
onBuy()
Code
875function Placeable:onBuy()
876 SpecializationUtil.raiseEvent(self, "onBuy")
877end

onFarmlandStateChanged

Description
Definition
onFarmlandStateChanged()
Code
948function Placeable:onFarmlandStateChanged(farmlandId, farmId)
949 if self.boughtWithFarmland then
950 if farmlandId == self.farmlandId then
951 self:updateOwnership()
952 end
953 end
954end

onFinishedLoading

Description
Definition
onFinishedLoading()
Code
382function Placeable:onFinishedLoading()
383 self:setVisibility(true)
384
385 if self.isServer and self.savegame ~= nil then
386 self.currentSavegameId = self.savegame.xmlFile:getValue(self.savegame.key .. "#id")
387
388 self.isLoadingFromSavegameXML = true
389 for id, spec in pairs(self.specializations) do
390 local name = self.specializationNames[id]
391
392 if spec.loadFromXMLFile ~= nil then
393 spec.loadFromXMLFile(self, self.savegame.xmlFile, self.savegame.key.."."..name, self.savegame.reset)
394 end
395 end
396 self.isLoadingFromSavegameXML = false
397
398 self.mapBoundId = self.savegame.xmlFile:getValue(self.savegame.key .. "#mapBoundId", self.mapBoundId)
399
400 self.name = self.savegame.xmlFile:getValue(self.savegame.key .. "#name")
401
402 self.age = self.savegame.xmlFile:getValue(self.savegame.key.."#age", 0)
403 self.price = self.savegame.xmlFile:getValue(self.savegame.key.."#price", self.price)
404
405 if not self.savegame.ignoreFarmId then
406 -- Use a call so any sub-objects of the placeable can be updated
407 self:setOwnerFarmId(self.savegame.xmlFile:getValue(self.savegame.key .. "#farmId", AccessHandler.EVERYONE), true)
408 end
409
410 self.isLoadedFromSavegame = true
411 end
412
413 self:setLoadingStep(Placeable.LOAD_STEP_FINISHED)
414 SpecializationUtil.raiseEvent(self, "onLoadFinished", self.savegame)
415
416 if self.isLoadedFromSavegame then
417 self:finalizePlacement()
418 end
419
420 -- if we are the server or in single player we don't need to be synchonized
421 if self.isServer then
422 self:setLoadingStep(Placeable.LOAD_STEP_SYNCHRONIZED)
423 end
424
425 self.finishedLoading = true
426
427 self:raiseLoadingCallback()
428
429 self.savegame = nil
430end

onLoadingError

Description
Definition
onLoadingError()
Code
434function Placeable:onLoadingError(msg, ...)
435 if self.xmlFile ~= nil then
436 Logging.xmlError(self.xmlFile, msg, ...)
437 self.xmlFile:delete()
438 self.xmlFile = nil
439 else
440 Logging.error(msg, ...)
441 end
442
443 self:setLoadingState(Placeable.LOADING_STATE_ERROR)
444 self:raiseLoadingCallback()
445end

onSell

Description
Definition
onSell()
Code
881function Placeable:onSell()
882 g_messageCenter:publish(MessageType.FARM_PROPERTY_CHANGED, self:getOwnerFarmId())
883 SpecializationUtil.raiseEvent(self, "onSell")
884end

performNodeDestruction

Description
Definition
performNodeDestruction()
Code
942function Placeable:performNodeDestruction(node)
943 return false
944end

periodChanged

Description
Definition
periodChanged()
Code
1197function Placeable:periodChanged(period)
1198 self.age = self.age + 1
1199 SpecializationUtil.raiseEvent(self, "onPeriodChanged", period)
1200end

postInit

Description
Definition
postInit()
Code
183function Placeable.postInit()
184end

postReadStream

Description
Called on client side when placeable was fully loaded
Definition
postReadStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
662function Placeable:postReadStream(streamId, connection)
663 self:finalizePlacement()
664
665 if Placeable.DEBUG_NETWORK then
666 print("-------------------------------------------------------------")
667 print(self.configFileName)
668 for _, spec in ipairs(self.eventListeners["onReadStream"]) do
669 local className = ClassUtil.getClassName(spec)
670 local startBits = streamGetReadOffset(streamId)
671 spec["onReadStream"](self, streamId, connection)
672 print(" "..tostring(className).." read " .. streamGetReadOffset(streamId)-startBits .. " bits")
673 end
674 else
675 SpecializationUtil.raiseEvent(self, "onReadStream", streamId, connection)
676 end
677
678 if streamReadBool(streamId) then
679 self:setName(streamReadString(streamId), true)
680 end
681
682 self:setLoadingStep(Placeable.LOAD_STEP_SYNCHRONIZED)
683
684 self:raiseActive()
685end

postWriteStream

Description
Called on server side when placeable was fully loaded on client side
Definition
postWriteStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
691function Placeable:postWriteStream(streamId, connection)
692 if Placeable.DEBUG_NETWORK then
693 print("-------------------------------------------------------------")
694 print(self.configFileName)
695 for _, spec in ipairs(self.eventListeners["onWriteStream"]) do
696 local className = ClassUtil.getClassName(spec)
697 local startBits = streamGetWriteOffset(streamId)
698 spec["onWriteStream"](self, streamId, connection)
699 print(" "..tostring(className).." Wrote " .. streamGetWriteOffset(streamId)-startBits .. " bits")
700 end
701 else
702 SpecializationUtil.raiseEvent(self, "onWriteStream", streamId, connection)
703 end
704
705 if streamWriteBool(streamId, self.name ~= nil) then
706 streamWriteString(streamId, self.name)
707 end
708end

previewNodeDestructionNodes

Description
Definition
previewNodeDestructionNodes()
Code
936function Placeable:previewNodeDestructionNodes(node)
937 return nil
938end

raiseLoadingCallback

Description
Definition
raiseLoadingCallback()
Code
472function Placeable:raiseLoadingCallback()
473 local asyncData = self.asyncData
474 local obj = self
475
476 if asyncData ~= nil and asyncData.callback ~= nil then
477 asyncData.callback(asyncData.object, obj, self.loadingState, asyncData.arguments)
478 end
479
480 self.asyncData = nil
481end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
598function Placeable:readStream(streamId, connection, objectId)
599 Placeable:superClass().readStream(self, streamId, connection, objectId)
600
601 local configFileName = NetworkUtil.convertFromNetworkFilename(streamReadString(streamId))
602 local typeName = streamReadString(streamId)
603
604 if configFileName ~= nil then
605 local data = {}
606 data.filename = configFileName
607 data.typeName = typeName
608 data.posX = streamReadFloat32(streamId)
609 data.posY = streamReadFloat32(streamId)
610 data.posZ = streamReadFloat32(streamId)
611 data.rotX = NetworkUtil.readCompressedAngle(streamId)
612 data.rotY = NetworkUtil.readCompressedAngle(streamId)
613 data.rotZ = NetworkUtil.readCompressedAngle(streamId)
614 data.initRandom = false
615
616 local isNew = self.configFileName == nil
617
618 local placeable = self
619 local asyncCallbackFunction = function(_, p, loadingState, args)
620 if loadingState == Placeable.LOADING_STATE_OK then
621 g_client:onObjectFinishedAsyncLoading(placeable)
622 else
623 Logging.error("Failed to load placeable on client")
624 if p ~= nil then
625 p:delete()
626 end
627 printCallstack()
628 return
629 end
630 end
631
632 if isNew then
633 self:load(data, asyncCallbackFunction)
634 end
635 end
636end

readUpdateStream

Description
Called on client side on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
715function Placeable:readUpdateStream(streamId, timestamp, connection)
716 if Placeable.DEBUG_NETWORK_UPDATE then
717 print("-------------------------------------------------------------")
718 print(self.configFileName)
719 for _, spec in ipairs(self.eventListeners["onReadUpdateStream"]) do
720 local className = ClassUtil.getClassName(spec)
721 local startBits = streamGetReadOffset(streamId)
722 spec["onReadUpdateStream"](self, streamId, timestamp, connection)
723 print(" "..tostring(className).." read " .. streamGetReadOffset(streamId)-startBits .. " bits")
724 end
725 else
726 SpecializationUtil.raiseEvent(self, "onReadUpdateStream", streamId, timestamp, connection)
727 end
728end

registerEvents

Description
Definition
registerEvents()
Code
63function Placeable.registerEvents(placeableType)
64 SpecializationUtil.registerEvent(placeableType, "onPreLoad")
65 SpecializationUtil.registerEvent(placeableType, "onLoad")
66 SpecializationUtil.registerEvent(placeableType, "onPostLoad")
67 SpecializationUtil.registerEvent(placeableType, "onLoadFinished")
68 SpecializationUtil.registerEvent(placeableType, "onPreDelete")
69 SpecializationUtil.registerEvent(placeableType, "onDelete")
70 SpecializationUtil.registerEvent(placeableType, "onSave")
71 SpecializationUtil.registerEvent(placeableType, "onReadStream")
72 SpecializationUtil.registerEvent(placeableType, "onWriteStream")
73 SpecializationUtil.registerEvent(placeableType, "onReadUpdateStream")
74 SpecializationUtil.registerEvent(placeableType, "onWriteUpdateStream")
75 SpecializationUtil.registerEvent(placeableType, "onPreFinalizePlacement")
76 SpecializationUtil.registerEvent(placeableType, "onFinalizePlacement")
77 SpecializationUtil.registerEvent(placeableType, "onPostFinalizePlacement")
78 SpecializationUtil.registerEvent(placeableType, "onUpdate")
79 SpecializationUtil.registerEvent(placeableType, "onUpdateTick")
80 SpecializationUtil.registerEvent(placeableType, "onDraw")
81 SpecializationUtil.registerEvent(placeableType, "onHourChanged")
82 SpecializationUtil.registerEvent(placeableType, "onMinuteChanged")
83 SpecializationUtil.registerEvent(placeableType, "onDayChanged")
84 SpecializationUtil.registerEvent(placeableType, "onPeriodChanged")
85 SpecializationUtil.registerEvent(placeableType, "onWeatherChanged")
86 SpecializationUtil.registerEvent(placeableType, "onFarmlandStateChanged")
87 SpecializationUtil.registerEvent(placeableType, "onBuy")
88 SpecializationUtil.registerEvent(placeableType, "onSell")
89 SpecializationUtil.registerEvent(placeableType, "onOwnerChanged")
90end

registerFunctions

Description
Definition
registerFunctions()
Code
94function Placeable.registerFunctions(placeableType)
95 SpecializationUtil.registerFunction(placeableType, "setOwnerFarmId", Placeable.setOwnerFarmId)
96 SpecializationUtil.registerFunction(placeableType, "setLoadingStep", Placeable.setLoadingStep)
97 SpecializationUtil.registerFunction(placeableType, "setLoadingState", Placeable.setLoadingState)
98 SpecializationUtil.registerFunction(placeableType, "addToPhysics", Placeable.addToPhysics)
99 SpecializationUtil.registerFunction(placeableType, "removeFromPhysics", Placeable.removeFromPhysics)
100 SpecializationUtil.registerFunction(placeableType, "raiseLoadingCallback", Placeable.raiseLoadingCallback)
101 SpecializationUtil.registerFunction(placeableType, "collectPickObjects", Placeable.collectPickObjects)
102 SpecializationUtil.registerFunction(placeableType, "getNeedWeatherChanged", Placeable.getNeedWeatherChanged)
103 SpecializationUtil.registerFunction(placeableType, "getNeedHourChanged", Placeable.getNeedHourChanged)
104 SpecializationUtil.registerFunction(placeableType, "getNeedMinuteChanged", Placeable.getNeedMinuteChanged)
105 SpecializationUtil.registerFunction(placeableType, "getNeedDayChanged", Placeable.getNeedDayChanged)
106 SpecializationUtil.registerFunction(placeableType, "initPose", Placeable.initPose)
107 SpecializationUtil.registerFunction(placeableType, "getName", Placeable.getName)
108 SpecializationUtil.registerFunction(placeableType, "getImageFilename", Placeable.getImageFilename)
109 SpecializationUtil.registerFunction(placeableType, "getCanBeRenamedByFarm", Placeable.getCanBeRenamedByFarm)
110 SpecializationUtil.registerFunction(placeableType, "setName", Placeable.setName)
111 SpecializationUtil.registerFunction(placeableType, "getPrice", Placeable.getPrice)
112 SpecializationUtil.registerFunction(placeableType, "canBuy", Placeable.canBuy)
113 SpecializationUtil.registerFunction(placeableType, "getCanBePlacedAt", Placeable.getCanBePlacedAt)
114 SpecializationUtil.registerFunction(placeableType, "canBeSold", Placeable.canBeSold)
115 SpecializationUtil.registerFunction(placeableType, "isMapBound", Placeable.isMapBound)
116 SpecializationUtil.registerFunction(placeableType, "getDestructionMethod", Placeable.getDestructionMethod)
117 SpecializationUtil.registerFunction(placeableType, "previewNodeDestructionNodes", Placeable.previewNodeDestructionNodes)
118 SpecializationUtil.registerFunction(placeableType, "performNodeDestruction", Placeable.performNodeDestruction)
119 SpecializationUtil.registerFunction(placeableType, "updateOwnership", Placeable.updateOwnership)
120 SpecializationUtil.registerFunction(placeableType, "setOverlayColor", Placeable.setOverlayColor)
121 SpecializationUtil.registerFunction(placeableType, "setOverlayColorNodes", Placeable.setOverlayColorNodes)
122 SpecializationUtil.registerFunction(placeableType, "getDailyUpkeep", Placeable.getDailyUpkeep)
123 SpecializationUtil.registerFunction(placeableType, "getSellPrice", Placeable.getSellPrice)
124 SpecializationUtil.registerFunction(placeableType, "setPreviewPosition", Placeable.setPreviewPosition)
125 SpecializationUtil.registerFunction(placeableType, "setPropertyState", Placeable.setPropertyState)
126 SpecializationUtil.registerFunction(placeableType, "getPropertyState", Placeable.getPropertyState)
127 SpecializationUtil.registerFunction(placeableType, "setVisibility", Placeable.setVisibility)
128 SpecializationUtil.registerFunction(placeableType, "getIsSynchronized", Placeable.getIsSynchronized)
129end

removeFromPhysics

Description
Definition
removeFromPhysics()
Code
1134function Placeable:removeFromPhysics()
1135 if self.rootNode ~= nil then
1136 removeFromPhysics(self.rootNode)
1137 end
1138end

saveToXMLFile

Description
Get save attributes and nodes
Definition
saveToXMLFile(string nodeIdent)
Arguments
stringnodeIdentnode ident
Return Values
stringattributesattributes
stringnodesnodes
Code
755function Placeable:saveToXMLFile(xmlFile, key, usedModNames)
756 local x,y,z = getTranslation(self.rootNode)
757 local xRot,yRot,zRot = getRotation(self.rootNode)
758
759 xmlFile:setValue(key.."#id", self.currentSavegameId)
760 xmlFile:setValue(key.."#filename", HTMLUtil.encodeToHTML(NetworkUtil.convertToNetworkFilename(self.configFileName)))
761 xmlFile:setValue(key.."#position", x, y, z)
762 xmlFile:setValue(key.."#rotation", xRot, yRot, zRot)
763 xmlFile:setValue(key.."#age", self.age)
764 xmlFile:setValue(key.."#price", self.price)
765 xmlFile:setValue(key.."#farmId", self:getOwnerFarmId() or 1)
766
767 -- custom name set by player
768 if self.canBeRenamed and self.name ~= nil and self.name:trim() ~= "" then
769 xmlFile:setValue(key.."#name", self.name)
770 end
771
772 if self.mapBoundId ~= nil then
773 xmlFile:setValue(key.."#mapBoundId", self.mapBoundId)
774 end
775
776 for id, spec in pairs(self.specializations) do
777 local name = self.specializationNames[id]
778
779 if spec.saveToXMLFile ~= nil then
780 spec.saveToXMLFile(self, xmlFile, key.."."..name, usedModNames)
781 end
782 end
783end

setLoadingState

Description
Definition
setLoadingState()
Code
1008function Placeable:setLoadingState(loadingState)
1009 if loadingState == Placeable.LOADING_STATE_OK or loadingState == Placeable.LOADING_STATE_ERROR then
1010 self.loadingState = loadingState
1011 else
1012 printCallstack()
1013 Logging.error("Invalid loading state '%s'!", loadingState)
1014 end
1015end

setLoadingStep

Description
Definition
setLoadingStep()
Code
1033function Placeable:setLoadingStep(loadingStep)
1034 if loadingStep == Placeable.LOAD_STEP_CREATED
1035 or loadingStep == Placeable.LOAD_STEP_PRE_LOAD
1036 or loadingStep == Placeable.LOAD_STEP_AWAIT_I3D
1037 or loadingStep == Placeable.LOAD_STEP_LOAD
1038 or loadingStep == Placeable.LOAD_STEP_POST_LOAD
1039 or loadingStep == Placeable.LOAD_STEP_AWAIT_SUB_I3D
1040 or loadingStep == Placeable.LOAD_STEP_FINISHED
1041 or loadingStep == Placeable.LOAD_STEP_SYNCHRONIZED then
1042 self.loadingStep = loadingStep
1043 else
1044 printCallstack()
1045 Logging.error("Invalid loading step '%s'!", loadingStep)
1046 end
1047end

setName

Description
Sets a (persistant) custom name for the placeable if allowed
Definition
setName(name name)
Arguments
namenameto be used, use nil to reset to default name (store item name)
Return Values
boolsuccess
Code
857function Placeable:setName(name, noEventSend)
858 if self.canBeRenamed then
859 if name and name:trim() == "" then
860 return false
861 end
862
863 PlaceableNameEvent.sendEvent(self, name, noEventSend)
864
865 self.name = name
866 g_messageCenter:publish(MessageType.UNLOADING_STATIONS_CHANGED) -- TODO: move to a less general placeable speci?
867 g_messageCenter:publish(MessageType.LOADING_STATIONS_CHANGED) -- TODO: move to a less general placeable speci?
868 return true
869 end
870 return false
871end

setOverlayColor

Description
Set the overlay color and its alpha
Definition
setOverlayColor()
Code
1051function Placeable:setOverlayColor(r, g, b, alpha)
1052 if self.overlayColorNodes == nil then
1053 self.overlayColorNodes = {}
1054 self:setOverlayColorNodes(self.rootNode, self.overlayColorNodes)
1055 end
1056
1057 for i = 1, #self.overlayColorNodes do
1058 setShaderParameter(self.overlayColorNodes[i], "placeableColorScale", r, g, b, alpha, false)
1059 end
1060end

setOverlayColorNodes

Description
Finds all shape nodes that support color overlay
Definition
setOverlayColorNodes(integer node, table nodeTable)
Arguments
integernodeid of node
tablenodeTabletable to save the nodes
Code
1066function Placeable:setOverlayColorNodes(node, nodeTable)
1067 if getHasClassId(node, ClassIds.SHAPE) and getHasShaderParameter(node, "placeableColorScale") then
1068 nodeTable[#nodeTable + 1] = node
1069 end
1070
1071 local numChildren = getNumOfChildren(node)
1072 for i=0, numChildren-1 do
1073 self:setOverlayColorNodes(getChildAt(node, i), nodeTable)
1074 end
1075end

setOwnerFarmId

Description
Definition
setOwnerFarmId()
Code
961function Placeable:setOwnerFarmId(farmId, noEventSend)
962 if self.buysFarmland then
963 g_farmlandManager:setLandOwnership(self.farmlandId, farmId)
964 end
965
966 Placeable:superClass().setOwnerFarmId(self, farmId, noEventSend)
967
968 -- only raise event if placeable LOAD-step passed as functions in specializations registered there
969 if self.loadingStep > Placeable.LOAD_STEP_LOAD then
970 SpecializationUtil.raiseEvent(self, "onOwnerChanged")
971 end
972
973 if self.propertyState ~= Placeable.PROPERTY_STATE_CONSTRUCTION_PREVIEW then
974 -- re-add the item, so the shop controller is updated correctly
975 g_currentMission:removeOwnedItem(self)
976 g_currentMission:addOwnedItem(self)
977 end
978end

setPreviewPosition

Description
Definition
setPreviewPosition()
Code
1142function Placeable:setPreviewPosition(x, y, z, rotX, rotY, rotZ)
1143 setWorldTranslation(self.rootNode, x, y, z)
1144 setRotation(self.rootNode, 0, rotY, 0)
1145end

setPropertyState

Description
Definition
setPropertyState()
Code
787function Placeable:setPropertyState(state)
788 self.propertyState = state
789end

setVisibility

Description
Definition
setVisibility()
Code
799function Placeable:setVisibility(state)
800 for _, component in pairs(self.components) do
801 setVisibility(component.node, state)
802 end
803end

update

Description
Definition
update()
Code
819function Placeable:update(dt)
820 SpecializationUtil.raiseEvent(self, "onUpdate", dt)
821end

updateTick

Description
Definition
updateTick()
Code
825function Placeable:updateTick(dt)
826 SpecializationUtil.raiseEvent(self, "onUpdateTick", dt)
827end

weatherChanged

Description
Definition
weatherChanged()
Code
1155function Placeable:weatherChanged()
1156 SpecializationUtil.raiseEvent(self, "onWeatherChanged")
1157end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
642function Placeable:writeStream(streamId, connection)
643 Placeable:superClass().writeStream(self, streamId, connection)
644
645 streamWriteString(streamId, NetworkUtil.convertToNetworkFilename(self.configFileName))
646 streamWriteString(streamId, self.typeName)
647
648 local x,y,z = getTranslation(self.rootNode)
649 local x_rot,y_rot,z_rot = getRotation(self.rootNode)
650 streamWriteFloat32(streamId, x)
651 streamWriteFloat32(streamId, y)
652 streamWriteFloat32(streamId, z)
653 NetworkUtil.writeCompressedAngle(streamId, x_rot)
654 NetworkUtil.writeCompressedAngle(streamId, y_rot)
655 NetworkUtil.writeCompressedAngle(streamId, z_rot)
656end

writeUpdateStream

Description
Called on server side on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
735function Placeable:writeUpdateStream(streamId, connection, dirtyMask)
736 if Placeable.DEBUG_NETWORK_UPDATE then
737 print("-------------------------------------------------------------")
738 print(self.configFileName)
739 for _, spec in ipairs(self.eventListeners["onWriteUpdateStream"]) do
740 local className = ClassUtil.getClassName(spec)
741 local startBits = streamGetWriteOffset(streamId)
742 spec["onWriteUpdateStream"](self, streamId, connection, dirtyMask)
743 print(" "..tostring(className).." Wrote " .. streamGetWriteOffset(streamId)-startBits .. " bits")
744 end
745 else
746 SpecializationUtil.raiseEvent(self, "onWriteUpdateStream", streamId, connection, dirtyMask)
747 end
748end