LUADOC - Farming Simulator 22

Script v1_7_1_0

Engine v1_7_1_0

Foundation Reference

PlaceableLights

Description
Specialization for placeables
Functions

getUseHighProfile

Description
Definition
getUseHighProfile()
Code
421function PlaceableLights:getUseHighProfile()
422 local lightsProfile = g_gameSettings:getValue("lightsProfile")
423 lightsProfile = Utils.getNoNil(Platform.gameplay.lightsProfile, lightsProfile)
424
425 return lightsProfile == GS_PROFILE_VERY_HIGH or lightsProfile == GS_PROFILE_HIGH
426end

lightSetupChanged

Description
Definition
lightSetupChanged()
Code
522function PlaceableLights:lightSetupChanged()
523 local spec = self.spec_lights
524 for k, group in ipairs(spec.groups) do
525 self:updateLightState(k, group.isActive)
526 end
527end

lightsTriggerCallback

Description
Definition
lightsTriggerCallback()
Code
493function PlaceableLights:lightsTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay)
494 local spec = self.spec_lights
495 local group = spec.triggerToGroup[triggerId]
496 if group ~= nil then
497 if onEnter or onLeave then
498 local player = g_currentMission.player
499 if player ~= nil and otherId == player.rootNode then
500 if onEnter then
501 group.playerInRange = true
502 g_currentMission.activatableObjectsSystem:addActivatable(spec.activatable)
503 spec.activatable:setGroupIndex(group.index)
504 else
505 group.playerInRange = false
506
507 local inRangeOfOtherGroups = false
508 for _, otherGroup in ipairs(spec.groups) do
509 inRangeOfOtherGroups = inRangeOfOtherGroups or otherGroup.playerInRange
510 end
511 if not inRangeOfOtherGroups then
512 g_currentMission.activatableObjectsSystem:removeActivatable(spec.activatable)
513 end
514 end
515 end
516 end
517 end
518end

onDelete

Description
Definition
onDelete()
Code
365function PlaceableLights:onDelete()
366 local spec = self.spec_lights
367
368 if spec.sharedLights ~= nil then
369 for _, light in ipairs(spec.sharedLights) do
370 if light.sharedLoadRequestId ~= nil then
371 g_i3DManager:releaseSharedI3DFile(light.sharedLoadRequestId)
372 light.sharedLoadRequestId = nil
373 end
374 end
375 spec.sharedLights = {}
376 end
377
378 g_messageCenter:unsubscribeAll(self)
379 g_currentMission.activatableObjectsSystem:removeActivatable(spec.activatable)
380
381 if spec.groups ~= nil then
382 for _, group in ipairs(spec.groups) do
383 if group.triggerNode ~= nil then
384 removeTrigger(group.triggerNode)
385 end
386
387 g_soundManager:deleteSamples(group.samples)
388 end
389 spec.groups = {}
390 end
391end

onFinalizePlacement

Description
Definition
onFinalizePlacement()
Code
287function PlaceableLights:onFinalizePlacement()
288 self:lightSetupChanged()
289end

onLoad

