LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

Vehicle

Description
This class handles all basic functionality of a vehicle - loading of i3d - syncing of components - handling of specializations
Parent
Object
Functions

actionEventToggleSelection

Description
Definition
actionEventToggleSelection()
Code
3984function Vehicle.actionEventToggleSelection(self, actionName, inputValue, callbackState, isAnalog)
3985 local currentSelection = self.currentSelection
3986 local currentObject = currentSelection.object
3987 local currentObjectIndex = currentSelection.index
3988 local currentSubObjectIndex = currentSelection.subIndex
3989
3990 local numSubSelections = 0
3991 if currentObject ~= nil then
3992 numSubSelections = #currentObject.subSelections
3993 end
3994
3995 local newSelectedSubObjectIndex = currentSubObjectIndex + 1
3996 local newSelectedObjectIndex = currentObjectIndex
3997 local newSelectedObject = currentObject
3998
3999 if newSelectedSubObjectIndex > numSubSelections then
4000 newSelectedSubObjectIndex = 1
4001 newSelectedObjectIndex = currentObjectIndex + 1
4002
4003 if newSelectedObjectIndex > #self.selectableObjects then
4004 newSelectedObjectIndex = 1
4005 end
4006 newSelectedObject = self.selectableObjects[newSelectedObjectIndex]
4007 end
4008
4009 if currentObject ~= newSelectedObject or currentObjectIndex ~= newSelectedObjectIndex or currentSubObjectIndex ~= newSelectedSubObjectIndex then
4010 -- event
4011 self:setSelectedObject(newSelectedObject, newSelectedSubObjectIndex)
4012 end
4013end

actionEventToggleSelectionReverse

Description
Definition
actionEventToggleSelectionReverse()
Code
4017function Vehicle.actionEventToggleSelectionReverse(self, actionName, inputValue, callbackState, isAnalog)
4018 local currentSelection = self.currentSelection
4019 local currentObject = currentSelection.object
4020 local currentObjectIndex = currentSelection.index
4021 local currentSubObjectIndex = currentSelection.subIndex
4022
4023 local newSelectedSubObjectIndex = currentSubObjectIndex - 1
4024 local newSelectedObjectIndex = currentObjectIndex
4025 local newSelectedObject = currentObject
4026
4027 if newSelectedSubObjectIndex < 1 then
4028 newSelectedSubObjectIndex = 1
4029 newSelectedObjectIndex = currentObjectIndex - 1
4030
4031 if newSelectedObjectIndex < 1 then
4032 newSelectedObjectIndex = #self.selectableObjects
4033 end
4034
4035 newSelectedObject = self.selectableObjects[newSelectedObjectIndex]
4036 if newSelectedObject ~= nil then
4037 newSelectedSubObjectIndex = #newSelectedObject.subSelections
4038 end
4039 end
4040
4041 if currentObject ~= newSelectedObject or currentObjectIndex ~= newSelectedObjectIndex or currentSubObjectIndex ~= newSelectedSubObjectIndex then
4042 -- event
4043 self:setSelectedObject(newSelectedObject, newSelectedSubObjectIndex)
4044 end
4045end

activate

Description
Called on activate
Definition
activate()
Code
3092function Vehicle:activate()
3093 SpecializationUtil.raiseEvent(self, "onActivate")
3094end

addChildVehicles

Description
Definition
addChildVehicles()
Code
2766function Vehicle:addChildVehicles(vehicles)
2767 table.insert(vehicles, self)
2768end

addNodeObjectMapping

Description
Add component nodes to list
Definition
addNodeObjectMapping(table list)
Arguments
tablelistlist
Code
2074function Vehicle:addNodeObjectMapping(list)
2075 for _,v in pairs(self.components) do
2076 list[v.node] = self
2077 end
2078end

addSubselection

Description
Definition
addSubselection()
Code
2723function Vehicle:addSubselection(subSelection)
2724 table.insert(self.selectionObject.subSelections, subSelection)
2725 return #self.selectionObject.subSelections
2726end

addToPhysics

Description
Add vehicle to physics
Definition
addToPhysics()
Return Values
booleansuccesssuccess
Code
2094function Vehicle:addToPhysics()
2095
2096 if not self.isAddedToPhysics then
2097 local lastMotorizedNode = nil
2098 for _, component in pairs(self.components) do
2099 addToPhysics(component.node)
2100 if component.motorized then
2101 if lastMotorizedNode ~= nil then
2102 if self.isServer then
2103 addVehicleLink(lastMotorizedNode, component.node)
2104 end
2105 end
2106 lastMotorizedNode = component.node
2107 end
2108 end
2109
2110 self.isAddedToPhysics = true
2111
2112 if self.isServer then
2113 for _, jointDesc in pairs(self.componentJoints) do
2114 self:createComponentJoint(self.components[jointDesc.componentIndices[1]], self.components[jointDesc.componentIndices[2]], jointDesc)
2115 end
2116
2117 -- if rootnode is sleeping all other components are sleeping as well
2118 addWakeUpReport(self.rootNode, "onVehicleWakeUpCallback", self)
2119 end
2120
2121 for _, collisionPair in pairs(self.collisionPairs) do
2122 setPairCollision(collisionPair.component1.node, collisionPair.component2.node, collisionPair.enabled)
2123 end
2124
2125 self:setMassDirty()
2126 end
2127
2128 return true
2129end

addVehicleToAIImplementList

Description
Definition
addVehicleToAIImplementList()
Code
3633function Vehicle:addVehicleToAIImplementList(list)
3634end

calculateDailyUpkeep

Description
Definition
calculateDailyUpkeep()
Code
3755function Vehicle.calculateDailyUpkeep(storeItem, age, operatingTime, configurations)
3756 local multiplier = 1
3757 if storeItem.lifetime ~= nil and storeItem.lifetime ~= 0 then
3758 local ageMultiplier = 0.3 * math.min(age / storeItem.lifetime, 1)
3759 operatingTime = operatingTime / (1000*60*60)
3760 local operatingTimeMultiplier = 0.7 * math.min(operatingTime / (storeItem.lifetime*EconomyManager.LIFETIME_OPERATINGTIME_RATIO), 1)
3761 multiplier = 1 + EconomyManager.MAX_DAILYUPKEEP_MULTIPLIER * (ageMultiplier+operatingTimeMultiplier)
3762 end
3763
3764 return StoreItemUtil.getDailyUpkeep(storeItem, configurations) * multiplier
3765end

calculateSellPrice

Description
Calculate price of vehicle given a bunch of parameters
Definition
calculateSellPrice()
Code
2285function Vehicle.calculateSellPrice(storeItem, age, operatingTime, price, repairPrice, repaintPrice)
2286 local operatingTimeHours = operatingTime / (60 * 60 * 1000)
2287 local maxVehicleAge = storeItem.lifetime
2288 local ageInYears = age / Environment.PERIODS_IN_YEAR
2289
2290 StoreItemUtil.loadSpecsFromXML(storeItem)
2291
2292 -- Motorized vehicles depreciate differently
2293 local motorizedFactor = 1.0
2294 if storeItem.specs.power == nil then
2295 motorizedFactor = 1.3
2296 end
2297
2298 local operatingTimeFactor = 1 - operatingTimeHours ^ motorizedFactor / maxVehicleAge
2299 local ageFactor = math.min(-0.1 * math.log(ageInYears) + 0.75, 0.8)
2300
2301 return math.max(price * operatingTimeFactor * ageFactor - repairPrice - repaintPrice, price * 0.03)
2302end

createComponentJoint

Description
Create component joint between two components
Definition
createComponentJoint(table component1, table component2, table jointDesc)
Arguments
tablecomponent1component 1
tablecomponent2component 2
tablejointDescjoint desc
Return Values
booleansuccesssuccess
Code
3433function Vehicle:createComponentJoint(component1, component2, jointDesc)
3434 if component1 == nil or component2 == nil or jointDesc == nil then
3435 Logging.xmlWarning(self.xmlFile, "Could not create component joint. No component1, component2 or jointDesc given!")
3436 return false
3437 end
3438
3439 local constr = JointConstructor.new()
3440 constr:setActors(component1.node, component2.node)
3441
3442 local localPoses1 = jointDesc.jointLocalPoses[1]
3443 local localPoses2 = jointDesc.jointLocalPoses[2]
3444 constr:setJointLocalPositions(localPoses1.trans[1], localPoses1.trans[2], localPoses1.trans[3], localPoses2.trans[1], localPoses2.trans[2], localPoses2.trans[3])
3445 constr:setJointLocalRotations(localPoses1.rot[1], localPoses1.rot[2], localPoses1.rot[3], localPoses2.rot[1], localPoses2.rot[2], localPoses2.rot[3])
3446 --constr:setJointTransforms(jointDesc.jointNode, jointDesc.jointNodeActor1)
3447
3448 constr:setRotationLimitSpring(jointDesc.rotLimitSpring[1], jointDesc.rotLimitDamping[1], jointDesc.rotLimitSpring[2], jointDesc.rotLimitDamping[2], jointDesc.rotLimitSpring[3], jointDesc.rotLimitDamping[3])
3449 constr:setTranslationLimitSpring(jointDesc.transLimitSpring[1], jointDesc.transLimitDamping[1], jointDesc.transLimitSpring[2], jointDesc.transLimitDamping[2], jointDesc.transLimitSpring[3], jointDesc.transLimitDamping[3])
3450 constr:setZRotationXOffset(jointDesc.zRotationXOffset)
3451 for i=1, 3 do
3452 if jointDesc.rotLimit[i] >= jointDesc.rotMinLimit[i] then
3453 constr:setRotationLimit(i-1, jointDesc.rotMinLimit[i], jointDesc.rotLimit[i])
3454 end
3455
3456 if jointDesc.transLimit[i] >= jointDesc.transMinLimit[i] then
3457 constr:setTranslationLimit(i-1, true, jointDesc.transMinLimit[i], jointDesc.transLimit[i])
3458 else
3459 constr:setTranslationLimit(i-1, false, 0, 0)
3460 end
3461 end
3462
3463 constr:setRotationLimitForceLimit(jointDesc.rotLimitForceLimit[1], jointDesc.rotLimitForceLimit[2], jointDesc.rotLimitForceLimit[3])
3464 constr:setTranslationLimitForceLimit(jointDesc.transLimitForceLimit[1], jointDesc.transLimitForceLimit[2], jointDesc.transLimitForceLimit[3])
3465
3466 if jointDesc.isBreakable then
3467 constr:setBreakable(jointDesc.breakForce, jointDesc.breakTorque)
3468 end
3469 constr:setEnableCollision(jointDesc.enableCollision)
3470
3471 for i=1,3 do
3472 if jointDesc.maxRotDriveForce[i] > 0.0001 and (jointDesc.rotDriveVelocity[i] ~= nil or jointDesc.rotDriveRotation[i] ~= nil) then
3473 local pos = Utils.getNoNil(jointDesc.rotDriveRotation[i], 0)
3474 local vel = Utils.getNoNil(jointDesc.rotDriveVelocity[i], 0)
3475 constr:setAngularDrive(i-1, jointDesc.rotDriveRotation[i] ~= nil, jointDesc.rotDriveVelocity[i] ~= nil, jointDesc.rotDriveSpring[i], jointDesc.rotDriveDamping[i], jointDesc.maxRotDriveForce[i], pos, vel)
3476 end
3477 if jointDesc.maxTransDriveForce[i] > 0.0001 and (jointDesc.transDriveVelocity[i] ~= nil or jointDesc.transDrivePosition[i] ~= nil) then
3478 local pos = Utils.getNoNil(jointDesc.transDrivePosition[i], 0)
3479 local vel = Utils.getNoNil(jointDesc.transDriveVelocity[i], 0)
3480 constr:setLinearDrive(i-1, jointDesc.transDrivePosition[i] ~= nil, jointDesc.transDriveVelocity[i] ~= nil, jointDesc.transDriveSpring[i], jointDesc.transDriveDamping[i], jointDesc.maxTransDriveForce[i], pos, vel)
3481 end
3482 end
3483
3484 jointDesc.jointIndex = constr:finalize()
3485
3486 return true
3487end

createMapHotspot

Description
Definition
createMapHotspot()
Code
3901function Vehicle:createMapHotspot()
3902 local mapHotspot = VehicleHotspot.new()
3903 mapHotspot:setVehicle(self)
3904 mapHotspot:setVehicleType(self.mapHotspotType)
3905 mapHotspot:setHasRotation(self.mapHotspotHasDirection)
3906 mapHotspot:setOwnerFarmId(self:getOwnerFarmId())
3907 self.mapHotspot = mapHotspot
3908
3909 g_currentMission:addMapHotspot(mapHotspot)
3910end

dayChanged

Description
Definition
dayChanged()
Code
3565function Vehicle:dayChanged()
3566end

deactivate

Description
Called on deactivate
Definition
deactivate()
Code
3098function Vehicle:deactivate()
3099 SpecializationUtil.raiseEvent(self, "onDeactivate")
3100end

delete

Description
Definition
delete()
Code
1262function Vehicle:delete()
1263 if self.isDeleted then
1264 Logging.devError("Trying to delete a already deleted vehicle")
1265 printCallstack()
1266 return
1267 end
1268
1269 VehicleDebug.delete(self)
1270
1271 if self.tourId ~= nil then
1272 if g_currentMission ~= nil then
1273 g_currentMission.guidedTour:removeVehicle(self.tourId)
1274 end
1275 end
1276
1277 self.isDeleting = true
1278 g_messageCenter:unsubscribeAll(self)
1279
1280 self:deleteMapHotspot()
1281
1282 local rootVehicle = self.rootVehicle
1283 if rootVehicle ~= nil and rootVehicle:getIsAIActive() then
1284 rootVehicle:stopCurrentAIJob(AIMessageErrorVehicleDeleted.new())
1285 end
1286
1287 g_inputBinding:beginActionEventsModification(Vehicle.INPUT_CONTEXT_NAME)
1288 self:removeActionEvents()
1289 g_inputBinding:endActionEventsModification()
1290
1291 SpecializationUtil.raiseEvent(self, "onPreDelete")
1292 SpecializationUtil.raiseEvent(self, "onDelete")
1293
1294 if self.isServer and self.componentJoints ~= nil then
1295 for _,v in pairs(self.componentJoints) do
1296 if v.jointIndex ~= 0 then
1297 removeJoint(v.jointIndex)
1298 end
1299 end
1300
1301 removeWakeUpReport(self.rootNode)
1302 end
1303
1304 self:removeNodeObjectMapping(g_currentMission.nodeToObject)
1305
1306 if self.components ~= nil then
1307 for _,v in pairs(self.components) do
1308 delete(v.node)
1309 end
1310 end
1311
1312 if self.sharedLoadRequestId ~= nil then
1313 g_i3DManager:releaseSharedI3DFile(self.sharedLoadRequestId)
1314 self.sharedLoadRequestId = nil
1315 end
1316
1317 self.xmlFile:delete()
1318
1319 if self.externalSoundsFile ~= nil then
1320 self.externalSoundsFile:delete()
1321 end
1322
1323 self.isDeleting = false
1324 self.isDeleted = true
1325
1326 Vehicle:superClass().delete(self)
1327
1328 if self.currentSavegameId ~= nil then
1329 g_currentMission.savegameIdToVehicle[self.currentSavegameId] = nil
1330 end
1331end

deleteMapHotspot

Description
Definition
deleteMapHotspot()
Code
3914function Vehicle:deleteMapHotspot()
3915 if self.mapHotspot ~= nil then
3916 g_currentMission:removeMapHotspot(self.mapHotspot)
3917 self.mapHotspot:delete()
3918 self.mapHotspot = nil
3919 end
3920end

doCheckSpeedLimit

Description
Definition
doCheckSpeedLimit()
Code
3582function Vehicle:doCheckSpeedLimit()
3583 return false
3584end

doCollisionMaskCheck

Description
Definition
doCollisionMaskCheck()
Code
3653function Vehicle:doCollisionMaskCheck(targetCollisionMask, path, node, str)
3654 local ignoreCheck = false
3655 if path ~= nil then
3656 ignoreCheck = self.xmlFile:getValue(path, false)
3657 end
3658
3659 if not ignoreCheck then
3660 local hasMask = false
3661 if node == nil then
3662 for _, component in ipairs(self.components) do
3663 hasMask = hasMask or bitAND(getCollisionMask(component.node), targetCollisionMask) == targetCollisionMask
3664 end
3665 else
3666 hasMask = hasMask or bitAND(getCollisionMask(node), targetCollisionMask) == targetCollisionMask
3667 end
3668
3669 if not hasMask then
3670 printCallstack()
3671 Logging.xmlWarning(self.xmlFile, "%s has wrong collision mask! Following bit(s) need to be set '%s' or use '%s'", str or self.typeName, MathUtil.numberToSetBitsStr(targetCollisionMask), path)
3672 return false
3673 end
3674 end
3675
3676 return true
3677end

draw

Description
Definition
draw()
Code
1987function Vehicle:draw(subDraw)
1988 if self:getIsSynchronized() then
1989 local rootVehicle = self.rootVehicle
1990 local selectedVehicle = self:getSelectedVehicle()
1991 if not subDraw then
1992 -- draw is only called on the 'entered' vehicle
1993 -- so if the 'entered' vehicle is not the root vehicle or not the selected vehicle we call draw on them
1994 if self ~= rootVehicle and selectedVehicle ~= rootVehicle then
1995 rootVehicle:draw(true)
1996 end
1997
1998 if selectedVehicle ~= nil and self ~= selectedVehicle and selectedVehicle ~= rootVehicle then
1999 selectedVehicle:draw(true)
2000 end
2001 end
2002
2003 if selectedVehicle == self or rootVehicle == self then
2004 local isActiveForInput = self:getIsActiveForInput()
2005 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
2006 SpecializationUtil.raiseEvent(self, "onDraw", isActiveForInput, isActiveForInputIgnoreSelection, true)
2007 end
2008
2009 -- DebugUtil.drawDebugNode(self.rootNode, "farm: " .. tostring(self:getOwnerFarmId()) .. ", controller: " .. tostring(self:getActiveFarm()))
2010
2011 -- if self == self.rootVehicle and self:getIsActiveForInput() then
2012 -- renderText(0.5, 0.95, 0.012, tostring(self:getSelectedVehicle()))
2013 -- for k, object in ipairs(self.selectableObjects) do
2014 -- renderText(0.5, 0.9-k*0.015, 0.012, tostring(object.vehicle) .. " " .. tostring(object.vehicle.configFileName) .. ": " .. #object.subSelections .. " " .. tostring(object.vehicle:getIsSelected()))
2015 -- end
2016 -- end
2017
2018 VehicleDebug.drawDebug(self)
2019
2020 if self.showTailwaterDepthWarning then
2021 g_currentMission:showBlinkingWarning(g_i18n:getText("warning_dontDriveIntoWater"), 2000)
2022 end
2023 end
2024end

drawUIInfo

Description
Draw UI info
Definition
drawUIInfo()
Code
2028function Vehicle:drawUIInfo()
2029 if self:getIsSynchronized() then
2030 SpecializationUtil.raiseEvent(self, "onDrawUIInfo")
2031
2032 if g_showVehicleDistance then
2033 local dist = calcDistanceFrom(self.rootNode, getCamera())
2034 if dist <= 350 then
2035 local x, y, z = getWorldTranslation(self.rootNode)
2036 Utils.renderTextAtWorldPosition(x, y+1, z, string.format("%.0f", dist), getCorrectTextSize(0.02), 0)
2037 end
2038 end
2039 end
2040end

findRootVehicle

Description
Definition
findRootVehicle()
Code
2754function Vehicle:findRootVehicle()
2755 return self
2756end

getActionControllerDirection

Description
Definition
getActionControllerDirection()
Code
3891function Vehicle:getActionControllerDirection()
3892 if self.actionController ~= nil then
3893 return self.actionController:getActionControllerDirection()
3894 end
3895
3896 return 1
3897end

getAdditionalComponentMass

Description
Definition
getAdditionalComponentMass()
Code
3000function Vehicle:getAdditionalComponentMass(component)
3001 return 0
3002end

getAdditionalSchemaText

Description
Definition
getAdditionalSchemaText()
Code
3553function Vehicle:getAdditionalSchemaText()
3554 return nil
3555end

getAreControlledActionsAllowed

Description
Returns if controlled actions are allowed
Definition
getAreControlledActionsAllowed()
Return Values
booleanallowallow controlled actions
stringwarningnot allowed warning
Code
3877function Vehicle:getAreControlledActionsAllowed()
3878 return not self:getIsAIActive(), ""
3879end

getAreControlledActionsAvailable

Description
Definition
getAreControlledActionsAvailable()
Code
3861function Vehicle:getAreControlledActionsAvailable()
3862 if self:getIsAIActive() then
3863 return false
3864 end
3865
3866 if self.actionController ~= nil then
3867 return self.actionController:getAreControlledActionsAvailable()
3868 end
3869
3870 return false
3871end

getAvailableComponentMass

Description
Definition
getAvailableComponentMass()
Code
2994function Vehicle:getAvailableComponentMass()
2995 return math.max((self.maxComponentMass - self.precalculatedMass) - self.serverMass, 0)
2996end

getBlockSelection

Description
Definition
getBlockSelection()
Code
2736function Vehicle:getBlockSelection()
2737 return false
2738end

getBrand

Description
Definition
getBrand()
Code
3801function Vehicle:getBrand()
3802 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
3803 if storeItem ~= nil and storeItem.configurations ~= nil then
3804 for configName, _ in pairs(storeItem.configurations) do
3805 local configId = self.configurations[configName]
3806 local config = storeItem.configurations[configName][configId]
3807 if config.vehicleBrand ~= nil then
3808 return config.vehicleBrand
3809 end
3810 end
3811 end
3812
3813 return storeItem.brandIndex
3814end

getCanBePickedUp

Description
Definition
getCanBePickedUp()
Code
3837function Vehicle:getCanBePickedUp(byPlayer)
3838 return self.supportsPickUp and g_currentMission.accessHandler:canPlayerAccess(self, byPlayer)
3839end

getCanBeReset

Description
Definition
getCanBeReset()
Code
3843function Vehicle:getCanBeReset()
3844 return self.canBeReset
3845end

getCanBeSelected

Description
Definition
getCanBeSelected()
Code
2730function Vehicle:getCanBeSelected()
2731 return VehicleDebug.state ~= 0 -- allow selection while any debug modes is active to debug any vehicle
2732end

getCanByMounted

Description
Definition
getCanByMounted()
Code
3741function Vehicle:getCanByMounted()
3742 return entityExists(self.components[1].node)
3743end

getCanToggleSelectable

Description
Definition
getCanToggleSelectable()
Code
2742function Vehicle:getCanToggleSelectable()
2743 return false
2744end

getChildVehicles

Description
Definition
getChildVehicles()
Code
2760function Vehicle:getChildVehicles()
2761 return self.childVehicles
2762end

getComponentMass

Description
Returns the mass of a component
Definition
getComponentMass(table component)
Arguments
tablecomponentcomponent
Return Values
floatmassmass
Code
3022function Vehicle:getComponentMass(component)
3023 if component ~= nil then
3024 return component.mass
3025 end
3026
3027 return 0
3028end

getDailyUpkeep

Description
Get daily up keep
Definition
getDailyUpkeep()
Return Values
floatdailyUpkeepdaily up keep
Code
3748function Vehicle:getDailyUpkeep()
3749 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
3750 return Vehicle.calculateDailyUpkeep(storeItem, self.age, self.operatingTime, self.configurations)
3751end

getDeactivateOnLeave

Description
Definition
getDeactivateOnLeave()
Code
2356function Vehicle:getDeactivateOnLeave()
2357 return true
2358end

getDefaultMass

Description
Definition
getDefaultMass()
Code
3032function Vehicle:getDefaultMass()
3033 local mass = 0
3034
3035 for _, component in ipairs(self.components) do
3036 mass = mass + (component.defaultMass or 0)
3037 end
3038
3039 return mass
3040end

getDistanceToNode

Description
Definition
getDistanceToNode()
Code
3607function Vehicle:getDistanceToNode(node)
3608 self.interactionFlag = Vehicle.INTERACTION_FLAG_NONE
3609 return math.huge
3610end

getFillLevelInformation

Description
Get fill level information
Definition
getFillLevelInformation(table fillLevelInformations)
Arguments
tablefillLevelInformationsfill level informations
Code
3087function Vehicle:getFillLevelInformation(display)
3088end

getFullName

Description
Definition
getFullName()
Code
3786function Vehicle:getFullName()
3787 local name = self:getName()
3788 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
3789 if storeItem ~= nil then
3790 local brand = g_brandManager:getBrandByIndex(self:getBrand())
3791 if brand ~= nil then
3792 name = brand.title .. " " .. name
3793 end
3794 end
3795
3796 return name
3797end

getImageFilename

Description
Definition
getImageFilename()
Code
3818function Vehicle:getImageFilename()
3819 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
3820 if storeItem ~= nil and storeItem.configurations ~= nil then
3821 for configName, _ in pairs(storeItem.configurations) do
3822 local configId = self.configurations[configName]
3823 local config = storeItem.configurations[configName][configId]
3824 if config == nil then
3825 Logging.xmlWarning(self.xmlFile, "Vehicle has an invalid configuration value %s for %s", configId, configName)
3826 elseif config.vehicleIcon ~= nil and config.vehicleIcon ~= "" then
3827 return config.vehicleIcon
3828 end
3829 end
3830 end
3831
3832 return storeItem.imageFilename
3833end

getInteractionHelp

Description
Definition
getInteractionHelp()
Code
3601function Vehicle:getInteractionHelp()
3602 return ""
3603end

getIsActive

Description
Definition
getIsActive()
Code
2400function Vehicle:getIsActive()
2401 if self.isBroken then
2402 return false
2403 end
2404
2405 if self.forceIsActive then
2406 return true
2407 end
2408
2409 return false
2410end

getIsActiveForInput

Description
Definition
getIsActiveForInput()
Code
2414function Vehicle:getIsActiveForInput(ignoreSelection, activeForAI)
2415 if not self.allowsInput then
2416 return false
2417 end
2418
2419 if not g_currentMission.isRunning then
2420 return false
2421 end
2422
2423 if (activeForAI == nil or not activeForAI) and self:getIsAIActive() then
2424 return false
2425 end
2426
2427 if not ignoreSelection or ignoreSelection == nil then
2428 local rootVehicle = self.rootVehicle
2429 if rootVehicle ~= nil then
2430 local selectedObject = rootVehicle:getSelectedVehicle()
2431 if self ~= selectedObject then
2432 return false
2433 end
2434 else
2435 return false
2436 end
2437 end
2438
2439 local rootAttacherVehicle = self.rootVehicle
2440 if rootAttacherVehicle ~= self then
2441 if not rootAttacherVehicle:getIsActiveForInput(true, activeForAI) then
2442 return false
2443 end
2444 else
2445 -- if it is the root vehicle and it is not enterable we check for a attacherVehicle
2446 if self.getIsEntered == nil and self.getAttacherVehicle ~= nil and self:getAttacherVehicle() == nil then
2447 return false
2448 end
2449 end
2450
2451 return true
2452end

getIsActiveForSound

Description
Definition
getIsActiveForSound()
Code
2456function Vehicle:getIsActiveForSound()
2457 print("Warning: Vehicle:getIsActiveForSound() is deprecated")
2458 return false
2459end

getIsAIActive

Description
Definition
getIsAIActive()
Code
3614function Vehicle:getIsAIActive()
3615 if self.getAttacherVehicle ~= nil then
3616 local attacherVehicle = self:getAttacherVehicle()
3617 if attacherVehicle ~= nil then
3618 return attacherVehicle:getIsAIActive()
3619 end
3620 end
3621
3622 return false
3623end

getIsAutomaticShiftingAllowed

Description
Definition
getIsAutomaticShiftingAllowed()
Code
3687function Vehicle:getIsAutomaticShiftingAllowed()
3688 return true
3689end

getIsInUse

Description
Definition
getIsInUse()
Code
3849function Vehicle:getIsInUse(connection)
3850 return false
3851end

getIsLowered

Description
Definition
getIsLowered()
Code
2463function Vehicle:getIsLowered(defaultIsLowered)
2464 return false
2465end

getIsMapHotspotVisible

Description
Definition
getIsMapHotspotVisible()
Code
3938function Vehicle:getIsMapHotspotVisible()
3939 return true
3940end

getIsOnField

Description
Returns true if vehicle is on a field
Definition
getIsOnField()
Return Values
booleanisOnFieldis on field
Code
2307function Vehicle:getIsOnField()
2308 for _,component in pairs(self.components) do
2309 local wx, wy, wz = localToWorld(component.node, getCenterOfMass(component.node))
2310
2311 local h = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, wx, wy, wz)
2312 if h-1 > wy then -- 1m threshold since ground tools are working slightly under the ground
2313 break
2314 end
2315
2316 local isOnField, _ = FSDensityMapUtil.getFieldDataAtWorldPosition(wx, wy, wz)
2317 if isOnField then
2318 return true
2319 end
2320 end
2321
2322 return false
2323end

