Skip to main content
Skip to main content

PlaceableConstructible

PlaceableConstructible

Description

Specialization for placeables

Functions

collectPickObjects

Description

Definition

collectPickObjects()

Arguments

anysuperFunc
anynode

Code

function PlaceableConstructible:collectPickObjects(superFunc, node)
local spec = self.spec_constructible

for i = 1 , #spec.unloadingStation.unloadTriggers do
local unloadTrigger = spec.unloadingStation.unloadTriggers[i]
if node = = unloadTrigger.exactFillRootNode then
return
end
end

superFunc( self , node)
end

loadFromXMLFile

Description

Definition

loadFromXMLFile()

Arguments

anyxmlFile
anykey

Code

function PlaceableConstructible:loadFromXMLFile(xmlFile, key)
local spec = self.spec_constructible

local stateName = xmlFile:getValue(key .. ".state#name" )
spec.stateIndexPending = spec.stateNameToIndex[stateName] or 1

-- this needs to be delayed to avoid Placeable:finalize overwriting already disabled physics on nodes
spec.postFinalize = function ()
local state = spec.stateMachine[spec.stateIndexPending]
state:loadFromXMLFile(xmlFile, key)
end

spec.storage:loadFromXMLFile(xmlFile, key .. ".storage" )
end

loadSpecValueFillTypes

Description

Definition

loadSpecValueFillTypes(XMLFile xmlFile, string? customEnvironment, string? baseDir, table? resultTable)

Arguments

XMLFilexmlFile
string?customEnvironment
string?baseDir
table?resultTable

Return Values

table?fillTypeNames

Code

function PlaceableConstructible.loadSpecValueFillTypes(xmlFile, customEnvironment, baseDir, resultTable)
if not xmlFile:hasProperty( "placeable.constructible" ) then
return resultTable
end

local fillTypeNames = resultTable or { }

for _, stateKey in xmlFile:iterator( "placeable.constructible.stateMachine.states.state" ) do
for _, inputKey in xmlFile:iterator(stateKey .. ".input" ) do
local fillTypeName = xmlFile:getString(inputKey .. "#fillType" )
fillTypeNames[fillTypeName] = true
end
end

return fillTypeNames
end

onDelete

Description

Definition

onDelete()

Code

function PlaceableConstructible:onDelete()
local spec = self.spec_constructible

removeConsoleCommand( "gsConstructibleFinishState" )

g_messageCenter:unsubscribeAll( self )

if spec.unloadingStation ~ = nil then
g_currentMission.storageSystem:removeUnloadingStation(spec.unloadingStation, self )
g_currentMission.economyManager:removeSellingStation(spec.unloadingStation)
spec.unloadingStation:delete()
spec.unloadingStation = nil
end

if spec.storage ~ = nil then
spec.storage:delete()
spec.storage = nil
end

if spec.stateMachine ~ = nil then
for _, state in ipairs(spec.stateMachine) do
state:delete()
end
spec.stateMachine = nil
end
end

onFinalizePlacement

Description

Definition

onFinalizePlacement()

Arguments

anysavegame

Code

function PlaceableConstructible:onFinalizePlacement(savegame)
local spec = self.spec_constructible

local farmId = self:getOwnerFarmId()
if spec.unloadingStation ~ = nil then
spec.unloadingStation:setOwnerFarmId(farmId, true )
end
if spec.storage ~ = nil then
spec.storage:setOwnerFarmId(farmId, true )
end

if self.isServer then
-- do this after finalize placement as addToPhysics for whole placeable is called there
if spec.stateIndexPending ~ = nil then
for i = 1 , spec.stateIndexPending do
self:setConstructibleState(i)
end

if spec.postFinalize ~ = nil then
spec.postFinalize()
end

spec.stateIndexPending = nil
spec.postFinalize = nil
else
self:setConstructibleState(spec.startStateIndex)
end

self:raiseActive()
end
end

onLoad

Description

Called on loading

Definition

onLoad(table savegame)

Arguments

tablesavegamesavegame

Code

function PlaceableConstructible:onLoad(savegame)
local spec = self.spec_constructible