Description
Called on loading
Definition
onLoad(table savegame)
Arguments
tablesavegamesavegame
Code
86function PlaceableLights:onLoad(savegame)
87 local spec = self.spec_lights
88 local xmlFile = self.xmlFile
89
90 local environmentMaskSystem = g_currentMission.environment.environmentMaskSystem
91
92 spec.sharedLights = {}
93 spec.groups = {}
94 spec.triggerToGroup = {}
95
96 spec.activatable = PlaceableLightsActivatable.new(self)
97
98 g_messageCenter:subscribe(MessageType.SETTING_CHANGED["lightsProfile"], self.lightSetupChanged, self)
99
100 xmlFile:iterate("placeable.lights.group", function (lightIndex, lightGroupKey)
101 local group = {}
102 group.triggerNode = xmlFile:getValue(lightGroupKey .. "#triggerNode", nil, self.components, self.i3dMappings)
103 if group.triggerNode ~= nil then
104 addTrigger(group.triggerNode, "lightsTriggerCallback", self)
105 spec.triggerToGroup[group.triggerNode] = group
106 end
107
108 local inputActionName = xmlFile:getValue(lightGroupKey .. "#inputAction", "INTERACT")
109 group.inputAction = InputAction[inputActionName] or InputAction.INTERACT
110
111 group.name = xmlFile:getValue(lightGroupKey .. "#name", "action_placeableLightShed", self.customEnvironment)
112 group.activateText = xmlFile:getValue(lightGroupKey .. "#activateText", "action_placeableLightPos", self.customEnvironment)
113 group.deactivateText = xmlFile:getValue(lightGroupKey .. "#deactivateText", "action_placeableLightNeg", self.customEnvironment)
114
115 local activateTimeStr = xmlFile:getValue(lightGroupKey .. "#activateTime", nil)
116 if activateTimeStr ~= nil then
117 group.activateMinute = Utils.getMinuteOfDayFromTime(activateTimeStr)
118 if group.activateMinute == nil then
119 Logging.xmlWarning(xmlFile, "Invalid activateTime string '%s' given for group '%s'. Use 'hh:mm' format", activateTimeStr, lightGroupKey)
120 else
121 group.activateMinute = math.max(1, group.activateMinute) -- if a time is set, it has to be at least 1 since 0 == disabled
122 end
123 end
124
125 local deactivateTimeStr = xmlFile:getValue(lightGroupKey .. "#deactivateTime", nil)
126 if deactivateTimeStr ~= nil then
127 group.deactivateMinute = Utils.getMinuteOfDayFromTime(deactivateTimeStr)
128 if group.deactivateMinute == nil then
129 Logging.xmlWarning(xmlFile, "Invalid deactivateTime string '%s' given for group '%s'. Use 'hh:mm' format", deactivateTimeStr, lightGroupKey)
130 else
131 group.deactivateMinute = math.max(1, group.deactivateMinute) -- if a time is set, it has to be at least 1 since 0 == disabled
132 end
133 end
134
135 group.weatherRequiredMask = environmentMaskSystem:getWeatherMaskFromFlagNames(xmlFile:getValue(lightGroupKey .. "#weatherRequiredFlags", nil))
136 group.weatherPreventMask = environmentMaskSystem:getWeatherMaskFromFlagNames(xmlFile:getValue(lightGroupKey .. "#weatherPreventFlags", nil))
137
138 if self.isClient then
139 group.samples = {}
140 group.samples.toggle = g_soundManager:loadSampleFromXML(xmlFile, lightGroupKey .. ".sounds", "toggle", self.baseDirectory, self.components, 1, AudioGroup.ENVIRONMENT, self.i3dMappings, nil)
141 end
142
143 if (group.activateMinute ~= nil and group.deactivateMinute) == nil or (group.deactivateMinute == nil and group.activateMinute ~= nil) then
144 Logging.xmlWarning(xmlFile, "Incomplete automatic toggle time in '%s'", lightGroupKey)
145 else
146 group.hasManualLights = group.triggerNode ~= nil
147
148 group.isActive = false
149 group.playerInRange = false
150
151 if #spec.groups < PlaceableLights.MAX_NUM_GROUPS then
152 table.insert(spec.groups, group)
153 group.index = #spec.groups
154 else
155 Logging.xmlWarning(xmlFile, "Too many light groups registered. Max. %d are allowed", PlaceableLights.MAX_NUM_GROUPS)
156 end
157 end
158 end)
159
160 xmlFile:iterate("placeable.lights.sharedLight", function (lightIndex, lightKey)
161 local sharedLight = {}
162
163 local xmlFilename = xmlFile:getValue(lightKey .. "#filename")
164 if xmlFilename ~= nil then
165 sharedLight.xmlFilename = Utils.getFilename(xmlFilename, self.baseDirectory)
166 sharedLight.groupIndex = xmlFile:getValue(lightKey .. "#groupIndex", 1)
167 sharedLight.color = xmlFile:getValue(lightKey .. "#color", nil, true)
168 sharedLight.linkNode = xmlFile:getValue(lightKey .. "#linkNode", "0>", self.components, self.i3dMappings)
169
170 local group = spec.groups[sharedLight.groupIndex]
171 if group == nil then
172 Logging.xmlError("Group index '%d' in '%s' does not exist", sharedLight.groupIndex, lightKey)
173 else
174 if sharedLight.linkNode ~= nil then
175 sharedLight.rotations = {}
176 xmlFile:iterate(lightKey .. ".rotationNode", function (rotIndex, rotKey)
177 local name = xmlFile:getValue(rotKey.."#name")
178 local rotation = xmlFile:getValue(rotKey.."#rotation", nil, true)
179 if name ~= nil then
180 sharedLight.rotations[name] = rotation
181 end
182 end)
183
184 local lightXMLFile = XMLFile.load("sharedLight", sharedLight.xmlFilename, Lights.sharedLightXMLSchema)
185 if lightXMLFile ~= nil then
186 local filename = lightXMLFile:getValue("light.filename")
187 if filename ~= nil then
188 local loadingTask = self:createLoadingTask(spec)
189 filename = Utils.getFilename(filename, self.baseDirectory)
190
191 local arguments = {
192 sharedLight = sharedLight,
193 lightXMLFile = lightXMLFile,
194 loadingTask = loadingTask,
195 group = group,
196 filename = filename
197 }
198 sharedLight.sharedLoadRequestId = g_i3DManager:loadSharedI3DFileAsync(filename, false, false, self.sharedLightLoaded, self, arguments)
199 table.insert(spec.sharedLights, sharedLight)
200 else
201 Logging.xmlWarning(lightXMLFile, "Missing light i3d filename!")
202 lightXMLFile:delete()
203 end
204 end
205 end
206 end
207 end
208 end)
209
210
211 spec.lightShapes = {} -- self illum faces within the placeable, only shader will be applied, always stay visible
212
213 local getNodeShaderLightIntensity = function(node)
214 if getHasShaderParameter(node, "lightControl") then
215 local x = getShaderParameter(node, "lightControl")
216 return x
217 end
218 return 1
219 end
220
221 xmlFile:iterate("placeable.lights.lightShape", function (lightIndex, lightKey)
222 local lightShape = {}
223
224 lightShape.groupIndex = xmlFile:getValue(lightKey .. "#groupIndex", 1)
225 lightShape.node = xmlFile:getValue(lightKey .. "#node", "0>", self.components, self.i3dMappings)
226 if lightShape.node ~= nil then
227 lightShape.intensity = xmlFile:getValue(lightKey .. "#intensity", getNodeShaderLightIntensity(lightShape.node))
228
229 local group = spec.groups[lightShape.groupIndex]
230 if group == nil then
231 Logging.xmlError(xmlFile, "Group index '%d' in '%s' does not exist", lightShape.groupIndex, lightKey)
232 else
233 if not group.hasManualLights then
234 if group.activateMinute ~= nil then
235 setVisibilityConditionMinuteOfDay(lightShape.node, group.activateMinute, group.deactivateMinute)
236 end
237 if group.weatherRequiredMask ~= nil or group.weatherPreventMask ~= nil then
238 setVisibilityConditionWeatherMask(lightShape.node, group.weatherRequiredMask or 0, group.weatherPreventMask or 0)
239 end
240
241 setVisibilityConditionRenderInvisible(lightShape.node, true) -- still render self illum faces when group is not visible, only apply shader
242 setVisibilityConditionVisibleShaderParameter(lightShape.node, lightShape.intensity)
243 end
244 end
245 table.insert(spec.lightShapes, lightShape)
246 end
247 end)
248
249
250 spec.realLights = {
251 low={},
252 high={},
253 }
254 local loadRealLight = function(realLightKey, insertTable)
255 local realLight = {}
256 realLight.node = xmlFile:getValue(realLightKey .. "#node", nil, self.components, self.i3dMappings)
257 if realLight.node ~= nil then
258 realLight.groupIndex = xmlFile:getValue(realLightKey .. "#groupIndex", 1)
259
260 local group = spec.groups[realLight.groupIndex]
261 if group == nil then
262 Logging.xmlError("Group index '%d' in '%s' does not exist", realLight.groupIndex, realLightKey)
263 else
264 if group.activateMinute ~= nil then
265 setVisibilityConditionMinuteOfDay(realLight.node, group.activateMinute, group.deactivateMinute)
266 end
267 if group.weatherRequiredMask ~= nil or group.weatherPreventMask ~= nil then
268 setVisibilityConditionWeatherMask(realLight.node, group.weatherRequiredMask or 0, group.weatherPreventMask or 0)
269 end
270
271 table.insert(insertTable, realLight)
272 end
273 end
274 end
275
276 xmlFile:iterate("placeable.lights.realLights.low.light", function (lightIndex, lightKey)
277 loadRealLight(lightKey, spec.realLights.low)
278 end)
279
280 xmlFile:iterate("placeable.lights.realLights.high.light", function (lightIndex, lightKey)
281 loadRealLight(lightKey, spec.realLights.high)
282 end)
283end