getIsOperating

Description
Returns true if is operating
Definition
getIsOperating()
Return Values
booleanisOperatingis operating
Code
2394function Vehicle:getIsOperating()
2395 return false
2396end

getIsPowered

Description
Definition
getIsPowered()
Code
3627function Vehicle:getIsPowered()
3628 return true
3629end

getIsReadyForAutomatedTrainTravel

Description
Definition
getIsReadyForAutomatedTrainTravel()
Code
3681function Vehicle:getIsReadyForAutomatedTrainTravel()
3682 return true
3683end

getIsSelected

Description
Definition
getIsSelected()
Code
2903function Vehicle:getIsSelected()
2904 return self.selectionObject.isSelected
2905end

getIsSynchronized

Description
Definition
getIsSynchronized()
Code
2362function Vehicle:getIsSynchronized()
2363 return self.loadingStep == Vehicle.LOAD_STEP_SYNCHRONIZED
2364end

getIsVehicleNode

Description
Returns true if node is from vehicle
Definition
getIsVehicleNode(Integer nodeId)
Arguments
IntegernodeIdnode id
Return Values
booleanisFromVehicleis from vehicle
Code
2387function Vehicle:getIsVehicleNode(nodeId)
2388 return self.vehicleNodes[nodeId] ~= nil
2389end

getLastSpeed

Description
Returns last speed in kph
Definition
getLastSpeed(boolean useAttacherVehicleSpeed)
Arguments
booleanuseAttacherVehicleSpeeduse speed of attacher vehicle
Return Values
floatlastSpeedlast speed
Code
2343function Vehicle:getLastSpeed(useAttacherVehicleSpeed)
2344 if useAttacherVehicleSpeed then
2345 if self.attacherVehicle ~= nil then
2346 return self.attacherVehicle:getLastSpeed(true)
2347 end
2348 end
2349
2350 return self.lastSpeed * 3600
2351end

getLimitedVehicleYPosition

Description
Definition
getLimitedVehicleYPosition()
Code
2197function Vehicle:getLimitedVehicleYPosition(position)
2198 if position.posY == nil then
2199 -- vehicle position based on yOffset
2200 local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, position.posX, 300, position.posZ)
2201 return terrainHeight + Utils.getNoNil(position.yOffset, 0)
2202 end
2203
2204 return position.posY
2205end

getMapHotspot

Description
Definition
getMapHotspot()
Code
3924function Vehicle:getMapHotspot()
3925 return self.mapHotspot
3926end

getMaxComponentMassReached

Description
Definition
getMaxComponentMassReached()
Code
2988function Vehicle:getMaxComponentMassReached()
2989 return (self.serverMass + 0.00001) >= (self.maxComponentMass - self.precalculatedMass)
2990end

getName

Description
Definition
getName()
Code
3769function Vehicle:getName()
3770 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
3771 if storeItem ~= nil and storeItem.configurations ~= nil then
3772 for configName, _ in pairs(storeItem.configurations) do
3773 local configId = self.configurations[configName]
3774 local config = storeItem.configurations[configName][configId]
3775 if config.vehicleName ~= nil and config.vehicleName ~= "" then
3776 return config.vehicleName
3777 end
3778 end
3779 end
3780
3781 return storeItem.name
3782end

getOperatingTime

Description
Definition
getOperatingTime()
Code
3647function Vehicle:getOperatingTime()
3648 return self.operatingTime
3649end

getOverallCenterOfMass

Description
Returns overall center of mass of vehicle
Definition
getOverallCenterOfMass()
Return Values
floatxx
floatyy
floatzz
Code
3047function Vehicle:getOverallCenterOfMass()
3048 local cx, cy, cz = 0, 0, 0
3049 local totalMass = self:getTotalMass(true)
3050 local numComponents = #self.components
3051 for i=1, numComponents do
3052 local component = self.components[i]
3053 local ccx, ccy, ccz = localToWorld(component.node, getCenterOfMass(component.node))
3054 local percentage = self:getComponentMass(component) / totalMass
3055
3056 cx, cy, cz = cx + ccx * percentage, cy + ccy * percentage, cz + ccz * percentage
3057 end
3058
3059 return cx, cy, cz
3060end

getOwner

Description
Get owner of vehicle
Definition
getOwner()
Return Values
tableownerowner
Code
2369function Vehicle:getOwner()
2370 if self.owner ~= nil then
2371 return self.owner
2372 end
2373
2374 return nil
2375end

getParentComponent

Description
Get parent component of node
Definition
getParentComponent(Integer node)
Arguments
Integernodeid of node
Return Values
IntegerparentComponentid of parent component node
Code
2329function Vehicle:getParentComponent(node)
2330 while node ~= 0 do
2331 if self:getIsVehicleNode(node) then
2332 return node
2333 end
2334 node = getParent(node)
2335 end
2336 return 0
2337end

getPrice

Description
Returns price
Definition
getPrice(float price)
Arguments
floatpriceprice
Code
2271function Vehicle:getPrice()
2272 return self.price
2273end

getPropertyState

Description
Definition
getPropertyState()
Code
3855function Vehicle:getPropertyState()
3856 return self.propertyState
3857end

getRawSpeedLimit

Description
Get raw speed limit of vehicle
Definition
getRawSpeedLimit()
Return Values
floatspeedLimitspeed limit
Code
3729function Vehicle:getRawSpeedLimit()
3730 return self.speedLimit
3731end

getReloadXML

Description
Get reload xml
Definition
getReloadXML(table vehicle)
Arguments
tablevehiclevehicle
Return Values
stringxmlxml
Code
4051function Vehicle.getReloadXML(vehicle)
4052 local vehicleXMLFile = XMLFile.create("vehicleXMLFile", "", "vehicles", Vehicle.xmlSchemaSavegame)
4053 if vehicleXMLFile ~= nil then
4054 local key = string.format("vehicles.vehicle(%d)", 0)
4055
4056 vehicleXMLFile:setValue(key.."#id", 1)
4057 vehicleXMLFile:setValue(key.."#filename", HTMLUtil.encodeToHTML(NetworkUtil.convertToNetworkFilename(vehicle.configFileName)))
4058 vehicle.currentSavegameId = 1
4059 vehicle:saveToXMLFile(vehicleXMLFile, key, {})
4060
4061 return vehicleXMLFile
4062 end
4063
4064 return nil
4065end

getRepaintPrice

Description
Definition
getRepaintPrice()
Code
2522function Vehicle:getRepaintPrice()
2523 return 0
2524end

getRepairPrice

Description
Definition
getRepairPrice()
Code
2516function Vehicle:getRepairPrice()
2517 return 0
2518end

getRootVehicle

Description
Definition
getRootVehicle()
Code
2748function Vehicle:getRootVehicle()
2749 return self.rootVehicle
2750end

getSelectedObject

Description
Definition
getSelectedObject()
Code
2909function Vehicle:getSelectedObject()
2910 local rootVehicle = self.rootVehicle
2911 if rootVehicle == self then
2912 return self.currentSelection.object
2913 end
2914
2915 return rootVehicle:getSelectedObject()
2916end

getSelectedVehicle

Description
Definition
getSelectedVehicle()
Code
2920function Vehicle:getSelectedVehicle()
2921 local selectedObject = self:getSelectedObject()
2922 if selectedObject ~= nil then
2923 return selectedObject.vehicle
2924 end
2925 return nil
2926end

getSellPrice

Description
Get sell price
Definition
getSellPrice()
Return Values
floatsellPricesell price
Code
2278function Vehicle:getSellPrice()
2279 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
2280 return Vehicle.calculateSellPrice(storeItem, self.age, self.operatingTime, self:getPrice(), self:getRepairPrice(), self:getRepaintPrice())
2281end

getSpecConfigValuesWeight

Description
Definition
getSpecConfigValuesWeight()
Code
4275function Vehicle.getSpecConfigValuesWeight(storeItem, realItem, configurations, saleItem, returnValues, returnRange)
4276 if storeItem.specs.weight ~= nil then
4277 if storeItem.specs.weight.storeDataConfigs ~= nil then
4278 return storeItem.specs.weight.storeDataConfigs
4279 end
4280 end
4281end

getSpecValueAdditionalWeight

Description
Definition
getSpecValueAdditionalWeight()
Code
4331function Vehicle.getSpecValueAdditionalWeight(storeItem, realItem, configurations, saleItem, returnValues, returnRange)
4332 if not g_currentMission.missionInfo.trailerFillLimit then
4333 return nil
4334 end
4335
4336 if storeItem.specs.additionalWeight ~= nil then
4337 local baseWeight = Vehicle.getSpecValueWeight(storeItem, realItem, configurations, saleItem, true)
4338 if baseWeight ~= nil then
4339 local additionalWeight = storeItem.specs.additionalWeight - baseWeight
4340
4341 if returnValues then
4342 return additionalWeight
4343 else
4344 return g_i18n:formatMass(additionalWeight)
4345 end
4346 end
4347 end
4348
4349 return nil
4350end

getSpecValueCombinations

Description
Definition
getSpecValueCombinations()
Code
4384function Vehicle.getSpecValueCombinations(storeItem, realItem)
4385 return storeItem.specs.combinations
4386end

getSpecValueDailyUpkeep

Description
Definition
getSpecValueDailyUpkeep()
Code
4083function Vehicle.getSpecValueDailyUpkeep(storeItem, realItem, _, saleItem)
4084 local dailyUpkeep = storeItem.dailyUpkeep
4085 if realItem ~= nil and realItem.getDailyUpkeep ~= nil then
4086 dailyUpkeep = realItem:getDailyUpkeep()
4087 elseif saleItem ~= nil then
4088 dailyUpkeep = 0--Vehicle.calculateDailyUpkeep(storeItem, saleItem.age, saleItem.operatingTime, {})
4089 end
4090
4091 -- Hide when no upkeep
4092 if dailyUpkeep == 0 then
4093 return nil
4094 end
4095
4096 return string.format(g_i18n:getText("shop_maintenanceValue"), g_i18n:formatMoney(dailyUpkeep, 2))
4097end

getSpecValueOperatingTime

Description
Definition
getSpecValueOperatingTime()
Code
4101function Vehicle.getSpecValueOperatingTime(storeItem, realItem, _, saleItem)
4102 local operatingTime
4103
4104 if realItem ~= nil and realItem.operatingTime ~= nil then
4105 operatingTime = realItem.operatingTime
4106 elseif saleItem ~= nil then
4107 operatingTime = saleItem.operatingTime
4108 else
4109 return nil
4110 end
4111
4112 local minutes = operatingTime / (1000 * 60)
4113 local hours = math.floor(minutes / 60)
4114 minutes = math.floor((minutes - hours * 60) / 6)
4115
4116 return string.format(g_i18n:getText("shop_operatingTime"), hours, minutes)
4117end

getSpecValueSlots

Description
Definition
getSpecValueSlots()
Code
4390function Vehicle.getSpecValueSlots(storeItem, realItem, configurations, saleItem, returnValues, returnRange)
4391 local numOwned = g_currentMission:getNumOfItems(storeItem)
4392 local valueText = ""
4393 if realItem ~= nil then
4394 local sellSlotUsage = g_currentMission.slotSystem:getStoreItemSlotUsage(storeItem, numOwned == 1)
4395 if sellSlotUsage ~= 0 then
4396 valueText = "+"..sellSlotUsage
4397 end
4398 else
4399 local buySlotUsage = g_currentMission.slotSystem:getStoreItemSlotUsage(storeItem, numOwned == 0)
4400 if storeItem.bundleInfo ~= nil then
4401 buySlotUsage = 0
4402 for i=1, #storeItem.bundleInfo.bundleItems do
4403 local bundleInfo = storeItem.bundleInfo.bundleItems[i]
4404 local numBundleItemOwned = g_currentMission:getNumOfItems(bundleInfo.item)
4405 local usage = g_currentMission.slotSystem:getStoreItemSlotUsage(bundleInfo.item, numBundleItemOwned == 0)
4406 buySlotUsage = buySlotUsage + usage
4407 end
4408 end
4409
4410 if buySlotUsage ~= 0 then
4411 valueText = "-"..buySlotUsage
4412 end
4413 end
4414
4415 if valueText ~= "" then
4416 return valueText
4417 else
4418 return nil
4419 end
4420end

getSpecValueSpeedLimit

Description
Definition
getSpecValueSpeedLimit()
Code
4222function Vehicle.getSpecValueSpeedLimit(storeItem, realItem)
4223 if storeItem.specs.speedLimit ~= nil then
4224 return string.format(g_i18n:getText("shop_maxSpeed"), string.format("%1d", g_i18n:getSpeed(storeItem.specs.speedLimit)), g_i18n:getSpeedMeasuringUnit())
4225 end
4226 return nil
4227end

getSpecValueWeight

Description
Definition
getSpecValueWeight()
Code
4284function Vehicle.getSpecValueWeight(storeItem, realItem, configurations, saleItem, returnValues, returnRange)
4285 if storeItem.specs.weight ~= nil then
4286 local vehicleMass, vehicleMassMax
4287 if realItem ~= nil then
4288 realItem:updateMass()
4289 vehicleMass = realItem:getTotalMass(true)
4290 else
4291 if storeItem.specs.weight.storeDataMin ~= nil then
4292 vehicleMass = (storeItem.specs.weight.storeDataMin or 0) / 1000
4293 vehicleMassMax = (storeItem.specs.weight.storeDataMax or 0) / 1000
4294 elseif storeItem.specs.weight.componentMass ~= nil then
4295 vehicleMass = storeItem.specs.weight.componentMass + (storeItem.specs.weight.wheelMassDefaultConfig or 0)
4296 vehicleMass = vehicleMass + FillUnit.getSpecValueStartFillUnitMassByMassData(storeItem.specs.weight.fillUnitMassData)
4297 end
4298 end
4299
4300 if vehicleMass ~= nil and vehicleMass ~= 0 then
4301 if returnValues then
4302 if returnRange then
4303 return vehicleMass, vehicleMassMax
4304 else
4305 return vehicleMass
4306 end
4307 else
4308 if vehicleMassMax ~= nil and vehicleMassMax ~= 0 then
4309 return g_i18n:formatMass(vehicleMass, vehicleMassMax)
4310 else
4311 return g_i18n:formatMass(vehicleMass)
4312 end
4313 end
4314 end
4315 end
4316
4317 return nil
4318end

getSpecValueWorkingWidth

Description
Definition
getSpecValueWorkingWidth()
Code
4127function Vehicle.getSpecValueWorkingWidth(storeItem, realItem)
4128 if storeItem.specs.workingWidth ~= nil then
4129 return string.format(g_i18n:getText("shop_workingWidthValue"), g_i18n:formatNumber(storeItem.specs.workingWidth, 1, true))
4130 end
4131 return nil
4132end

getSpecValueWorkingWidthConfig

Description
Definition
getSpecValueWorkingWidthConfig()
Code
4175function Vehicle.getSpecValueWorkingWidthConfig(storeItem, realItem, configurations, saleItem, returnValues, returnRange)
4176 if storeItem.specs.workingWidthConfig ~= nil then
4177 local minWorkingWidth = 0
4178 local workingWidth = 0
4179 if configurations ~= nil and (realItem ~= nil or saleItem ~= nil) then
4180 for configName, config in pairs(configurations) do
4181 local width = storeItem.specs.workingWidthConfig[configName][config]
4182 if width ~= nil then
4183 workingWidth = width
4184 end
4185 end
4186 else
4187 local minWidth = math.huge
4188 local maxWidth = 0
4189 for configName, configs in pairs(storeItem.specs.workingWidthConfig) do
4190 for _, width in pairs(configs) do
4191 minWidth = math.min(minWidth, width)
4192 maxWidth = math.max(maxWidth, width)
4193 end
4194 end
4195
4196 minWorkingWidth = minWidth
4197 workingWidth = maxWidth
4198 end
4199
4200 if not returnValues then
4201 if minWorkingWidth ~= 0 and minWorkingWidth ~= math.huge and minWorkingWidth ~= workingWidth then
4202 return string.format(g_i18n:getText("shop_workingWidthValue"), string.format("%s-%s", g_i18n:formatNumber(minWorkingWidth, 1, true), g_i18n:formatNumber(workingWidth, 1, true)))
4203 else
4204 return string.format(g_i18n:getText("shop_workingWidthValue"), g_i18n:formatNumber(workingWidth, 1, true))
4205 end
4206 else
4207 return workingWidth
4208 end
4209 end
4210
4211 return nil
4212end

getSpeedLimit

Description
Get speed limit
Definition
getSpeedLimit(boolean onlyIfWorking)
Arguments
booleanonlyIfWorkingonly if working
Return Values
floatlimitlimit
booleandoCheckSpeedLimitdo check speed limit
Code
3696function Vehicle:getSpeedLimit(onlyIfWorking)
3697 local limit = math.huge
3698 local doCheckSpeedLimit = self:doCheckSpeedLimit()
3699 if onlyIfWorking == nil or (onlyIfWorking and doCheckSpeedLimit) then
3700 limit = self:getRawSpeedLimit()
3701
3702 local damage = self:getVehicleDamage()
3703 if damage > 0 then
3704 limit = limit * (1 - damage * Vehicle.DAMAGED_SPEEDLIMIT_REDUCTION)
3705 end
3706 end
3707
3708 local attachedImplements
3709 if self.getAttachedImplements ~= nil then
3710 attachedImplements = self:getAttachedImplements()
3711 end
3712 if attachedImplements ~= nil then
3713 for _, implement in pairs(attachedImplements) do
3714 if implement.object ~= nil then
3715 local speed, implementDoCheckSpeedLimit = implement.object:getSpeedLimit(onlyIfWorking)
3716 if onlyIfWorking == nil or (onlyIfWorking and implementDoCheckSpeedLimit) then
3717 limit = math.min(limit, speed)
3718 end
3719 doCheckSpeedLimit = doCheckSpeedLimit or implementDoCheckSpeedLimit
3720 end
3721 end
3722 end
3723 return limit, doCheckSpeedLimit
3724end

getTotalMass

Description
Returns total mass of vehicle (optional including attached vehicles)
Definition
getTotalMass(boolean onlyGivenVehicle)
Arguments
booleanonlyGivenVehicleuse only the given vehicle, if false or nil it includes all attachables
Return Values
floattotalMasstotal mass
Code
3008function Vehicle:getTotalMass(onlyGivenVehicle)
3009 local mass = 0
3010
3011 for _, component in ipairs(self.components) do
3012 mass = mass + self:getComponentMass(component)
3013 end
3014
3015 return mass
3016end

getUseTurnedOnSchema

Description
Definition
getUseTurnedOnSchema()
Code
3559function Vehicle:getUseTurnedOnSchema()
3560 return false
3561end

getVehicleDamage

Description
Definition
getVehicleDamage()
Code
2510function Vehicle:getVehicleDamage()
2511 return 0
2512end

getVehicleWorldDirection

Description
Returns the world space direction of the vehicle
Definition
getVehicleWorldDirection()
Return Values
floatxx
floatyy
floatzz
Code
3080function Vehicle:getVehicleWorldDirection()
3081 return localDirectionToWorld(self.components[1].node, 0, 0, 1)
3082end

getVehicleWorldXRot

Description
Returns the world space x rotation in rad
Definition
getVehicleWorldXRot()
Return Values
floatrotationrotation
Code
3065function Vehicle:getVehicleWorldXRot()
3066 local _, y, _ = localDirectionToWorld(self.components[1].node, 0, 0, 1)
3067 local slopeAngle = math.pi * 0.5 - math.atan(1/y)
3068 if slopeAngle > math.pi * 0.5 then
3069 slopeAngle = slopeAngle - math.pi
3070 end
3071
3072 return slopeAngle
3073end

getWorkLoad

Description
Definition
getWorkLoad()
Code
3589function Vehicle:getWorkLoad()
3590 return 0, 0
3591end

hasInputConflictWithSelection

Description
Definition
hasInputConflictWithSelection()
Code
2930function Vehicle:hasInputConflictWithSelection(inputs)
2931 printCallstack()
2932 Logging.xmlWarning(self.xmlFile, "Vehicle:hasInputConflictWithSelection() is deprecated!")
2933 return false
2934end

init