spec.unloadingStation = SellingStation.new( self.isServer, self.isClient)
spec.unloadingStation:load( self.components, self.xmlFile, "placeable.constructible.sellingStation" , self.customEnvironment, self.i3dMappings, self.components[ 1 ].node)
spec.unloadingStation.owningPlaceable = self
spec.unloadingStation.getStoreGoods = function (_, farmId, fillTypeIndex)
return true
end
spec.unloadingStation.getSkipSell = function (_, farmId, fillTypeIndex)
-- owned by a farm
local ownerFarmId = self:getOwnerFarmId()
if ownerFarmId ~ = AccessHandler.EVERYONE then
return true
end

return false
end
spec.unloadingStation:register( true )

spec.storage = Storage.new( self.isServer, self.isClient)
spec.storage:load( self.components, self.xmlFile, "placeable.constructible.storage" , self.i3dMappings, self.baseDirectory)
spec.storage:register( true )
spec.storage:addFillLevelChangedListeners( function () self:raiseActive() end ) -- trigger update loop after storage was changed
spec.fillTypesAndLevelsAuxiliary = { }
spec.fillTypeToFillTypeStorageTable = { }
spec.infoTriggerFillTypesAndLevels = { }

spec.infoTableEntryStorage = {
title = g_i18n:getText( "statistic_storage" ),
accentuate = true
}

spec.unloadingStation:addTargetStorage(spec.storage)

g_currentMission.storageSystem:addUnloadingStation(spec.unloadingStation, self )
g_currentMission.economyManager:addSellingStation(spec.unloadingStation)

-- load statemachine after animation so it can be passed for initialization
spec.stateMachine = { }
spec.stateNameToIndex = { }
spec.stateTransitions = { }
spec.stateIndex = - 1
spec.startStateIndex = 1
spec.previewStateIndex = 1

spec.statesDirtyMask = 0 -- dirty mask for all state dirty flags to easily check if a state needs updating
local maxNumStates = ( 2 ^ 8 ) - 1
local dirtyFlags = { }
local maxNumDirtyFlags = 10
local stateMachineNextIndex = 1
for _, stateKey in self.xmlFile:iterator( "placeable.constructible.stateMachine.states.state" ) do
if stateMachineNextIndex > maxNumStates then
Logging.xmlWarning( self.xmlFile, "Maximum number of states reached(%d)" , maxNumStates)
break
end

local stateName = string.upper( self.xmlFile:getValue(stateKey .. "#name" , "" ))
if spec.stateNameToIndex[stateName] ~ = nil then
Logging.xmlError( self.xmlFile, "State '%s' already defined" , stateName, stateKey)
break
end

local stateClassName = self.xmlFile:getValue(stateKey .. "#class" , "" )
local class = ClassUtil.getClassObject(stateClassName)
if class = = nil then
Logging.xmlError( self.xmlFile, "State class '%s' at '%s' not defined" , stateClassName, stateKey)
break
end

if not class:isa(ConstructibleState) then
Logging.xmlError( self.xmlFile, "State class '%s' is not a ConstructibleState at '%s'" , stateClassName, stateKey)
break
end

if #dirtyFlags < maxNumDirtyFlags then
table.insert(dirtyFlags, self:getNextDirtyFlag())
end

local stateIndex = stateMachineNextIndex
spec.stateNameToIndex[stateName] = stateIndex

-- wrap around dirty flags to avoid using too many flags
local dirtyFlagIndex = ((stateMachineNextIndex - 1 ) % maxNumDirtyFlags) + 1
local dirtyFlag = dirtyFlags[dirtyFlagIndex]

local state = class.new( self , dirtyFlag)
state:load( self.xmlFile, stateKey)
spec.stateMachine[stateIndex] = state
spec.statesDirtyMask = bit32.bor(spec.statesDirtyMask, dirtyFlag) -- accumulate all flags from states to one mask

if self.xmlFile:getValue(stateKey .. "#isStartState" ) then
spec.startStateIndex = stateIndex
end

if self.xmlFile:getValue(stateKey .. "#isPreviewState" ) then
spec.previewStateIndex = stateIndex
end

stateMachineNextIndex = stateMachineNextIndex + 1
end

for _, transitionKey in self.xmlFile:iterator( "placeable.constructible.stateMachine.transitions.transition" ) do
local stateFromName = string.upper( self.xmlFile:getValue(transitionKey .. "#from" , "" ))
local stateFromIndex = spec.stateNameToIndex[stateFromName]
if stateFromIndex = = nil then
Logging.xmlError( self.xmlFile, "Invalid state.Transition from name '%s' not defined for '%s'" , stateFromName, transitionKey)
break
end