onReadStream

Description
Called on client side on join
Definition
onReadStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
397function PlaceableLights:onReadStream(streamId, connection)
398 local spec = self.spec_lights
399 for k, group in ipairs(spec.groups) do
400 if group.hasManualLights then
401 self:setGroupIsActive(k, streamReadBool(streamId), true)
402 end
403 end
404end

onWriteStream

Description
Called on server side on join
Definition
onWriteStream(integer streamId, table connection)
Arguments
integerstreamIdstream ID
tableconnectionconnection
Code
410function PlaceableLights:onWriteStream(streamId, connection)
411 local spec = self.spec_lights
412 for _, group in ipairs(spec.groups) do
413 if group.hasManualLights then
414 streamWriteBool(streamId, group.isActive)
415 end
416 end
417end

prerequisitesPresent

Description
Checks if all prerequisite specializations are loaded
Definition
prerequisitesPresent(table specializations)
Arguments
tablespecializationsspecializations
Return Values
booleanhasPrerequisitetrue if all prerequisite specializations are loaded
Code
22function PlaceableLights.prerequisitesPresent(specializations)
23 return true
24end

registerEventListeners

Description
Definition
registerEventListeners()
Code
39function PlaceableLights.registerEventListeners(placeableType)
40 SpecializationUtil.registerEventListener(placeableType, "onLoad", PlaceableLights)
41 SpecializationUtil.registerEventListener(placeableType, "onDelete", PlaceableLights)
42 SpecializationUtil.registerEventListener(placeableType, "onWriteStream", PlaceableLights)
43 SpecializationUtil.registerEventListener(placeableType, "onReadStream", PlaceableLights)
44 SpecializationUtil.registerEventListener(placeableType, "onFinalizePlacement", PlaceableLights)
45end