Description
Definition
init()
Code
258function Vehicle.init()
259 g_configurationManager:addConfigurationType("baseColor", g_i18n:getText("configuration_baseColor"), nil, nil, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_COLOR)
260 g_configurationManager:addConfigurationType("design", g_i18n:getText("configuration_design"), nil, nil, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_MULTIOPTION)
261 g_configurationManager:addConfigurationType("designColor", g_i18n:getText("configuration_designColor"), nil, nil, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_COLOR)
262 g_configurationManager:addConfigurationType("vehicleType", g_i18n:getText("configuration_design"), nil, nil, ConfigurationUtil.getStoreAdditionalConfigData, nil, ConfigurationUtil.SELECTOR_MULTIOPTION)
263
264 for i=2, 8 do
265 g_configurationManager:addConfigurationType(string.format("design%d", i), g_i18n:getText("configuration_design"), nil, nil, ConfigurationUtil.getConfigColorSingleItemLoad, ConfigurationUtil.getConfigColorPostLoad, ConfigurationUtil.SELECTOR_MULTIOPTION)
266 end
267
268 g_storeManager:addSpecType("age", "shopListAttributeIconLifeTime", nil, Vehicle.getSpecValueAge, "vehicle")
269 g_storeManager:addSpecType("operatingTime", "shopListAttributeIconOperatingHours", nil, Vehicle.getSpecValueOperatingTime, "vehicle")
270 g_storeManager:addSpecType("dailyUpkeep", "shopListAttributeIconMaintenanceCosts", nil, Vehicle.getSpecValueDailyUpkeep, "vehicle")
271 g_storeManager:addSpecType("workingWidth", "shopListAttributeIconWorkingWidth", Vehicle.loadSpecValueWorkingWidth, Vehicle.getSpecValueWorkingWidth, "vehicle")
272 g_storeManager:addSpecType("workingWidthConfig", "shopListAttributeIconWorkingWidth", Vehicle.loadSpecValueWorkingWidthConfig, Vehicle.getSpecValueWorkingWidthConfig, "vehicle")
273 g_storeManager:addSpecType("speedLimit", "shopListAttributeIconWorkSpeed", Vehicle.loadSpecValueSpeedLimit, Vehicle.getSpecValueSpeedLimit, "vehicle")
274 g_storeManager:addSpecType("weight", "shopListAttributeIconWeight", Vehicle.loadSpecValueWeight, Vehicle.getSpecValueWeight, "vehicle", nil, Vehicle.getSpecConfigValuesWeight)
275 g_storeManager:addSpecType("additionalWeight", "shopListAttributeIconAdditionalWeight", Vehicle.loadSpecValueAdditionalWeight, Vehicle.getSpecValueAdditionalWeight, "vehicle")
276 g_storeManager:addSpecType("combinations", nil, Vehicle.loadSpecValueCombinations, Vehicle.getSpecValueCombinations, "vehicle")
277 g_storeManager:addSpecType("slots", "shopListAttributeIconSlots", nil, Vehicle.getSpecValueSlots, "vehicle")
278
279 Vehicle.xmlSchema = XMLSchema.new("vehicle")
280 Vehicle.xmlSchemaSounds = XMLSchema.new("vehicle_sounds")
281 Vehicle.xmlSchemaSounds:setRootNodeName("sounds")
282 Vehicle.xmlSchema:addSubSchema(Vehicle.xmlSchemaSounds, "sounds")
283
284 Vehicle.xmlSchemaSavegame = XMLSchema.new("savegame_vehicles")
285
286 Vehicle.registers()
287end

interact

Description
Definition
interact()
Code
3596function Vehicle:interact()
3597end

load

Description
Definition
load()
Code
525function Vehicle:load(vehicleData, asyncCallbackFunction, asyncCallbackObject, asyncCallbackArguments)
526 if asyncCallbackFunction == nil then
527 Logging.xmlWarning(self.xmlFile, "Missing async callback function for '%s'", vehicleData.filename)
528 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
529 printCallstack()
530 return self.loadingState
531 end
532
533 local modName, baseDirectory = Utils.getModNameAndBaseDirectory(vehicleData.filename)
534
535 self:setLoadingStep(Vehicle.LOAD_STEP_PRE_LOAD)
536
537 self.configFileName = vehicleData.filename
538 self.configFileNameClean = Utils.getFilenameInfo(vehicleData.filename, true)
539 self.baseDirectory = baseDirectory
540 self.customEnvironment = modName
541 self.typeName = vehicleData.typeName
542 self.isVehicleSaved = Utils.getNoNil(vehicleData.isVehicleSaved, true)
543 self.configurations = Utils.getNoNil(vehicleData.configurations, {})
544 self.boughtConfigurations = Utils.getNoNil(vehicleData.boughtConfigurations, {})
545
546 local typeDef = g_vehicleTypeManager:getTypeByName(self.typeName)
547 if typeDef == nil then
548 Logging.xmlWarning(self.xmlFile, "Unable to find vehicleType '%s'", self.typeName)
549 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
550 return self.loadingState
551 end
552
553 self.type = typeDef
554 self.specializations = typeDef.specializations
555 self.specializationNames = typeDef.specializationNames
556 self.specializationsByName = typeDef.specializationsByName
557 self.eventListeners = table.copy(typeDef.eventListeners, 2)
558 self.actionEvents = {}
559 self.xmlFile = XMLFile.load("vehicleXml", vehicleData.filename, Vehicle.xmlSchema)
560 self.savegame = vehicleData.savegame
561 self.isAddedToPhysics = false
562
563 self.additionalLoadParameters = vehicleData.additionalLoadParameters
564
565 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
566 if storeItem ~= nil then
567 self.brand = g_brandManager:getBrandByIndex(storeItem.brandIndex)
568 self.lifetime = storeItem.lifetime
569 end
570
571 self.externalSoundsFilename = self.xmlFile:getValue("vehicle.base.sounds#filename")
572 if self.externalSoundsFilename ~= nil then
573 self.externalSoundsFilename = Utils.getFilename(self.externalSoundsFilename, self.baseDirectory)
574 self.externalSoundsFile = XMLFile.load("TempExternalSounds", self.externalSoundsFilename, Vehicle.xmlSchemaSounds)
575 end
576
577 self.soundVolumeFactor = self.xmlFile:getValue("vehicle.base.sounds#volumeFactor")
578
579 -- pass function pointers from specializations to 'self'
580 for funcName, func in pairs(typeDef.functions) do
581 self[funcName] = func
582 end
583
584 local data = {}
585 data.position = {posX=vehicleData.posX, posY=vehicleData.posY, posZ=vehicleData.posZ, yOffset=vehicleData.yOffset, isAbsolute=vehicleData.isAbsolute}
586 data.rotation = {rotX=vehicleData.rotX, rotY=vehicleData.rotY, rotZ=vehicleData.rotZ}
587 data.isVehicleSaved = vehicleData.isVehicleSaved
588 data.propertyState = vehicleData.propertyState
589 data.ownerFarmId = vehicleData.ownerFarmId
590 data.price = vehicleData.price
591 data.savegame = vehicleData.savegame
592 data.asyncCallbackFunction = asyncCallbackFunction
593 data.asyncCallbackObject = asyncCallbackObject
594 data.asyncCallbackArguments = asyncCallbackArguments
595 data.componentPositions = vehicleData.componentPositions
596
597 -- check if one of the configurations is not set - e.g. if new configurations are available but not in savegame
598 local item = g_storeManager:getItemByXMLFilename(self.configFileName)
599 if item ~= nil and item.configurations ~= nil then
600 -- check if the loaded configurations do match the configuration sets
601 -- if not we apply the set which has the most common configurations
602 -- e.g. if a new configuration was added to the configuration set we make sure we don't break old savegames
603 if item.configurationSets ~= nil and #item.configurationSets > 0 then
604 if not StoreItemUtil.getConfigurationsMatchConfigSets(self.configurations, item.configurationSets) then
605 local closestSet, closestSetMatches = StoreItemUtil.getClosestConfigurationSet(self.configurations, item.configurationSets)
606 if closestSet ~= nil then
607 for configName, index in pairs(closestSet.configurations) do
608 self.configurations[configName] = index
609 end
610
611 Logging.xmlInfo(self.xmlFile, "Savegame configurations to not match the configuration sets! Apply closest configuration set '%s' with %d matching configurations.", closestSet.name, closestSetMatches)
612 end
613 end
614 end
615
616 for configName, _ in pairs(item.configurations) do
617 local defaultConfigId = StoreItemUtil.getDefaultConfigId(item, configName)
618 if self.configurations[configName] == nil then
619 ConfigurationUtil.setConfiguration(self, configName, defaultConfigId)
620 end
621 -- base configuration is always included
622 ConfigurationUtil.addBoughtConfiguration(self, configName, defaultConfigId)
623 end
624 -- check if currently used configurations are still available
625 for configName, value in pairs(self.configurations) do
626 if item.configurations[configName] == nil then
627 Logging.xmlWarning(self.xmlFile, "Configurations are not present anymore. Ignoring this configuration (%s)!", configName)
628 self.configurations[configName] = nil
629 self.boughtConfigurations[configName] = nil
630 else
631 local defaultConfigId = StoreItemUtil.getDefaultConfigId(item, configName)
632 if #item.configurations[configName] < value then
633 Logging.xmlWarning(self.xmlFile, "Configuration with index '%d' is not present anymore. Using default configuration instead!", value)
634
635 if self.boughtConfigurations[configName] ~= nil then
636 self.boughtConfigurations[configName][value] = nil
637 if next(self.boughtConfigurations[configName]) == nil then
638 self.boughtConfigurations[configName] = nil
639 end
640 end
641 ConfigurationUtil.setConfiguration(self, configName, defaultConfigId)
642 else
643 ConfigurationUtil.addBoughtConfiguration(self, configName, value)
644 end
645 end
646 end
647 end
648
649 for i=1, #self.specializations do
650 local specEntryName = "spec_" .. self.specializationNames[i]
651 if self[specEntryName] ~= nil then
652 Logging.xmlError(self.xmlFile, "The vehicle specialization '%s' could not be added because variable '%s' already exists!", self.specializationNames[i], specEntryName)
653 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
654 end
655
656 local env = {}
657 setmetatable(env, { __index = self } )
658 env.actionEvents = {}
659 self[specEntryName] = env
660 end
661
662 SpecializationUtil.raiseEvent(self, "onPreLoad", vehicleData.savegame)
663 if self.loadingState ~= VehicleLoadingUtil.VEHICLE_LOAD_OK then
664 Logging.xmlError(self.xmlFile, "Vehicle pre-loading failed!")
665 self.xmlFile:delete()
666 asyncCallbackFunction(asyncCallbackObject, nil, self.loadingState, asyncCallbackArguments)
667 return
668 end
669
670 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.filename", "vehicle.base.filename") --FS17 to FS19
671
672 self.i3dFilename = Utils.getFilename(self.xmlFile:getValue("vehicle.base.filename"), baseDirectory)
673
674 self:setLoadingStep(Vehicle.LOAD_STEP_AWAIT_I3D)
675
676 self.sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(self.i3dFilename, true, false, self.loadFinished, self, data)
677end

loadComponentFromXML

Description
Load component from xml
Definition
loadComponentFromXML(table component, integer xmlFile, string key, table rootPosition, Integer i)
Arguments
tablecomponentcomponent
integerxmlFileid of xml object
stringkeykey
tablerootPositionroot position (x, y, z)
Integericomponent index
Return Values
booleansuccesssuccess
Code
3179function Vehicle:loadComponentFromXML(component, xmlFile, key, rootPosition, i)
3180 if not self.isServer then
3181 if getRigidBodyType(component.node) == RigidBodyType.DYNAMIC then
3182 setRigidBodyType(component.node, RigidBodyType.KINEMATIC)
3183 end
3184 end
3185 link(getRootNode(), component.node)
3186 if i == 1 then
3187 rootPosition[1], rootPosition[2], rootPosition[3] = getTranslation(component.node)
3188 if rootPosition[2] ~= 0 then
3189 Logging.xmlWarning(self.xmlFile, "Y-Translation of component 1 (node 0>) has to be 0. Current value is: %.5f", rootPosition[2])
3190 end
3191 end
3192
3193 if getRigidBodyType(component.node) == RigidBodyType.STATIC then
3194 component.isStatic = true
3195 elseif getRigidBodyType(component.node) == RigidBodyType.KINEMATIC then
3196 component.isKinematic = true
3197 elseif getRigidBodyType(component.node) == RigidBodyType.DYNAMIC then
3198 component.isDynamic = true
3199 end
3200
3201 if not CollisionFlag.getHasFlagSet(component.node, CollisionFlag.VEHICLE) then
3202 Logging.xmlWarning(self.xmlFile, "Missing collision mask bit '%d'. Please add this bit to component node '%s'", CollisionFlag.getBit(CollisionFlag.VEHICLE), getName(component.node))
3203 end
3204
3205 if not CollisionFlag.getHasFlagSet(component.node, CollisionFlag.TRIGGER_VEHICLE) then
3206 Logging.xmlWarning(self.xmlFile, "Missing collision mask bit '%d'. Please add this bit to component node '%s'", CollisionFlag.getBit(CollisionFlag.TRIGGER_VEHICLE), getName(component.node))
3207 end
3208
3209 if not getVisibility(component.node) then
3210 Logging.xmlDevWarning(self.xmlFile, "Found hidden component '%s' in i3d file. Components are not allowed to be hidden!", getName(component.node))
3211 setVisibility(component.node, true)
3212 end
3213
3214 -- the position of the first component is the zero
3215 translate(component.node, -rootPosition[1], -rootPosition[2], -rootPosition[3])
3216 local x,y,z = getTranslation(component.node)
3217 local rx,ry,rz = getRotation(component.node)
3218 component.originalTranslation = {x,y,z}
3219 component.originalRotation = {rx,ry,rz}
3220
3221 component.sentTranslation = {x,y,z}
3222 component.sentRotation = {rx,ry,rz}
3223
3224 component.defaultMass = nil
3225 component.mass = nil
3226
3227 local mass = xmlFile:getValue(key.."#mass")
3228 if mass ~= nil then
3229 if mass < 10 then
3230 Logging.xmlDevWarning(self.xmlFile, "Mass is lower than 10kg for '%s'. Mass unit is kilogramms. Is this correct?", key)
3231 end
3232 if component.isDynamic then
3233 setMass(component.node, mass/1000)
3234 end
3235
3236 component.defaultMass = mass/1000
3237 component.mass = component.defaultMass
3238 component.lastMass = component.mass
3239 else
3240 Logging.xmlWarning(self.xmlFile, "Missing 'mass' for '%s'. Using default mass 500kg instead!", key)
3241 component.defaultMass = 0.5
3242 component.mass = 0.5
3243 component.lastMass = component.mass
3244 end
3245
3246 local comX, comY, comZ = xmlFile:getValue(key .. "#centerOfMass")
3247 if comX ~= nil then
3248 setCenterOfMass(component.node, comX, comY, comZ)
3249 end
3250 local count = xmlFile:getValue(key .. "#solverIterationCount")
3251 if count ~= nil then
3252 setSolverIterationCount(component.node, count)
3253 component.solverIterationCount = count
3254 end
3255 component.motorized = xmlFile:getValue(key .. "#motorized") -- Note: motorized is nil if not set in the xml, and can be set by the wheels
3256 self.vehicleNodes[component.node] = {component=component}
3257 local clipDistance = getClipDistance(component.node)
3258 if clipDistance >= 1000000 and getVisibility(component.node) then
3259 local defaultClipdistance = 300
3260 Logging.xmlWarning(self.xmlFile, "No clipdistance is set to component node '%s' (%s>). Set default clipdistance '%d'", getName(component.node), i-1, defaultClipdistance)
3261 setClipDistance(component.node, defaultClipdistance)
3262 end
3263
3264 component.collideWithAttachables = xmlFile:getValue(key.."#collideWithAttachables", false)
3265
3266 if getRigidBodyType(component.node) ~= RigidBodyType.NONE then
3267 if getLinearDamping(component.node) > 0.01 then
3268 Logging.xmlDevWarning(self.xmlFile, "Non-zero linear damping (%.4f) for component node '%s' (%s>). Is this correct?", getLinearDamping(component.node), getName(component.node), i-1)
3269 elseif getAngularDamping(component.node) > 0.05 then
3270 Logging.xmlDevWarning(self.xmlFile, "Large angular damping (%.4f) for component node '%s' (%s>). Is this correct?", getAngularDamping(component.node), getName(component.node), i-1)
3271 elseif getAngularDamping(component.node) < 0.0001 then
3272 Logging.xmlDevWarning(self.xmlFile, "Zero damping for component node '%s' (%s>). Is this correct?", getName(component.node), i-1)
3273 end
3274 end
3275
3276 local name = getName(component.node)
3277 if not name:endsWith("component"..i) then
3278 Logging.xmlDevWarning(self.xmlFile, "Name of component '%d' ('%s') does not correpond with the component naming convention! (vehicleName_componentName_component%d)", i, name, i)
3279 end
3280
3281 return true
3282end

loadComponentJointFromXML

Description
Load component joints from xml
Definition
loadComponentJointFromXML(table jointDesc, integer xmlFile, string key, Integer componentJointI, Integer jointNode, Integer index1, Integer index2)
Arguments
tablejointDescjoint desc
integerxmlFileid of xml object
stringkeykey
IntegercomponentJointIcomponent joint index
IntegerjointNodeid of joint node
Integerindex1index of component 1
Integerindex2index of component 2
Return Values
booleansuccesssuccess
Code
3294function Vehicle:loadComponentJointFromXML(jointDesc, xmlFile, key, componentJointI, jointNode, index1, index2)
3295 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key .. "#indexActor1", key .. "#nodeActor1") --FS17 to FS19
3296
3297 jointDesc.componentIndices = {index1, index2}
3298 jointDesc.jointNode = jointNode
3299 jointDesc.jointNodeActor1 = xmlFile:getValue(key.."#nodeActor1", jointNode, self.components, self.i3dMappings)
3300 if self.isServer then
3301 if self.components[index1] == nil or self.components[index2] == nil then
3302 Logging.xmlWarning(self.xmlFile, "Invalid component indices (component1: %d, component2: %d) for component joint %d. Indices start with 1!", index1, index2, componentJointI)
3303 return false
3304 end
3305
3306 local x, y, z = xmlFile:getValue( key.."#rotLimit")
3307 local rotLimits = { math.rad(Utils.getNoNil(x, 0)), math.rad(Utils.getNoNil(y, 0)), math.rad(Utils.getNoNil(z, 0)) }
3308 x, y, z = xmlFile:getValue( key.."#transLimit")
3309 local transLimits = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3310 jointDesc.rotLimit = rotLimits
3311 jointDesc.transLimit = transLimits
3312
3313 x, y, z = xmlFile:getValue( key.."#rotMinLimit")
3314 local rotMinLimits = { Utils.getNoNilRad(x, nil), Utils.getNoNilRad(y, nil), Utils.getNoNilRad(z, nil) }
3315
3316 x, y, z = xmlFile:getValue( key.."#transMinLimit")
3317 local transMinLimits = { x,y,z }
3318
3319 for i=1,3 do
3320 if rotMinLimits[i] == nil then
3321 if rotLimits[i] >= 0 then
3322 rotMinLimits[i] = -rotLimits[i]
3323 else
3324 rotMinLimits[i] = rotLimits[i]+1
3325 end
3326 end
3327 if transMinLimits[i] == nil then
3328 if transLimits[i] >= 0 then
3329 transMinLimits[i] = -transLimits[i]
3330 else
3331 transMinLimits[i] = transLimits[i]+1
3332 end
3333 end
3334 end
3335
3336 jointDesc.jointLocalPoses = {}
3337 local trans = {localToLocal(jointDesc.jointNode, self.components[index1].node, 0, 0, 0)}
3338 local rot = {localRotationToLocal(jointDesc.jointNode, self.components[index1].node, 0, 0, 0)}
3339 jointDesc.jointLocalPoses[1] = {trans=trans, rot=rot}
3340
3341 trans = {localToLocal(jointDesc.jointNodeActor1, self.components[index2].node, 0, 0, 0)}
3342 rot = {localRotationToLocal(jointDesc.jointNodeActor1, self.components[index2].node, 0, 0, 0)}
3343 jointDesc.jointLocalPoses[2] = {trans=trans, rot=rot}
3344
3345 jointDesc.rotMinLimit = rotMinLimits
3346 jointDesc.transMinLimit = transMinLimits
3347
3348 x, y, z = xmlFile:getValue( key.."#rotLimitSpring")
3349 local rotLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3350 x, y, z = xmlFile:getValue( key.."#rotLimitDamping")
3351 local rotLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }
3352 jointDesc.rotLimitSpring = rotLimitSpring
3353 jointDesc.rotLimitDamping = rotLimitDamping
3354
3355 x, y, z = xmlFile:getValue( key.."#rotLimitForceLimit")
3356 local rotLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) }
3357 x, y, z = xmlFile:getValue( key.."#transLimitForceLimit")
3358 local transLimitForceLimit = { Utils.getNoNil(x, -1), Utils.getNoNil(y, -1), Utils.getNoNil(z, -1) }
3359 jointDesc.rotLimitForceLimit = rotLimitForceLimit
3360 jointDesc.transLimitForceLimit = transLimitForceLimit
3361
3362 x, y, z = xmlFile:getValue( key.."#transLimitSpring")
3363 local transLimitSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3364 x, y, z = xmlFile:getValue( key.."#transLimitDamping")
3365 local transLimitDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }
3366 jointDesc.transLimitSpring = transLimitSpring
3367 jointDesc.transLimitDamping = transLimitDamping
3368
3369 jointDesc.zRotationXOffset = 0
3370 local zRotationNode = xmlFile:getValue(key.."#zRotationNode", nil, self.components, self.i3dMappings)
3371 if zRotationNode ~= nil then
3372 local _
3373 jointDesc.zRotationXOffset,_,_ = localToLocal(zRotationNode, jointNode, 0,0,0)
3374 end
3375
3376 jointDesc.isBreakable = xmlFile:getValue(key.."#breakable", false)
3377 if jointDesc.isBreakable then
3378 jointDesc.breakForce = xmlFile:getValue(key.."#breakForce", 10)
3379 jointDesc.breakTorque = xmlFile:getValue(key.."#breakTorque", 10)
3380 end
3381 jointDesc.enableCollision = xmlFile:getValue(key.."#enableCollision", false)
3382
3383 -- Rotational drive
3384 x, y, z = xmlFile:getValue( key.."#maxRotDriveForce")
3385 local maxRotDriveForce = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3386 x, y, z = xmlFile:getValue( key.."#rotDriveVelocity")
3387 local rotDriveVelocity = { Utils.getNoNilRad(x, nil), Utils.getNoNilRad(y, nil), Utils.getNoNilRad(z, nil) } -- convert from deg/s to rad/s
3388 x, y, z = xmlFile:getValue( key.."#rotDriveRotation")
3389 local rotDriveRotation = { Utils.getNoNilRad(x, nil), Utils.getNoNilRad(y, nil), Utils.getNoNilRad(z, nil) } -- convert from deg to rad
3390 x, y, z = xmlFile:getValue( key.."#rotDriveSpring")
3391 local rotDriveSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3392 x, y, z = xmlFile:getValue( key.."#rotDriveDamping")
3393 local rotDriveDamping = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3394
3395 jointDesc.rotDriveVelocity = rotDriveVelocity
3396 jointDesc.rotDriveRotation = rotDriveRotation
3397 jointDesc.rotDriveSpring = rotDriveSpring
3398 jointDesc.rotDriveDamping = rotDriveDamping
3399 jointDesc.maxRotDriveForce = maxRotDriveForce
3400
3401 -- Translational drive
3402 x, y, z = xmlFile:getValue( key.."#maxTransDriveForce")
3403 local maxTransDriveForce = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3404 x, y, z = xmlFile:getValue( key.."#transDriveVelocity")
3405 local transDriveVelocity = { x,y,z }
3406 x, y, z = xmlFile:getValue( key.."#transDrivePosition")
3407 local transDrivePosition = { x,y,z }
3408 x, y, z = xmlFile:getValue( key.."#transDriveSpring")
3409 local transDriveSpring = { Utils.getNoNil(x, 0), Utils.getNoNil(y, 0), Utils.getNoNil(z, 0) }
3410 x, y, z = xmlFile:getValue( key.."#transDriveDamping")
3411 local transDriveDamping = { Utils.getNoNil(x, 1), Utils.getNoNil(y, 1), Utils.getNoNil(z, 1) }
3412
3413 jointDesc.transDriveVelocity = transDriveVelocity
3414 jointDesc.transDrivePosition = transDrivePosition
3415 jointDesc.transDriveSpring = transDriveSpring
3416 jointDesc.transDriveDamping = transDriveDamping
3417 jointDesc.maxTransDriveForce = maxTransDriveForce
3418
3419 jointDesc.initComponentPosition = xmlFile:getValue(key.."#initComponentPosition", true)
3420
3421 jointDesc.jointIndex = 0
3422 end
3423
3424 return true
3425end

loadFinished

