This repository has been archived by the owner on May 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 525
/
ActionEventsLoader.lua
455 lines (392 loc) · 19.7 KB
/
ActionEventsLoader.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
---@class ActionEventsLoader
ActionEventsLoader = CpObject()
---All the normal action events attributes
ActionEventsLoader.actionEventAttributes = {
{name = 'name', getXmlFunction = getXMLString},
{name = 'class', getXmlFunction = getXMLString},
{name = 'callbackFunc', getXmlFunction = getXMLString},
{name = 'callbackParameter', getXmlFunction = getXMLString},
{name = 'callbackState', getXmlFunction = getXMLInt},
{name = 'isDisabledCallbackFunc', getXmlFunction = getXMLString},
{name = 'text', getXmlFunction = getXMLString},
{name = 'textAlwaysVisible', getXmlFunction = getXMLBool},
}
---All the setting action events attributes
ActionEventsLoader.settingActionEventAttributes = {
{name = 'name', getXmlFunction = getXMLString},
{name = 'setting', getXmlFunction = getXMLString},
{name = 'callbackFunc', getXmlFunction = getXMLString},
{name = 'callbackParameter', getXmlFunction = getXMLString},
{name = 'callbackState', getXmlFunction = getXMLInt},
{name = 'isDisabledCallbackFunc', getXmlFunction = getXMLString},
{name = 'text', getXmlFunction = getXMLString},
{name = 'textAlwaysVisible', getXmlFunction = getXMLBool},
}
---String to class reference, only for global classes.
ActionEventsLoader.classStringToClass = {
["courseEditor"] = courseEditor
}
---Table where the global action events gets saved in.
ActionEventsLoader.globalActionEventNameToID = {}
---Every action event name translation text needs "input_"
---at the beginning. With this it's possible
---to get the action event text: courseplay:loc(textPrefix..actionEventName)
ActionEventsLoader.textPrefix = "input_"
function ActionEventsLoader:init()
self.actionEvents = {}
self.settingActionEvents = {}
self.globalActionEvents = {}
if g_currentMission then
self:loadFromXml()
end
end
function ActionEventsLoader:loadFromXml()
self.xmlFileName = Utils.getFilename('config/ActionEventsConfig.xml', courseplay.path)
self.xmlFile = self:loadXmlFile(self.xmlFileName)
end
---Loads ActionEventsConfig file
---@param string file path
function ActionEventsLoader:loadXmlFile(fileName)
courseplay.info('Loading action events configuration from %s ...', fileName)
if fileExists(fileName) then
local xmlFile = loadXMLFile('actionEventsConfig', fileName)
local rootElement = 'ActionEventsConfig'
if xmlFile and hasXMLProperty(xmlFile, rootElement) then
local baseElement = string.format('%s.%s', rootElement,'ActionEvents')
self:loadActionEvents(xmlFile, baseElement,'ActionEvent',self.actionEventAttributes,self.actionEvents)
baseElement = string.format('%s.%s', rootElement,'SettingActionEvents')
self:loadActionEvents(xmlFile, baseElement,'SettingActionEvent',self.settingActionEventAttributes,self.settingActionEvents)
baseElement = string.format('%s.%s', rootElement,'GlobalActionEvents')
self:loadActionEvents(xmlFile, baseElement,'GlobalActionEvent',self.actionEventAttributes,self.globalActionEvents)
return xmlFile
end
else
courseplay.info('Action events configuration file %s does not exist.', fileName)
end
end
---Loads an action events table from ActionEventsConfig.xml
---@param int xmlFile id
---@param string rootElement of the action event table
---@param string key for each single action event
---@param table attributes of the action event table
---@param table actionEventTable to store the data in
function ActionEventsLoader:loadActionEvents(xmlFile, rootElement,key,attributes,actionEventTable)
if hasXMLProperty(xmlFile, rootElement) then
local i = 0
while true do
local baseElement = string.format('%s.%s(%d)', rootElement,key, i)
if hasXMLProperty(xmlFile, baseElement) then
self:loadAttributes(xmlFile, baseElement,attributes,actionEventTable)
else
break
end
i = i + 1
end
end
end
---Loads all attribute of an action event
---@param int xmlFile id
---@param string rootElement of the attributes
---@param table attributes of the action event table
---@param table actionEventTable to store the data in
function ActionEventsLoader:loadAttributes(xmlFile, rootElement,attributes,actionEventTable)
local attributesTable = {}
for _,attributeData in ipairs(attributes) do
attributesTable[attributeData.name] = attributeData.getXmlFunction(xmlFile, rootElement.."#"..attributeData.name)
end
table.insert(actionEventTable,attributesTable)
end
---Gets all simple action events
function ActionEventsLoader:getActionEvents()
return self.actionEvents
end
---Gets all setting action events
function ActionEventsLoader:getSettingActionEvents()
return self.settingActionEvents
end
---Gets all setting action events
function ActionEventsLoader:getGlobalActionEvents()
return self.globalActionEvents
end
---Registers all action events
---@param object vehicle
---@param boolean isActiveForInput
---@param boolean isActiveForInputIgnoreSelection
function ActionEventsLoader.onRegisterVehicleActionEvents(vehicle,isActiveForInput, isActiveForInputIgnoreSelection)
if vehicle.isClient then
---Table where the action events gets saved in the vehicle.
if vehicle.cpActionEvents == nil then
vehicle.cpActionEvents = {}
else
vehicle:clearActionEventsTable(vehicle.cpActionEvents)
end
if vehicle:getIsActiveForInput(true, true) then
---Register all vehicle action events
ActionEventsLoader.registerVehicleActionEvents(vehicle,isActiveForInput, isActiveForInputIgnoreSelection)
ActionEventsLoader.registerVehicleSettingActionEvents(vehicle,isActiveForInput, isActiveForInputIgnoreSelection)
end
end
end
---Registers all none setting vehicle action events
---@param object vehicle
---@param boolean isActiveForInput
---@param boolean isActiveForInputIgnoreSelection
function ActionEventsLoader.registerVehicleActionEvents(vehicle,isActiveForInput, isActiveForInputIgnoreSelection)
local actionEvents = g_ActionEventsLoader:getActionEvents()
for _,actionEventData in ipairs(actionEvents) do
ActionEventsLoader.registerActionEvent(actionEventData,vehicle,false)
end
end
---Registers all setting vehicle action events
---@param object vehicle
---@param boolean isActiveForInput
---@param boolean isActiveForInputIgnoreSelection
function ActionEventsLoader.registerVehicleSettingActionEvents(vehicle,isActiveForInput, isActiveForInputIgnoreSelection)
local actionEvents = g_ActionEventsLoader:getSettingActionEvents()
for _,actionEventData in ipairs(actionEvents) do
ActionEventsLoader.registerActionEvent(actionEventData,vehicle,true)
end
end
---Registers all global none setting action events
function ActionEventsLoader.registerGlobalActionEvents()
if g_client then
local actionEvents = g_ActionEventsLoader:getGlobalActionEvents()
for _,actionEventData in ipairs(actionEvents) do
local actionEventName = ActionEventsLoaderUtil.getActionEventName(actionEventData)
local class = ActionEventsLoaderUtil.getActionEventClass(actionEventData,ActionEventCallbacks)
local classParameter = ActionEventsLoaderUtil.getActionEventCallbackParameter(actionEventData)
local actionEventCallback = ActionEventsLoaderUtil.getActionEventCallback(actionEventData,class)
local actionEventText = ActionEventsLoaderUtil.getActionEventText(actionEventData)
local actionEventTextVisible = ActionEventsLoaderUtil.isActionEventTextVisible(actionEventData,vehicle)
local isDisabled = ActionEventsLoaderUtil.getActionEventIsDisabled(actionEventData,class,classParameter)
courseplay.debugFormat(courseplay.DBG_HUD,"Register action event: name= %s, text= %s, isDisabled= %s, isVisible:%s",
actionEventName, courseplay:loc(actionEventText), tostring(isDisabled),tostring(actionEventTextVisible))
---Registers an action event.
local _, eventId = g_inputBinding:registerActionEvent(actionEventName, class, actionEventCallback, false, true, false, true,actionEventData.callbackState)
g_inputBinding:setActionEventTextPriority(eventId, GS_PRIO_HIGH)
g_inputBinding:setActionEventText(eventId, courseplay:loc(actionEventText))
g_inputBinding:setActionEventActive(eventId, not isDisabled)
g_inputBinding:setActionEventTextVisibility(eventId,actionEventTextVisible)
ActionEventsLoader.globalActionEventNameToID[actionEventName] = eventId
end
end
end
FSBaseMission.registerActionEvents = Utils.appendedFunction(FSBaseMission.registerActionEvents, ActionEventsLoader.registerGlobalActionEvents)
---Registers an action event
---@param table actionEventData from the config xml
---@param object vehicle
---@param boolean isSetting, is the action event linked to a setting class?
function ActionEventsLoader.registerActionEvent(actionEventData,vehicle,isSetting)
local actionEventName = ActionEventsLoaderUtil.getActionEventName(actionEventData)
local class,classParameter
---If the action event is a setting we get the setting by the settings name
if isSetting then
class = ActionEventsLoaderUtil.getActionEventSetting(actionEventData,vehicle)
classParameter = class
else
class = ActionEventsLoaderUtil.getActionEventClass(actionEventData,ActionEventCallbacks)
classParameter = ActionEventsLoaderUtil.getActionEventCallbackParameter(actionEventData,vehicle)
end
local actionEventCallback = ActionEventsLoaderUtil.getActionEventCallback(actionEventData,class)
local actionEventText = ActionEventsLoaderUtil.getActionEventText(actionEventData)
local actionEventTextVisible = ActionEventsLoaderUtil.isActionEventTextVisible(actionEventData,vehicle)
local isDisabled = ActionEventsLoaderUtil.getActionEventIsDisabled(actionEventData,class,classParameter)
courseplay.debugVehicle(courseplay.DBG_HUD,vehicle,"Register action event: name= %s, text= %s, isDisabled= %s, isVisible:%s",
actionEventName, courseplay:loc(actionEventText), tostring(isDisabled),tostring(actionEventTextVisible))
---Registers an action event into the vehicle.
local _, eventId = vehicle:addActionEvent(vehicle.cpActionEvents,actionEventName, classParameter, actionEventCallback, true, false, false, true,actionEventData.callbackState)
g_inputBinding:setActionEventTextPriority(eventId, GS_PRIO_HIGH)
---Display text in the F1 window in the top left.
g_inputBinding:setActionEventText(eventId, courseplay:loc(actionEventText))
g_inputBinding:setActionEventActive(eventId, not isDisabled)
g_inputBinding:setActionEventTextVisibility(eventId,actionEventTextVisible)
---addActionEvent( action event table, action event name, action event class,
--- callback function, trigger key up, trigger key down, trigger always,
--- is active, callback state, action event icon)
end
---Updates action events and disables them if not needed
---@param object vehicle
---@param table actionEvents table of action events
---@param boolean isSetting, is the action event linked to a setting class?
function ActionEventsLoader.updateActionEvents(actionEvents,actionEventsNameToID,isSetting,vehicle)
if actionEventsNameToID == nil then
return
end
for _,actionEventData in ipairs(actionEvents) do
local actionEventName = ActionEventsLoaderUtil.getActionEventName(actionEventData)
local actionEventText = ActionEventsLoaderUtil.getActionEventText(actionEventData)
local actionEventTextVisible = ActionEventsLoaderUtil.isActionEventTextVisible(actionEventData,vehicle)
local actionEvent = InputAction[actionEventName] and actionEventsNameToID[InputAction[actionEventName]]
if actionEvent then
local class,classParameter
---If the action event is a setting we get the setting by the settings name
if isSetting then
class = ActionEventsLoaderUtil.getActionEventSetting(actionEventData,vehicle)
classParameter = class
else
class = ActionEventsLoaderUtil.getActionEventClass(actionEventData,ActionEventCallbacks)
classParameter = ActionEventsLoaderUtil.getActionEventCallbackParameter(actionEventData,vehicle)
end
local isDisabled = ActionEventsLoaderUtil.getActionEventIsDisabled(actionEventData,class,classParameter)
if vehicle then
courseplay.debugVehicle(courseplay.DBG_HUD,vehicle,"Update action event: name= %s, text= %s, isDisabled= %s, isVisible:%s",
actionEventName, courseplay:loc(actionEventText), tostring(isDisabled),tostring(actionEventTextVisible))
else
courseplay.debugFormat(courseplay.DBG_HUD,"Update action event: name= %s, text= %s, isDisabled= %s, isVisible:%s",
actionEventName, courseplay:loc(actionEventText), tostring(isDisabled),tostring(actionEventTextVisible))
end
---Enable/disable the action event
g_inputBinding:setActionEventActive(actionEvent.actionEventId, not isDisabled)
g_inputBinding:setActionEventTextVisibility(actionEvent.actionEventId,actionEventTextVisible)
end
end
end
---Updates all vehicle action events and disables them if not needed
---@param object vehicle
function ActionEventsLoader.updateAllActionEvents(vehicle)
local actionEvents = g_ActionEventsLoader:getActionEvents()
ActionEventsLoader.updateActionEvents(actionEvents,vehicle.cpActionEvents,false,vehicle)
actionEvents = g_ActionEventsLoader:getSettingActionEvents()
ActionEventsLoader.updateActionEvents(actionEvents,vehicle.cpActionEvents,true,vehicle)
---TODO: This one needs some fine tuning
-- actionEvents = g_ActionEventsLoader:getGlobalActionEvents()
-- ActionEventsLoader.updateActionEvents(actionEvents,ActionEventsLoader.actionEventsNameToID)
end
g_ActionEventsLoader = ActionEventsLoader()
ActionEventsLoaderUtil = {}
---Gets the action event name of the xml data
function ActionEventsLoaderUtil.getActionEventName(actionEventData)
return InputAction[actionEventData.name]
end
---Gets the action event class of the xml data or returns the default class
---@param table actionEventData from the config xml
---@param object default class for the callbacks
function ActionEventsLoaderUtil.getActionEventClass(actionEventData,defaultClass)
return actionEventData.class and ActionEventsLoader.classStringToClass[actionEventData.class] or defaultClass
end
---Gets the action event callback function parameter of the xml data, default is default class
---@param table actionEventData from the config xml
---@param object default class for the callbacks
function ActionEventsLoaderUtil.getActionEventCallbackParameter(actionEventData,defaultClass)
return actionEventData.callbackParameter and ActionEventsLoader.classStringToClass[actionEventData.callbackParameter] or defaultClass
end
---Gets the action event setting of the xml data
---@param table actionEventData from the config xml
---@param object vehicle
function ActionEventsLoaderUtil.getActionEventSetting(actionEventData,vehicle)
return vehicle.cp.settings[actionEventData.setting]
end
---Gets the action event callback function of the xml data
---@param table actionEventData from the config xml
---@param object callback class
function ActionEventsLoaderUtil.getActionEventCallback(actionEventData,class)
return class[actionEventData.callbackFunc]
end
---Gets the action event text of the xml data, default is the action event name
---@param table actionEventData from the config xml
function ActionEventsLoaderUtil.getActionEventText(actionEventData)
---If no explicit action event text was set,
---the action events name is used with the prefix:"input_",
---as all action event translation need this to be correctly displayed
---in the Input bindings menu by giants.
return actionEventData.text or ActionEventsLoader.textPrefix..actionEventData.name
end
---Needs the action event text to be visible?
---@param table actionEventData from the config xml
function ActionEventsLoaderUtil.isActionEventTextVisible(actionEventData)
return courseplay.globalSettings.showActionEventsTexts:get() or actionEventData.textAlwaysVisible
end
---Is the action event disabled ?
---Defaults to class.isDisabled , if the is disabled callback function is not defined or it is always enabled
---@param table actionEventData from the config xml
---@param object callback class
---@param int callback parameter
function ActionEventsLoaderUtil.getActionEventIsDisabled(actionEventData,class,classParameter)
local isDisabledCallback = actionEventData.isDisabledCallbackFunc and class[actionEventData.isDisabledCallbackFunc] or class.isDisabled
local callbackState = actionEventData.callbackState
if isDisabledCallback then
return isDisabledCallback(classParameter,callbackState)
end
return false
end
ActionEventCallbacks = {}
--[[
Every action event callback has the following parameters:
- class of the callback, here vehicle
- action event name
- input value: not sure
- a possible additional variable, for example an integer
- isAnalog: not sure
]]--
function ActionEventCallbacks.actionEventOpenCloseHud(vehicle, actionName, inputValue, callbackState, isAnalog)
courseplay:openCloseHud(vehicle, not vehicle.cp.hud.show)
ActionEventsLoader.updateAllActionEvents(vehicle)
end
function ActionEventCallbacks.actionEventNextDriverMode(vehicle, actionName, inputValue, callbackState, isAnalog)
vehicle.cp.settings.driverMode:setNext()
end
function ActionEventCallbacks.actionEventPreviousDriverMode(vehicle, actionName, inputValue, callbackState, isAnalog)
vehicle.cp.settings.driverMode:setPrevious()
end
function ActionEventCallbacks.actionEventNextHudPage(vehicle, actionName, inputValue, callbackState, isAnalog)
local newPage = courseplay.hud.getNextPage(vehicle)
if newPage ~= courseplay.hud.getCurrentPage(vehicle) then
vehicle:setCourseplayFunc('setHudPage', newPage)
end
end
function ActionEventCallbacks.actionEventPreviousHudPage(vehicle, actionName, inputValue, callbackState, isAnalog)
local newPage = courseplay.hud.getPrevPage(vehicle)
if newPage ~= courseplay.hud.getCurrentPage(vehicle) then
vehicle:setCourseplayFunc('setHudPage', newPage)
end
end
function ActionEventCallbacks.actionEventStartStopRecording(vehicle, actionName, inputValue, callbackState, isAnalog)
if not vehicle.cp.canDrive then
if not vehicle.cp.recordingIsPaused then
if not vehicle.cp.isRecording and vehicle.cp.numWaypoints == 0 then
vehicle:setCourseplayFunc('start_record', nil);
elseif not vehicle.cp.isRecordingTurnManeuver then
vehicle:setCourseplayFunc('stop_record', nil);
end
end
end
end
function ActionEventCallbacks.actionEventPauseRecording(vehicle, actionName, inputValue, callbackState, isAnalog)
vehicle:setCourseplayFunc('setRecordingPause', nil, false, 1);
end
function ActionEventCallbacks.actionEventToggleReverseRecording(vehicle, actionName, inputValue, callbackState, isAnalog)
vehicle:setCourseplayFunc('change_DriveDirection', nil, false, 1);
end
function ActionEventCallbacks.actionEventStartStopDriving(vehicle, actionName, inputValue, callbackState, isAnalog)
courseplay:startStop(vehicle)
end
---Not used right now.
function ActionEventCallbacks.actionEventDriveNow(vehicle, actionName, inputValue, callbackState, isAnalog)
end
---Is disabled callbacks to disable action events.
---@param vehicle
---Not used right now.
function ActionEventCallbacks.isActionEventOpenCloseHudDisabled(vehicle)
end
function ActionEventCallbacks.isActionEventChangeDriverModeDisabled(vehicle)
return not vehicle.cp.hud.show or vehicle:getIsCourseplayDriving() or vehicle.cp.isRecording
end
function ActionEventCallbacks.isActionEventChangeHudPageDisabled(vehicle)
return not vehicle.cp.hud.show or vehicle.cp.isRecording
end
function ActionEventCallbacks.isActionEventStartStopRecordingDisabled(vehicle)
return vehicle.cp.canDrive
end
function ActionEventCallbacks.isActionEventPauseRecordingDisabled(vehicle)
return vehicle.cp.canDrive or vehicle.cp.numWaypoints < 3
end
function ActionEventCallbacks.isActionEventToggleReverseRecortdingDisabled(vehicle)
return vehicle.cp.canDrive or not vehicle.cp.isRecording
end
function ActionEventCallbacks.isActionEventStartStopDrivingDisabled(vehicle)
return not vehicle.cp.canDrive
end
---Not used right now.
function ActionEventCallbacks.isActionEventDriveNowDisabled(vehicle)
return true
end