local stateToName = string.upper( self.xmlFile:getValue(transitionKey .. "#to" , "" ))
local stateToIndex = spec.stateNameToIndex[stateToName]
if stateToIndex = = nil then
Logging.xmlError( self.xmlFile, "Invalid state.Transition to name '%s' not defined for '%s'" , stateToName, transitionKey)
break
end

spec.stateTransitions[stateFromIndex] = stateToIndex
end

-- ensure setup state is applied in preview, e.g.that things are hidden
if self.propertyState = = PlaceablePropertyState.CONSTRUCTION_PREVIEW then
self:setConstructiblePreviewState()
end
end

onReadStream

Description

Definition

onReadStream()

Arguments

anystreamId
anyconnection

Code

function PlaceableConstructible:onReadStream(streamId, connection)
local spec = self.spec_constructible

-- unloading station
local unloadingStationId = NetworkUtil.readNodeObjectId(streamId)
spec.unloadingStation:readStream(streamId, connection)
g_client:finishRegisterObject(spec.unloadingStation, unloadingStationId)

-- storage
local storageId = NetworkUtil.readNodeObjectId(streamId)
spec.storage:readStream(streamId, connection)
g_client:finishRegisterObject(spec.storage, storageId)

-- state
local stateIndex = streamReadUInt8(streamId)
for i = 1 , stateIndex do
self:setConstructibleState(i)
end

local state = spec.stateMachine[stateIndex]
state:onReadStream(streamId, connection)
end

onWriteStream

Description

Definition

onWriteStream()

Arguments

anystreamId
anyconnection

Code

function PlaceableConstructible:onWriteStream(streamId, connection)
local spec = self.spec_constructible

-- unloading station
NetworkUtil.writeNodeObjectId(streamId, NetworkUtil.getObjectId(spec.unloadingStation))
spec.unloadingStation:writeStream(streamId, connection)
g_server:registerObjectInStream(connection, spec.unloadingStation)

-- storage
NetworkUtil.writeNodeObjectId(streamId, NetworkUtil.getObjectId(spec.storage))
spec.storage:writeStream(streamId, connection)
g_server:registerObjectInStream(connection, spec.storage)

-- state
streamWriteUInt8(streamId, spec.stateIndex)
local state = spec.stateMachine[spec.stateIndex]
state:onWriteStream(streamId, connection)
end

prerequisitesPresent

Description

Checks if all prerequisite specializations are loaded

Definition

prerequisitesPresent(table specializations)

Arguments

tablespecializationsspecializations

Return Values

tablehasPrerequisitetrue if all prerequisite specializations are loaded

Code

function PlaceableConstructible.prerequisitesPresent(specializations)
return true
end

registerEventListeners

Description

Definition

registerEventListeners()

Arguments

anyplaceableType

Code

function PlaceableConstructible.registerEventListeners(placeableType)
SpecializationUtil.registerEventListener(placeableType, "onLoad" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onFinalizePlacement" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onDelete" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onUpdate" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onReadStream" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onWriteStream" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onReadUpdateStream" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onWriteUpdateStream" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onInfoTriggerEnter" , PlaceableConstructible )
SpecializationUtil.registerEventListener(placeableType, "onInfoTriggerLeave" , PlaceableConstructible )
end

registerFunctions

Description

Definition

registerFunctions()

Arguments

anyplaceableType

Code