Description
Definition
loadFinished()
Code
681function Vehicle:loadFinished(i3dNode, failedReason, arguments, i3dLoadingId)
682 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_OK)
683 self:setLoadingStep(Vehicle.LOAD_STEP_LOAD)
684
685 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.forcedMapHotspotType", "vehicle.base.mapHotspot#type") --FS17 to FS19
686 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.base.forcedMapHotspotType", "vehicle.base.mapHotspot#type") --FS17 to FS19
687 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.speedLimit#value", "vehicle.base.speedLimit#value") --FS17 to FS19
688 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.steeringAxleNode#index", "vehicle.base.steeringAxle#node") --FS17 to FS19
689 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.size#width", "vehicle.base.size#width") --FS17 to FS19
690 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.size#length", "vehicle.base.size#length") --FS17 to FS19
691 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.size#widthOffset", "vehicle.base.size#widthOffset") --FS17 to FS19
692 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.size#lengthOffset", "vehicle.base.size#lengthOffset") --FS17 to FS19
693 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.typeDesc", "vehicle.base.typeDesc") --FS17 to FS19
694 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.components", "vehicle.base.components") --FS17 to FS19
695 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.components.component", "vehicle.base.components.component") --FS17 to FS19
696 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.base.components.component1", "vehicle.base.components.component") --FS17 to FS19
697
698 local position = arguments.position
699 local rotation = arguments.rotation
700 local propertyState = arguments.propertyState
701 local ownerFarmId = arguments.ownerFarmId
702 local price = arguments.price
703 local savegame = arguments.savegame
704 local asyncCallbackFunction = arguments.asyncCallbackFunction
705 local asyncCallbackObject = arguments.asyncCallbackObject
706 local asyncCallbackArguments = arguments.asyncCallbackArguments
707 local componentPositions = arguments.componentPositions
708
709 if i3dNode == 0 then
710 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
711 Logging.xmlError(self.xmlFile, "Vehicle i3d loading failed!")
712 asyncCallbackFunction(asyncCallbackObject, self, self.loadingState, asyncCallbackArguments)
713 return
714 end
715
716 if savegame ~= nil then
717 local i = 0
718 while true do
719 local key = string.format(savegame.key..".boughtConfiguration(%d)", i)
720 if not savegame.xmlFile:hasProperty(key) then
721 break
722 end
723 local name = savegame.xmlFile:getValue(key.."#name")
724 local id = savegame.xmlFile:getValue(key.."#id")
725 ConfigurationUtil.addBoughtConfiguration(self, name, ConfigurationUtil.getConfigIdBySaveId(self.configFileName, name, id))
726 i = i + 1
727 end
728
729 self.tourId = nil
730 local tourId = savegame.xmlFile:getValue(savegame.key.."#tourId")
731 if tourId ~= nil then
732 self.tourId = tourId
733 if g_currentMission ~= nil then
734 g_currentMission.guidedTour:addVehicle(self, self.tourId)
735 end
736 end
737 end
738
739 self.age = 0
740 self.propertyState = propertyState
741 self:setOwnerFarmId(ownerFarmId, true)
742
743 if savegame ~= nil then
744 -- Load this early: it used by the vehicle load functions already
745 local farmId = savegame.xmlFile:getValue(savegame.key .. "#farmId", AccessHandler.EVERYONE)
746 if g_farmManager.spFarmWasMerged and farmId ~= AccessHandler.EVERYONE then
747 farmId = FarmManager.SINGLEPLAYER_FARM_ID
748 end
749 self:setOwnerFarmId(farmId, true)
750 end
751
752 self.price = price
753 if self.price == 0 or self.price == nil then
754 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
755 self.price = StoreItemUtil.getDefaultPrice(storeItem, self.configurations)
756 end
757 self.typeDesc = self.xmlFile:getValue("vehicle.base.typeDesc", "TypeDescription", self.customEnvironment, true)
758 self.synchronizePosition = self.xmlFile:getValue("vehicle.base.synchronizePosition", true)
759 self.highPrecisionPositionSynchronization = false
760 self.supportsPickUp = self.xmlFile:getValue("vehicle.base.supportsPickUp", self.isPallet)
761 self.canBeReset = self.xmlFile:getValue("vehicle.base.canBeReset", true)
762 self.showInVehicleMenu = self.xmlFile:getValue("vehicle.base.showInVehicleMenu", true)
763
764
765 self.rootNode = getChildAt(i3dNode, 0)
766 self.serverMass = 0
767 self.precalculatedMass = 0 -- mass of vehicle that is not included in serverMass (e.g. wheels)
768 self.isMassDirty = false
769
770 self.currentUpdateDistance = 0
771 self.lastDistanceToCamera = 0
772 self.lodDistanceCoeff = getLODDistanceCoeff()
773
774 self.components = {}
775 self.vehicleNodes = {}
776
777 local realNumComponents = getNumOfChildren(i3dNode)
778 local rootPosition = {0,0,0}
779 local i = 1
780
781 local numComponents = self.xmlFile:getValue("vehicle.base.components#numComponents", realNumComponents)
782 self.maxComponentMass = self.xmlFile:getValue("vehicle.base.components#maxMass", math.huge) / 1000
783
784 while true do
785 local namei = string.format("vehicle.base.components.component(%d)", i - 1)
786 if not self.xmlFile:hasProperty(namei) then
787 break
788 end
789 if i > numComponents then
790 Logging.xmlWarning(self.xmlFile, "Invalid components count. I3D file has '%d' components, but tried to load component no. '%d'!", numComponents, i+1)
791 break
792 end
793
794 local component = {node = getChildAt(i3dNode, 0)}
795
796 if self:loadComponentFromXML(component, self.xmlFile, namei, rootPosition, i) then
797 local x,y,z = getWorldTranslation(component.node)
798 local qx,qy,qz,qw = getWorldQuaternion(component.node)
799 component.networkInterpolators = {}
800 component.networkInterpolators.position = InterpolatorPosition.new(x, y, z)
801 component.networkInterpolators.quaternion = InterpolatorQuaternion.new(qx, qy, qz, qw)
802 table.insert(self.components, component)
803 end
804 i = i + 1
805 end
806 delete(i3dNode)
807
808 self.numComponents = #self.components
809 if numComponents ~= self.numComponents then
810 Logging.xmlWarning(self.xmlFile, "I3D file offers '%d' objects, but '%d' components have been loaded!", numComponents, self.numComponents)
811 end
812
813 if self.numComponents == 0 then
814 Logging.xmlWarning(self.xmlFile, "No components defined for vehicle!")
815
816 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_ERROR)
817 asyncCallbackFunction(asyncCallbackObject, self, self.loadingState, asyncCallbackArguments)
818 return
819 end
820
821 self.defaultMass = 0
822 for j=1, #self.components do
823 self.defaultMass = self.defaultMass + self.components[j].defaultMass
824 end
825
826 -- load i3d mappings
827 self.i3dMappings = {}
828 I3DUtil.loadI3DMapping(self.xmlFile, "vehicle", self.components, self.i3dMappings, realNumComponents)
829
830 -- need to be defined in vehicle because all vehicles can define a steering axle ref node
831 self.steeringAxleNode = self.xmlFile:getValue("vehicle.base.steeringAxle#node", nil, self.components, self.i3dMappings)
832 if self.steeringAxleNode == nil then
833 self.steeringAxleNode = self.components[1].node
834 end
835
836 self:loadSchemaOverlay(self.xmlFile)
837
838 -- load component joints
839 self.componentJoints = {}
840
841 local componentJointI = 0
842 while true do
843 local key = string.format("vehicle.base.components.joint(%d)", componentJointI)
844 local index1 = self.xmlFile:getValue(key.."#component1")
845 local index2 = self.xmlFile:getValue(key.."#component2")
846
847 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, key .. "#index", key .. "#node") --FS17 to FS19
848
849 if index1 == nil or index2 == nil then
850 break
851 end
852
853 local jointNode = self.xmlFile:getValue(key.."#node", nil, self.components, self.i3dMappings)
854 if jointNode ~= nil and jointNode ~= 0 then
855 local jointDesc = {}
856 if self:loadComponentJointFromXML(jointDesc, self.xmlFile, key, componentJointI, jointNode, index1, index2) then
857 table.insert(self.componentJoints, jointDesc)
858 jointDesc.index = #self.componentJoints
859 end
860 end
861 componentJointI = componentJointI +1
862 end
863
864 local collisionPairI = 0
865 self.collisionPairs = {}
866 while true do
867 local key = string.format("vehicle.base.components.collisionPair(%d)", collisionPairI)
868 if not self.xmlFile:hasProperty(key) then
869 break
870 end
871 local enabled = self.xmlFile:getValue(key.."#enabled")
872 local index1 = self.xmlFile:getValue(key.."#component1")
873 local index2 = self.xmlFile:getValue(key.."#component2")
874 if index1 ~= nil and index2 ~= nil and enabled ~= nil then
875 local component1 = self.components[index1]
876 local component2 = self.components[index2]
877 if component1 ~= nil and component2 ~= nil then
878 if not enabled then
879 table.insert(self.collisionPairs, {component1=component1, component2=component2, enabled=enabled})
880 end
881 else
882 Logging.xmlWarning(self.xmlFile, "Failed to load collision pair '%s'. Unknown component indices. Indices start with 1.", key)
883 end
884 end
885 collisionPairI = collisionPairI +1
886 end
887
888 self.supportsRadio = self.xmlFile:getValue("vehicle.base.supportsRadio", true)
889 self.allowsInput = self.xmlFile:getValue("vehicle.base.input#allowed", true)
890 self.size = StoreItemUtil.getSizeValuesFromXML(self.xmlFile, "vehicle", 0, self.configurations)
891 self.yRotationOffset = self.xmlFile:getValue("vehicle.base.size#yRotation", 0.0)
892 self.showTailwaterDepthWarning = false
893 self.thresholdTailwaterDepthWarning = self.xmlFile:getValue("vehicle.base.tailwaterDepth#warning", 1.0)
894 self.thresholdTailwaterDepth = self.xmlFile:getValue("vehicle.base.tailwaterDepth#threshold", 2.5)
895 self.networkTimeInterpolator = InterpolationTime.new(1.2)
896 self.movingDirection = 0
897 self.requiredDriveMode = 1
898 self.rotatedTime = 0
899 self.isBroken = false
900 self.forceIsActive = false
901 self.finishedFirstUpdate = false
902 self.lastPosition = nil
903 self.lastSpeed = 0
904 self.lastSpeedReal = 0
905 self.lastSignedSpeed = 0
906 self.lastSignedSpeedReal = 0
907 self.lastMovedDistance = 0
908 self.lastSpeedAcceleration = 0
909 self.lastMoveTime = -10000
910 self.operatingTime = 0
911 self.isSelectable = true
912
913 self.isInWater = false
914 self.isInShallowWater = false
915 self.isInMediumWater = false
916 self.waterY = -200
917 self.tailwaterDepth = -200
918 self.waterCheckPosition = {0, 0, 0}
919
920 self.selectionObjects = {}
921 self.currentSelection = {object=nil, index=0, subIndex=1}
922 self.selectionObject = {index=0, isSelected=false, vehicle=self, subSelections={}}
923
924 self.childVehicles = {self} -- table including all attached children and the vehicle itself
925 self.rootVehicle = self
926
927 self.registeredActionEvents = {}
928 self.actionEventUpdateRequested = false
929 self.vehicleDirtyFlag = self:getNextDirtyFlag()
930
931 if g_currentMission ~= nil and g_currentMission.environment ~= nil then
932 g_messageCenter:subscribe(MessageType.DAY_CHANGED, self.dayChanged, self)
933 g_messageCenter:subscribe(MessageType.PERIOD_CHANGED, self.periodChanged, self)
934 end
935
936 self.mapHotspotAvailable = self.xmlFile:getValue("vehicle.base.mapHotspot#available", true)
937 if self.mapHotspotAvailable then
938 local hotspotType = self.xmlFile:getValue("vehicle.base.mapHotspot#type", "OTHER")
939 self.mapHotspotType = VehicleHotspot.getTypeByName(hotspotType) or VehicleHotspot.TYPE.OTHER
940 self.mapHotspotHasDirection = self.xmlFile:getValue("vehicle.base.mapHotspot#hasDirection", true)
941 end
942
943 local speedLimit = math.huge
944 for i=1, #self.specializations do
945 if self.specializations[i].getDefaultSpeedLimit ~= nil then
946 local limit = self.specializations[i].getDefaultSpeedLimit(self)
947 speedLimit = math.min(limit, speedLimit)
948 end
949 end
950
951 self.checkSpeedLimit = speedLimit == math.huge
952 self.speedLimit = self.xmlFile:getValue("vehicle.base.speedLimit#value", speedLimit)
953
954 --
955 local objectChanges = {}
956 ObjectChangeUtil.loadObjectChangeFromXML(self.xmlFile, "vehicle.base.objectChanges", objectChanges, self.components, self)
957 ObjectChangeUtil.setObjectChanges(objectChanges, true)
958
959 if self.configurations["vehicleType"] ~= nil then
960 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.vehicleTypeConfigurations.vehicleTypeConfiguration", self.configurations["vehicleType"], self.components, self)
961 end
962
963 local preLoadDesignConfigurations = self.xmlFile:getValue("vehicle.designConfigurations#preLoad", false)
964 if preLoadDesignConfigurations then
965 if self.configurations["design"] ~= nil then
966 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.designConfigurations.designConfiguration", self.configurations["design"], self.components, self)
967 end
968 end
969
970
971 SpecializationUtil.raiseEvent(self, "onLoad", savegame)
972 if self.loadingState ~= VehicleLoadingUtil.VEHICLE_LOAD_OK then
973 Logging.xmlError(self.xmlFile, "Vehicle loading failed!")
974 asyncCallbackFunction(asyncCallbackObject, self, self.loadingState, asyncCallbackArguments)
975 return
976 end
977
978 if self.actionController ~= nil then
979 self.actionController:load(savegame)
980 end
981
982 SpecializationUtil.raiseEvent(self, "onRootVehicleChanged", self)
983
984 -- apply material from all configurations
985 for configName, configId in pairs(self.configurations) do
986 ConfigurationUtil.applyConfigMaterials(self, self.xmlFile, configName, configId)
987 end
988
989 -- apply design
990 if not preLoadDesignConfigurations then
991 if self.configurations["design"] ~= nil then
992 ObjectChangeUtil.updateObjectChanges(self.xmlFile, "vehicle.designConfigurations.designConfiguration", self.configurations["design"], self.components, self)
993 end
994 end
995
996 for j=2, 8 do
997 local name = string.format("design%d", j)
998 if self.configurations[name] ~= nil then
999 ObjectChangeUtil.updateObjectChanges(self.xmlFile, string.format("vehicle.%sConfigurations.%sConfiguration", name, name), self.configurations[name], self.components, self)
1000 end
1001 end
1002
1003 -- do coloring
1004 if self.configurations["baseColor"] ~= nil then
1005 ConfigurationUtil.setColor(self, self.xmlFile, "baseColor", self.configurations["baseColor"])
1006 end
1007
1008 -- do coloring
1009 if self.configurations["designColor"] ~= nil then
1010 ConfigurationUtil.setColor(self, self.xmlFile, "designColor", self.configurations["designColor"])
1011 end
1012
1013 -- move all components that are joint to other components to the joint node, so all specializations can move them in there postLoad
1014 if self.isServer then
1015 for _, jointDesc in pairs(self.componentJoints) do
1016 if jointDesc.initComponentPosition then
1017 local component2 = self.components[jointDesc.componentIndices[2]].node
1018 local jointNode = jointDesc.jointNode
1019
1020 if self:getParentComponent(jointNode) == component2 then
1021 jointNode = jointDesc.jointNodeActor1
1022 end
1023
1024 if self:getParentComponent(jointNode) ~= component2 then
1025 setTranslation(component2, localToLocal(component2, jointNode, 0, 0, 0))
1026 setRotation(component2, localRotationToLocal(component2, jointNode, 0, 0, 0))
1027 link(jointNode, component2)
1028 end
1029 end
1030 end
1031 end
1032
1033 self:setLoadingStep(Vehicle.LOAD_STEP_POST_LOAD)
1034
1035 SpecializationUtil.raiseEvent(self, "onPostLoad", savegame)
1036 if self.loadingState ~= VehicleLoadingUtil.VEHICLE_LOAD_OK then
1037 Logging.xmlError(self.xmlFile, "Vehicle post-loading failed!")
1038 asyncCallbackFunction(asyncCallbackObject, self, self.loadingState, asyncCallbackArguments)
1039 return
1040 end
1041
1042 -- move all components that are joint to other components back to the world, so the changes from the specs post load is applied to the world trans/rot
1043 if self.isServer then
1044 for _, jointDesc in pairs(self.componentJoints) do
1045 if jointDesc.initComponentPosition then
1046 local component2 = self.components[jointDesc.componentIndices[2]]
1047 local jointNode = jointDesc.jointNode
1048
1049 if self:getParentComponent(jointNode) == component2.node then
1050 jointNode = jointDesc.jointNodeActor1
1051 end
1052
1053 if self:getParentComponent(jointNode) ~= component2.node then
1054 if getParent(component2.node) == jointNode then
1055 local ox, oy, oz = 0, 0, 0
1056 if jointDesc.jointNodeActor1 ~= jointDesc.jointNode then
1057 local x1, y1, z1 = localToLocal(jointDesc.jointNode, component2.node, 0, 0, 0)
1058 local x2, y2, z2 = localToLocal(jointDesc.jointNodeActor1, component2.node, 0, 0, 0)
1059 ox, oy, oz = x1-x2, y1-y2, z1-z2
1060 end
1061
1062 local x, y, z = localToWorld(component2.node, ox, oy, oz)
1063 local rx, ry, rz = localRotationToWorld(component2.node, 0, 0, 0)
1064
1065 link(getRootNode(), component2.node)
1066 setWorldTranslation(component2.node, x, y, z)
1067 setWorldRotation(component2.node, rx, ry, rz)
1068
1069 component2.originalTranslation = {x, y, z}
1070 component2.originalRotation = {rx, ry, rz}
1071
1072 component2.sentTranslation = {x, y, z}
1073 component2.sentRotation = {rx, ry, rz}
1074 end
1075 end
1076 end
1077 end
1078
1079 for _, jointDesc in pairs(self.componentJoints) do
1080 self:setComponentJointFrame(jointDesc, 0)
1081 self:setComponentJointFrame(jointDesc, 1)
1082 end
1083 end
1084
1085 if savegame ~= nil then
1086 self.currentSavegameId = savegame.xmlFile:getValue(savegame.key .. "#id")
1087 self.age = savegame.xmlFile:getValue(savegame.key.."#age", 0)
1088 self.price = savegame.xmlFile:getValue(savegame.key.."#price", self.price)
1089 self.propertyState = savegame.xmlFile:getValue(savegame.key.."#propertyState", self.propertyState)
1090 self.activeMissionId = savegame.xmlFile:getValue(savegame.key .. "#activeMissionId")
1091
1092 local operatingTime = savegame.xmlFile:getValue(savegame.key .. "#operatingTime", self.operatingTime) * 1000
1093 self:setOperatingTime(operatingTime, true)
1094 local findPlace = savegame.resetVehicles and not savegame.keepPosition
1095 if not findPlace then
1096 local isAbsolute = savegame.xmlFile:getValue(savegame.key.."#isAbsolute", false)
1097 if isAbsolute then
1098 local componentPosition = {}
1099 local i = 0
1100 while true do
1101 local componentKey = string.format(savegame.key..".component(%d)", i)
1102 if not savegame.xmlFile:hasProperty(componentKey) then
1103 break
1104 end
1105 local componentIndex = savegame.xmlFile:getValue(componentKey.."#index")
1106 local x, y, z = savegame.xmlFile:getValue(componentKey.."#position")
1107 local xRot, yRot, zRot = savegame.xmlFile:getValue(componentKey.."#rotation")
1108 if x == nil or y == nil or z == nil or xRot == nil or yRot == nil or zRot == nil then
1109 findPlace = true
1110 break
1111 end
1112 if componentPosition[componentIndex] ~= nil then
1113 Logging.xmlWarning(savegame.xmlFile, "Duplicate component index '%s' in '%s' (%s)!", componentIndex, savegame.key, self.xmlFile.filename)
1114 else
1115 componentPosition[componentIndex] = {x=x, y=y, z=z, xRot=xRot, yRot=yRot, zRot=zRot}
1116 end
1117 i = i + 1
1118 end
1119 local numSavegameComponents = table.size(componentPosition)
1120 if numSavegameComponents == #self.components then
1121 for j=1, #self.components do
1122 local p = componentPosition[j]
1123 self:setWorldPosition(p.x, p.y, p.z, p.xRot, p.yRot, p.zRot, j, true)
1124 end
1125 elseif numSavegameComponents >= 1 then
1126 local p = componentPosition[1]
1127 self:setAbsolutePosition(p.x, p.y, p.z, p.xRot, p.yRot, p.zRot)
1128 Logging.xmlWarning(savegame.xmlFile, "Invalid component count found in savegame for '%s'. Reset component positions.", self.xmlFile.filename)
1129 else
1130 findPlace = true
1131 Logging.xmlWarning(savegame.xmlFile, "No component positions found in savegame for '%s'!", self.xmlFile.filename)
1132 end
1133 else
1134 local yOffset = savegame.xmlFile:getValue(savegame.key.."#yOffset")
1135 local xPosition = savegame.xmlFile:getValue(savegame.key.."#xPosition")
1136 local zPosition = savegame.xmlFile:getValue(savegame.key.."#zPosition")
1137 local yRotation = savegame.xmlFile:getValue(savegame.key.."#yRotation")
1138 if yOffset == nil or xPosition == nil or zPosition == nil or yRotation == nil then
1139 findPlace = true
1140 else
1141 self:setRelativePosition(xPosition, yOffset, zPosition, math.rad(yRotation))
1142 end
1143 end
1144 end
1145 if findPlace then
1146 if savegame.resetVehicles and not savegame.keepPosition then
1147 local x, _, z, place, width, offset = PlacementUtil.getPlace(g_currentMission:getResetPlaces(), self.size, g_currentMission.usedLoadPlaces, true, false, true)
1148 if x ~= nil then
1149 local yRot = MathUtil.getYRotationFromDirection(place.dirPerpX, place.dirPerpZ)
1150 PlacementUtil.markPlaceUsed(g_currentMission.usedLoadPlaces, place, width)
1151 self:setRelativePosition(x, offset, z, yRot)
1152 else
1153 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_NO_SPACE)
1154 asyncCallbackFunction(asyncCallbackObject, self, self.loadingState, asyncCallbackArguments)
1155 return
1156 end
1157 else
1158 self:setLoadingState(VehicleLoadingUtil.VEHICLE_LOAD_DELAYED)
1159 end
1160 end
1161 else
1162 self:setAbsolutePosition(position.posX, self:getLimitedVehicleYPosition(position), position.posZ, rotation.rotX, rotation.rotY, rotation.rotZ, componentPositions)
1163 end
1164
1165 self:updateSelectableObjects()
1166 self:setSelectedVehicle(self, nil, true)
1167
1168 if self.rootVehicle == self then
1169 if savegame ~= nil then
1170 self.loadedSelectedObjectIndex = savegame.xmlFile:getValue(savegame.key.."#selectedObjectIndex")
1171 self.loadedSubSelectedObjectIndex = savegame.xmlFile:getValue(savegame.key.."#subSelectedObjectIndex")
1172 end
1173 end
1174
1175 if componentPositions ~= nil and savegame == nil then
1176 self:setAbsolutePosition(position.posX, self:getLimitedVehicleYPosition(position), position.posZ, rotation.rotX, rotation.rotY, rotation.rotZ, componentPositions)
1177 end
1178
1179 SpecializationUtil.raiseEvent(self, "onPreLoadFinished", self.savegame)
1180
1181 self:addNodeObjectMapping(g_currentMission.nodeToObject)
1182
1183 if not self.subLoadingTasksFinished then
1184 self:setLoadingStep(Vehicle.LOAD_STEP_AWAIT_SUB_I3D)
1185 end
1186
1187 self.syncVehicleLoadingFinished = true
1188
1189 self.subLoadingTasksFinishedAsyncData = {asyncCallbackFunction=asyncCallbackFunction,
1190 asyncCallbackObject=asyncCallbackObject,
1191 asyncCallbackArguments=asyncCallbackArguments}
1192 -- hide vehicle and remove from physics as long as the sub tasks are not finished
1193 self:setVisibility(false)
1194
1195 self:tryFinishLoading()
1196end

loadObjectChangeValuesFromXML

Description
Load object change from xml
Definition
loadObjectChangeValuesFromXML(integer xmlFile, string key, integer node, table object)
Arguments
integerxmlFileid of xml object
stringkeykey
integernodenode id
tableobjectobject
Code
3956function Vehicle:loadObjectChangeValuesFromXML(xmlFile, key, node, object)
3957end

loadSchemaOverlay