registerFunctions

Description
Definition
registerFunctions()
Code
28function PlaceableLights.registerFunctions(placeableType)
29 SpecializationUtil.registerFunction(placeableType, "lightSetupChanged", PlaceableLights.lightSetupChanged)
30 SpecializationUtil.registerFunction(placeableType, "getUseHighProfile", PlaceableLights.getUseHighProfile)
31 SpecializationUtil.registerFunction(placeableType, "setGroupIsActive", PlaceableLights.setGroupIsActive)
32 SpecializationUtil.registerFunction(placeableType, "lightsTriggerCallback", PlaceableLights.lightsTriggerCallback)
33 SpecializationUtil.registerFunction(placeableType, "sharedLightLoaded", PlaceableLights.sharedLightLoaded)
34 SpecializationUtil.registerFunction(placeableType, "updateLightState", PlaceableLights.updateLightState)
35end

registerXMLPaths

Description
Definition
registerXMLPaths()
Code
49function PlaceableLights.registerXMLPaths(schema, basePath)
50 schema:setXMLSpecializationType("Lights")
51 schema:register(XMLValueType.STRING, basePath .. ".lights.sharedLight(?)#filename", "Path to shared light xml file")
52 schema:register(XMLValueType.INT, basePath .. ".lights.sharedLight(?)#groupIndex", "Parent group", 1)
53 schema:register(XMLValueType.NODE_INDEX, basePath .. ".lights.sharedLight(?)#linkNode", "Link node")
54 schema:register(XMLValueType.COLOR, basePath .. ".lights.sharedLight(?)#color", "Light color")
55 schema:register(XMLValueType.STRING, basePath .. ".lights.sharedLight(?).rotationNode(?)#name", "Rotation node name")
56 schema:register(XMLValueType.VECTOR_ROT, basePath .. ".lights.sharedLight(?).rotationNode(?)#rotation", "Rotation to set")
57
58 schema:register(XMLValueType.INT, basePath .. ".lights.lightShape(?)#groupIndex", "Parent group", 1)
59 schema:register(XMLValueType.NODE_INDEX, basePath .. ".lights.lightShape(?)#node", "Light shape / self-illum-mesh node. Always visible, only shader is set")
60 schema:register(XMLValueType.FLOAT, basePath .. ".lights.lightShape(?)#intensity", "Intensity for the shader if active", 25)
61
62 schema:register(XMLValueType.NODE_INDEX, basePath .. ".lights.realLights.low.light(?)#node", "Real light node used on low performance profile. Visibility is toggled based on settings")
63 schema:register(XMLValueType.INT, basePath .. ".lights.realLights.low.light(?)#groupIndex", "Parent group", 1)
64 schema:register(XMLValueType.NODE_INDEX, basePath .. ".lights.realLights.high.light(?)#node", "Real light node used on high performance profile. Visibility is toggled based on settings")
65 schema:register(XMLValueType.INT, basePath .. ".lights.realLights.high.light(?)#groupIndex", "Parent group", 1)
66
67 schema:register(XMLValueType.NODE_INDEX, basePath .. ".lights.group(?)#triggerNode", "Activation Trigger for manual control")
68 schema:register(XMLValueType.STRING, basePath .. ".lights.group(?)#inputAction", "Input Action name", "INTERACT")
69 schema:register(XMLValueType.L10N_STRING, basePath .. ".lights.group(?)#name", "Group name for display", "action_placeableLightShed")
70 schema:register(XMLValueType.L10N_STRING, basePath .. ".lights.group(?)#activateText", "Activate text to display in help menu", "action_placeableLightPos")
71 schema:register(XMLValueType.L10N_STRING, basePath .. ".lights.group(?)#deactivateText", "Deactivate text to display in help menu", "action_placeableLightNeg")
72
73 schema:register(XMLValueType.STRING, basePath .. ".lights.group(?)#activateTime", "If defined, light will be turned on at this time of day. Format hh:mm")
74 schema:register(XMLValueType.STRING, basePath .. ".lights.group(?)#deactivateTime", "If defined, light will be turned off at this time of day. Format hh:mm")
75 schema:register(XMLValueType.STRING, basePath .. ".lights.group(?)#weatherRequiredFlags", "Space separeted list of environment flag names to be used as required mask")
76 schema:register(XMLValueType.STRING, basePath .. ".lights.group(?)#weatherPreventFlags", "Space separeted list of environment flag names to be used as prevent mask")
77
78 SoundManager.registerSampleXMLPaths(schema, basePath .. ".lights.group(?).sounds", "toggle")
79
80 schema:setXMLSpecializationType()
81end

