mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Refactor luagenerator
- cleaned up the generation - created special class to handle the serialization - improved string escaping: Replace OS Path separator with normal slash and allow the usage of a single quote in unit names by changing the delimiter to double quote instead (1797) - adjusted unit_name generation to prevent scripting errors with unescaped characters
This commit is contained in:
parent
8f16f242b1
commit
138e48dc2d
@ -19,6 +19,7 @@ from game.layout import LAYOUTS
|
|||||||
from game.layout.layout import TgoLayout, TgoLayoutGroup
|
from game.layout.layout import TgoLayout, TgoLayoutGroup
|
||||||
from game.point_with_heading import PointWithHeading
|
from game.point_with_heading import PointWithHeading
|
||||||
from game.theater.theatergroup import TheaterGroup
|
from game.theater.theatergroup import TheaterGroup
|
||||||
|
from game.utils import escape_string_for_lua
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game import Game
|
from game import Game
|
||||||
@ -251,7 +252,10 @@ class ForceGroup:
|
|||||||
# Assign UniqueID, name and align relative to ground_object
|
# Assign UniqueID, name and align relative to ground_object
|
||||||
for unit in units:
|
for unit in units:
|
||||||
unit.id = game.next_unit_id()
|
unit.id = game.next_unit_id()
|
||||||
unit.name = unit.unit_type.name if unit.unit_type else unit.type.name
|
# Add unit name escaped so that we do not have scripting issues later
|
||||||
|
unit.name = escape_string_for_lua(
|
||||||
|
unit.unit_type.name if unit.unit_type else unit.type.name
|
||||||
|
)
|
||||||
unit.position = PointWithHeading.from_point(
|
unit.position = PointWithHeading.from_point(
|
||||||
ground_object.position + unit.position,
|
ground_object.position + unit.position,
|
||||||
# Align heading to GroundObject defined by the campaign designer
|
# Align heading to GroundObject defined by the campaign designer
|
||||||
|
|||||||
@ -2,8 +2,9 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
from dcs import Mission
|
from dcs import Mission
|
||||||
from dcs.action import DoScript, DoScriptFile
|
from dcs.action import DoScript, DoScriptFile
|
||||||
@ -13,6 +14,7 @@ from dcs.triggers import TriggerStart
|
|||||||
from game.ato import FlightType
|
from game.ato import FlightType
|
||||||
from game.plugins import LuaPluginManager
|
from game.plugins import LuaPluginManager
|
||||||
from game.theater import TheaterGroundObject
|
from game.theater import TheaterGroundObject
|
||||||
|
from game.utils import escape_string_for_lua
|
||||||
|
|
||||||
from .aircraft.flightdata import FlightData
|
from .aircraft.flightdata import FlightData
|
||||||
from .airsupport import AirSupport
|
from .airsupport import AirSupport
|
||||||
@ -40,43 +42,42 @@ class LuaGenerator:
|
|||||||
self.inject_plugins()
|
self.inject_plugins()
|
||||||
|
|
||||||
def generate_plugin_data(self) -> None:
|
def generate_plugin_data(self) -> None:
|
||||||
# TODO: Refactor this
|
lua_data = LuaData("dcsLiberation")
|
||||||
lua_data = {
|
|
||||||
"AircraftCarriers": {},
|
|
||||||
"Tankers": {},
|
|
||||||
"AWACs": {},
|
|
||||||
"JTACs": {},
|
|
||||||
"TargetPoints": {},
|
|
||||||
"RedAA": {},
|
|
||||||
"BlueAA": {},
|
|
||||||
} # type: ignore
|
|
||||||
|
|
||||||
for i, tanker in enumerate(self.air_support.tankers):
|
install_path = lua_data.add_item("installPath")
|
||||||
lua_data["Tankers"][i] = {
|
install_path.set_value(os.path.abspath("."))
|
||||||
"dcsGroupName": tanker.group_name,
|
|
||||||
"callsign": tanker.callsign,
|
|
||||||
"variant": tanker.variant,
|
|
||||||
"radio": tanker.freq.mhz,
|
|
||||||
"tacan": str(tanker.tacan.number) + tanker.tacan.band.name,
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, awacs in enumerate(self.air_support.awacs):
|
lua_data.add_item("Airbases")
|
||||||
lua_data["AWACs"][i] = {
|
lua_data.add_item("Carriers")
|
||||||
"dcsGroupName": awacs.group_name,
|
|
||||||
"callsign": awacs.callsign,
|
|
||||||
"radio": awacs.freq.mhz,
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, jtac in enumerate(self.air_support.jtacs):
|
tankers_object = lua_data.add_item("Tankers")
|
||||||
lua_data["JTACs"][i] = {
|
for tanker in self.air_support.tankers:
|
||||||
"dcsGroupName": jtac.group_name,
|
tanker_item = tankers_object.add_item()
|
||||||
"callsign": jtac.callsign,
|
tanker_item.add_key_value("dcsGroupName", tanker.group_name)
|
||||||
"zone": jtac.region,
|
tanker_item.add_key_value("callsign", tanker.callsign)
|
||||||
"dcsUnit": jtac.unit_name,
|
tanker_item.add_key_value("variant", tanker.variant)
|
||||||
"laserCode": jtac.code,
|
tanker_item.add_key_value("radio", str(tanker.freq.mhz))
|
||||||
"radio": jtac.freq.mhz,
|
tanker_item.add_key_value(
|
||||||
}
|
"tacan", str(tanker.tacan.number) + tanker.tacan.band.name
|
||||||
flight_count = 0
|
)
|
||||||
|
|
||||||
|
awacs_object = lua_data.add_item("AWACs")
|
||||||
|
for awacs in self.air_support.awacs:
|
||||||
|
awacs_item = awacs_object.add_item()
|
||||||
|
awacs_item.add_key_value("dcsGroupName", awacs.group_name)
|
||||||
|
awacs_item.add_key_value("callsign", awacs.callsign)
|
||||||
|
awacs_item.add_key_value("radio", str(awacs.freq.mhz))
|
||||||
|
|
||||||
|
jtacs_object = lua_data.add_item("JTACs")
|
||||||
|
for jtac in self.air_support.jtacs:
|
||||||
|
jtac_item = jtacs_object.add_item()
|
||||||
|
jtac_item.add_key_value("dcsGroupName", jtac.group_name)
|
||||||
|
jtac_item.add_key_value("callsign", jtac.callsign)
|
||||||
|
jtac_item.add_key_value("zone", jtac.region)
|
||||||
|
jtac_item.add_key_value("dcsUnit", jtac.unit_name)
|
||||||
|
jtac_item.add_key_value("laserCode", jtac.code)
|
||||||
|
|
||||||
|
target_points = lua_data.add_item("TargetPoints")
|
||||||
for flight in self.flights:
|
for flight in self.flights:
|
||||||
if flight.friendly and flight.flight_type in [
|
if flight.friendly and flight.flight_type in [
|
||||||
FlightType.ANTISHIP,
|
FlightType.ANTISHIP,
|
||||||
@ -97,17 +98,24 @@ class LuaGenerator:
|
|||||||
elif hasattr(flight_target, "name"):
|
elif hasattr(flight_target, "name"):
|
||||||
flight_target_name = flight_target.name
|
flight_target_name = flight_target.name
|
||||||
flight_target_type = flight_type + " TGT (Airbase)"
|
flight_target_type = flight_type + " TGT (Airbase)"
|
||||||
lua_data["TargetPoints"][flight_count] = {
|
target_item = target_points.add_item()
|
||||||
"name": flight_target_name,
|
if flight_target_name:
|
||||||
"type": flight_target_type,
|
target_item.add_key_value("name", flight_target_name)
|
||||||
"position": {
|
if flight_target_type:
|
||||||
"x": flight_target.position.x,
|
target_item.add_key_value("type", flight_target_type)
|
||||||
"y": flight_target.position.y,
|
target_item.add_key_value(
|
||||||
},
|
"positionX", str(flight_target.position.x)
|
||||||
}
|
)
|
||||||
flight_count += 1
|
target_item.add_key_value(
|
||||||
|
"positionY", str(flight_target.position.y)
|
||||||
|
)
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
for cp in self.game.theater.controlpoints:
|
||||||
|
coalition_object = (
|
||||||
|
lua_data.get_or_create_item("BlueAA")
|
||||||
|
if cp.captured
|
||||||
|
else lua_data.get_or_create_item("RedAA")
|
||||||
|
)
|
||||||
for ground_object in cp.ground_objects:
|
for ground_object in cp.ground_objects:
|
||||||
if ground_object.might_have_aa and not ground_object.is_dead:
|
if ground_object.might_have_aa and not ground_object.is_dead:
|
||||||
for g in ground_object.groups:
|
for g in ground_object.groups:
|
||||||
@ -116,160 +124,18 @@ class LuaGenerator:
|
|||||||
if not threat_range:
|
if not threat_range:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
faction = "BlueAA" if cp.captured else "RedAA"
|
aa_item = coalition_object.add_item()
|
||||||
|
aa_item.add_key_value("name", ground_object.name)
|
||||||
lua_data[faction][g.group_name] = {
|
aa_item.add_key_value("range", str(threat_range.meters))
|
||||||
"name": ground_object.name,
|
aa_item.add_key_value(
|
||||||
"range": threat_range.meters,
|
"positionX", str(ground_object.position.x)
|
||||||
"position": {
|
)
|
||||||
"x": ground_object.position.x,
|
aa_item.add_key_value(
|
||||||
"y": ground_object.position.y,
|
"positionY", str(ground_object.position.y)
|
||||||
},
|
)
|
||||||
}
|
|
||||||
|
|
||||||
# set a LUA table with data from Liberation that we want to set
|
|
||||||
# at the moment it contains Liberation's install path, and an overridable
|
|
||||||
# definition for the JTACAutoLase function later, we'll add data about the units
|
|
||||||
# and points having been generated, in order to facilitate the configuration of
|
|
||||||
# the plugin lua scripts
|
|
||||||
state_location = "[[" + os.path.abspath(".") + "]]"
|
|
||||||
lua = (
|
|
||||||
"""
|
|
||||||
-- setting configuration table
|
|
||||||
env.info("DCSLiberation|: setting configuration table")
|
|
||||||
|
|
||||||
-- all data in this table is overridable.
|
|
||||||
dcsLiberation = {}
|
|
||||||
|
|
||||||
-- the base location for state.json; if non-existent, it'll be replaced with
|
|
||||||
-- LIBERATION_EXPORT_DIR, TEMP, or DCS working directory
|
|
||||||
dcsLiberation.installPath="""
|
|
||||||
+ state_location
|
|
||||||
+ """
|
|
||||||
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
# Process the tankers
|
|
||||||
lua += """
|
|
||||||
|
|
||||||
-- list the tankers generated by Liberation
|
|
||||||
dcsLiberation.Tankers = {
|
|
||||||
"""
|
|
||||||
for key in lua_data["Tankers"]:
|
|
||||||
data = lua_data["Tankers"][key]
|
|
||||||
dcs_group_name = data["dcsGroupName"]
|
|
||||||
callsign = data["callsign"]
|
|
||||||
variant = data["variant"]
|
|
||||||
tacan = data["tacan"]
|
|
||||||
radio = data["radio"]
|
|
||||||
lua += (
|
|
||||||
f" {{dcsGroupName='{dcs_group_name}', callsign='{callsign}', "
|
|
||||||
f"variant='{variant}', tacan='{tacan}', radio='{radio}' }}, \n"
|
|
||||||
)
|
|
||||||
lua += "}"
|
|
||||||
|
|
||||||
# Process the AWACSes
|
|
||||||
lua += """
|
|
||||||
|
|
||||||
-- list the AWACs generated by Liberation
|
|
||||||
dcsLiberation.AWACs = {
|
|
||||||
"""
|
|
||||||
for key in lua_data["AWACs"]:
|
|
||||||
data = lua_data["AWACs"][key]
|
|
||||||
dcs_group_name = data["dcsGroupName"]
|
|
||||||
callsign = data["callsign"]
|
|
||||||
radio = data["radio"]
|
|
||||||
lua += (
|
|
||||||
f" {{dcsGroupName='{dcs_group_name}', callsign='{callsign}', "
|
|
||||||
f"radio='{radio}' }}, \n"
|
|
||||||
)
|
|
||||||
lua += "}"
|
|
||||||
|
|
||||||
# Process the JTACs
|
|
||||||
lua += """
|
|
||||||
|
|
||||||
-- list the JTACs generated by Liberation
|
|
||||||
dcsLiberation.JTACs = {
|
|
||||||
"""
|
|
||||||
for key in lua_data["JTACs"]:
|
|
||||||
data = lua_data["JTACs"][key]
|
|
||||||
dcs_group_name = data["dcsGroupName"]
|
|
||||||
callsign = data["callsign"]
|
|
||||||
zone = data["zone"]
|
|
||||||
laser_code = data["laserCode"]
|
|
||||||
dcs_unit = data["dcsUnit"]
|
|
||||||
radio = data["radio"]
|
|
||||||
lua += (
|
|
||||||
f" {{dcsGroupName='{dcs_group_name}', callsign='{callsign}', "
|
|
||||||
f"zone={repr(zone)}, laserCode='{laser_code}', dcsUnit='{dcs_unit}', "
|
|
||||||
f"radio='{radio}' }}, \n"
|
|
||||||
)
|
|
||||||
lua += "}"
|
|
||||||
|
|
||||||
# Process the Target Points
|
|
||||||
lua += """
|
|
||||||
|
|
||||||
-- list the target points generated by Liberation
|
|
||||||
dcsLiberation.TargetPoints = {
|
|
||||||
"""
|
|
||||||
for key in lua_data["TargetPoints"]:
|
|
||||||
data = lua_data["TargetPoints"][key]
|
|
||||||
name = data["name"]
|
|
||||||
point_type = data["type"]
|
|
||||||
position_x = data["position"]["x"]
|
|
||||||
position_y = data["position"]["y"]
|
|
||||||
lua += (
|
|
||||||
f" {{name='{name}', pointType='{point_type}', "
|
|
||||||
f"positionX='{position_x}', positionY='{position_y}' }}, \n"
|
|
||||||
)
|
|
||||||
lua += "}"
|
|
||||||
|
|
||||||
lua += """
|
|
||||||
|
|
||||||
-- list the airbases generated by Liberation
|
|
||||||
-- dcsLiberation.Airbases = {}
|
|
||||||
|
|
||||||
-- list the aircraft carriers generated by Liberation
|
|
||||||
-- dcsLiberation.Carriers = {}
|
|
||||||
|
|
||||||
-- list the Red AA generated by Liberation
|
|
||||||
dcsLiberation.RedAA = {
|
|
||||||
"""
|
|
||||||
for key in lua_data["RedAA"]:
|
|
||||||
data = lua_data["RedAA"][key]
|
|
||||||
name = data["name"]
|
|
||||||
radius = data["range"]
|
|
||||||
position_x = data["position"]["x"]
|
|
||||||
position_y = data["position"]["y"]
|
|
||||||
lua += (
|
|
||||||
f" {{dcsGroupName='{key}', name='{name}', range='{radius}', "
|
|
||||||
f"positionX='{position_x}', positionY='{position_y}' }}, \n"
|
|
||||||
)
|
|
||||||
lua += "}"
|
|
||||||
|
|
||||||
lua += """
|
|
||||||
|
|
||||||
-- list the Blue AA generated by Liberation
|
|
||||||
dcsLiberation.BlueAA = {
|
|
||||||
"""
|
|
||||||
for key in lua_data["BlueAA"]:
|
|
||||||
data = lua_data["BlueAA"][key]
|
|
||||||
name = data["name"]
|
|
||||||
radius = data["range"]
|
|
||||||
position_x = data["position"]["x"]
|
|
||||||
position_y = data["position"]["y"]
|
|
||||||
lua += (
|
|
||||||
f" {{dcsGroupName='{key}', name='{name}', range='{radius}', "
|
|
||||||
f"positionX='{position_x}', positionY='{position_y}' }}, \n"
|
|
||||||
)
|
|
||||||
lua += "}"
|
|
||||||
|
|
||||||
lua += """
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
trigger = TriggerStart(comment="Set DCS Liberation data")
|
trigger = TriggerStart(comment="Set DCS Liberation data")
|
||||||
trigger.add_action(DoScript(String(lua)))
|
trigger.add_action(DoScript(String(lua_data.create_operations_lua())))
|
||||||
self.mission.triggerrules.triggers.append(trigger)
|
self.mission.triggerrules.triggers.append(trigger)
|
||||||
|
|
||||||
def inject_lua_trigger(self, contents: str, comment: str) -> None:
|
def inject_lua_trigger(self, contents: str, comment: str) -> None:
|
||||||
@ -307,3 +173,152 @@ class LuaGenerator:
|
|||||||
if plugin.enabled:
|
if plugin.enabled:
|
||||||
plugin.inject_scripts(self)
|
plugin.inject_scripts(self)
|
||||||
plugin.inject_configuration(self)
|
plugin.inject_configuration(self)
|
||||||
|
|
||||||
|
|
||||||
|
class LuaValue:
|
||||||
|
key: Optional[str]
|
||||||
|
value: str | list[str]
|
||||||
|
|
||||||
|
def __init__(self, key: Optional[str], value: str | list[str]):
|
||||||
|
self.key = key
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
def _escape_value(self, value: str) -> str:
|
||||||
|
value = value.replace('"', "'") # Replace Double Quote as this is the delimiter
|
||||||
|
value = value.replace(os.sep, "/") # Replace Backslash as path separator
|
||||||
|
return '"{0}"'.format(value)
|
||||||
|
|
||||||
|
def serialize(self) -> str:
|
||||||
|
serialized_value = self.key + " = " if self.key else ""
|
||||||
|
if isinstance(self.value, str):
|
||||||
|
serialized_value += f'"{escape_string_for_lua(self.value)}"'
|
||||||
|
else:
|
||||||
|
escaped_values = [f'"{escape_string_for_lua(v)}"' for v in self.value]
|
||||||
|
serialized_value += "{" + ", ".join(escaped_values) + "}"
|
||||||
|
return serialized_value
|
||||||
|
|
||||||
|
|
||||||
|
class LuaItem(ABC):
|
||||||
|
value: LuaValue | list[LuaValue]
|
||||||
|
name: Optional[str]
|
||||||
|
|
||||||
|
def __init__(self, name: Optional[str]):
|
||||||
|
self.value = []
|
||||||
|
self.name = name
|
||||||
|
|
||||||
|
def set_value(self, value: str) -> None:
|
||||||
|
self.value = LuaValue(None, value)
|
||||||
|
|
||||||
|
def add_data_array(self, key: str, values: list[str]) -> None:
|
||||||
|
self._add_value(LuaValue(key, values))
|
||||||
|
|
||||||
|
def add_key_value(self, key: str, value: str) -> None:
|
||||||
|
self._add_value(LuaValue(key, value))
|
||||||
|
|
||||||
|
def _add_value(self, value: LuaValue) -> None:
|
||||||
|
if isinstance(self.value, list):
|
||||||
|
self.value.append(value)
|
||||||
|
else:
|
||||||
|
self.value = value
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def add_item(self, item_name: Optional[str] = None) -> LuaItem:
|
||||||
|
"""adds a new item to the LuaArray without checking the existence"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_item(self, item_name: str) -> Optional[LuaItem]:
|
||||||
|
"""gets item from LuaArray. Returns None if it does not exist"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_or_create_item(self, item_name: Optional[str] = None) -> LuaItem:
|
||||||
|
"""gets item from the LuaArray or creates one if it does not exist already"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def serialize(self) -> str:
|
||||||
|
if isinstance(self.value, LuaValue):
|
||||||
|
return self.value.serialize()
|
||||||
|
else:
|
||||||
|
serialized_data = [d.serialize() for d in self.value]
|
||||||
|
return "{" + ", ".join(serialized_data) + "}"
|
||||||
|
|
||||||
|
|
||||||
|
class LuaData(LuaItem):
|
||||||
|
objects: list[LuaData]
|
||||||
|
base_name: Optional[str]
|
||||||
|
|
||||||
|
def __init__(self, name: Optional[str], is_base_name: bool = True):
|
||||||
|
self.objects = []
|
||||||
|
self.base_name = name if is_base_name else None
|
||||||
|
super().__init__(name)
|
||||||
|
|
||||||
|
def add_item(self, item_name: Optional[str] = None) -> LuaItem:
|
||||||
|
"""adds a new item to the LuaArray without checking the existence"""
|
||||||
|
item = LuaData(item_name, False)
|
||||||
|
self.objects.append(item)
|
||||||
|
return item
|
||||||
|
|
||||||
|
def get_item(self, item_name: str) -> Optional[LuaItem]:
|
||||||
|
"""gets item from LuaArray. Returns None if it does not exist"""
|
||||||
|
for lua_object in self.objects:
|
||||||
|
if lua_object.name == item_name:
|
||||||
|
return lua_object
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_or_create_item(self, item_name: Optional[str] = None) -> LuaItem:
|
||||||
|
"""gets item from the LuaArray or creates one if it does not exist already"""
|
||||||
|
if item_name:
|
||||||
|
item = self.get_item(item_name)
|
||||||
|
if item:
|
||||||
|
return item
|
||||||
|
return self.add_item(item_name)
|
||||||
|
|
||||||
|
def serialize(self, level: int = 0) -> str:
|
||||||
|
"""serialize the LuaData to a string"""
|
||||||
|
serialized_data: list[str] = []
|
||||||
|
serialized_name = ""
|
||||||
|
linebreak = "\n"
|
||||||
|
tab = "\t"
|
||||||
|
tab_end = ""
|
||||||
|
for _ in range(level):
|
||||||
|
tab += "\t"
|
||||||
|
tab_end += "\t"
|
||||||
|
if self.base_name:
|
||||||
|
# Only used for initialization of the object in lua
|
||||||
|
serialized_name += self.base_name + " = "
|
||||||
|
if self.objects:
|
||||||
|
# nested objects
|
||||||
|
serialized_objects = [o.serialize(level + 1) for o in self.objects]
|
||||||
|
if self.name:
|
||||||
|
if self.name is not self.base_name:
|
||||||
|
serialized_name += self.name + " = "
|
||||||
|
serialized_data.append(
|
||||||
|
serialized_name
|
||||||
|
+ "{"
|
||||||
|
+ linebreak
|
||||||
|
+ tab
|
||||||
|
+ ("," + linebreak + tab).join(serialized_objects)
|
||||||
|
+ linebreak
|
||||||
|
+ tab_end
|
||||||
|
+ "}"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# key with value
|
||||||
|
if self.name:
|
||||||
|
serialized_data.append(self.name + " = " + super().serialize())
|
||||||
|
# only value
|
||||||
|
else:
|
||||||
|
serialized_data.append(super().serialize())
|
||||||
|
|
||||||
|
return "\n".join(serialized_data)
|
||||||
|
|
||||||
|
def create_operations_lua(self) -> str:
|
||||||
|
"""crates the liberation lua script for the dcs mission"""
|
||||||
|
lua_prefix = """
|
||||||
|
-- setting configuration table
|
||||||
|
env.info("DCSLiberation|: setting configuration table")
|
||||||
|
"""
|
||||||
|
|
||||||
|
return lua_prefix + self.serialize()
|
||||||
|
|||||||
@ -466,3 +466,11 @@ def interpolate(value1: float, value2: float, factor: float, clamp: bool) -> flo
|
|||||||
|
|
||||||
def dcs_to_shapely_point(point: Point) -> ShapelyPoint:
|
def dcs_to_shapely_point(point: Point) -> ShapelyPoint:
|
||||||
return ShapelyPoint(point.x, point.y)
|
return ShapelyPoint(point.x, point.y)
|
||||||
|
|
||||||
|
|
||||||
|
def escape_string_for_lua(value: str) -> str:
|
||||||
|
"""Escapes special characters from a string.
|
||||||
|
This prevents scripting errors in lua scripts"""
|
||||||
|
value = value.replace('"', "'") # Replace Double Quote as this is the delimiter
|
||||||
|
value = value.replace(os.sep, "/") # Replace Backslash as path separator
|
||||||
|
return "{0}".format(value)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user