Description
Load schema overlay data from xml file The HUD draws the schema from this information and handles all required visual components.
Definition
loadSchemaOverlay(integer xmlFile)
Arguments
integerxmlFileid of xml object
Code
3507function Vehicle:loadSchemaOverlay(xmlFile)
3508 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#file") --FS17 to FS19
3509 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#width") --FS17 to FS19
3510 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#height") --FS17 to FS19
3511 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#invisibleBorderRight", "vehicle.base.schemaOverlay#invisibleBorderRight") --FS17 to FS19
3512 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#invisibleBorderLeft", "vehicle.base.schemaOverlay#invisibleBorderLeft") --FS17 to FS19
3513 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#attacherJointPosition", "vehicle.base.schemaOverlay#attacherJointPosition") --FS17 to FS19
3514 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#basePosition", "vehicle.base.schemaOverlay#basePosition") --FS17 to FS19
3515 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#fileSelected") --FS17 to FS19
3516 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#fileTurnedOn") --FS17 to FS19
3517 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.schemaOverlay#fileSelectedTurnedOn") --FS17 to FS19
3518
3519 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.base.schemaOverlay.default#name", "vehicle.base.schemaOverlay#name") --FS19 to FS22
3520 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.base.schemaOverlay.turnedOn#name") --FS19 to FS22
3521 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.base.schemaOverlay.selected#name") --FS19 to FS22
3522 XMLUtil.checkDeprecatedXMLElements(self.xmlFile, "vehicle.base.schemaOverlay.turnedOnSelected#name") --FS19 to FS22
3523
3524 if xmlFile:hasProperty("vehicle.base.schemaOverlay") then
3525 XMLUtil.checkDeprecatedXMLElements(xmlFile, "vehicle.schemaOverlay.attacherJoint", "vehicle.attacherJoints.attacherJoint.schema") -- FS17
3526
3527 local x, y = xmlFile:getValue("vehicle.base.schemaOverlay#attacherJointPosition")
3528 local baseX, baseY = xmlFile:getValue("vehicle.base.schemaOverlay#basePosition")
3529
3530 if baseX == nil then
3531 baseX = x
3532 end
3533
3534 if baseY == nil then
3535 baseY = y
3536 end
3537
3538 local schemaName = xmlFile:getValue("vehicle.base.schemaOverlay#name", "")
3539
3540 local modPrefix = self.customEnvironment or ""
3541 schemaName = Vehicle.prefixSchemaOverlayName(schemaName, modPrefix)
3542
3543 self.schemaOverlay = VehicleSchemaOverlayData.new(
3544 baseX, baseY,
3545 schemaName,
3546 xmlFile:getValue("vehicle.base.schemaOverlay#invisibleBorderRight"),
3547 xmlFile:getValue("vehicle.base.schemaOverlay#invisibleBorderLeft"))
3548 end
3549end

loadSpecValueAdditionalWeight

Description
Definition
loadSpecValueAdditionalWeight()
Code
4322function Vehicle.loadSpecValueAdditionalWeight(xmlFile, customEnvironment, baseDir)
4323 local maxWeight = xmlFile:getValue("vehicle.base.components#maxMass")
4324 if maxWeight ~= nil then
4325 return maxWeight / 1000
4326 end
4327end

loadSpecValueCombinations

Description
Definition
loadSpecValueCombinations()
Code
4354function Vehicle.loadSpecValueCombinations(xmlFile, customEnvironment, baseDirectory)
4355 local combinations = {}
4356
4357 xmlFile:iterate("vehicle.storeData.specs.combination", function(index, key)
4358 local combinationData = {}
4359 local xmlFilename = xmlFile:getValue(key .. "#xmlFilename")
4360 if xmlFilename ~= nil then
4361 combinationData.xmlFilename = Utils.getFilename(xmlFilename)
4362 combinationData.customXMLFilename = Utils.getFilename(xmlFilename, baseDirectory)
4363 end
4364
4365 local filterCategoryStr = xmlFile:getValue(key .. "#filterCategory")
4366 if filterCategoryStr ~= nil then
4367 combinationData.filterCategories = filterCategoryStr:split(" ")
4368 end
4369
4370 combinationData.filterSpec = xmlFile:getValue(key .. "#filterSpec")
4371 combinationData.filterSpecMin = xmlFile:getValue(key .. "#filterSpecMin", 0)
4372 combinationData.filterSpecMax = xmlFile:getValue(key .. "#filterSpecMax", 1)
4373
4374 if combinationData.xmlFilename ~= nil or combinationData.filterCategories ~= nil or combinationData.filterSpec then
4375 table.insert(combinations, combinationData)
4376 end
4377 end)
4378
4379 return combinations
4380end

loadSpecValueSpeedLimit

Description
Definition
loadSpecValueSpeedLimit()
Code
4216function Vehicle.loadSpecValueSpeedLimit(xmlFile, customEnvironment, baseDir)
4217 return xmlFile:getValue("vehicle.base.speedLimit#value")
4218end

loadSpecValueWeight

Description
Definition
loadSpecValueWeight()
Code
4231function Vehicle.loadSpecValueWeight(xmlFile, customEnvironment, baseDir)
4232 local massData = {}
4233 massData.componentMass = 0
4234 xmlFile:iterate("vehicle.base.components.component", function(index, key)
4235 local mass = xmlFile:getValue(key .. "#mass", 0) / 1000
4236
4237 massData.componentMass = massData.componentMass + mass
4238 end)
4239
4240 massData.fillUnitMassData = FillUnit.loadSpecValueFillUnitMassData(xmlFile, customEnvironment, baseDir)
4241 massData.wheelMassDefaultConfig = Wheels.loadSpecValueWheelWeight(xmlFile, customEnvironment, baseDir)
4242
4243 local configMin, configMax
4244 massData.storeDataConfigs = {}
4245 xmlFile:iterate("vehicle.storeData.specs.weight.config", function(index, key)
4246 local config = {}
4247 config.name = xmlFile:getValue(key .. "#name")
4248 if config.name ~= nil then
4249 config.index = xmlFile:getValue(key .. "#index", 1)
4250 config.value = xmlFile:getValue(key .. "#value", 0) / 1000
4251
4252 configMin = math.min(configMin or math.huge, config.value * 1000)
4253 configMax = math.max(configMax or -math.huge, config.value * 1000)
4254
4255 table.insert(massData.storeDataConfigs, config)
4256 end
4257 end)
4258
4259 if #massData.storeDataConfigs == 0 then
4260 massData.storeDataConfigs = nil
4261 end
4262
4263 if not xmlFile:getValue("vehicle.storeData.specs.weight#ignore", false) then
4264 massData.storeDataMin = xmlFile:getValue("vehicle.storeData.specs.weight#minValue", configMin)
4265 massData.storeDataMax = xmlFile:getValue("vehicle.storeData.specs.weight#maxValue", configMax)
4266
4267 if massData.componentMass > 0 or massData.storeDataMin ~= nil then
4268 return massData
4269 end
4270 end
4271end

loadSpecValueWorkingWidth

Description
Definition
loadSpecValueWorkingWidth()
Code
4121function Vehicle.loadSpecValueWorkingWidth(xmlFile, customEnvironment, baseDir)
4122 return xmlFile:getValue("vehicle.storeData.specs.workingWidth")
4123end

loadSpecValueWorkingWidthConfig

Description
Definition
loadSpecValueWorkingWidthConfig()
Code
4136function Vehicle.loadSpecValueWorkingWidthConfig(xmlFile, customEnvironment, baseDir)
4137 local workingWidths = {}
4138 local isValid = false
4139
4140 for name, id in pairs(g_configurationManager:getConfigurations()) do
4141 local specializationKey = g_configurationManager:getConfigurationAttribute(name, "xmlKey")
4142 if specializationKey ~= nil then
4143 specializationKey = "." .. specializationKey
4144 else
4145 specializationKey = ""
4146 end
4147
4148 local configrationsKey = string.format("vehicle%s.%sConfigurations", specializationKey, name)
4149
4150 workingWidths[name] = {}
4151
4152 local i = 0
4153 while true do
4154 local baseKey = string.format("%s.%sConfiguration(%d)", configrationsKey, name, i)
4155 if not xmlFile:hasProperty(baseKey) then
4156 break
4157 end
4158
4159 workingWidths[name][i+1] = xmlFile:getValue(baseKey.."#workingWidth")
4160 if workingWidths[name][i+1] ~= nil then
4161 isValid = true
4162 end
4163
4164 i = i + 1
4165 end
4166 end
4167
4168 if isValid then
4169 return workingWidths
4170 end
4171end

loadSubSharedI3DFile

Description
Definition
loadSubSharedI3DFile()
Code
1200function Vehicle:loadSubSharedI3DFile(filename, callOnCreate, addToPhysics, asyncCallbackFunction, asyncCallbackObject, asyncCallbackArguments)
1201 if asyncCallbackFunction ~= nil and not self.syncVehicleLoadingFinished then
1202 local targetAsyncCallbackFunction = asyncCallbackFunction
1203 asyncCallbackFunction = function(target, i3dNode, ...)
1204 self.numPendingSubLoadingTasks = self.numPendingSubLoadingTasks - 1
1205 self.subLoadingTasksFinished = self.numPendingSubLoadingTasks == 0
1206
1207 if self.isDeleted or self.isDeleting then
1208 delete(i3dNode)
1209 targetAsyncCallbackFunction(target, 0, ...)
1210 return
1211 else
1212 targetAsyncCallbackFunction(target, i3dNode, ...)
1213
1214 if self.syncVehicleLoadingFinished then
1215 self:tryFinishLoading()
1216 end
1217 end
1218 end
1219
1220 self.subLoadingTasksFinished = false
1221 self.numPendingSubLoadingTasks = self.numPendingSubLoadingTasks + 1
1222 end
1223
1224 local sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(filename, callOnCreate, addToPhysics, asyncCallbackFunction, asyncCallbackObject, asyncCallbackArguments)
1225
1226 return sharedLoadRequestId
1227end

new

Description
Definition
new()
Code
498function Vehicle.new(isServer, isClient, customMt)
499
500 local self = Object.new(isServer, isClient, customMt or Vehicle_mt)
501
502 self.finishedLoading = false
503 self.isAddedToMission = false
504 self.isDeleted = false
505 self.updateLoopIndex = -1
506 self.sharedLoadRequestId = nil
507 self.loadingState = VehicleLoadingUtil.VEHICLE_LOAD_OK
508 self.loadingStep = Vehicle.LOAD_STEP_CREATED
509
510 self.syncVehicleLoadingFinished = false
511 self.subLoadingTasksFinished = true
512 self.numPendingSubLoadingTasks = 0
513
514 self.synchronizedConnections = {} -- start update stream if connection to client was synchronized
515
516 self.actionController = VehicleActionController.new(self)
517
518 self.tireTrackSystem = g_currentMission.tireTrackSystem
519
520 return self
521end

onVehicleWakeUpCallback

Description
Definition
onVehicleWakeUpCallback()
Code
3735function Vehicle:onVehicleWakeUpCallback(id)
3736 self:raiseActive()
3737end

onWaterRaycastCallback

Description
Definition
onWaterRaycastCallback()
Code
2480function Vehicle:onWaterRaycastCallback(waterY, args)
2481 local y = self.waterCheckPosition[2]
2482 waterY = waterY or -2000
2483 self.waterY = waterY
2484 self.isInWater = waterY > y
2485 self.isInShallowWater = false
2486 self.isInMediumWater = false
2487 if self.isInWater then
2488 local x, z = self.waterCheckPosition[1], self.waterCheckPosition[3]
2489 local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, x, 0, z)
2490 local waterDepth = math.max(0, waterY-terrainHeight)
2491 self.isInShallowWater = waterDepth <= 0.5
2492 self.isInMediumWater = not self.isInShallowWater
2493 end
2494 self.tailwaterDepth = math.max(0, waterY-y)
2495end

periodChanged

Description
Called if period changed
Definition
periodChanged()
Code
3570function Vehicle:periodChanged()
3571 self.age = self.age + 1
3572end

playControlledActions

Description
Definition
playControlledActions()
Code
3883function Vehicle:playControlledActions()
3884 if self.actionController ~= nil then
3885 self.actionController:playControlledActions()
3886 end
3887end

postInit

Description
Definition
postInit()
Code
291function Vehicle.postInit()
292 local schema = Vehicle.xmlSchema
293 for name, _ in pairs(g_configurationManager:getConfigurations()) do
294 local specializationKey = g_configurationManager:getConfigurationAttribute(name, "xmlKey")
295 if specializationKey ~= nil then
296 specializationKey = "." .. specializationKey
297 else
298 specializationKey = ""
299 end
300
301 local configrationsKey = string.format("vehicle%s.%sConfigurations", specializationKey, name)
302 local configrationKey = string.format("%s.%sConfiguration(?)", configrationsKey, name)
303
304 schema:setXMLSharedRegistration("configSize", configrationKey)
305 schema:register(XMLValueType.FLOAT, configrationKey .. ".size#width", "occupied width of the vehicle when loaded in this configuration")
306 schema:register(XMLValueType.FLOAT, configrationKey .. ".size#length", "occupied length of the vehicle when loaded in this configuration")
307 schema:register(XMLValueType.FLOAT, configrationKey .. ".size#height", "occupied height of the vehicle when loaded in this configuration")
308 schema:register(XMLValueType.FLOAT, configrationKey .. ".size#widthOffset", "width offset")
309 schema:register(XMLValueType.FLOAT, configrationKey .. ".size#lengthOffset", "length offset")
310 schema:register(XMLValueType.FLOAT, configrationKey .. ".size#heightOffset", "height offset")
311 schema:setXMLSharedRegistration()
312
313 schema:register(XMLValueType.L10N_STRING, configrationsKey .. "#title", "Configration title to display in shop")
314
315 schema:register(XMLValueType.L10N_STRING, configrationKey .. "#name", "Configuration name")
316 schema:register(XMLValueType.STRING, configrationKey .. "#params", "Extra paramters to insert in #name text")
317 schema:register(XMLValueType.L10N_STRING, configrationKey .. "#desc", "Configuration description")
318 schema:register(XMLValueType.FLOAT, configrationKey .. "#price", "Price of configuration", 0)
319 schema:register(XMLValueType.FLOAT, configrationKey .. "#dailyUpkeep", "Daily up keep with this configration", 0)
320 schema:register(XMLValueType.BOOL, configrationKey .. "#isDefault", "Is selected by default in shop config screen", false)
321 schema:register(XMLValueType.BOOL, configrationKey .. "#isSelectable", "Configuration can be selected in the shop", true)
322 schema:register(XMLValueType.STRING, configrationKey .. "#saveId", "Custom save id", "Number of configuration")
323
324 schema:register(XMLValueType.STRING, configrationKey .. "#displayBrand", "If defined a brand icon is displayed in the shop config screen")
325
326 schema:register(XMLValueType.STRING, configrationKey .. "#vehicleBrand", "Custom brand to display after bought with this configuration")
327 schema:register(XMLValueType.STRING, configrationKey .. "#vehicleName", "Custom vehicle name to display after bought with this configuration")
328 schema:register(XMLValueType.STRING, configrationKey .. "#vehicleIcon", "Custom icon to display after bought with this configuration")
329
330 schema:register(XMLValueType.FLOAT, configrationKey .. "#workingWidth", "Work width to display in shop while config is active")
331
332 ConfigurationUtil.registerMaterialConfigurationXMLPaths(schema, configrationKey)
333 end
334end

postReadStream

Description
Called on client side on join when the vehicle was fully loaded
Definition
postReadStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
1528function Vehicle:postReadStream(streamId, connection)
1529 -- remove from physics to set static components correctly (normally they should not be added yet)
1530 self:removeFromPhysics()
1531
1532 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1533 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1534 for i=1, #self.components do
1535 local component = self.components[i]
1536 local x = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1537 local y = NetworkUtil.readCompressedWorldPosition(streamId, paramsY)
1538 local z = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1539 local x_rot = NetworkUtil.readCompressedAngle(streamId)
1540 local y_rot = NetworkUtil.readCompressedAngle(streamId)
1541 local z_rot = NetworkUtil.readCompressedAngle(streamId)
1542
1543 local qx,qy,qz,qw = mathEulerToQuaternion(x_rot,y_rot,z_rot)
1544 self:setWorldPositionQuaternion(x,y,z, qx,qy,qz,qw, i, true)
1545
1546 component.networkInterpolators.position:setPosition(x,y,z)
1547 component.networkInterpolators.quaternion:setQuaternion(qx,qy,qz,qw)
1548 end
1549 self.networkTimeInterpolator:reset()
1550
1551 -- add to physics and make visible
1552 self:setVisibility(true)
1553 self:addToPhysics()
1554
1555 self.serverMass = streamReadFloat32(streamId)
1556 self.age = streamReadUInt16(streamId)
1557 self:setOperatingTime(streamReadFloat32(streamId), true)
1558 self.price = streamReadInt32(streamId)
1559
1560 if Vehicle.DEBUG_NETWORK_READ_WRITE then
1561 print("-------------------------------------------------------------")
1562 print(self.configFileName)
1563 for _, spec in ipairs(self.eventListeners["onReadStream"]) do
1564 local className = ClassUtil.getClassName(spec)
1565 local startBits = streamGetReadOffset(streamId)
1566 spec["onReadStream"](self, streamId, connection)
1567 print(" "..tostring(className).." read " .. streamGetReadOffset(streamId)-startBits .. " bits")
1568 end
1569 else
1570 SpecializationUtil.raiseEvent(self, "onReadStream", streamId, connection)
1571 end
1572
1573 self:setLoadingStep(Vehicle.LOAD_STEP_SYNCHRONIZED)
1574end

postWriteStream

Description
Called on server side when vehicle is fully loaded on client side
Definition
postWriteStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
1624function Vehicle:postWriteStream(streamId, connection)
1625 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1626 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1627 for i=1, #self.components do
1628 local component = self.components[i]
1629 local x,y,z = getWorldTranslation(component.node)
1630 local x_rot,y_rot,z_rot = getWorldRotation(component.node)
1631 NetworkUtil.writeCompressedWorldPosition(streamId, x, paramsXZ)
1632 NetworkUtil.writeCompressedWorldPosition(streamId, y, paramsY)
1633 NetworkUtil.writeCompressedWorldPosition(streamId, z, paramsXZ)
1634 NetworkUtil.writeCompressedAngle(streamId, x_rot)
1635 NetworkUtil.writeCompressedAngle(streamId, y_rot)
1636 NetworkUtil.writeCompressedAngle(streamId, z_rot)
1637 end
1638
1639 streamWriteFloat32(streamId, self.serverMass)
1640 streamWriteUInt16(streamId, self.age)
1641 streamWriteFloat32(streamId, self.operatingTime)
1642 streamWriteInt32(streamId, self.price)
1643
1644 if Vehicle.DEBUG_NETWORK_READ_WRITE then
1645 print("-------------------------------------------------------------")
1646 print(self.configFileName)
1647 for _, spec in ipairs(self.eventListeners["onWriteStream"]) do
1648 local className = ClassUtil.getClassName(spec)
1649 local startBits = streamGetWriteOffset(streamId)
1650 spec["onWriteStream"](self, streamId, connection)
1651 print(" "..tostring(className).." Wrote " .. streamGetWriteOffset(streamId)-startBits .. " bits")
1652 end
1653 else
1654 SpecializationUtil.raiseEvent(self, "onWriteStream", streamId, connection)
1655 end
1656end

raiseStateChange

Description
Definition
raiseStateChange()
Code
3576function Vehicle:raiseStateChange(state, ...)
3577 SpecializationUtil.raiseEvent(self, "onStateChange", state, ...)
3578end

readStream

Description
Called on client side on join
Definition
readStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
1453function Vehicle:readStream(streamId, connection, objectId)
1454 Vehicle:superClass().readStream(self, streamId, connection, objectId)
1455
1456 local configFile = NetworkUtil.convertFromNetworkFilename(streamReadString(streamId))
1457 local typeName = streamReadString(streamId)
1458
1459 local configurations = {}
1460 local numConfigs = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
1461 for _=1, numConfigs do
1462 local configNameId = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
1463 local configId = streamReadUInt16(streamId)
1464
1465 local configName = g_configurationManager:getConfigurationNameByIndex(configNameId+1)
1466 if configName ~= nil then
1467 configurations[configName] = configId+1
1468 end
1469 end
1470
1471 local boughtConfigurations = {}
1472 numConfigs = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
1473 for _=1, numConfigs do
1474 local configNameId = streamReadUIntN(streamId, ConfigurationUtil.SEND_NUM_BITS)
1475 local configName = g_configurationManager:getConfigurationNameByIndex(configNameId+1)
1476 boughtConfigurations[configName] = {}
1477 local numBoughtConfigIds = streamReadUInt16(streamId)
1478 for _=1, numBoughtConfigIds do
1479 local boughtConfigId = streamReadUInt16(streamId)
1480 boughtConfigurations[configName][boughtConfigId + 1] = true
1481 end
1482 end
1483
1484 self.propertyState = streamReadUIntN(streamId, 2)
1485
1486 if self.configFileName == nil then
1487 local vehicleData = {}
1488 vehicleData.filename = configFile
1489 vehicleData.isAbsolute = false
1490 vehicleData.typeName = typeName
1491 vehicleData.posX = 0
1492 vehicleData.posY = nil
1493 vehicleData.posZ = 0
1494 vehicleData.yOffset = 0
1495 vehicleData.rotX = 0
1496 vehicleData.rotY = 0
1497 vehicleData.rotZ = 0
1498 vehicleData.isVehicleSaved = true
1499 vehicleData.price = 0
1500 vehicleData.propertyState = self.propertyState
1501 -- assign parent class Object's ownerFarmId field here to ensure ownership synchronization in MP:
1502 vehicleData.ownerFarmId = self.ownerFarmId
1503 vehicleData.isLeased = 0
1504 vehicleData.configurations = configurations
1505 vehicleData.boughtConfigurations = boughtConfigurations
1506
1507 local vehicle = self
1508 local asyncCallbackFunction = function(_, v, loadingState, args)
1509 if loadingState == VehicleLoadingUtil.VEHICLE_LOAD_OK then
1510 g_client:onObjectFinishedAsyncLoading(vehicle)
1511 else
1512 Logging.error("Failed to load vehicle on client")
1513 if v ~= nil then
1514 v:delete()
1515 end
1516 printCallstack()
1517 return
1518 end
1519 end
1520 self:load(vehicleData, asyncCallbackFunction, self)
1521 end
1522end

readUpdateStream

Description
Called on client side on update
Definition
readUpdateStream(integer streamId, integer timestamp, table connection)
Arguments
integerstreamIdstream ID
integertimestamptimestamp
tableconnectionconnection
Code
1663function Vehicle:readUpdateStream(streamId, timestamp, connection)
1664 if connection.isServer then
1665 local hasUpdate = streamReadBool(streamId)
1666 if hasUpdate then
1667 self.networkTimeInterpolator:startNewPhaseNetwork()
1668
1669 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1670 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1671 for i=1, #self.components do
1672 local component = self.components[i]
1673 if not component.isStatic then
1674 local x = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1675 local y = NetworkUtil.readCompressedWorldPosition(streamId, paramsY)
1676 local z = NetworkUtil.readCompressedWorldPosition(streamId, paramsXZ)
1677 local x_rot = NetworkUtil.readCompressedAngle(streamId)
1678 local y_rot = NetworkUtil.readCompressedAngle(streamId)
1679 local z_rot = NetworkUtil.readCompressedAngle(streamId)
1680 local qx,qy,qz,qw = mathEulerToQuaternion(x_rot,y_rot,z_rot)
1681
1682 component.networkInterpolators.position:setTargetPosition(x,y,z)
1683 component.networkInterpolators.quaternion:setTargetQuaternion(qx,qy,qz,qw)
1684 end
1685 end
1686 SpecializationUtil.raiseEvent(self, "onReadPositionUpdateStream", streamId, connection)
1687 end
1688 end
1689
1690 if Vehicle.DEBUG_NETWORK_READ_WRITE_UPDATE then
1691 print("-------------------------------------------------------------")
1692 print(self.configFileName)
1693 for _, spec in ipairs(self.eventListeners["onReadUpdateStream"]) do
1694 local className = ClassUtil.getClassName(spec)
1695 local startBits = streamGetReadOffset(streamId)
1696 spec["onReadUpdateStream"](self, streamId, timestamp, connection)
1697 print(" "..tostring(className).." read " .. streamGetReadOffset(streamId)-startBits .. " bits")
1698 end
1699 else
1700 SpecializationUtil.raiseEvent(self, "onReadUpdateStream", streamId, timestamp, connection)
1701 end
1702end

registerActionEvents