setGroupIsActive

Description
Definition
setGroupIsActive()
Code
430function PlaceableLights:setGroupIsActive(groupIndex, isActive, noEventSend)
431 local spec = self.spec_lights
432 local group = spec.groups[groupIndex]
433 if group ~= nil then
434 -- group is always active unless toggled by script
435 group.isActive = Utils.getNoNil(isActive, not group.isActive)
436
437 self:updateLightState(groupIndex, group.isActive)
438
439 PlaceableLightsStateEvent.sendEvent(self, groupIndex, group.isActive, noEventSend)
440
441 if self.isClient then
442 g_soundManager:playSample(group.samples.toggle, 1)
443 end
444 end
445end

sharedLightLoaded

Description
Definition
sharedLightLoaded()
Code
293function PlaceableLights:sharedLightLoaded(i3dNode, failedReason, args)
294 local spec = self.spec_lights
295
296 local sharedLight = args.sharedLight
297 local lightXMLFile = args.lightXMLFile
298 local loadingTask = args.loadingTask
299 local lightGroup = args.group
300 local i3dFilename = args.filename
301
302 if i3dNode ~= nil and i3dNode ~= 0 then
303 if self.loadingState == Placeable.LOADING_STATE_OK then
304 sharedLight.node = lightXMLFile:getValue("light.rootNode#node", "0", i3dNode)
305 sharedLight.i3dFilename = i3dFilename
306
307 sharedLight.lightShapes = {}
308 lightXMLFile:iterate("light.defaultLight", function (lightIndex, lightKey)
309 local lightShape = {}
310 lightShape.node = lightXMLFile:getValue(lightKey.."#node", nil, i3dNode)
311 if lightShape.node ~= nil then
312 if getHasShaderParameter(lightShape.node, "lightControl") then
313 lightShape.intensity = lightXMLFile:getValue(lightKey.."#intensity", 25)
314
315 if lightGroup.hasManualLights then
316 setShaderParameter(lightShape.node, "lightControl", 0, 0, 0, 0, false)
317 else
318 if lightGroup.activateMinute ~= nil then
319 setVisibilityConditionMinuteOfDay(lightShape.node, lightGroup.activateMinute, lightGroup.deactivateMinute)
320 end
321 if lightGroup.weatherRequiredMask ~= nil or lightGroup.weatherPreventMask ~= nil then
322 setVisibilityConditionWeatherMask(lightShape.node, lightGroup.weatherRequiredMask or 0, lightGroup.weatherPreventMask or 0)
323 end
324 setVisibilityConditionRenderInvisible(lightShape.node, true) -- still render self illum faces when group is not visible, only apply shader
325 setVisibilityConditionVisibleShaderParameter(lightShape.node, lightShape.intensity)
326 end
327
328 table.insert(sharedLight.lightShapes, lightShape)
329 else
330 Logging.xmlWarning(lightXMLFile, "Node '%s' has no shaderparameter 'lightControl'. Ignoring node!", getName(lightShape.node))
331 end
332
333 if sharedLight.color ~= nil and getHasShaderParameter(lightShape.node, "colorScale") then
334 setShaderParameter(lightShape.node, "colorScale", sharedLight.color[1], sharedLight.color[2], sharedLight.color[3], 0, false)
335 end
336 else
337 Logging.xmlWarning(lightXMLFile, "Could not find node for '%s'!", lightKey)
338 end
339 end)
340
341 lightXMLFile:iterate("light.rotationNode", function (rotIndex, rotKey)
342 local name = lightXMLFile:getValue(rotKey .."#name")
343 if name ~= nil then
344 local node = lightXMLFile:getValue(rotKey .. "#node", nil, i3dNode)
345 if sharedLight.rotations[name] ~= nil then
346 setRotation(node, unpack(sharedLight.rotations[name]))
347 end
348 end
349 end)
350 sharedLight.rotations = nil
351
352 link(sharedLight.linkNode, sharedLight.node)
353 end
354
355 delete(i3dNode)
356 end
357
358 lightXMLFile:delete()
359
360 self:finishLoadingTask(loadingTask)
361end