function PlaceableConstructible.registerFunctions(placeableType)
SpecializationUtil.registerFunction(placeableType, "setConstructibleState" , PlaceableConstructible.setConstructibleState)
SpecializationUtil.registerFunction(placeableType, "finalizeConstruction" , PlaceableConstructible.finalizeConstruction)
SpecializationUtil.registerFunction(placeableType, "getConstructibleFillLevel" , PlaceableConstructible.getConstructibleFillLevel)
SpecializationUtil.registerFunction(placeableType, "getConstructibleSupportsFillType" , PlaceableConstructible.getConstructibleSupportsFillType)
SpecializationUtil.registerFunction(placeableType, "removeConstructibleFillLevel" , PlaceableConstructible.removeConstructibleFillLevel)
SpecializationUtil.registerFunction(placeableType, "getConstructibleStateIndexByName" , PlaceableConstructible.getConstructibleStateIndexByName)
SpecializationUtil.registerFunction(placeableType, "setConstructiblePreviewState" , PlaceableConstructible.setConstructiblePreviewState)
SpecializationUtil.registerFunction(placeableType, "getConstructibleStateIndex" , PlaceableConstructible.getConstructibleStateIndex)
SpecializationUtil.registerFunction(placeableType, "resetConstructibleToState" , PlaceableConstructible.resetConstructibleToState)
SpecializationUtil.registerFunction(placeableType, "consoleCommandFinishConstructionState" , PlaceableConstructible.consoleCommandFinishConstructionState)
SpecializationUtil.registerFunction(placeableType, "getNumFinishedConstructibleStates" , PlaceableConstructible.getNumFinishedConstructibleStates)
end

registerOverwrittenFunctions

Description

Definition

registerOverwrittenFunctions()

Arguments

anyplaceableType

Code

function PlaceableConstructible.registerOverwrittenFunctions(placeableType)
SpecializationUtil.registerOverwrittenFunction(placeableType, "collectPickObjects" , PlaceableConstructible.collectPickObjects)
SpecializationUtil.registerOverwrittenFunction(placeableType, "updateInfo" , PlaceableConstructible.updateInfo)
SpecializationUtil.registerOverwrittenFunction(placeableType, "setOwnerFarmId" , PlaceableConstructible.setOwnerFarmId)
end

registerSavegameXMLPaths

Description

Definition

registerSavegameXMLPaths()

Arguments

anyschema
anybasePath

Code

function PlaceableConstructible.registerSavegameXMLPaths(schema, basePath)
schema:register(XMLValueType.INT, basePath .. ".state#index" , "" )
schema:register(XMLValueType.STRING, basePath .. ".state#name" , "" )
ConstructibleStateBuilding.registerSavegameXMLPaths(schema, basePath)
Storage.registerSavegameXMLPaths(schema, basePath .. ".storage" )
end

registerXMLPaths

Description

Definition

registerXMLPaths()

Arguments

anyschema
anybasePath

Code

function PlaceableConstructible.registerXMLPaths(schema, basePath)
schema:setXMLSpecializationType( "Constructible" )

schema:register(XMLValueType.STRING, basePath .. ".constructible.stateMachine.states.state(?)#name" , "State name" )
schema:register(XMLValueType.STRING, basePath .. ".constructible.stateMachine.states.state(?)#class" , "State class" )
schema:register(XMLValueType.BOOL, basePath .. ".constructible.stateMachine.states.state(?)#isStartState" , "Marks a state as starting state" )
schema:register(XMLValueType.BOOL, basePath .. ".constructible.stateMachine.states.state(?)#isPreviewState" , "State is shown while placing the placeable or used in the icon generator" )
ConstructibleState.registerXMLPaths(schema, basePath .. ".constructible.stateMachine.states.state(?)" )
ConstructibleStateBuilding.registerXMLPaths(schema, basePath .. ".constructible.stateMachine.states.state(?)" )
ConstructibleStateFinalize.registerXMLPaths(schema, basePath .. ".constructible.stateMachine.states.state(?)" )

schema:register(XMLValueType.STRING, basePath .. ".constructible.stateMachine.transitions.transition(?)#from" , "State name from" )
schema:register(XMLValueType.STRING, basePath .. ".constructible.stateMachine.transitions.transition(?)#to" , "State name to" )

SellingStation.registerXMLPaths(schema, basePath .. ".constructible.sellingStation" )
Storage.registerXMLPaths(schema, basePath .. ".constructible.storage" )

schema:setXMLSpecializationType()
end

saveToXMLFile

Description

Definition

saveToXMLFile()

Arguments

anyxmlFile
anykey
anyusedModNames

Code

function PlaceableConstructible:saveToXMLFile(xmlFile, key, usedModNames)
local spec = self.spec_constructible

if spec.stateIndex ~ = nil and spec.stateIndex > 0 then
local state = spec.stateMachine[spec.stateIndex]
xmlFile:setValue(key .. ".state#name" , state.name)

state:saveToXMLFile(xmlFile, key, usedModNames)
end

spec.storage:saveToXMLFile(xmlFile, key .. ".storage" )
end