Description
Definition
registerActionEvents()
Code
2556function Vehicle:registerActionEvents(excludedVehicle)
2557 if not g_gui:getIsGuiVisible() and not g_currentMission.isPlayerFrozen and excludedVehicle ~= self then
2558 self.actionEventUpdateRequested = false
2559
2560 local isActiveForInput = self:getIsActiveForInput()
2561 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
2562
2563 if isActiveForInput then
2564 -- reset the action binding enabled state for bindings previously disabled during conflict resolution:
2565 g_inputBinding:resetActiveActionBindings()
2566 end
2567
2568 -- safety: set the input registration context without changing the actual input context in case we're currently
2569 -- not in the vehicle context (e.g. due to network events)
2570 g_inputBinding:beginActionEventsModification(Vehicle.INPUT_CONTEXT_NAME)
2571
2572 SpecializationUtil.raiseEvent(self, "onRegisterActionEvents", isActiveForInput, isActiveForInputIgnoreSelection)
2573
2574 self:clearActionEventsTable(self.actionEvents)
2575 if self:getCanToggleSelectable() then
2576 local numSelectableObjects = 0
2577
2578 for _, object in ipairs(self.selectableObjects) do
2579 numSelectableObjects = numSelectableObjects + 1 + #object.subSelections
2580 end
2581
2582 if numSelectableObjects > 1 then
2583 local _, actionEventId = self:addActionEvent(self.actionEvents, InputAction.SWITCH_IMPLEMENT, self, Vehicle.actionEventToggleSelection, false, true, false, true, nil)
2584 g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_LOW)
2585
2586 _, actionEventId = self:addActionEvent(self.actionEvents, InputAction.SWITCH_IMPLEMENT_BACK, self, Vehicle.actionEventToggleSelectionReverse, false, true, false, true, nil)
2587 g_inputBinding:setActionEventTextVisibility(actionEventId, false)
2588 end
2589 end
2590
2591 VehicleDebug.registerActionEvents(self)
2592
2593 if Platform.gameplay.automaticVehicleControl then
2594 if self.actionController ~= nil then
2595 if self:getIsActiveForInput(true) then
2596 if self == self.rootVehicle then
2597 self.actionController:registerActionEvents(isActiveForInput, isActiveForInputIgnoreSelection)
2598 end
2599 end
2600 end
2601 end
2602
2603 g_inputBinding:endActionEventsModification()
2604 end
2605end

registerEvents

Description
Definition
registerEvents()
Code
93function Vehicle.registerEvents(vehicleType)
94 SpecializationUtil.registerEvent(vehicleType, "onPreLoad")
95 SpecializationUtil.registerEvent(vehicleType, "onLoad")
96 SpecializationUtil.registerEvent(vehicleType, "onPostLoad")
97 SpecializationUtil.registerEvent(vehicleType, "onPreLoadFinished")
98 SpecializationUtil.registerEvent(vehicleType, "onLoadFinished")
99 SpecializationUtil.registerEvent(vehicleType, "onPreDelete")
100 SpecializationUtil.registerEvent(vehicleType, "onDelete")
101 SpecializationUtil.registerEvent(vehicleType, "onSave")
102 SpecializationUtil.registerEvent(vehicleType, "onReadStream")
103 SpecializationUtil.registerEvent(vehicleType, "onWriteStream")
104 SpecializationUtil.registerEvent(vehicleType, "onReadUpdateStream")
105 SpecializationUtil.registerEvent(vehicleType, "onWriteUpdateStream")
106 SpecializationUtil.registerEvent(vehicleType, "onReadPositionUpdateStream")
107 SpecializationUtil.registerEvent(vehicleType, "onWritePositionUpdateStream")
108 SpecializationUtil.registerEvent(vehicleType, "onPreUpdate")
109 SpecializationUtil.registerEvent(vehicleType, "onUpdate")
110 SpecializationUtil.registerEvent(vehicleType, "onUpdateInterpolation")
111 SpecializationUtil.registerEvent(vehicleType, "onUpdateDebug")
112 SpecializationUtil.registerEvent(vehicleType, "onPostUpdate")
113 SpecializationUtil.registerEvent(vehicleType, "onUpdateTick")
114 SpecializationUtil.registerEvent(vehicleType, "onPostUpdateTick")
115 SpecializationUtil.registerEvent(vehicleType, "onUpdateEnd")
116 SpecializationUtil.registerEvent(vehicleType, "onDraw")
117 SpecializationUtil.registerEvent(vehicleType, "onDrawUIInfo")
118 SpecializationUtil.registerEvent(vehicleType, "onActivate")
119 SpecializationUtil.registerEvent(vehicleType, "onDeactivate")
120 SpecializationUtil.registerEvent(vehicleType, "onStateChange")
121 SpecializationUtil.registerEvent(vehicleType, "onRegisterActionEvents")
122 SpecializationUtil.registerEvent(vehicleType, "onRootVehicleChanged")
123 SpecializationUtil.registerEvent(vehicleType, "onSelect")
124 SpecializationUtil.registerEvent(vehicleType, "onUnselect")
125 SpecializationUtil.registerEvent(vehicleType, "onSetBroken")
126end

registerFunctions

Description
Definition
registerFunctions()
Code
130function Vehicle.registerFunctions(vehicleType)
131 SpecializationUtil.registerFunction(vehicleType, "setOwnerFarmId", Vehicle.setOwnerFarmId)
132 SpecializationUtil.registerFunction(vehicleType, "loadSubSharedI3DFile", Vehicle.loadSubSharedI3DFile)
133 SpecializationUtil.registerFunction(vehicleType, "drawUIInfo", Vehicle.drawUIInfo)
134 SpecializationUtil.registerFunction(vehicleType, "raiseActive", Vehicle.raiseActive)
135 SpecializationUtil.registerFunction(vehicleType, "setLoadingState", Vehicle.setLoadingState)
136 SpecializationUtil.registerFunction(vehicleType, "setLoadingStep", Vehicle.setLoadingStep)
137 SpecializationUtil.registerFunction(vehicleType, "addNodeObjectMapping", Vehicle.addNodeObjectMapping)
138 SpecializationUtil.registerFunction(vehicleType, "removeNodeObjectMapping", Vehicle.removeNodeObjectMapping)
139 SpecializationUtil.registerFunction(vehicleType, "addToPhysics", Vehicle.addToPhysics)
140 SpecializationUtil.registerFunction(vehicleType, "removeFromPhysics", Vehicle.removeFromPhysics)
141 SpecializationUtil.registerFunction(vehicleType, "setVisibility", Vehicle.setVisibility)
142 SpecializationUtil.registerFunction(vehicleType, "setRelativePosition", Vehicle.setRelativePosition)
143 SpecializationUtil.registerFunction(vehicleType, "setAbsolutePosition", Vehicle.setAbsolutePosition)
144 SpecializationUtil.registerFunction(vehicleType, "getLimitedVehicleYPosition", Vehicle.getLimitedVehicleYPosition)
145 SpecializationUtil.registerFunction(vehicleType, "setWorldPosition", Vehicle.setWorldPosition)
146 SpecializationUtil.registerFunction(vehicleType, "setWorldPositionQuaternion", Vehicle.setWorldPositionQuaternion)
147 SpecializationUtil.registerFunction(vehicleType, "updateVehicleSpeed", Vehicle.updateVehicleSpeed)
148 SpecializationUtil.registerFunction(vehicleType, "getUpdatePriority", Vehicle.getUpdatePriority)
149 SpecializationUtil.registerFunction(vehicleType, "getPrice", Vehicle.getPrice)
150 SpecializationUtil.registerFunction(vehicleType, "getSellPrice", Vehicle.getSellPrice)
151 SpecializationUtil.registerFunction(vehicleType, "getDailyUpkeep", Vehicle.getDailyUpkeep)
152 SpecializationUtil.registerFunction(vehicleType, "getIsOnField", Vehicle.getIsOnField)
153 SpecializationUtil.registerFunction(vehicleType, "getParentComponent", Vehicle.getParentComponent)
154 SpecializationUtil.registerFunction(vehicleType, "getLastSpeed", Vehicle.getLastSpeed)
155 SpecializationUtil.registerFunction(vehicleType, "getDeactivateOnLeave", Vehicle.getDeactivateOnLeave)
156 SpecializationUtil.registerFunction(vehicleType, "getOwner", Vehicle.getOwner)
157 SpecializationUtil.registerFunction(vehicleType, "getIsVehicleNode", Vehicle.getIsVehicleNode)
158 SpecializationUtil.registerFunction(vehicleType, "getIsOperating", Vehicle.getIsOperating)
159 SpecializationUtil.registerFunction(vehicleType, "getIsActive", Vehicle.getIsActive)
160 SpecializationUtil.registerFunction(vehicleType, "getIsActiveForInput", Vehicle.getIsActiveForInput)
161 SpecializationUtil.registerFunction(vehicleType, "getIsActiveForSound", Vehicle.getIsActiveForSound)
162 SpecializationUtil.registerFunction(vehicleType, "getIsLowered", Vehicle.getIsLowered)
163 SpecializationUtil.registerFunction(vehicleType, "updateWaterInfo", Vehicle.updateWaterInfo)
164 SpecializationUtil.registerFunction(vehicleType, "onWaterRaycastCallback", Vehicle.onWaterRaycastCallback)
165 SpecializationUtil.registerFunction(vehicleType, "setBroken", Vehicle.setBroken)
166 SpecializationUtil.registerFunction(vehicleType, "getVehicleDamage", Vehicle.getVehicleDamage)
167 SpecializationUtil.registerFunction(vehicleType, "getRepairPrice", Vehicle.getRepairPrice)
168 SpecializationUtil.registerFunction(vehicleType, "getRepaintPrice", Vehicle.getRepaintPrice)
169 SpecializationUtil.registerFunction(vehicleType, "setMassDirty", Vehicle.setMassDirty)
170 SpecializationUtil.registerFunction(vehicleType, "updateMass", Vehicle.updateMass)
171 SpecializationUtil.registerFunction(vehicleType, "getMaxComponentMassReached", Vehicle.getMaxComponentMassReached)
172 SpecializationUtil.registerFunction(vehicleType, "getAdditionalComponentMass", Vehicle.getAdditionalComponentMass)
173 SpecializationUtil.registerFunction(vehicleType, "getTotalMass", Vehicle.getTotalMass)
174 SpecializationUtil.registerFunction(vehicleType, "getComponentMass", Vehicle.getComponentMass)
175 SpecializationUtil.registerFunction(vehicleType, "getDefaultMass", Vehicle.getDefaultMass)
176 SpecializationUtil.registerFunction(vehicleType, "getOverallCenterOfMass", Vehicle.getOverallCenterOfMass)
177 SpecializationUtil.registerFunction(vehicleType, "getVehicleWorldXRot", Vehicle.getVehicleWorldXRot)
178 SpecializationUtil.registerFunction(vehicleType, "getVehicleWorldDirection", Vehicle.getVehicleWorldDirection)
179 SpecializationUtil.registerFunction(vehicleType, "getFillLevelInformation", Vehicle.getFillLevelInformation)
180 SpecializationUtil.registerFunction(vehicleType, "activate", Vehicle.activate)
181 SpecializationUtil.registerFunction(vehicleType, "deactivate", Vehicle.deactivate)
182 SpecializationUtil.registerFunction(vehicleType, "setComponentJointFrame", Vehicle.setComponentJointFrame)
183 SpecializationUtil.registerFunction(vehicleType, "setComponentJointRotLimit", Vehicle.setComponentJointRotLimit)
184 SpecializationUtil.registerFunction(vehicleType, "setComponentJointTransLimit", Vehicle.setComponentJointTransLimit)
185 SpecializationUtil.registerFunction(vehicleType, "loadComponentFromXML", Vehicle.loadComponentFromXML)
186 SpecializationUtil.registerFunction(vehicleType, "loadComponentJointFromXML", Vehicle.loadComponentJointFromXML)
187 SpecializationUtil.registerFunction(vehicleType, "createComponentJoint", Vehicle.createComponentJoint)
188 SpecializationUtil.registerFunction(vehicleType, "loadSchemaOverlay", Vehicle.loadSchemaOverlay)
189 SpecializationUtil.registerFunction(vehicleType, "getAdditionalSchemaText", Vehicle.getAdditionalSchemaText)
190 SpecializationUtil.registerFunction(vehicleType, "getUseTurnedOnSchema", Vehicle.getUseTurnedOnSchema)
191 SpecializationUtil.registerFunction(vehicleType, "dayChanged", Vehicle.dayChanged)
192 SpecializationUtil.registerFunction(vehicleType, "periodChanged", Vehicle.periodChanged)
193 SpecializationUtil.registerFunction(vehicleType, "raiseStateChange", Vehicle.raiseStateChange)
194 SpecializationUtil.registerFunction(vehicleType, "doCheckSpeedLimit", Vehicle.doCheckSpeedLimit)
195 SpecializationUtil.registerFunction(vehicleType, "interact", Vehicle.interact)
196 SpecializationUtil.registerFunction(vehicleType, "getInteractionHelp", Vehicle.getInteractionHelp)
197 SpecializationUtil.registerFunction(vehicleType, "getDistanceToNode", Vehicle.getDistanceToNode)
198 SpecializationUtil.registerFunction(vehicleType, "getIsAIActive", Vehicle.getIsAIActive)
199 SpecializationUtil.registerFunction(vehicleType, "getIsPowered", Vehicle.getIsPowered)
200 SpecializationUtil.registerFunction(vehicleType, "addVehicleToAIImplementList", Vehicle.addVehicleToAIImplementList)
201 SpecializationUtil.registerFunction(vehicleType, "setOperatingTime", Vehicle.setOperatingTime)
202
203 SpecializationUtil.registerFunction(vehicleType, "requestActionEventUpdate", Vehicle.requestActionEventUpdate)
204 SpecializationUtil.registerFunction(vehicleType, "removeActionEvents", Vehicle.removeActionEvents)
205 SpecializationUtil.registerFunction(vehicleType, "updateActionEvents", Vehicle.updateActionEvents)
206 SpecializationUtil.registerFunction(vehicleType, "registerActionEvents", Vehicle.registerActionEvents)
207 SpecializationUtil.registerFunction(vehicleType, "addActionEvent", Vehicle.addActionEvent)
208
209 SpecializationUtil.registerFunction(vehicleType, "updateSelectableObjects", Vehicle.updateSelectableObjects)
210 SpecializationUtil.registerFunction(vehicleType, "registerSelectableObjects", Vehicle.registerSelectableObjects)
211 SpecializationUtil.registerFunction(vehicleType, "addSubselection", Vehicle.addSubselection)
212 SpecializationUtil.registerFunction(vehicleType, "getRootVehicle", Vehicle.getRootVehicle)
213 SpecializationUtil.registerFunction(vehicleType, "findRootVehicle", Vehicle.findRootVehicle)
214 SpecializationUtil.registerFunction(vehicleType, "getChildVehicles", Vehicle.getChildVehicles)
215 SpecializationUtil.registerFunction(vehicleType, "addChildVehicles", Vehicle.addChildVehicles)
216 SpecializationUtil.registerFunction(vehicleType, "updateVehicleChain", Vehicle.updateVehicleChain)
217 SpecializationUtil.registerFunction(vehicleType, "getCanBeSelected", Vehicle.getCanBeSelected)
218 SpecializationUtil.registerFunction(vehicleType, "getBlockSelection", Vehicle.getBlockSelection)
219 SpecializationUtil.registerFunction(vehicleType, "getCanToggleSelectable", Vehicle.getCanToggleSelectable)
220 SpecializationUtil.registerFunction(vehicleType, "unselectVehicle", Vehicle.unselectVehicle)
221 SpecializationUtil.registerFunction(vehicleType, "selectVehicle", Vehicle.selectVehicle)
222 SpecializationUtil.registerFunction(vehicleType, "getIsSelected", Vehicle.getIsSelected)
223 SpecializationUtil.registerFunction(vehicleType, "getSelectedObject", Vehicle.getSelectedObject)
224 SpecializationUtil.registerFunction(vehicleType, "getSelectedVehicle", Vehicle.getSelectedVehicle)
225 SpecializationUtil.registerFunction(vehicleType, "setSelectedVehicle", Vehicle.setSelectedVehicle)
226 SpecializationUtil.registerFunction(vehicleType, "setSelectedObject", Vehicle.setSelectedObject)
227 SpecializationUtil.registerFunction(vehicleType, "getIsReadyForAutomatedTrainTravel", Vehicle.getIsReadyForAutomatedTrainTravel)
228 SpecializationUtil.registerFunction(vehicleType, "getIsAutomaticShiftingAllowed", Vehicle.getIsAutomaticShiftingAllowed)
229 SpecializationUtil.registerFunction(vehicleType, "getSpeedLimit", Vehicle.getSpeedLimit)
230 SpecializationUtil.registerFunction(vehicleType, "getRawSpeedLimit", Vehicle.getRawSpeedLimit)
231 SpecializationUtil.registerFunction(vehicleType, "getActiveFarm", Vehicle.getActiveFarm)
232 SpecializationUtil.registerFunction(vehicleType, "onVehicleWakeUpCallback", Vehicle.onVehicleWakeUpCallback)
233 SpecializationUtil.registerFunction(vehicleType, "getCanByMounted", Vehicle.getCanByMounted)
234 SpecializationUtil.registerFunction(vehicleType, "getName", Vehicle.getName)
235 SpecializationUtil.registerFunction(vehicleType, "getFullName", Vehicle.getFullName)
236 SpecializationUtil.registerFunction(vehicleType, "getBrand", Vehicle.getBrand)
237 SpecializationUtil.registerFunction(vehicleType, "getImageFilename", Vehicle.getImageFilename)
238 SpecializationUtil.registerFunction(vehicleType, "getCanBePickedUp", Vehicle.getCanBePickedUp)
239 SpecializationUtil.registerFunction(vehicleType, "getCanBeReset", Vehicle.getCanBeReset)
240 SpecializationUtil.registerFunction(vehicleType, "getIsInUse", Vehicle.getIsInUse)
241 SpecializationUtil.registerFunction(vehicleType, "getPropertyState", Vehicle.getPropertyState)
242 SpecializationUtil.registerFunction(vehicleType, "getAreControlledActionsAllowed", Vehicle.getAreControlledActionsAllowed)
243 SpecializationUtil.registerFunction(vehicleType, "getAreControlledActionsAvailable", Vehicle.getAreControlledActionsAvailable)
244 SpecializationUtil.registerFunction(vehicleType, "playControlledActions", Vehicle.playControlledActions)
245 SpecializationUtil.registerFunction(vehicleType, "getActionControllerDirection", Vehicle.getActionControllerDirection)
246 SpecializationUtil.registerFunction(vehicleType, "createMapHotspot", Vehicle.createMapHotspot)
247 SpecializationUtil.registerFunction(vehicleType, "getMapHotspot", Vehicle.getMapHotspot)
248 SpecializationUtil.registerFunction(vehicleType, "updateMapHotspot", Vehicle.updateMapHotspot)
249 SpecializationUtil.registerFunction(vehicleType, "getIsMapHotspotVisible", Vehicle.getIsMapHotspotVisible)
250 SpecializationUtil.registerFunction(vehicleType, "showInfo", Vehicle.showInfo)
251 SpecializationUtil.registerFunction(vehicleType, "loadObjectChangeValuesFromXML", Vehicle.loadObjectChangeValuesFromXML)
252 SpecializationUtil.registerFunction(vehicleType, "setObjectChangeValues", Vehicle.setObjectChangeValues)
253 SpecializationUtil.registerFunction(vehicleType, "getIsSynchronized", Vehicle.getIsSynchronized)
254end

registerInteractionFlag

Description
Register interaction flag
Definition
registerInteractionFlag(string name)
Arguments
stringnamename of flag
Code
71function Vehicle.registerInteractionFlag(name)
72 local key = "INTERACTION_FLAG_"..string.upper(name)
73 if Vehicle[key] == nil then
74 Vehicle.NUM_INTERACTION_FLAGS = Vehicle.NUM_INTERACTION_FLAGS + 1
75 Vehicle[key] = Vehicle.NUM_INTERACTION_FLAGS
76 end
77end

registers