updateLightState

Description
Definition
updateLightState()
Code
449function PlaceableLights:updateLightState(groupIndex, isActive)
450 local spec = self.spec_lights
451 local group = spec.groups[groupIndex]
452
453 if group.hasManualLights then
454 -- visibility condition shapes have their intensity set once on load
455 for _, sharedLight in ipairs(spec.sharedLights) do
456 if sharedLight.groupIndex == groupIndex then
457 for j=1, #sharedLight.lightShapes do
458 local lightShape = sharedLight.lightShapes[j]
459 setShaderParameter(lightShape.node, "lightControl", isActive and lightShape.intensity or 0, 0, 0, 0, false)
460 end
461 end
462 end
463
464 for _, lightShape in ipairs(spec.lightShapes) do
465 if lightShape.groupIndex == groupIndex then
466 setShaderParameter(lightShape.node, "lightControl", isActive and lightShape.intensity or 0, 0, 0, 0, false)
467 end
468 end
469 end
470
471 local activeLightSetup = spec.realLights.low
472 local inactiveLightSetup = spec.realLights.high
473 if self:getUseHighProfile() then
474 activeLightSetup = spec.realLights.high
475 inactiveLightSetup = spec.realLights.low
476 end
477
478 for _, realLight in ipairs(activeLightSetup) do
479 if realLight.groupIndex == groupIndex then
480 setVisibility(realLight.node, not group.hasManualLights or isActive) -- lights are always active for groups which cannot be toggled manually (visiblity condition)
481 end
482 end
483
484 for _, realLight in ipairs(inactiveLightSetup) do
485 if realLight.groupIndex == groupIndex then
486 setVisibility(realLight.node, false)
487 end
488 end
489end