changed the system to make use of JSON files

This commit is contained in:
David Pierron 2020-10-18 18:23:31 +02:00
parent 373924a959
commit ed92e9afb9
25 changed files with 7305 additions and 417 deletions

2
.gitignore vendored
View File

@ -21,5 +21,3 @@ logs/
qt_ui/logs/liberation.log
*.psd
resources/plugins/custom/__plugins.lst
resources/plugins/custom/*.lua

View File

@ -28,7 +28,7 @@ from .event.event import Event, UnitsDeliveryEvent
from .event.frontlineattack import FrontlineAttackEvent
from .infos.information import Information
from .settings import Settings
from plugin import INSTALLED_PLUGINS
from plugin import LuaPluginManager
COMMISION_UNIT_VARIETY = 4
COMMISION_LIMITS_SCALE = 1.5
@ -220,8 +220,7 @@ class Game:
ObjectiveDistanceCache.set_theater(self.theater)
# set the settings in all plugins
for pluginName in INSTALLED_PLUGINS:
plugin = INSTALLED_PLUGINS[pluginName]
for plugin in LuaPluginManager().getPlugins():
plugin.setSettings(self.settings)
def pass_turn(self, no_action=False):

View File

@ -31,7 +31,7 @@ from gen.triggergen import TRIGGER_RADIUS_MEDIUM, TriggersGenerator
from theater import ControlPoint
from .. import db
from ..debriefing import Debriefing
from plugin import BasePlugin, INSTALLED_PLUGINS
from plugin import LuaPluginManager
class Operation:
attackers_starting_position = None # type: db.StartingPosition
@ -146,10 +146,7 @@ class Operation:
if not scriptFileMnemonic in self.listOfPluginsScripts:
self.listOfPluginsScripts.append(scriptFileMnemonic)
if pluginName == None:
pluginName = "custom"
plugin_path = Path("./resources/plugins",pluginName)
logging.debug(f"plugin_path = {plugin_path}")
if scriptFile != None:
scriptFile_path = Path(plugin_path, scriptFile)
@ -469,8 +466,7 @@ dcsLiberation.TargetPoints = {
# Inject Plugins Lua Scripts and data
self.listOfPluginsScripts = []
for pluginName in INSTALLED_PLUGINS:
plugin = INSTALLED_PLUGINS[pluginName]
for plugin in LuaPluginManager().getPlugins():
plugin.injectScripts(self)
plugin.injectConfiguration(self)

View File

@ -1,4 +1,4 @@
from plugin import INSTALLED_PLUGINS
from plugin import LuaPluginManager
class Settings:
@ -41,8 +41,7 @@ class Settings:
# LUA Plugins system
self.plugins = {}
for pluginName in INSTALLED_PLUGINS:
plugin = INSTALLED_PLUGINS[pluginName]
for plugin in LuaPluginManager().getPlugins():
plugin.setSettings(self)

View File

@ -34,7 +34,7 @@ from gen.ground_forces.ai_ground_planner import (
from .callsigns import callsign_for_support_unit
from .conflictgen import Conflict
from .ground_forces.combat_stance import CombatStance
from plugin import INSTALLED_PLUGINS
from plugin import LuaPluginManager
SPREAD_DISTANCE_FACTOR = 0.1, 0.3
SPREAD_DISTANCE_SIZE_FACTOR = 0.1
@ -140,7 +140,8 @@ class GroundConflictGenerator:
self.plan_action_for_groups(self.enemy_stance, enemy_groups, player_groups, self.conflict.heading - 90, self.conflict.to_cp, self.conflict.from_cp)
# Add JTAC
useJTAC = INSTALLED_PLUGINS and INSTALLED_PLUGINS["JtacAutolasePlugin"] and INSTALLED_PLUGINS["JtacAutolasePlugin"].isEnabled()
jtacPlugin = LuaPluginManager().getPlugin("jtacautolase")
useJTAC = jtacPlugin and jtacPlugin.isEnabled()
if "has_jtac" in self.game.player_faction and self.game.player_faction["has_jtac"] and useJTAC:
n = "JTAC" + str(self.conflict.from_cp.id) + str(self.conflict.to_cp.id)
code = 1688 - len(self.jtacs)

View File

@ -1,10 +1,2 @@
from .base_plugin import BasePlugin
from .veaf_plugin import VeafPlugin
from .jtacautolase_plugin import JtacAutolasePlugin
from .liberation_plugin import LiberationPlugin
INSTALLED_PLUGINS={
"VeafPlugin": VeafPlugin(),
"JtacAutolasePlugin": JtacAutolasePlugin(),
"LiberationPlugin": LiberationPlugin(),
}
from .luaplugin import LuaPlugin
from .manager import LuaPluginManager

View File

@ -1,48 +0,0 @@
from PySide2.QtCore import QSize, Qt, QItemSelectionModel, QPoint
from PySide2.QtWidgets import QLabel, QDialog, QGridLayout, QListView, QStackedLayout, QComboBox, QWidget, \
QAbstractItemView, QPushButton, QGroupBox, QCheckBox, QVBoxLayout, QSpinBox
class BasePlugin():
nameInUI:str = "Base plugin"
nameInSettings:str = "plugin.base"
enabledDefaultValue:bool = False
def __init__(self):
self.uiWidget: QCheckBox = None
self.enabled = self.enabledDefaultValue
self.settings = None
def setupUI(self, settingsWindow, row:int):
self.settings = settingsWindow.game.settings
self.uiWidget = QCheckBox()
self.uiWidget.setChecked(self.isEnabled())
self.uiWidget.toggled.connect(lambda: self.applySetting(settingsWindow))
settingsWindow.pluginsGroupLayout.addWidget(QLabel(self.nameInUI), row, 0)
settingsWindow.pluginsGroupLayout.addWidget(self.uiWidget, row, 1, Qt.AlignRight)
def setSettings(self, settings):
self.settings = settings
if not self.nameInSettings in self.settings.plugins:
self.settings.plugins[self.nameInSettings] = self.enabledDefaultValue
def applySetting(self, settingsWindow):
self.settings.plugins[self.nameInSettings] = self.uiWidget.isChecked()
self.enabled = self.settings.plugins[self.nameInSettings]
def injectScripts(self, operation):
self.settings = operation.game.settings
return self.isEnabled()
def injectConfiguration(self, operation):
self.settings = operation.game.settings
return self.isEnabled()
def isEnabled(self) -> bool:
if not self.settings:
return False
self.setSettings(self.settings) # create the necessary settings keys if needed
return self.settings != None and self.settings.plugins[self.nameInSettings]

View File

@ -1,95 +0,0 @@
from dcs.triggers import TriggerStart
from PySide2.QtCore import QSize, Qt, QItemSelectionModel, QPoint
from PySide2.QtWidgets import QLabel, QDialog, QGridLayout, QListView, QStackedLayout, QComboBox, QWidget, \
QAbstractItemView, QPushButton, QGroupBox, QCheckBox, QVBoxLayout, QSpinBox
from .base_plugin import BasePlugin
class JtacAutolasePlugin(BasePlugin):
nameInUI:str = "JTAC Autolase"
nameInSettings:str = "plugin.jtacAutolase"
enabledDefaultValue:bool = True
#Allow spawn option
nameInUI_useSmoke:str = "JTACs use smoke"
nameInSettings_useSmoke:str = "plugin.jtacAutolase.useSmoke"
enabledDefaultValue_useSmoke:bool = True
def setupUI(self, settingsWindow, row:int):
# call the base method to add the plugin selection checkbox
super().setupUI(settingsWindow, row)
if settingsWindow.pluginsOptionsPageLayout:
self.optionsGroup = QGroupBox(self.nameInUI)
optionsGroupLayout = QGridLayout();
optionsGroupLayout.setAlignment(Qt.AlignTop)
self.optionsGroup.setLayout(optionsGroupLayout)
settingsWindow.pluginsOptionsPageLayout.addWidget(self.optionsGroup)
# JTAC use smoke
if not self.nameInSettings_useSmoke in self.settings.plugins:
self.settings.plugins[self.nameInSettings_useSmoke] = True
self.uiWidget_useSmoke = QCheckBox()
self.uiWidget_useSmoke.setChecked(self.settings.plugins[self.nameInSettings_useSmoke])
self.uiWidget_useSmoke.toggled.connect(lambda: self.applySetting(settingsWindow))
optionsGroupLayout.addWidget(QLabel(self.nameInUI_useSmoke), 0, 0)
optionsGroupLayout.addWidget(self.uiWidget_useSmoke, 0, 1, Qt.AlignRight)
# disable or enable the UI in the plugins special page
self.enableOptionsGroup()
def enableOptionsGroup(self):
pluginEnabled = self.uiWidget.isChecked()
self.optionsGroup.setEnabled(pluginEnabled)
def setSettings(self, settings):
# call the base method
super().setSettings(settings)
if not self.nameInSettings_useSmoke in self.settings.plugins:
self.settings.plugins[self.nameInSettings_useSmoke] = self.enabledDefaultValue_useSmoke
def applySetting(self, settingsWindow):
# call the base method to apply the plugin selection checkbox value
super().applySetting(settingsWindow)
# save the "use smoke" option
self.settings.plugins[self.nameInSettings_useSmoke] = self.uiWidget_useSmoke.isChecked()
# disable or enable the UI in the plugins special page
self.enableOptionsGroup()
def injectScripts(self, operation):
if super().injectScripts(operation):
operation.injectPluginScript("jtacautolase", "JTACAutoLase.lua", "jtacautolase")
def injectConfiguration(self, operation):
if super().injectConfiguration(operation):
# add a configuration for JTACAutoLase and start lasing for all JTACs
smoke = "local smoke = false"
if self.isUseSmoke():
smoke = "local smoke = true"
lua = smoke + """
-- setting and starting JTACs
env.info("DCSLiberation|: setting and starting JTACs")
for _, jtac in pairs(dcsLiberation.JTACs) do
if dcsLiberation.JTACAutoLase then
dcsLiberation.JTACAutoLase(jtac.dcsUnit, jtac.code, smoke, 'vehicle')
end
end
"""
operation.injectLuaTrigger(lua, "Setting and starting JTACs")
def isUseSmoke(self) -> bool:
if not self.settings:
return False
self.setSettings(self.settings) # create the necessary settings keys if needed
return self.settings.plugins[self.nameInSettings_useSmoke]

View File

@ -1,23 +0,0 @@
from .base_plugin import BasePlugin
class LiberationPlugin(BasePlugin):
nameInUI:str = "Liberation script"
nameInSettings:str = "plugin.liberation"
enabledDefaultValue:bool = True
def setupUI(self, settingsWindow, row:int):
# Don't setup any UI, this plugin is mandatory
pass
def injectScripts(self, operation):
if super().injectScripts(operation):
operation.injectPluginScript("base", "mist_4_3_74.lua", "mist")
operation.injectPluginScript("base", "json.lua", "json")
operation.injectPluginScript("base", "dcs_liberation.lua", "liberation")
def injectConfiguration(self, operation):
if super().injectConfiguration(operation):
pass
def isEnabled(self) -> bool:
return True # mandatory plugin

199
plugin/luaplugin.py Normal file
View File

@ -0,0 +1,199 @@
from typing import List
from pathlib import Path
from PySide2.QtCore import QSize, Qt, QItemSelectionModel, QPoint
from PySide2.QtWidgets import QLabel, QDialog, QGridLayout, QListView, QStackedLayout, QComboBox, QWidget, \
QAbstractItemView, QPushButton, QGroupBox, QCheckBox, QVBoxLayout, QSpinBox
import json
class LuaPluginWorkOrder():
def __init__(self, parent, filename:str, mnemonic:str, disable:bool):
self.filename = filename
self.mnemonic = mnemonic
self.disable = disable
self.parent = parent
def work(self, mnemonic:str, operation):
if self.disable:
operation.bypassPluginScript(self.parent.mnemonic, self.mnemonic)
else:
operation.injectPluginScript(self.parent.mnemonic, self.filename, self.mnemonic)
class LuaPluginSpecificOption():
def __init__(self, parent, mnemonic:str, nameInUI:str, defaultValue:bool):
self.mnemonic = mnemonic
self.nameInUI = nameInUI
self.defaultValue = defaultValue
self.parent = parent
class LuaPlugin():
NAME_IN_SETTINGS_BASE:str = "plugins."
def __init__(self, jsonFilename:str):
self.mnemonic:str = None
self.skipUI:bool = False
self.nameInUI:str = None
self.nameInSettings:str = None
self.defaultValue:bool = False
self.specificOptions = []
self.scriptsWorkOrders: List[LuaPluginWorkOrder] = None
self.configurationWorkOrders: List[LuaPluginWorkOrder] = None
self.initFromJson(jsonFilename)
self.enabled = self.defaultValue
self.settings = None
def initFromJson(self, jsonFilename:str):
jsonFile:Path = Path(jsonFilename)
if jsonFile.exists():
jsonData = json.loads(jsonFile.read_text())
self.mnemonic = jsonData.get("mnemonic")
self.skipUI = jsonData.get("skipUI", False)
self.nameInUI = jsonData.get("nameInUI")
self.nameInSettings = LuaPlugin.NAME_IN_SETTINGS_BASE + self.mnemonic
self.defaultValue = jsonData.get("defaultValue", False)
self.specificOptions = []
for jsonSpecificOption in jsonData.get("specificOptions"):
mnemonic = jsonSpecificOption.get("mnemonic")
nameInUI = jsonSpecificOption.get("nameInUI", mnemonic)
defaultValue = jsonSpecificOption.get("defaultValue")
self.specificOptions.append(LuaPluginSpecificOption(self, mnemonic, nameInUI, defaultValue))
self.scriptsWorkOrders = []
for jsonWorkOrder in jsonData.get("scriptsWorkOrders"):
file = jsonWorkOrder.get("file")
mnemonic = jsonWorkOrder.get("mnemonic")
disable = jsonWorkOrder.get("disable", False)
self.scriptsWorkOrders.append(LuaPluginWorkOrder(self, file, mnemonic, disable))
self.configurationWorkOrders = []
for jsonWorkOrder in jsonData.get("configurationWorkOrders"):
file = jsonWorkOrder.get("file")
mnemonic = jsonWorkOrder.get("mnemonic")
disable = jsonWorkOrder.get("disable", False)
self.configurationWorkOrders.append(LuaPluginWorkOrder(self, file, mnemonic, disable))
def setupUI(self, settingsWindow, row:int):
# set the game settings
self.settings = settingsWindow.game.settings
if not self.skipUI:
# create the plugin choice checkbox interface
self.uiWidget: QCheckBox = QCheckBox()
self.uiWidget.setChecked(self.isEnabled())
self.uiWidget.toggled.connect(lambda: self.applySetting(settingsWindow))
settingsWindow.pluginsGroupLayout.addWidget(QLabel(self.nameInUI), row, 0)
settingsWindow.pluginsGroupLayout.addWidget(self.uiWidget, row, 1, Qt.AlignRight)
# if needed, create the plugin options special page
if settingsWindow.pluginsOptionsPageLayout and self.specificOptions != None:
self.optionsGroup: QGroupBox = QGroupBox(self.nameInUI)
optionsGroupLayout = QGridLayout();
optionsGroupLayout.setAlignment(Qt.AlignTop)
self.optionsGroup.setLayout(optionsGroupLayout)
settingsWindow.pluginsOptionsPageLayout.addWidget(self.optionsGroup)
# browse each option in the specific options list
row = 0
for specificOption in self.specificOptions:
nameInSettings = self.nameInSettings + specificOption.mnemonic
if not nameInSettings in self.settings.plugins:
self.settings.plugins[nameInSettings] = specificOption.defaultValue
specificOption.uiWidget = QCheckBox()
specificOption.uiWidget.setChecked(self.settings.plugins[nameInSettings])
#specificOption.uiWidget.setEnabled(False)
specificOption.uiWidget.toggled.connect(lambda: self.applySetting(settingsWindow))
optionsGroupLayout.addWidget(QLabel(specificOption.nameInUI), row, 0)
optionsGroupLayout.addWidget(specificOption.uiWidget, row, 1, Qt.AlignRight)
row += 1
# disable or enable the UI in the plugins special page
self.enableOptionsGroup()
def enableOptionsGroup(self):
if self.optionsGroup:
self.optionsGroup.setEnabled(self.isEnabled())
def setSettings(self, settings):
self.settings = settings
# ensure the setting exist
if not self.nameInSettings in self.settings.plugins:
self.settings.plugins[self.nameInSettings] = self.defaultValue
# do the same for each option in the specific options list
for specificOption in self.specificOptions:
nameInSettings = self.nameInSettings + "." + specificOption.mnemonic
if not nameInSettings in self.settings.plugins:
self.settings.plugins[nameInSettings] = specificOption.defaultValue
def applySetting(self, settingsWindow):
# apply the main setting
self.settings.plugins[self.nameInSettings] = self.uiWidget.isChecked()
self.enabled = self.settings.plugins[self.nameInSettings]
# do the same for each option in the specific options list
for specificOption in self.specificOptions:
nameInSettings = self.nameInSettings + specificOption.mnemonic
self.settings.plugins[nameInSettings] = specificOption.uiWidget.isChecked()
# disable or enable the UI in the plugins special page
self.enableOptionsGroup()
def injectScripts(self, operation):
# set the game settings
self.settings = operation.game.settings
# execute the work order
if self.scriptsWorkOrders != None:
for workOrder in self.scriptsWorkOrders:
workOrder.work(self.mnemonic, operation)
# serves for subclasses
return self.isEnabled()
def injectConfiguration(self, operation):
# set the game settings
self.settings = operation.game.settings
# inject the plugin options
if len(self.specificOptions) > 0:
defineAllOptions = ""
for specificOption in self.specificOptions:
nameInSettings = self.nameInSettings + specificOption.mnemonic
value = "true" if self.settings.plugins[nameInSettings] else "false"
defineAllOptions += f" dcsLiberation.plugins.{self.mnemonic}.{specificOption.mnemonic} = {value} \n"
lua = f"-- {self.mnemonic} plugin configuration.\n"
lua += "\n"
lua += "if dcsLiberation then\n"
lua += " if not dcsLiberation.plugins then \n"
lua += " dcsLiberation.plugins = {}\n"
lua += " end\n"
lua += f" dcsLiberation.plugins.{self.mnemonic} = {{}}\n"
lua += defineAllOptions
lua += "end"
operation.injectLuaTrigger(lua, f"{self.mnemonic} plugin configuration")
# execute the work order
if self.configurationWorkOrders != None:
for workOrder in self.configurationWorkOrders:
workOrder.work(self.mnemonic, operation)
# serves for subclasses
return self.isEnabled()
def isEnabled(self) -> bool:
if not self.settings:
return False
self.setSettings(self.settings) # create the necessary settings keys if needed
return self.settings != None and self.settings.plugins[self.nameInSettings]
def hasUI(self) -> bool:
return not self.skipUI

43
plugin/manager.py Normal file
View File

@ -0,0 +1,43 @@
from .luaplugin import LuaPlugin
from typing import List
import glob
from pathlib import Path
import json
import logging
class LuaPluginManager():
PLUGINS_RESOURCE_PATH = Path("resources/plugins")
PLUGINS_LIST_FILENAME = "plugins.json"
PLUGINS_JSON_FILENAME = "plugin.json"
__plugins = None
def __init__(self):
if not LuaPluginManager.__plugins:
LuaPluginManager.__plugins= []
jsonFile:Path = Path(LuaPluginManager.PLUGINS_RESOURCE_PATH, LuaPluginManager.PLUGINS_LIST_FILENAME)
if jsonFile.exists():
logging.info(f"Reading plugins list from {jsonFile}")
jsonData = json.loads(jsonFile.read_text())
for plugin in jsonData:
jsonPluginFolder = Path(LuaPluginManager.PLUGINS_RESOURCE_PATH, plugin)
jsonPluginFile = Path(jsonPluginFolder, LuaPluginManager.PLUGINS_JSON_FILENAME)
if jsonPluginFile.exists():
logging.info(f"Reading plugin {plugin} from {jsonPluginFile}")
plugin = LuaPlugin(jsonPluginFile)
LuaPluginManager.__plugins.append(plugin)
else:
logging.error(f"Missing configuration file {jsonPluginFile} for plugin {plugin}")
else:
logging.error(f"Missing plugins list file {jsonFile}")
def getPlugins(self):
return LuaPluginManager.__plugins
def getPlugin(self, pluginName):
for plugin in LuaPluginManager.__plugins:
if plugin.mnemonic == pluginName:
return plugin
return None

View File

@ -1,90 +0,0 @@
from PySide2.QtCore import QSize, Qt, QItemSelectionModel, QPoint
from PySide2.QtWidgets import QLabel, QDialog, QGridLayout, QListView, QStackedLayout, QComboBox, QWidget, \
QAbstractItemView, QPushButton, QGroupBox, QCheckBox, QVBoxLayout, QSpinBox
from .base_plugin import BasePlugin
class VeafPlugin(BasePlugin):
nameInUI:str = "VEAF framework"
nameInSettings:str = "plugin.veaf"
enabledDefaultValue:bool = False
#Allow spawn option
nameInUI_allowSpawn:str = "Allow units spawn via markers and CTLD (not implemented yet)"
nameInSettings_allowSpawn:str = "plugin.veaf.allowSpawn"
def setupUI(self, settingsWindow, row:int):
# call the base method to add the plugin selection checkbox
super().setupUI(settingsWindow, row)
if settingsWindow.pluginsOptionsPageLayout:
self.optionsGroup = QGroupBox(self.nameInUI)
optionsGroupLayout = QGridLayout();
optionsGroupLayout.setAlignment(Qt.AlignTop)
self.optionsGroup.setLayout(optionsGroupLayout)
settingsWindow.pluginsOptionsPageLayout.addWidget(self.optionsGroup)
# allow spawn of objects
if not self.nameInSettings_allowSpawn in self.settings.plugins:
self.settings.plugins[self.nameInSettings_allowSpawn] = True
self.uiWidget_allowSpawn = QCheckBox()
self.uiWidget_allowSpawn.setChecked(self.settings.plugins[self.nameInSettings_allowSpawn])
self.uiWidget_allowSpawn.setEnabled(False)
self.uiWidget_allowSpawn.toggled.connect(lambda: self.applySetting(settingsWindow))
optionsGroupLayout.addWidget(QLabel(self.nameInUI_allowSpawn), 0, 0)
optionsGroupLayout.addWidget(self.uiWidget_allowSpawn, 0, 1, Qt.AlignRight)
# disable or enable the UI in the plugins special page
self.enableOptionsGroup()
def enableOptionsGroup(self):
pluginEnabled = self.uiWidget.isChecked()
self.optionsGroup.setEnabled(pluginEnabled)
def applySetting(self, settingsWindow):
# call the base method to apply the plugin selection checkbox value
super().applySetting(settingsWindow)
# save the "allow spawn" option
self.settings.plugins[self.nameInSettings_allowSpawn] = self.uiWidget_allowSpawn.isChecked()
# disable or enable the UI in the plugins special page
self.enableOptionsGroup()
def injectScripts(self, operation):
if super().injectScripts(operation):
# bypass JTACAutoLase
operation.bypassPluginScript("veaf", "jtacautolase")
# inject the required scripts
operation.injectPluginScript("veaf", "src\\scripts\\mist.lua", "mist")
operation.injectPluginScript("veaf", "src\\scripts\\Moose.lua", "moose")
operation.injectPluginScript("veaf", "src\\scripts\\CTLD.lua", "ctld")
#operation.injectPluginScript("veaf", "src\\scripts\\NIOD.lua", "niod")
operation.injectPluginScript("veaf", "src\\scripts\\WeatherMark.lua", "weathermark")
operation.injectPluginScript("veaf", "src\\scripts\\veaf.lua", "veaf")
operation.injectPluginScript("veaf", "src\\scripts\\dcsUnits.lua", "dcsunits")
operation.injectPluginScript("veaf", "src\\scripts\\veafAssets.lua", "veafassets")
operation.injectPluginScript("veaf", "src\\scripts\\veafCarrierOperations.lua", "veafcarrieroperations")
operation.injectPluginScript("veaf", "src\\scripts\\veafCasMission.lua", "veafcasmission")
operation.injectPluginScript("veaf", "src\\scripts\\veafCombatMission.lua", "veafcombatmission")
operation.injectPluginScript("veaf", "src\\scripts\\veafCombatZone.lua", "veafcombatzone")
operation.injectPluginScript("veaf", "src\\scripts\\veafGrass.lua", "veafgrass")
operation.injectPluginScript("veaf", "src\\scripts\\veafInterpreter.lua", "veafinterpreter")
operation.injectPluginScript("veaf", "src\\scripts\\veafMarkers.lua", "veafmarkers")
operation.injectPluginScript("veaf", "src\\scripts\\veafMove.lua", "veafmove")
operation.injectPluginScript("veaf", "src\\scripts\\veafNamedPoints.lua", "veafnamedpoints")
operation.injectPluginScript("veaf", "src\\scripts\\veafRadio.lua", "veafradio")
operation.injectPluginScript("veaf", "src\\scripts\\veafRemote.lua", "veafremote")
operation.injectPluginScript("veaf", "src\\scripts\\veafSecurity.lua", "veafsecurity")
operation.injectPluginScript("veaf", "src\\scripts\\veafShortcuts.lua", "veafshortcuts")
operation.injectPluginScript("veaf", "src\\scripts\\veafSpawn.lua", "veafspawn")
operation.injectPluginScript("veaf", "src\\scripts\\veafTransportMission.lua", "veaftransportmission")
operation.injectPluginScript("veaf", "src\\scripts\\veafUnits.lua", "veafunits")
def injectConfiguration(self, operation):
if super().injectConfiguration(operation):
operation.injectPluginScript("veaf", "src\\config\\missionConfig.lua", "veaf-config")

View File

@ -11,7 +11,7 @@ from game.game import Game
from game.infos.information import Information
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from qt_ui.windows.finances.QFinancesMenu import QHorizontalSeparationLine
from plugin import BasePlugin, INSTALLED_PLUGINS
from plugin import LuaPluginManager
class QSettingsWindow(QDialog):
@ -19,6 +19,8 @@ class QSettingsWindow(QDialog):
super(QSettingsWindow, self).__init__()
self.game = game
self.pluginsPage = None
self.pluginsOptionsPage = None
self.setModal(True)
self.setWindowTitle("Settings")
@ -37,53 +39,53 @@ class QSettingsWindow(QDialog):
self.categoryModel = QStandardItemModel(self.categoryList)
self.categoryList.setIconSize(QSize(32, 32))
self.initDifficultyLayout()
difficulty = QStandardItem("Difficulty")
difficulty.setIcon(CONST.ICONS["Missile"])
difficulty.setEditable(False)
difficulty.setSelectable(True)
self.categoryModel.appendRow(difficulty)
self.right_layout.addWidget(self.difficultyPage)
self.initGeneratorLayout()
generator = QStandardItem("Mission Generator")
generator.setIcon(CONST.ICONS["Generator"])
generator.setEditable(False)
generator.setSelectable(True)
self.categoryModel.appendRow(generator)
self.right_layout.addWidget(self.generatorPage)
self.initCheatLayout()
cheat = QStandardItem("Cheat Menu")
cheat.setIcon(CONST.ICONS["Cheat"])
cheat.setEditable(False)
cheat.setSelectable(True)
plugins = QStandardItem("LUA Plugins")
plugins.setIcon(CONST.ICONS["Plugins"])
plugins.setEditable(False)
plugins.setSelectable(True)
pluginsOptions = QStandardItem("LUA Plugins Options")
pluginsOptions.setIcon(CONST.ICONS["PluginsOptions"])
pluginsOptions.setEditable(False)
pluginsOptions.setSelectable(True)
self.categoryList.setIconSize(QSize(32, 32))
self.categoryModel.appendRow(difficulty)
self.categoryModel.appendRow(generator)
self.categoryModel.appendRow(cheat)
self.categoryModel.appendRow(plugins)
self.categoryModel.appendRow(pluginsOptions)
self.right_layout.addWidget(self.cheatPage)
self.initPluginsLayout()
if self.pluginsPage:
plugins = QStandardItem("LUA Plugins")
plugins.setIcon(CONST.ICONS["Plugins"])
plugins.setEditable(False)
plugins.setSelectable(True)
self.categoryModel.appendRow(plugins)
self.right_layout.addWidget(self.pluginsPage)
if self.pluginsOptionsPage:
pluginsOptions = QStandardItem("LUA Plugins Options")
pluginsOptions.setIcon(CONST.ICONS["PluginsOptions"])
pluginsOptions.setEditable(False)
pluginsOptions.setSelectable(True)
self.categoryModel.appendRow(pluginsOptions)
self.right_layout.addWidget(self.pluginsOptionsPage)
self.categoryList.setSelectionBehavior(QAbstractItemView.SelectRows)
self.categoryList.setModel(self.categoryModel)
self.categoryList.selectionModel().setCurrentIndex(self.categoryList.indexAt(QPoint(1,1)), QItemSelectionModel.Select)
self.categoryList.selectionModel().selectionChanged.connect(self.onSelectionChanged)
self.initDifficultyLayout()
self.initGeneratorLayout()
self.initCheatLayout()
self.initPluginsLayout()
self.right_layout.addWidget(self.difficultyPage)
self.right_layout.addWidget(self.generatorPage)
self.right_layout.addWidget(self.cheatPage)
self.right_layout.addWidget(self.pluginsPage)
self.right_layout.addWidget(self.pluginsOptionsPage)
self.layout.addWidget(self.categoryList, 0, 0, 1, 1)
self.layout.addLayout(self.right_layout, 0, 1, 5, 1)
@ -281,28 +283,32 @@ class QSettingsWindow(QDialog):
self.cheatLayout.addWidget(self.moneyCheatBox, 0, 0)
def initPluginsLayout(self):
self.pluginsOptionsPage = QWidget()
self.pluginsOptionsPageLayout = QVBoxLayout()
self.pluginsOptionsPageLayout.setAlignment(Qt.AlignTop)
self.pluginsOptionsPage.setLayout(self.pluginsOptionsPageLayout)
self.pluginsPage = QWidget()
self.pluginsPageLayout = QVBoxLayout()
self.pluginsPageLayout.setAlignment(Qt.AlignTop)
self.pluginsPage.setLayout(self.pluginsPageLayout)
self.pluginsGroup = QGroupBox("Plugins")
self.pluginsGroupLayout = QGridLayout();
self.pluginsGroupLayout.setAlignment(Qt.AlignTop)
self.pluginsGroup.setLayout(self.pluginsGroupLayout)
uiPrepared = False
row:int = 0
for pluginName in INSTALLED_PLUGINS:
plugin = INSTALLED_PLUGINS[pluginName]
plugin.setupUI(self, row)
row = row + 1
for plugin in LuaPluginManager().getPlugins():
if plugin.hasUI():
if not uiPrepared:
uiPrepared = True
self.pluginsPageLayout.addWidget(self.pluginsGroup)
self.pluginsOptionsPage = QWidget()
self.pluginsOptionsPageLayout = QVBoxLayout()
self.pluginsOptionsPageLayout.setAlignment(Qt.AlignTop)
self.pluginsOptionsPage.setLayout(self.pluginsOptionsPageLayout)
self.pluginsPage = QWidget()
self.pluginsPageLayout = QVBoxLayout()
self.pluginsPageLayout.setAlignment(Qt.AlignTop)
self.pluginsPage.setLayout(self.pluginsPageLayout)
self.pluginsGroup = QGroupBox("Plugins")
self.pluginsGroupLayout = QGridLayout();
self.pluginsGroupLayout.setAlignment(Qt.AlignTop)
self.pluginsGroup.setLayout(self.pluginsGroupLayout)
self.pluginsPageLayout.addWidget(self.pluginsGroup)
plugin.setupUI(self, row)
row = row + 1
def cheatLambda(self, amount):
return lambda: self.cheatMoney(amount)

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,84 @@
# LUA Plugin system
This plugin system was made for injecting LUA scripts in dcs-liberation missions.
The resources for the plugins are stored in the `resources/plugins` folder ; each plugin has its own folder.
## How does the system work ?
The application first reads the `resources/plugins/plugins.json` file to get a list of plugins to load, in order.
Each entry in this list should correspond to a subfolder of the `resources/plugins` directory, where a `plugin.json` file exists.
This file is the description of the plugin.
### plugin.json
The *base* and *jtacautolase* plugins both are included in the standard dcs-liberation distribution.
You can check their respective `plugin.json` files to understand how they work.
Here's a quick rundown of the file's components :
- `mnemonic` : the short, technical name of the plugin. It's the name of the folder, and the name of the plugin in the application's settings
- `skipUI` : if *true*, this plugin will not appear in the plugins selection user interface. Useful to force a plugin ON or OFF (see the *base* plugin)
- `nameInUI` : the title of the plugin as it will appear in the plugins selection user interface.
- `defaultValue` : the selection value of the plugin, when first installed ; if true, plugin is selected.
- `specificOptions` : a list of specific plugin options
- `nameInUI` : the title of the option as it will appear in the plugins specific options user interface.
- `mnemonic` : the short, technical name of the option. It's the name of the LUA variable passed to the configuration script, and the name of the option in the application's settings
- `defaultValue` : the selection value of the option, when first installed ; if true, option is selected.
- `scriptsWorkOrders` : a list of work orders that can be used to load or disable loading a specific LUA script
- `file` : the name of the LUA file in the plugin folder.
- `mnemonic` : the technical name of the LUA component. The filename may be more precise than needed (e.g. include a version number) ; this is used to load each file only once, and also to disable loading a file
- `disable` : if true, the script will be disabled instead of loaded
- `configurationWorkOrders` : a list of work orders that can be used to load a configuration LUA script (same description as above)
## Standard plugins
### The *base* plugin
The *base* plugin contains the scripts that are going to be injected in every dcs-liberation missions.
It is mandatory.
### The *JTACAutolase* plugin
This plugin replaces the vanilla JTAC functionality in dcs-liberation.
### The *VEAF framework* plugin
When enabled, this plugin will inject and configure the VEAF Framework scripts in the mission.
These scripts add a lot of runtime functionalities :
- spawning of units and groups (and portable TACANs)
- air-to-ground missions
- air-to-air missions
- transport missions
- carrier operations (not Moose)
- tanker move
- weather and ATC
- shelling a zone, lighting it up
- managing assets (tankers, awacs, aircraft carriers) : getting info, state, respawning them if needed
- managing named points (position, info, ATC)
- managing a dynamic radio menu
- managing remote calls to the mission through NIOD (RPC) and SLMOD (LUA sockets)
- managing security (not allowing everyone to do every action)
- define groups templates
You can find the *VEAF Framework* plugin [on GitHub](https://github.com/VEAF/dcs-liberation-veaf-framework/releases)
For more information, please visit the [VEAF Framework documentation site](https://veaf.github.io/VEAF-Mission-Creation-Tools/) (work in progress)
## Custom plugins
The easiest way to create a custom plugin is to copy an existing plugin, and modify the files.
## New settings pages
![New settings pages](0.png "New settings pages")
Custom plugins can be enabled or disabled in the new *LUA Plugins* settings page.
![LUA Plugins settings page](1.png "LUA Plugins settings page")
For plugins which expose specific options (such as "use smoke" for the *JTACAutoLase* plugin), the *LUA Plugins Options* settings page lists these options.
![LUA Plugins Options settings page](2.png "LUA Plugins settings page")

View File

@ -0,0 +1,22 @@
{
"mnemonic": "base",
"skipUI": true,
"nameInUI": "",
"defaultValue": true,
"specificOptions": [],
"scriptsWorkOrders": [
{
"file": "mist_4_3_74.lua",
"mnemonic": "mist"
},
{
"file": "json.lua",
"mnemonic": "json"
},
{
"file": "dcs_liberation.lua",
"mnemonic": "liberation"
}
],
"configurationWorkOrders": []
}

View File

@ -1,29 +0,0 @@
# this is a list of lua scripts that will be injected in the mission, in the same order
mist.lua
Moose.lua
CTLD.lua
NIOD.lua
WeatherMark.lua
veaf.lua
dcsUnits.lua
# JTACAutoLase is an empty file, only there to disable loading the official script (already included in CTLD)
JTACAutoLase.lua
veafAssets.lua
veafCarrierOperations.lua
veafCarrierOperations2.lua
veafCasMission.lua
veafCombatMission.lua
veafCombatZone.lua
veafGrass.lua
veafInterpreter.lua
veafMarkers.lua
veafMove.lua
veafNamedPoints.lua
veafRadio.lua
veafRemote.lua
veafSecurity.lua
veafShortcuts.lua
veafSpawn.lua
veafTransportMission.lua
veafUnits.lua
missionConfig.lua

View File

@ -1,58 +0,0 @@
# LUA Plugin system
This plugin system was made for injecting LUA scripts in dcs-liberation missions.
The resources for the plugins are stored in the `resources/plugins` folder ; each plugin has its own folder.
## Standard plugins
### The *base* plugin
The *base* plugin contains the scripts that are going to be injected in every dcs-liberation missions.
It is mandatory.
### The *JTACAutolase* plugin
This plugin replaces the vanilla JTAC functionality in dcs-liberation.
### The *VEAF framework* plugin
When enabled, this plugin will inject and configure the VEAF Framework scripts in the mission.
These scripts add a lot of runtime functionalities :
- spawning of units and groups (and portable TACANs)
- air-to-ground missions
- air-to-air missions
- transport missions
- carrier operations (not Moose)
- tanker move
- weather and ATC
- shelling a zone, lighting it up
- managing assets (tankers, awacs, aircraft carriers) : getting info, state, respawning them if needed
- managing named points (position, info, ATC)
- managing a dynamic radio menu
- managing remote calls to the mission through NIOD (RPC) and SLMOD (LUA sockets)
- managing security (not allowing everyone to do every action)
- define groups templates
For more information, please visit the [VEAF Framework documentation site](https://veaf.github.io/VEAF-Mission-Creation-Tools/) (work in progress)
## Custom plugins
Custom scripts can also be injected by dropping them in the `resources/plugins/custom` folder, and writing a `__plugins.lst` file listing them in order.
See the `__plugins.lst.sample` file for an example.
## New settings pages
![New settings pages](0.png "New settings pages")
Custom plugins can be enabled or disabled in the new *LUA Plugins* settings page.
![LUA Plugins settings page](1.png "LUA Plugins settings page")
For plugins which expose specific options (such as "use smoke" for the *JTACAutoLase* plugin), the *LUA Plugins Options* settings page lists these options.
![LUA Plugins Options settings page](2.png "LUA Plugins settings page")

View File

@ -0,0 +1,38 @@
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- configuration file for the JTAC Autolase framework
--
-- This configuration is tailored for a mission generated by DCS Liberation
-- see https://github.com/Khopa/dcs_liberation
-------------------------------------------------------------------------------------------------------------------------------------------------------------
-- JTACAutolase plugin - configuration
env.info("DCSLiberation|JTACAutolase plugin - configuration")
if dcsLiberation then
veaf.logTrace("dcsLiberation")
-- specific options
local smoke = false
-- retrieve specific options values
if dcsLiberation.plugins then
veaf.logTrace("dcsLiberation.plugins")
if dcsLiberation.plugins.jtacautolase then
veaf.logTrace("dcsLiberation.plugins.jtacautolase")
veaf.logTrace(string.format("dcsLiberation.plugins.jtacautolase.smoke=%s",veaf.p(dcsLiberation.plugins.jtacautolase.smoke)))
smoke = dcsLiberation.plugins.jtacautolase.smoke
end
end
veaf.logTrace(string.format("smoke=%s",veaf.p(smoke)))
-- actual configuration code
for _, jtac in pairs(dcsLiberation.JTACs) do
if dcsLiberation.JTACAutoLase then
dcsLiberation.JTACAutoLase(jtac.dcsUnit, jtac.code, smoke, 'vehicle')
end
end
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
{
"mnemonic": "jtacautolase",
"nameInUI": "JTAC Autolase",
"defaultValue": true,
"specificOptions": [
{
"nameInUI": "Use smoke",
"mnemonic": "smoke",
"defaultValue": true
}
],
"scriptsWorkOrders": [
{
"file": "mist_4_3_74.lua",
"mnemonic": "mist"
},
{
"file": "JTACAutoLase.lua",
"mnemonic": "jtacautolase-script"
}
],
"configurationWorkOrders": [
{
"file": "configuration.lua",
"mnemonic": "jtacautolase-config"
}
]
}

View File

@ -0,0 +1,5 @@
[
"veaf",
"jtacautolase",
"base"
]

@ -1 +0,0 @@
Subproject commit 219cdffef087660fe448a41e1f187c4856e9d80f