Description
Definition
registers()
Code
338function Vehicle.registers()
339 local schema = Vehicle.xmlSchema
340 local schemaSavegame = Vehicle.xmlSchemaSavegame
341
342 schema:register(XMLValueType.STRING, "vehicle#type", "Vehicle type")
343 schema:register(XMLValueType.STRING, "vehicle.annotation", "Annotation", nil, true)
344
345 StoreManager.registerStoreDataXMLPaths(schema, "vehicle")
346
347 schema:register(XMLValueType.STRING, "vehicle.storeData.specs.workingWidth", "Working width to display in shop")
348 schema:register(XMLValueType.STRING, "vehicle.storeData.specs.combination(?)#xmlFilename", "Combination to display in shop")
349 schema:register(XMLValueType.STRING, "vehicle.storeData.specs.combination(?)#filterCategory", "Filter in this category")
350 schema:register(XMLValueType.STRING, "vehicle.storeData.specs.combination(?)#filterSpec", "Filter for this spec type")
351 schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.combination(?)#filterSpecMin", "Filter spec type in this range (min.)")
352 schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.combination(?)#filterSpecMax", "Filter spec type in this range (max.)")
353
354 schema:register(XMLValueType.BOOL, "vehicle.storeData.specs.weight#ignore", "Hide vehicle weight in shop", false)
355 schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.weight#minValue", "Min. weight to display in shop")
356 schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.weight#maxValue", "Max. weight to display in shop")
357 schema:register(XMLValueType.STRING, "vehicle.storeData.specs.weight.config(?)#name", "Name of configuration")
358 schema:register(XMLValueType.INT, "vehicle.storeData.specs.weight.config(?)#index", "Index of selected configuration")
359 schema:register(XMLValueType.FLOAT, "vehicle.storeData.specs.weight.config(?)#value", "Weight value which can be reached with this configuration")
360
361 schema:register(XMLValueType.STRING, "vehicle.base.filename", "Path to i3d filename", nil)
362 schema:register(XMLValueType.L10N_STRING, "vehicle.base.typeDesc", "Type description", nil)
363 schema:register(XMLValueType.BOOL, "vehicle.base.synchronizePosition", "Vehicle position synchronized", true)
364 schema:register(XMLValueType.BOOL, "vehicle.base.supportsPickUp", "Vehicle can be picked up by hand", "true if vehicle is a pallet, false otherwise")
365 schema:register(XMLValueType.BOOL, "vehicle.base.canBeReset", "Vehicle can be reset to shop", true)
366 schema:register(XMLValueType.BOOL, "vehicle.base.showInVehicleMenu", "Vehicle shows in vehicle menu", true)
367 schema:register(XMLValueType.BOOL, "vehicle.base.supportsRadio", "Vehicle supported radio", true)
368 schema:register(XMLValueType.BOOL, "vehicle.base.input#allowed", "Vehicle allows key input", true)
369 schema:register(XMLValueType.FLOAT, "vehicle.base.tailwaterDepth#warning", "Tailwater depth warning is shown from this water depth", 1)
370 schema:register(XMLValueType.FLOAT, "vehicle.base.tailwaterDepth#threshold", "Vehicle is broken after this water depth", 2.5)
371 schema:register(XMLValueType.STRING, "vehicle.base.mapHotspot#type", "Map hotspot type")
372 schema:register(XMLValueType.BOOL, "vehicle.base.mapHotspot#hasDirection", "Map hotspot has direction")
373 schema:register(XMLValueType.BOOL, "vehicle.base.mapHotspot#available", "Map hotspot is available", true)
374 schema:register(XMLValueType.FLOAT, "vehicle.base.speedLimit#value", "Speed limit")
375 schema:register(XMLValueType.FLOAT, "vehicle.base.size#width", "Occupied width of the vehicle when loaded", nil, true)
376 schema:register(XMLValueType.FLOAT, "vehicle.base.size#length", "Occupied length of the vehicle when loaded", nil, true)
377 schema:register(XMLValueType.FLOAT, "vehicle.base.size#height", "Occupied height of the vehicle when loaded")
378 schema:register(XMLValueType.FLOAT, "vehicle.base.size#widthOffset", "Width offset")
379 schema:register(XMLValueType.FLOAT, "vehicle.base.size#lengthOffset", "Width offset")
380 schema:register(XMLValueType.FLOAT, "vehicle.base.size#heightOffset", "Height offset")
381 schema:register(XMLValueType.ANGLE, "vehicle.base.size#yRotation", "Y Rotation offset in i3d (Needs to be set to the vehicle's rotation in the i3d file and is e.g. used to check ai working direction)", 0)
382 schema:register(XMLValueType.NODE_INDEX, "vehicle.base.steeringAxle#node", "Steering axle node used to calculate the steering angle of attachments")
383 schema:register(XMLValueType.STRING, "vehicle.base.sounds#filename", "Path to external sound files")
384 schema:register(XMLValueType.FLOAT, "vehicle.base.sounds#volumeFactor", "This factor will be applied to all sounds of this vehicle")
385
386 I3DUtil.registerI3dMappingXMLPaths(schema, "vehicle")
387
388 schema:register(XMLValueType.INT, "vehicle.base.components#numComponents", "Number of components loaded from i3d", "number of components the i3d contains")
389 schema:register(XMLValueType.FLOAT, "vehicle.base.components#maxMass", "Max. overall mass the vehicle can have", "unlimited")
390 schema:register(XMLValueType.FLOAT, "vehicle.base.components.component(?)#mass", "Mass of component", "Mass of component in i3d")
391 schema:register(XMLValueType.VECTOR_TRANS, "vehicle.base.components.component(?)#centerOfMass", "Center of mass", "Center of mass in i3d")
392 schema:register(XMLValueType.INT, "vehicle.base.components.component(?)#solverIterationCount", "Solver iterations count")
393 schema:register(XMLValueType.BOOL, "vehicle.base.components.component(?)#motorized", "Is motorized component", "set by motorized specialization")
394 schema:register(XMLValueType.BOOL, "vehicle.base.components.component(?)#collideWithAttachables", "Collides with attachables", false)
395
396 schema:register(XMLValueType.INT, "vehicle.base.components.joint(?)#component1", "First component of the joint")
397 schema:register(XMLValueType.INT, "vehicle.base.components.joint(?)#component2", "Second component of the joint")
398 schema:register(XMLValueType.NODE_INDEX, "vehicle.base.components.joint(?)#node", "Joint node")
399 schema:register(XMLValueType.NODE_INDEX, "vehicle.base.components.joint(?)#nodeActor1", "Actor node of second component", "Joint node")
400 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotLimit", "Rotation limit", "0 0 0")
401 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transLimit", "Translation limit", "0 0 0")
402 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotMinLimit", "Min rotation limit", "inversed rotation limit")
403 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transMinLimit", "Min translation limit", "inversed translation limit")
404
405 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotLimitSpring", "Rotation spring limit", "0 0 0")
406 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotLimitDamping", "Rotation damping limit", "1 1 1")
407 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotLimitForceLimit", "Rotation limit force limit (-1 = infinite)", "-1 -1 -1")
408 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transLimitForceLimit", "Translation limit force limit (-1 = infinite)", "-1 -1 -1")
409 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transLimitSpring", "Translation spring limit", "0 0 0")
410 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transLimitDamping", "Translation damping limit", "1 1 1")
411
412 schema:register(XMLValueType.NODE_INDEX, "vehicle.base.components.joint(?)#zRotationNode", "Position of joints z rotation")
413 schema:register(XMLValueType.BOOL, "vehicle.base.components.joint(?)#breakable", "Joint is breakable", false)
414 schema:register(XMLValueType.FLOAT, "vehicle.base.components.joint(?)#breakForce", "Joint force until it breaks", 10)
415 schema:register(XMLValueType.FLOAT, "vehicle.base.components.joint(?)#breakTorque", "Joint torque until it breaks", 10)
416 schema:register(XMLValueType.BOOL, "vehicle.base.components.joint(?)#enableCollision", "Enable collision between both components", false)
417
418 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#maxRotDriveForce", "Max rotational drive force", "0 0 0")
419 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotDriveVelocity", "Rotational drive velocity")
420 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotDriveRotation", "Rotational drive rotation")
421 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotDriveSpring", "Rotational drive spring", "0 0 0")
422 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#rotDriveDamping", "Rotational drive damping", "0 0 0")
423
424 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transDriveVelocity", "Translational drive velocity")
425 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transDrivePosition", "Translational drive position")
426 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transDriveSpring", "Translational drive spring", "0 0 0")
427 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#transDriveDamping", "Translational drive damping", "1 1 1")
428 schema:register(XMLValueType.VECTOR_3, "vehicle.base.components.joint(?)#maxTransDriveForce", "Max translational drive force", "0 0 0")
429
430 schema:register(XMLValueType.BOOL, "vehicle.base.components.joint(?)#initComponentPosition", "Defines if the component is translated and rotated during loading based on joint movement", true)
431
432 schema:register(XMLValueType.BOOL, "vehicle.base.components.collisionPair(?)#enabled", "Collision between components enabled")
433 schema:register(XMLValueType.INT, "vehicle.base.components.collisionPair(?)#component1", "Index of first component")
434 schema:register(XMLValueType.INT, "vehicle.base.components.collisionPair(?)#component2", "Index of second component")
435
436 ObjectChangeUtil.registerObjectChangesXMLPaths(schema, "vehicle.base")
437
438 schema:register(XMLValueType.VECTOR_2, "vehicle.base.schemaOverlay#attacherJointPosition", "Position of attacher joint")
439 schema:register(XMLValueType.VECTOR_2, "vehicle.base.schemaOverlay#basePosition", "Position of vehicle")
440 schema:register(XMLValueType.STRING, "vehicle.base.schemaOverlay#name", "Name of schema overlay")
441 schema:register(XMLValueType.FLOAT, "vehicle.base.schemaOverlay#invisibleBorderRight", "Size of invisible border on the right")
442 schema:register(XMLValueType.FLOAT, "vehicle.base.schemaOverlay#invisibleBorderLeft", "Size of invisible border on the left")
443
444 ConfigurationUtil.registerColorConfigurationXMLPaths(schema, "baseColor")
445 ConfigurationUtil.registerColorConfigurationXMLPaths(schema, "designColor")
446 ConfigurationUtil.registerColorConfigurationXMLPaths(schema, "design")
447
448 ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.designConfigurations.designConfiguration(?)")
449 ObjectChangeUtil.registerObjectChangeXMLPaths(schema, "vehicle.vehicleTypeConfigurations.vehicleTypeConfiguration(?)")
450 schema:register(XMLValueType.STRING, "vehicle.vehicleTypeConfigurations.vehicleTypeConfiguration(?)#vehicleType", "Vehicle type for configuration")
451
452 for i=2, 8 do
453 ConfigurationUtil.registerColorConfigurationXMLPaths(schema, string.format("design%d", i))
454 ObjectChangeUtil.registerObjectChangeXMLPaths(schema, string.format("vehicle.design%dConfigurations.design%dConfiguration(?)", i, i))
455 end
456
457 schema:register(XMLValueType.BOOL, "vehicle.designConfigurations#preLoad", "Defines if the design configurations are applied before the execution of load or after. Can help if the configurations manipulate the wheel positions for example.", false)
458
459 StoreItemUtil.registerConfigurationSetXMLPaths(schema, "vehicle")
460
461 schemaSavegame:register(XMLValueType.BOOL, "vehicles#loadAnyFarmInSingleplayer", "Load any farm in singleplayer", false)
462 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?)#filename", "XML filename")
463 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?)#modName", "Vehicle mod name")
464 schemaSavegame:register(XMLValueType.BOOL, "vehicles.vehicle(?)#defaultFarmProperty", "Property of default farm", false)
465 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?)#id", "Vehicle id")
466 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?)#tourId", "Tour id")
467 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?)#farmId", "Farm id")
468 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?)#age", "Age in number of months")
469 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?)#price", "Price")
470 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?)#propertyState", "Property state")
471 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?)#activeMissionId", "Active mission id")
472 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?)#operatingTime", "Operating time")
473 schemaSavegame:register(XMLValueType.BOOL, "vehicles.vehicle(?)#isAbsolute", "Position is Absolute")
474 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?)#yOffset", "Y Offset")
475 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?)#xPosition", "X Position")
476 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?)#zPosition", "Z Position")
477 schemaSavegame:register(XMLValueType.FLOAT, "vehicles.vehicle(?)#yRotation", "Y Rotation")
478 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?)#selectedObjectIndex", "Selected object index")
479 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?)#subSelectedObjectIndex", "Sub selected object index")
480
481 schemaSavegame:register(XMLValueType.INT, "vehicles.vehicle(?).component(?)#index", "Component index")
482 schemaSavegame:register(XMLValueType.VECTOR_TRANS, "vehicles.vehicle(?).component(?)#position", "Component position")
483 schemaSavegame:register(XMLValueType.VECTOR_ROT, "vehicles.vehicle(?).component(?)#rotation", "Component rotation")
484
485 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?).boughtConfiguration(?)#name", "Configuration name")
486 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?).boughtConfiguration(?)#id", "Configuration save id")
487
488 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?).configuration(?)#name", "Configuration name")
489 schemaSavegame:register(XMLValueType.STRING, "vehicles.vehicle(?).configuration(?)#id", "Configuration save id")
490
491 VehicleActionController.registerXMLPaths(schemaSavegame, "vehicles.vehicle(?).actionController")
492
493 schemaSavegame:register(XMLValueType.INT, "vehicles.attachments(?)#rootVehicleId", "Id of root vehicle")
494end

registerSelectableObjects

Description
Definition
registerSelectableObjects()
Code
2714function Vehicle:registerSelectableObjects(selectableObjects)
2715 if self:getCanBeSelected() and not self:getBlockSelection() then
2716 table.insert(selectableObjects, self.selectionObject)
2717 self.selectionObject.index = #selectableObjects
2718 end
2719end

registerStateChange

Description
Definition
registerStateChange()
Code
81function Vehicle.registerStateChange(name)
82 local key = "STATE_CHANGE_"..string.upper(name)
83 if Vehicle[key] == nil then
84 Vehicle.NUM_STATE_CHANGES = Vehicle.NUM_STATE_CHANGES + 1
85 Vehicle[key] = Vehicle.NUM_STATE_CHANGES
86 end
87end

removeActionEvent

Description
Definition
removeActionEvent()
Code
2690function Vehicle:removeActionEvent(actionEventsTable, inputAction)
2691 if actionEventsTable[inputAction] ~= nil then
2692 g_inputBinding:removeActionEvent(actionEventsTable[inputAction].actionEventId)
2693 actionEventsTable[inputAction] = nil
2694 end
2695end

removeActionEvents

Description
Definition
removeActionEvents()
Code
2543function Vehicle:removeActionEvents()
2544 g_inputBinding:removeActionEventsByTarget(self)
2545end

removeFromPhysics

Description
Remove vehicle from physics
Definition
removeFromPhysics()
Code
2133function Vehicle:removeFromPhysics()
2134 for _, component in pairs(self.components) do
2135 removeFromPhysics(component.node)
2136 end
2137 -- invalidate wheel shapes and component joints (removing the components removes the wheels and joints too)
2138 if self.isServer then
2139 for _, jointDesc in pairs(self.componentJoints) do
2140 jointDesc.jointIndex = 0
2141 end
2142 removeWakeUpReport(self.rootNode)
2143 end
2144 self.isAddedToPhysics = false
2145
2146 return true
2147end

removeNodeObjectMapping

Description
Remove component nodes from list
Definition
removeNodeObjectMapping(table list)
Arguments
tablelistlist
Code
2083function Vehicle:removeNodeObjectMapping(list)
2084 if self.components ~= nil then
2085 for _,v in pairs(self.components) do
2086 list[v.node] = nil
2087 end
2088 end
2089end

requestActionEventUpdate

Description
Definition
requestActionEventUpdate()
Code
2528function Vehicle:requestActionEventUpdate()
2529 -- pass request to rootVehicle
2530 local vehicle = self.rootVehicle
2531 if vehicle == self then
2532 self.actionEventUpdateRequested = true
2533 else
2534 vehicle:requestActionEventUpdate()
2535 end
2536
2537 -- remove all actionEvents
2538 vehicle:removeActionEvents()
2539end

saveStatsToXMLFile

Description
Get xml states attributes
Definition
saveStatsToXMLFile()
Return Values
stringattributesattributes
Code
1412function Vehicle:saveStatsToXMLFile(xmlFile, key)
1413 local isTabbable = self.getIsTabbable == nil or self:getIsTabbable()
1414 if self.isDeleted or not self.isVehicleSaved or not isTabbable then
1415 return false
1416 end
1417 local name = "Unknown"
1418 local categoryName = "unknown"
1419 local storeItem = g_storeManager:getItemByXMLFilename(self.configFileName)
1420 if storeItem ~= nil then
1421 if storeItem.name ~= nil then
1422 name = tostring(storeItem.name)
1423 end
1424 if storeItem.categoryName ~= nil and storeItem.categoryName ~= "" then
1425 categoryName = tostring(storeItem.categoryName)
1426 end
1427 end
1428
1429 setXMLString(xmlFile, key.."#name", HTMLUtil.encodeToHTML(name))
1430 setXMLString(xmlFile, key.."#category", HTMLUtil.encodeToHTML(categoryName))
1431 setXMLString(xmlFile, key.."#type", HTMLUtil.encodeToHTML(tostring(self.typeName)))
1432
1433 if self.components[1] ~= nil and self.components[1].node ~= 0 then
1434 local x,y,z = getWorldTranslation(self.components[1].node)
1435 setXMLFloat(xmlFile, key.."#x", x)
1436 setXMLFloat(xmlFile, key.."#y", y)
1437 setXMLFloat(xmlFile, key.."#z", z)
1438 end
1439
1440 for id, spec in pairs(self.specializations) do
1441 if spec.saveStatsToXMLFile ~= nil then
1442 spec.saveStatsToXMLFile(self, xmlFile, key)
1443 end
1444 end
1445
1446 return true
1447end

saveToXMLFile

Description
Definition
saveToXMLFile()
Code
1335function Vehicle:saveToXMLFile(xmlFile, key, usedModNames)
1336 xmlFile:setValue(key.."#id", self.currentSavegameId)
1337 xmlFile:setValue(key.."#isAbsolute", true)
1338 xmlFile:setValue(key.."#age", self.age)
1339 xmlFile:setValue(key.."#price", self.price)
1340 xmlFile:setValue(key.."#farmId", self:getOwnerFarmId())
1341 xmlFile:setValue(key.."#propertyState", self.propertyState)
1342 xmlFile:setValue(key.."#operatingTime", self.operatingTime / 1000)
1343
1344 if self.activeMissionId ~= nil then
1345 xmlFile:setValue(key.."#activeMissionId", self.activeMissionId)
1346 end
1347
1348 if self.tourId ~= nil then
1349 xmlFile:setValue(key.."#tourId", self.tourId)
1350 end
1351
1352 if self.rootVehicle == self then
1353 xmlFile:setValue(key.."#selectedObjectIndex", self.currentSelection.index)
1354 if self.currentSelection.subIndex ~= nil then
1355 xmlFile:setValue(key.."#subSelectedObjectIndex", self.currentSelection.subIndex)
1356 end
1357 end
1358
1359 if not self.isBroken then
1360 for k, component in ipairs(self.components) do
1361 local compKey = string.format("%s.component(%d)", key, k-1)
1362 local node = component.node
1363 local x,y,z = getWorldTranslation(node)
1364 local xRot,yRot,zRot = getWorldRotation(node)
1365
1366 xmlFile:setValue(compKey.."#index", k)
1367 xmlFile:setValue(compKey.."#position", x, y, z)
1368 xmlFile:setValue(compKey.."#rotation", xRot, yRot, zRot)
1369 end
1370 end
1371
1372 local configIndex = 0
1373 for configName, configId in pairs(self.configurations) do
1374 local saveId = ConfigurationUtil.getSaveIdByConfigId(self.configFileName, configName, configId)
1375 if saveId ~= nil then
1376 local configKey = string.format("%s.configuration(%d)", key, configIndex)
1377 xmlFile:setValue(configKey.."#name", configName)
1378 xmlFile:setValue(configKey.."#id", saveId)
1379 configIndex = configIndex + 1
1380 end
1381 end
1382
1383 configIndex = 0
1384 for configName, configIds in pairs(self.boughtConfigurations) do
1385 for configId,_ in pairs(configIds) do
1386 local saveId = ConfigurationUtil.getSaveIdByConfigId(self.configFileName, configName, configId)
1387 if saveId ~= nil then
1388 local configKey = string.format("%s.boughtConfiguration(%d)", key, configIndex)
1389 xmlFile:setValue(configKey.."#name", configName)
1390 xmlFile:setValue(configKey.."#id", saveId)
1391 configIndex = configIndex + 1
1392 end
1393 end
1394 end
1395
1396 for id, spec in pairs(self.specializations) do
1397 local name = self.specializationNames[id]
1398
1399 if spec.saveToXMLFile ~= nil then
1400 spec.saveToXMLFile(self, xmlFile, key.."."..name, usedModNames)
1401 end
1402 end
1403
1404 if self.actionController ~= nil then
1405 self.actionController:saveToXMLFile(xmlFile, key..".actionController", usedModNames)
1406 end
1407end

selectVehicle

Description
Definition
selectVehicle()
Code
2810function Vehicle:selectVehicle(subSelectionIndex, ignoreActionEventUpdate)
2811 self.selectionObject.isSelected = true
2812 SpecializationUtil.raiseEvent(self, "onSelect", subSelectionIndex)
2813
2814 if ignoreActionEventUpdate == nil or not ignoreActionEventUpdate then
2815 self:requestActionEventUpdate()
2816 end
2817end

setAbsolutePosition

Description
Definition
setAbsolutePosition()
Code
2173function Vehicle:setAbsolutePosition(positionX, positionY, positionZ, xRot, yRot, zRot, componentPositions)
2174 local tempRootNode = createTransformGroup("tempRootNode")
2175 setTranslation(tempRootNode, positionX, positionY, positionZ)
2176 setRotation(tempRootNode, xRot, yRot, zRot)
2177
2178 -- now move the objects to the scene root node
2179 for i, component in pairs(self.components) do
2180 local x,y,z = localToWorld(tempRootNode, unpack(component.originalTranslation))
2181 local rx,ry,rz = localRotationToWorld(tempRootNode, unpack(component.originalRotation))
2182
2183 if componentPositions ~= nil and #componentPositions == #self.components then
2184 x,y,z = unpack(componentPositions[i][1])
2185 rx,ry,rz = unpack(componentPositions[i][2])
2186 end
2187
2188 self:setWorldPosition(x, y, z, rx, ry, rz, i, true)
2189 end
2190 delete(tempRootNode)
2191
2192 self.networkTimeInterpolator:reset()
2193end

setBroken

Description
Definition
setBroken()
Code
2499function Vehicle:setBroken()
2500 if self.isServer and not self.isBroken then
2501 g_server:broadcastEvent(VehicleBrokenEvent.new(self), nil, nil, self)
2502 end
2503
2504 self.isBroken = true
2505 SpecializationUtil.raiseEvent(self, "onSetBroken")
2506end

setComponentJointFrame

Description
Set component joint frame
Definition
setComponentJointFrame(Integer jointDesc, Integer anchorActor)
Arguments
IntegerjointDescjoint desc index
IntegeranchorActoranchor actor
Code
3107function Vehicle:setComponentJointFrame(jointDesc, anchorActor)
3108 if anchorActor == 0 then
3109 local localPoses = jointDesc.jointLocalPoses[1]
3110 localPoses.trans[1], localPoses.trans[2], localPoses.trans[3] = localToLocal(jointDesc.jointNode, self.components[jointDesc.componentIndices[1]].node, 0, 0, 0)
3111 localPoses.rot[1], localPoses.rot[2], localPoses.rot[3] = localRotationToLocal(jointDesc.jointNode, self.components[jointDesc.componentIndices[1]].node, 0, 0, 0)
3112 else
3113 local localPoses = jointDesc.jointLocalPoses[2]
3114 localPoses.trans[1], localPoses.trans[2], localPoses.trans[3] = localToLocal(jointDesc.jointNodeActor1, self.components[jointDesc.componentIndices[2]].node, 0, 0, 0)
3115 localPoses.rot[1], localPoses.rot[2], localPoses.rot[3] = localRotationToLocal(jointDesc.jointNodeActor1, self.components[jointDesc.componentIndices[2]].node, 0, 0, 0)
3116 end
3117
3118 local jointNode = jointDesc.jointNode
3119 if anchorActor == 1 then
3120 jointNode = jointDesc.jointNodeActor1
3121 end
3122
3123 if jointDesc.jointIndex ~= 0 then
3124 setJointFrame(jointDesc.jointIndex, anchorActor, jointNode)
3125 end
3126end

setComponentJointRotLimit

Description
Set component joint rot limit
Definition
setComponentJointRotLimit(Integer componentJoint, Integer axis, float minLimit, float maxLimit)
Arguments
IntegercomponentJointindex of component joint
Integeraxisaxis
floatminLimitmin limit
floatmaxLimitmax limit
Code
3135function Vehicle:setComponentJointRotLimit(componentJoint, axis, minLimit, maxLimit)
3136 if self.isServer then
3137 componentJoint.rotLimit[axis] = maxLimit
3138 componentJoint.rotMinLimit[axis] = minLimit
3139
3140 if componentJoint.jointIndex ~= 0 then
3141 if minLimit <= maxLimit then
3142 setJointRotationLimit(componentJoint.jointIndex, axis-1, true, minLimit, maxLimit)
3143 else
3144 setJointRotationLimit(componentJoint.jointIndex, axis-1, false, 0, 0)
3145 end
3146 end
3147 end
3148end

setComponentJointTransLimit

Description
Set component joint trans limit
Definition
setComponentJointTransLimit(Integer componentJoint, Integer axis, float minLimit, float maxLimit)
Arguments
IntegercomponentJointindex of component joint
Integeraxisaxis
floatminLimitmin limit
floatmaxLimitmax limit
Code
3156function Vehicle:setComponentJointTransLimit(componentJoint, axis, minLimit, maxLimit)
3157 if self.isServer then
3158 componentJoint.transLimit[axis] = maxLimit
3159 componentJoint.transMinLimit[axis] = minLimit
3160
3161 if componentJoint.jointIndex ~= 0 then
3162 if minLimit <= maxLimit then
3163 setJointTranslationLimit(componentJoint.jointIndex, axis-1, true, minLimit, maxLimit)
3164 else
3165 setJointTranslationLimit(componentJoint.jointIndex, axis-1, false, 0, 0)
3166 end
3167 end
3168 end
3169end

setLoadingState

Description
Definition
setLoadingState()
Code
2044function Vehicle:setLoadingState(loadingState)
2045 if loadingState == VehicleLoadingUtil.VEHICLE_LOAD_OK or loadingState == VehicleLoadingUtil.VEHICLE_LOAD_ERROR or loadingState == VehicleLoadingUtil.VEHICLE_LOAD_DELAYED or loadingState == VehicleLoadingUtil.VEHICLE_LOAD_NO_SPACE then
2046 self.loadingState = loadingState
2047 else
2048 printCallstack()
2049 Logging.error("Invalid loading state '%s'!", loadingState)
2050 end
2051end

setLoadingStep

Description
Definition
setLoadingStep()
Code
2055function Vehicle:setLoadingStep(loadingStep)
2056 if loadingStep == Vehicle.LOAD_STEP_CREATED
2057 or loadingStep == Vehicle.LOAD_STEP_PRE_LOAD
2058 or loadingStep == Vehicle.LOAD_STEP_AWAIT_I3D
2059 or loadingStep == Vehicle.LOAD_STEP_LOAD
2060 or loadingStep == Vehicle.LOAD_STEP_POST_LOAD
2061 or loadingStep == Vehicle.LOAD_STEP_AWAIT_SUB_I3D
2062 or loadingStep == Vehicle.LOAD_STEP_FINISHED
2063 or loadingStep == Vehicle.LOAD_STEP_SYNCHRONIZED then
2064 self.loadingStep = loadingStep
2065 else
2066 printCallstack()
2067 Logging.error("Invalid loading step '%s'!", loadingStep)
2068 end
2069end

setMassDirty

Description
Definition
setMassDirty()
Code
2938function Vehicle:setMassDirty()
2939 self.isMassDirty = true
2940end

setObjectChangeValues

Description
Sets object change values
Definition
setObjectChangeValues(table object, boolean isActive)
Arguments
tableobjectobject
booleanisActiveis active
Code
3963function Vehicle:setObjectChangeValues(object, isActive)
3964end

setOperatingTime

Description
Definition
setOperatingTime()
Code
3638function Vehicle:setOperatingTime(operatingTime, isLoading)
3639 if not isLoading and self.propertyState == Vehicle.PROPERTY_STATE_LEASED and g_currentMission ~= nil and g_currentMission.economyManager ~= nil and math.floor(operatingTime/(1000*60*60)) > math.floor(self.operatingTime/(1000*60*60)) then
3640 g_currentMission.economyManager:vehicleOperatingHourChanged(self)
3641 end
3642 self.operatingTime = math.max(Utils.getNoNil(operatingTime, 0), 0)
3643end

setOwnerFarmId

Description
Definition
setOwnerFarmId()
Code
3974function Vehicle:setOwnerFarmId(farmId, noEventSend)
3975 Vehicle:superClass().setOwnerFarmId(self, farmId, noEventSend)
3976
3977 if self.mapHotspot ~= nil then
3978 self.mapHotspot:setOwnerFarmId(farmId)
3979 end
3980end

setRelativePosition

Description
Set relative position of vehicle
Definition
setRelativePosition(float positionX, float offsetY, float positionZ, float yRot)
Arguments
floatpositionXx position
floatoffsetYy offset
floatpositionZz position
floatyRoty rotation
Code
2164function Vehicle:setRelativePosition(positionX, offsetY, positionZ, yRot)
2165 -- position the vehicle
2166 local terrainHeight = getTerrainHeightAtWorldPos(g_currentMission.terrainRootNode, positionX, 300, positionZ)
2167
2168 self:setAbsolutePosition(positionX, terrainHeight+offsetY, positionZ, 0, yRot, 0)
2169end

setSelectedObject

Description
Definition
setSelectedObject()
Code
2844function Vehicle:setSelectedObject(object, subSelectionIndex, ignoreActionEventUpdate)
2845 local currentSelection = self.currentSelection
2846
2847 if object == nil then
2848 object = self:getSelectedObject()
2849 end
2850
2851 local found = false
2852 for _, o in ipairs(self.selectableObjects) do
2853 if o == object then
2854 found = true
2855 end
2856 end
2857
2858 if found then
2859 -- if object was found unselect all other vehicles
2860 for _, o in ipairs(self.selectableObjects) do
2861 if o ~= object and o.vehicle:getIsSelected() then
2862 o.vehicle:unselectVehicle()
2863 end
2864 end
2865
2866 if object ~= currentSelection.object or subSelectionIndex ~= currentSelection.subIndex then
2867 currentSelection.object = object
2868 currentSelection.index = object.index
2869 if subSelectionIndex ~= nil then
2870 currentSelection.subIndex = subSelectionIndex
2871 end
2872 if currentSelection.subIndex > #object.subSelections then
2873 currentSelection.subIndex = 1
2874 end
2875
2876 currentSelection.object.vehicle:selectVehicle(currentSelection.subIndex, ignoreActionEventUpdate)
2877
2878 return true
2879 end
2880 else
2881 object = self:getSelectedObject()
2882
2883 found = false
2884 for _, o in ipairs(self.selectableObjects) do
2885 if o == object then
2886 found = true
2887 end
2888 end
2889
2890 -- if the object to select could not be found and the object that was selected is not available anymore we clear the selection
2891 if not found then
2892 currentSelection.object = nil
2893 currentSelection.index = 1
2894 currentSelection.subIndex = 1
2895 end
2896 end
2897
2898 return false
2899end

setSelectedVehicle

Description
Definition
setSelectedVehicle()
Code
2821function Vehicle:setSelectedVehicle(vehicle, subSelectionIndex, ignoreActionEventUpdate)
2822 local object = nil
2823
2824 -- if vehicle could not be selected we select the next possible vehicle
2825 if vehicle == nil or not vehicle:getCanBeSelected() or self:getBlockSelection() then
2826 vehicle = nil
2827 for _, o in ipairs(self.selectableObjects) do
2828 if o.vehicle:getCanBeSelected() and not o.vehicle:getBlockSelection() then
2829 vehicle = o.vehicle
2830 break
2831 end
2832 end
2833 end
2834
2835 if vehicle ~= nil then
2836 object = vehicle.selectionObject
2837 end
2838
2839 return self:setSelectedObject(object, subSelectionIndex, ignoreActionEventUpdate)
2840end

setVisibility

Description
Sets visibility of a vehicle
Definition
setVisibility(boolean state)
Arguments
booleanstatevisibility state
Code
2152function Vehicle:setVisibility(state)
2153 for _, component in pairs(self.components) do
2154 setVisibility(component.node, state)
2155 end
2156end

setWorldPosition

Description
Set world position and rotation of component
Definition
setWorldPosition(float x, float y, float z, float xRot, float yRot, float zRot, Integer i, boolean changeInterp)
Arguments
floatxx position
floatyy position
floatzz position
floatxRotx rotation
floatyRoty rotation
floatzRotz rotation
Integeriindex if component
booleanchangeInterpchange interpolation
Code
2217function Vehicle:setWorldPosition(x,y,z, xRot,yRot,zRot, i, changeInterp)
2218 local component = self.components[i]
2219 setWorldTranslation(component.node, x,y,z)
2220 setWorldRotation(component.node, xRot,yRot,zRot)
2221 if changeInterp then
2222 local qx, qy, qz, qw = mathEulerToQuaternion(xRot,yRot,zRot)
2223 component.networkInterpolators.quaternion:setQuaternion(qx, qy, qz, qw)
2224 component.networkInterpolators.position:setPosition(x,y,z)
2225 end
2226end

setWorldPositionQuaternion

Description
Set world position and quaternion rotation of component
Definition
setWorldPositionQuaternion(float x, float y, float z, float qx, float qy, float qz, float qw, Integer i, boolean changeInterp)
Arguments
floatxx position
floatyy position
floatzz position
floatqxx rotation
floatqyy rotation
floatqzz rotation
floatqww rotation
Integeriindex if component
booleanchangeInterpchange interpolation
Code
2239function Vehicle:setWorldPositionQuaternion(x,y,z, qx,qy,qz,qw, i, changeInterp)
2240 local component = self.components[i]
2241 setWorldTranslation(component.node, x,y,z)
2242 setWorldQuaternion(component.node, qx,qy,qz,qw)
2243 if changeInterp then
2244 component.networkInterpolators.quaternion:setQuaternion(qx, qy, qz, qw)
2245 component.networkInterpolators.position:setPosition(x,y,z)
2246 end
2247end

showInfo

Description
Definition
showInfo()
Code
3944function Vehicle:showInfo(box)
3945 if self.isBroken then
3946 box:addLine(g_i18n:getText("infohud_vehicleBrokenNeedToReset"), nil, true)
3947 end
3948end

tryFinishLoading

Description
Definition
tryFinishLoading()
Code
1231function Vehicle:tryFinishLoading()
1232 if self.subLoadingTasksFinished then
1233 if self.isServer then
1234 -- Only servers add to physics and make visible now. Clients will do this later in postReadStream
1235 self:setVisibility(true)
1236 self:addToPhysics()
1237 end
1238
1239 self:setLoadingStep(Vehicle.LOAD_STEP_FINISHED)
1240 SpecializationUtil.raiseEvent(self, "onLoadFinished", self.savegame)
1241
1242 -- if we are the server or in single player we don't need to be synchonized
1243 if self.isServer then
1244 self:setLoadingStep(Vehicle.LOAD_STEP_SYNCHRONIZED)
1245 end
1246
1247 if g_currentMission ~= nil and self.propertyState ~= Vehicle.PROPERTY_STATE_SHOP_CONFIG and self.mapHotspotAvailable then
1248 self:createMapHotspot()
1249 end
1250
1251 self.finishedLoading = true
1252
1253 local asyncData = self.subLoadingTasksFinishedAsyncData
1254 asyncData.asyncCallbackFunction(asyncData.asyncCallbackObject, self, self.loadingState, asyncData.asyncCallbackArguments)
1255
1256 self.savegame = nil
1257 end
1258end

unselectVehicle

Description
Definition
unselectVehicle()
Code
2801function Vehicle:unselectVehicle()
2802 self.selectionObject.isSelected = false
2803 SpecializationUtil.raiseEvent(self, "onUnselect")
2804
2805 self:requestActionEventUpdate()
2806end

update

Description
Definition
update()
Code
1830function Vehicle:update(dt)
1831 -- states
1832 self.isActive = self:getIsActive()
1833 local isActiveForInput = self:getIsActiveForInput()
1834 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1835 local isSelected = self:getIsSelected()
1836 self.lastDistanceToCamera = calcDistanceFrom(self.rootNode, getCamera())
1837 self.currentUpdateDistance = self.lastDistanceToCamera / self.lodDistanceCoeff
1838 self.isActiveForInputIgnoreSelectionIgnoreAI = self:getIsActiveForInput(true, true)
1839 self.isActiveForLocalSound = self.isActiveForInputIgnoreSelectionIgnoreAI
1840
1841 self.updateLoopIndex = g_updateLoopIndex
1842
1843 SpecializationUtil.raiseEvent(self, "onPreUpdate", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1844
1845 -- interpolation of position
1846 if not self.isServer and self.synchronizePosition then
1847 self.networkTimeInterpolator:update(dt)
1848 local interpolationAlpha = self.networkTimeInterpolator:getAlpha()
1849 for i, component in pairs(self.components) do
1850 if not component.isStatic then
1851 local posX, posY, posZ = component.networkInterpolators.position:getInterpolatedValues(interpolationAlpha)
1852 local quatX, quatY, quatZ, quatW = component.networkInterpolators.quaternion:getInterpolatedValues(interpolationAlpha)
1853 self:setWorldPositionQuaternion(posX, posY, posZ, quatX, quatY, quatZ, quatW, i, false)
1854 end
1855 end
1856
1857 if self.networkTimeInterpolator:isInterpolating() then
1858 self:raiseActive()
1859 end
1860 end
1861 SpecializationUtil.raiseEvent(self, "onUpdateInterpolation", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1862
1863 self:updateVehicleSpeed(dt)
1864
1865 if self.actionEventUpdateRequested then
1866 self:updateActionEvents()
1867 end
1868
1869 if Platform.gameplay.automaticVehicleControl then
1870 if self.actionController ~= nil then
1871 self.actionController:update(dt)
1872 self.actionController:updateForAI(dt)
1873 end
1874 else
1875 if self.actionController ~= nil then
1876 self.actionController:updateForAI(dt)
1877 end
1878 end
1879
1880 SpecializationUtil.raiseEvent(self, "onUpdate", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1881 if Vehicle.debuggingActive then
1882 SpecializationUtil.raiseEvent(self, "onUpdateDebug", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1883 end
1884 SpecializationUtil.raiseEvent(self, "onPostUpdate", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1885
1886 if self.finishedFirstUpdate and self.isMassDirty then
1887 self.isMassDirty = false
1888 self:updateMass()
1889 end
1890
1891 self.finishedFirstUpdate = true
1892
1893 if self.isServer then
1894 if not getIsSleeping(self.rootNode) then
1895 self:raiseActive()
1896 end
1897 end
1898
1899 VehicleDebug.updateDebug(self, dt)
1900
1901 self:updateMapHotspot()
1902end

updateActionEvents

Description
Definition
updateActionEvents()
Code
2549function Vehicle:updateActionEvents()
2550 local rootVehicle = self.rootVehicle
2551 rootVehicle:registerActionEvents()
2552end

updateEnd

Description
Definition
updateEnd()
Code
1977function Vehicle:updateEnd(dt)
1978 local isActiveForInput = self:getIsActiveForInput()
1979 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1980 local isSelected = self:getIsSelected()
1981
1982 SpecializationUtil.raiseEvent(self, "onUpdateEnd", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1983end

updateMapHotspot

Description
Definition
updateMapHotspot()
Code
3930function Vehicle:updateMapHotspot()
3931 if self.mapHotspot ~= nil then
3932 self.mapHotspot:setVisible(self:getIsMapHotspotVisible())
3933 end
3934end

updateMass

Description
Definition
updateMass()
Code
2944function Vehicle:updateMass()
2945 self.serverMass = 0
2946
2947 for _, component in ipairs(self.components) do
2948 if component.defaultMass == nil then
2949 if component.isDynamic then
2950 component.defaultMass = getMass(component.node)
2951 else
2952 component.defaultMass = 1
2953 end
2954 component.mass = component.defaultMass
2955 end
2956
2957 local mass = self:getAdditionalComponentMass(component)
2958 component.mass = component.defaultMass + mass
2959 self.serverMass = self.serverMass + component.mass
2960 end
2961
2962 local realTotalMass = 0
2963 for _, component in ipairs(self.components) do
2964 realTotalMass = realTotalMass + self:getComponentMass(component)
2965 end
2966
2967 self.precalculatedMass = realTotalMass - self.serverMass
2968
2969 for _, component in ipairs(self.components) do
2970 local maxFactor = self.serverMass / (self.maxComponentMass - self.precalculatedMass)
2971
2972 if maxFactor > 1 then
2973 component.mass = component.mass / maxFactor
2974 end
2975
2976 -- only update physically mass if difference to last mass is greater 20kg
2977 if self.isServer and component.isDynamic and math.abs(component.lastMass-component.mass) > 0.02 then
2978 setMass(component.node, component.mass)
2979 component.lastMass = component.mass
2980 end
2981 end
2982
2983 self.serverMass = math.min(self.serverMass, self.maxComponentMass - self.precalculatedMass)
2984end

updateSelectableObjects

Description
Definition
updateSelectableObjects()
Code
2705function Vehicle:updateSelectableObjects()
2706 self.selectableObjects = {}
2707 if self == self.rootVehicle then
2708 self:registerSelectableObjects(self.selectableObjects)
2709 end
2710end

updateTick

Description
updateTick
Definition
updateTick(float dt)
Arguments
floatdttime since last call in ms
Code
1907function Vehicle:updateTick(dt)
1908 local isActiveForInput = self:getIsActiveForInput()
1909 local isActiveForInputIgnoreSelection = self:getIsActiveForInput(true)
1910 local isSelected = self:getIsSelected()
1911
1912 self.wasTooFast = false
1913
1914 if self.isActive then
1915 self:updateWaterInfo()
1916 end
1917
1918 if self.isServer then
1919 if self.synchronizePosition then
1920 local hasOwner = self:getOwner() ~= nil
1921 for i=1, #self.components do
1922 local component = self.components[i]
1923 if not component.isStatic then
1924 local x,y,z = getWorldTranslation(component.node)
1925 local x_rot,y_rot,z_rot=getWorldRotation(component.node)
1926 local sentTranslation = component.sentTranslation
1927 local sentRotation = component.sentRotation
1928 if hasOwner or
1929 math.abs(x-sentTranslation[1]) > 0.005 or
1930 math.abs(y-sentTranslation[2]) > 0.005 or
1931 math.abs(z-sentTranslation[3]) > 0.005 or
1932 math.abs(x_rot-sentRotation[1]) > 0.1 or
1933 math.abs(y_rot-sentRotation[2]) > 0.1 or
1934 math.abs(z_rot-sentRotation[3]) > 0.1
1935 then
1936 self:raiseDirtyFlags(self.vehicleDirtyFlag)
1937 sentTranslation[1] = x
1938 sentTranslation[2] = y
1939 sentTranslation[3] = z
1940 sentRotation[1] = x_rot
1941 sentRotation[2] = y_rot
1942 sentRotation[3] = z_rot
1943
1944 self.lastMoveTime = g_currentMission.time
1945 end
1946 end
1947 end
1948 end
1949
1950 -- is the vehicle sunken in the water?
1951 self.showTailwaterDepthWarning = false
1952 if not self.isBroken and not g_gui:getIsGuiVisible() then
1953 if self.tailwaterDepth > self.thresholdTailwaterDepthWarning then
1954 self.showTailwaterDepthWarning = true
1955 if self.tailwaterDepth > self.thresholdTailwaterDepth then
1956 self:setBroken()
1957 end
1958 end
1959 end
1960
1961 local rootAttacherVehicle = self.rootVehicle
1962 if rootAttacherVehicle ~= nil and rootAttacherVehicle ~= self then
1963 rootAttacherVehicle.showTailwaterDepthWarning = rootAttacherVehicle.showTailwaterDepthWarning or self.showTailwaterDepthWarning
1964 end
1965 end
1966
1967 if self:getIsOperating() then
1968 self:setOperatingTime(self.operatingTime + dt)
1969 end
1970
1971 SpecializationUtil.raiseEvent(self, "onUpdateTick", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1972 SpecializationUtil.raiseEvent(self, "onPostUpdateTick", dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
1973end

updateVehicleChain

Description
Definition
updateVehicleChain()
Code
2772function Vehicle:updateVehicleChain(secondCall)
2773 local rootVehicle = self:findRootVehicle()
2774 if rootVehicle ~= self.rootVehicle then
2775 self.rootVehicle = rootVehicle
2776 SpecializationUtil.raiseEvent(self, "onRootVehicleChanged", rootVehicle)
2777 end
2778
2779 if rootVehicle ~= self and not secondCall then
2780 rootVehicle:updateVehicleChain()
2781 return
2782 end
2783
2784 for i=#self.childVehicles, 1, -1 do
2785 self.childVehicles[i] = nil
2786 end
2787
2788 self:addChildVehicles(self.childVehicles)
2789
2790 if rootVehicle == self then
2791 for i=1, #self.childVehicles do
2792 if self.childVehicles[i] ~= rootVehicle then
2793 self.childVehicles[i]:updateVehicleChain(true)
2794 end
2795 end
2796 end
2797end

updateVehicleSpeed

Description
Definition
updateVehicleSpeed()
Code
1748function Vehicle:updateVehicleSpeed(dt)
1749 -- On servers, the physics state is only change
1750 if self.finishedFirstUpdate and not self.components[1].isStatic then
1751 local speedReal = 0
1752 local movedDistance = 0
1753 local movingDirection = 0
1754 local signedSpeedReal = 0
1755
1756 if not self.isServer or self.components[1].isKinematic then
1757 if not self.isServer and self.synchronizePosition then
1758 -- Client code can use the interpolation information that is driving the position change
1759 local interpPos = self.components[1].networkInterpolators.position
1760 local dx, dy, dz = 0, 0, 0
1761 if self.networkTimeInterpolator:isInterpolating() then
1762 dx, dy, dz = worldDirectionToLocal(self.components[1].node, interpPos.targetPositionX-interpPos.lastPositionX, interpPos.targetPositionY-interpPos.lastPositionY, interpPos.targetPositionZ-interpPos.lastPositionZ)
1763 end
1764
1765 if dz > 0.001 then
1766 movingDirection = 1
1767 elseif dz < -0.001 then
1768 movingDirection = -1
1769 end
1770 speedReal = MathUtil.vector3Length(dx, dy, dz) / self.networkTimeInterpolator.interpolationDuration
1771 signedSpeedReal = speedReal * (dz >= 0 and 1 or -1)
1772 movedDistance = speedReal * dt
1773 else
1774 -- Client or kinematic code can't use physics velocity, so calculate based on the position change
1775 local x,y,z = getWorldTranslation(self.components[1].node)
1776 if self.lastPosition == nil then
1777 self.lastPosition = {x,y,z}
1778 end
1779 local dx, dy, dz = worldDirectionToLocal(self.components[1].node, x-self.lastPosition[1], y-self.lastPosition[2], z-self.lastPosition[3])
1780 self.lastPosition[1], self.lastPosition[2], self.lastPosition[3] = x, y, z
1781 if dz > 0.001 then
1782 movingDirection = 1
1783 elseif dz < -0.001 then
1784 movingDirection = -1
1785 end
1786 movedDistance = MathUtil.vector3Length(dx, dy, dz)
1787 speedReal = movedDistance / dt
1788 signedSpeedReal = speedReal * (dz >= 0 and 1 or -1)
1789 end
1790 elseif self.components[1].isDynamic then
1791 -- Dynamic objects on server use velocity provided by the physics engine
1792 local vx, vy, vz = getLocalLinearVelocity(self.components[1].node)
1793 speedReal = MathUtil.vector3Length(vx, vy, vz)*0.001
1794 movedDistance = speedReal*g_physicsDt
1795 signedSpeedReal = speedReal * (vz >= 0 and 1 or -1)
1796 if vz > 0.001 then
1797 movingDirection = 1
1798 elseif vz < -0.001 then
1799 movingDirection = -1
1800 end
1801 end
1802
1803 if self.isServer then
1804 -- On the server, the velocity only changes when a physics simulation step is performed (thus only update the acceleration when something was simulated)
1805 if g_physicsDtNonInterpolated > 0 then
1806 self.lastSpeedAcceleration = (speedReal*movingDirection - self.lastSpeedReal*self.movingDirection) / g_physicsDtNonInterpolated
1807 end
1808 else
1809 -- On the client, the position is driven by the interpolation (updated with dt)
1810 self.lastSpeedAcceleration = (speedReal*movingDirection - self.lastSpeedReal*self.movingDirection) / dt
1811 end
1812
1813 -- Update smooth values (use less smoothing on the server)
1814 if self.isServer then
1815 self.lastSpeed = self.lastSpeed*0.5 + speedReal*0.5
1816 self.lastSignedSpeed = self.lastSignedSpeed*0.5 + signedSpeedReal*0.5
1817 else
1818 self.lastSpeed = self.lastSpeed*0.9 + speedReal*0.1
1819 self.lastSignedSpeed = self.lastSignedSpeed*0.9 + signedSpeedReal*0.1
1820 end
1821 self.lastSpeedReal = speedReal
1822 self.lastSignedSpeedReal = signedSpeedReal
1823 self.movingDirection = movingDirection
1824 self.lastMovedDistance = movedDistance
1825 end
1826end

updateWaterInfo

Description
Definition
updateWaterInfo()
Code
2469function Vehicle:updateWaterInfo()
2470 -- water info is always one frame delayed for current position (async)
2471 local x, y, z = getWorldTranslation(self.rootNode)
2472 self.waterCheckPosition[1] = x
2473 self.waterCheckPosition[2] = y
2474 self.waterCheckPosition[3] = z
2475 g_currentMission.environmentAreaSystem:getWaterYAtWorldPositionAsync(x, y, z, self.onWaterRaycastCallback, self, nil)
2476end

wakeUp

Description
Shortly wake up the vehicle physics
Definition
wakeUp()
Code
3968function Vehicle:wakeUp()
3969 I3DUtil.wakeUpObject(self.components[1].node)
3970end

writeStream

Description
Called on server side on join
Definition
writeStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
1580function Vehicle:writeStream(streamId, connection)
1581 Vehicle:superClass().writeStream(self, streamId, connection)
1582
1583 streamWriteString(streamId, NetworkUtil.convertToNetworkFilename(self.configFileName))
1584 streamWriteString(streamId, self.typeName)
1585
1586 local numConfigs = 0
1587 for _,_ in pairs(self.configurations) do
1588 numConfigs = numConfigs + 1
1589 end
1590
1591 streamWriteUIntN(streamId, numConfigs, ConfigurationUtil.SEND_NUM_BITS)
1592 for configName, configId in pairs(self.configurations) do
1593 local configNameId = g_configurationManager:getConfigurationIndexByName(configName)
1594 streamWriteUIntN(streamId, configNameId-1, ConfigurationUtil.SEND_NUM_BITS)
1595 streamWriteUInt16(streamId, configId-1)
1596 end
1597
1598 local numBoughtConfigs = 0
1599 for _,_ in pairs(self.boughtConfigurations) do
1600 numBoughtConfigs = numBoughtConfigs + 1
1601 end
1602
1603 streamWriteUIntN(streamId, numBoughtConfigs, ConfigurationUtil.SEND_NUM_BITS)
1604 for configName, configIds in pairs(self.boughtConfigurations) do
1605 local numBoughtConfigIds = 0
1606 for _,_ in pairs(configIds) do
1607 numBoughtConfigIds = numBoughtConfigIds + 1
1608 end
1609 local configNameId = g_configurationManager:getConfigurationIndexByName(configName)
1610 streamWriteUIntN(streamId, configNameId-1, ConfigurationUtil.SEND_NUM_BITS)
1611 streamWriteUInt16(streamId, numBoughtConfigIds)
1612 for id, _ in pairs(configIds) do
1613 streamWriteUInt16(streamId, id-1)
1614 end
1615 end
1616
1617 streamWriteUIntN(streamId, self.propertyState, 2)
1618end

writeUpdateStream

Description
Called on server side on update
Definition
writeUpdateStream(integer streamId, table connection, integer dirtyMask)
Arguments
integerstreamIdstream ID
tableconnectionconnection
integerdirtyMaskdirty mask
Code
1709function Vehicle:writeUpdateStream(streamId, connection, dirtyMask)
1710 if not connection.isServer then
1711 if streamWriteBool(streamId, bitAND(dirtyMask, self.vehicleDirtyFlag) ~= 0) then
1712
1713 local paramsXZ = self.highPrecisionPositionSynchronization and g_currentMission.vehicleXZPosHighPrecisionCompressionParams or g_currentMission.vehicleXZPosCompressionParams
1714 local paramsY = self.highPrecisionPositionSynchronization and g_currentMission.vehicleYPosHighPrecisionCompressionParams or g_currentMission.vehicleYPosCompressionParams
1715 for i=1, #self.components do
1716 local component = self.components[i]
1717 if not component.isStatic then
1718 local x,y,z = getWorldTranslation(component.node)
1719 local x_rot,y_rot,z_rot = getWorldRotation(component.node)
1720 NetworkUtil.writeCompressedWorldPosition(streamId, x, paramsXZ)
1721 NetworkUtil.writeCompressedWorldPosition(streamId, y, paramsY)
1722 NetworkUtil.writeCompressedWorldPosition(streamId, z, paramsXZ)
1723 NetworkUtil.writeCompressedAngle(streamId, x_rot)
1724 NetworkUtil.writeCompressedAngle(streamId, y_rot)
1725 NetworkUtil.writeCompressedAngle(streamId, z_rot)
1726 end
1727 end
1728 SpecializationUtil.raiseEvent(self, "onWritePositionUpdateStream", streamId, connection, dirtyMask)
1729 end
1730 end
1731
1732 if Vehicle.DEBUG_NETWORK_READ_WRITE_UPDATE then
1733 print("-------------------------------------------------------------")
1734 print(self.configFileName)
1735 for _, spec in ipairs(self.eventListeners["onWriteUpdateStream"]) do
1736 local className = ClassUtil.getClassName(spec)
1737 local startBits = streamGetWriteOffset(streamId)
1738 spec["onWriteUpdateStream"](self, streamId, connection, dirtyMask)
1739 print(" "..tostring(className).." Wrote " .. streamGetWriteOffset(streamId)-startBits .. " bits")
1740 end
1741 else
1742 SpecializationUtil.raiseEvent(self, "onWriteUpdateStream", streamId, connection, dirtyMask)
1743 end
1744end