Develop to Main (#32)
Reviewed-on: #32 Co-authored-by: dutchie031 <timrorije@gmail.com>
This commit was merged in pull request #32.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
name: Publish Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- src/**
|
||||
- .gitea/workflows/release-beta.yml
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Read Version from version.txt
|
||||
id: read_version
|
||||
run: |
|
||||
VERSION=beta
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "tag=v$VERSION" >> "$GITHUB_OUTPUT"
|
||||
echo "Version: $VERSION"
|
||||
|
||||
- name: Extract Release Notes
|
||||
id: release_notes
|
||||
run: |
|
||||
VERSION=beta
|
||||
RELEASE_NOTES=$(awk -v ver="Unreleased" '
|
||||
/^## \[/ {
|
||||
if (found) exit
|
||||
if (index($0, "[" ver "]") > 0) found = 1
|
||||
next
|
||||
}
|
||||
found { print }
|
||||
' RELEASENOTES.md)
|
||||
|
||||
# Write multi-line output properly
|
||||
echo "body<<EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "$RELEASE_NOTES" >> "$GITHUB_OUTPUT"
|
||||
echo "EOF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Compile Spearhead
|
||||
uses: https://git.dutchie031.com/dutchie031/DcsMissionScriptingTools/github-action@action/v0
|
||||
with:
|
||||
source-root: ./src
|
||||
output-file: ./output/spearhead.lua
|
||||
|
||||
- name: Remove existing tag if it exists
|
||||
id: check_tag
|
||||
run: |
|
||||
TAG="${{ steps.read_version.outputs.tag }}"
|
||||
if git tag | grep -q "^$TAG$"; then
|
||||
echo "Tag exists. Removing it..."
|
||||
git push origin :refs/tags/"$TAG" || true
|
||||
git tag -d "$TAG" || true
|
||||
fi
|
||||
echo "Ready to create fresh tag: $TAG"
|
||||
|
||||
- name: Apply Tag to Current Commit
|
||||
run: |
|
||||
git config user.name "github-actions"
|
||||
git config user.email "github-actions@github.com"
|
||||
git tag ${{ steps.read_version.outputs.tag }}
|
||||
git push origin ${{ steps.read_version.outputs.tag }}
|
||||
|
||||
- name: Copy Release to Versioned File
|
||||
run: |
|
||||
cp ./output/spearhead.lua ./output/spearhead.${{ steps.read_version.outputs.tag }}.lua
|
||||
echo "Versioned file created: spearhead.${{ steps.read_version.outputs.tag }}.lua"
|
||||
|
||||
- name: Create Release and Upload Assets
|
||||
uses: akkuman/gitea-release-action@v1
|
||||
with:
|
||||
tag_name: ${{ steps.read_version.outputs.tag }}
|
||||
name: Release ${{ steps.read_version.outputs.tag }}
|
||||
body: ${{ steps.release_notes.outputs.body }}
|
||||
prerelease: true
|
||||
files: |-
|
||||
./output/spearhead.lua
|
||||
./output/spearhead.${{ steps.read_version.outputs.tag }}.lua
|
||||
#token: ${{ secrets.GITHUB_TOKEN }}
|
||||
env:
|
||||
NODE_OPTIONS: '--experimental-fetch'
|
||||
|
||||
- name: Announce Release
|
||||
uses: tsickert/discord-webhook@v7.0.0
|
||||
with:
|
||||
webhook-url: ${{ secrets.WEBHOOK_URL }}
|
||||
content: "New Beta Release"
|
||||
username: "Spearhead Release Bot"
|
||||
#TODO: avatar-url spearhead avatar
|
||||
thread-id: 1538520488442331227
|
||||
embed-title: "Spearhead Release Beta"
|
||||
embed-color: 3093247
|
||||
embed-description:
|
||||
${{ steps.release_notes.outputs.body }}
|
||||
embed-url:
|
||||
https://git.dutchie031.com/Spearhead/spearhead/releases/tag/${{ steps.read_version.outputs.tag }}
|
||||
|
||||
@@ -84,3 +84,18 @@ jobs:
|
||||
env:
|
||||
NODE_OPTIONS: '--experimental-fetch'
|
||||
|
||||
- name: Announce Release
|
||||
uses: tsickert/discord-webhook@v7.0.0
|
||||
with:
|
||||
webhook-url: ${{ secrets.WEBHOOK_URL }}
|
||||
content: "New Beta Release"
|
||||
username: "Spearhead Release Bot"
|
||||
#TODO: avatar-url spearhead avatar
|
||||
thread-id: 1538520596802175037
|
||||
embed-title: "Spearhead Release"
|
||||
embed-color: 3093247
|
||||
embed-description:
|
||||
${{ steps.release_notes.outputs.body }}
|
||||
embed-url:
|
||||
https://git.dutchie031.com/Spearhead/spearhead/releases/tag/${{ steps.read_version.outputs.tag }}
|
||||
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
/dist
|
||||
|
||||
.vscode/settings.json
|
||||
**\settings.json
|
||||
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"farp",
|
||||
"Sams",
|
||||
"SEAD"
|
||||
],
|
||||
"Lua.diagnostics.globals": [
|
||||
"lfs"
|
||||
],
|
||||
"maptz.regionfolder": {
|
||||
"[lua]" : {
|
||||
"foldEnd": "--endregion",
|
||||
"foldEndRegex": "[\\s]*--endregion",
|
||||
"foldStart": "--region [NAME]",
|
||||
"foldStartRegex": "[\\s]*--region[\\s]*(.*)",
|
||||
"disableFolding": false
|
||||
}
|
||||
},
|
||||
"livePreview.serverRoot": "/_docs",
|
||||
"Lua.workspace.library": [
|
||||
"/Users/ex61wi/Developer/personal/DcsMissionScriptingTools/dutchies-dcs-scripting-tools/lua-addons",
|
||||
"c:\\Users\\Tim\\.vscode\\extensions\\dutchie031.dutchies-dcs-scripting-tools-0.0.3\\lua-addons"
|
||||
],
|
||||
"dutchies-dcs-scripting-tools.compileAt": "onSave",
|
||||
}
|
||||
+27
-2
@@ -7,16 +7,41 @@
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
## [0.13.0] 2026-08
|
||||
|
||||
## [0.12.1] 2026-07
|
||||
A good first release that finally has all major bugs fixed that were caused by the migration from both the underlying script transpiler and the migration to Gitea. <br>
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
### New Features
|
||||
|
||||
- Issue #26
|
||||
Possibility to have Stage Overview briefings (which include current missions sorted by distance) to be shown on spawning of a player.
|
||||
PR #31
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed stage drawing to only be checked when a stage completed. Now done on stage number changed.
|
||||
- Issue #11
|
||||
Supply crate spawning now checks for free space and will not spawn if the area is too crowded.
|
||||
Additionally different units will spawn in different areas depending on loading side.
|
||||
PR #17
|
||||
- Fixed command wiring for supply hubs for better and more accurate detection of units spawning and entering/exiting zone.
|
||||
PR #15
|
||||
- Fixed custom drawings not being drawn correctly.
|
||||
PR #18
|
||||
- Fixed CAP Callbacks not working since the change to a transpiled script. Now a global callback circumvents this issue.
|
||||
PR #18
|
||||
- Fixed #9
|
||||
Changed order of checking mission briefings
|
||||
PR #19
|
||||
- Fixed Configuration defaulting to true for all booleans in StageConfig
|
||||
PR #28
|
||||
- Fixed Pre-Activated stages not always drawing or pre-activating correctly.
|
||||
PR #28
|
||||
- Addressed #24
|
||||
CAP max commit range is now configurable in the config.lua file.
|
||||
Issue remains open in order to apply further fine grained tuning.
|
||||
PR #29
|
||||
|
||||
## [0.12.0] 2026-06
|
||||
|
||||
|
||||
+7
-1
@@ -6,7 +6,7 @@ SpearheadConfig = {
|
||||
|
||||
--- The time briefings should be displayed by default.
|
||||
--- Players can always "Clear Messages" through the F10 menu, so setting it to a high value can be
|
||||
briefingMessageDuration = 30, --default 30
|
||||
briefingMessageDuration = 60, --default 60
|
||||
|
||||
CapConfig = {
|
||||
--quickly enable of disable the entire CAP Logic
|
||||
@@ -29,6 +29,12 @@ SpearheadConfig = {
|
||||
-- unit: feet
|
||||
maxAlt = 28000, -- default 28000
|
||||
|
||||
--The "maxDistance" that's set on the CAP tasking for the aircraft to commit to a target.
|
||||
--This is the distance from the aircraft to the target that the aircraft will commit to engaging
|
||||
--This is shared for CAP, Intercept and Sweep missions for now.
|
||||
-- unit: nautical miles
|
||||
maxCommitRange = 35, -- default 35
|
||||
|
||||
-- DELAYS.
|
||||
-- Delays work as follow.
|
||||
-- When an aircraft lands alive and well it will be rearmed and ready to go.
|
||||
|
||||
@@ -220,7 +220,7 @@ function CAP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishOnStation, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishOnStation, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ function CAP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
},
|
||||
stopCondition = {
|
||||
duration = durationBefore10,
|
||||
condition = "return Spearhead.DcsUtil.NeedsRTBInTen(\"" .. groupName .. "\", 0.10)",
|
||||
condition = "return GlobalCapCallBacks.NeedsRTBInTen(\"" .. groupName .. "\", 0.10)",
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -273,7 +273,7 @@ function CAP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTBInTen, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTBInTen, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,7 +299,7 @@ function CAP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
},
|
||||
stopCondition = {
|
||||
duration = durationAfter10,
|
||||
condition = "return Spearhead.DcsUtil.IsBingoFuel(\"" .. groupName .. "\")",
|
||||
condition = "return GlobalCapCallBacks.IsBingoFuel(\"" .. groupName .. "\", 0.10)",
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -312,7 +312,7 @@ function CAP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTB, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTB, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
local DcsUtil = require("classes.util.DcsUtil")
|
||||
local Events = require("classes.spearhead_events")
|
||||
|
||||
|
||||
GlobalCapCallBacks = {}
|
||||
|
||||
function GlobalCapCallBacks.IsBingoFuel(groupName, fuelPercent)
|
||||
return DcsUtil.IsBingoFuel(groupName, fuelPercent)
|
||||
end
|
||||
|
||||
function GlobalCapCallBacks.NeedsRTBInTen(groupName, fuelOffset)
|
||||
return DcsUtil.NeedsRTBInTen(groupName, fuelOffset)
|
||||
end
|
||||
|
||||
function GlobalCapCallBacks.PublishRTBInTen(groupName)
|
||||
return Events.PublishRTBInTen(groupName)
|
||||
end
|
||||
|
||||
function GlobalCapCallBacks.PublishRTB(groupName)
|
||||
return Events.PublishRTB(groupName)
|
||||
end
|
||||
|
||||
function GlobalCapCallBacks.PublishOnStation(groupName)
|
||||
return Events.PublishOnStation(groupName)
|
||||
end
|
||||
@@ -247,7 +247,7 @@ function INTERCEPT.getInterceptTaskPoint(groupName, currentPoint, targetPoint, a
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTB, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTB, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,7 +379,7 @@ function INTERCEPT.getUnitInterceptTaskPoint(groupName, currentPoint, targetPosi
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTB, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTB, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ function SWEEP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishOnStation, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishOnStation, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,7 +270,7 @@ function SWEEP.getAsTasking(groupName, airbase, capZone, capConfig)
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTB, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTB, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ function CapConfig.new()
|
||||
self._minDurationOnStation = 1200
|
||||
self._maxDurationOnStation = 2700
|
||||
|
||||
self._maxDeviationRange = 35 * 1852 -- in meters
|
||||
self._maxDeviationRange = (tonumber(SpearheadConfig.CapConfig.maxCommitRange) or 35) * 1852 -- in meters
|
||||
self._rearmDelay = tonumber(SpearheadConfig.CapConfig.rearmDelay) or 600
|
||||
self._repairDelay = tonumber(SpearheadConfig.CapConfig.repairDelay) or 600
|
||||
self._deathDelay = tonumber(SpearheadConfig.CapConfig.deathDelay) or 1800
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
local briefingMessageTime = nil
|
||||
|
||||
---@class GlobalConfig
|
||||
---@field private _briefingTime number ;
|
||||
---@field private _briefingTime number
|
||||
---@field private _debugEnabled boolean
|
||||
local GlobalConfig = {}
|
||||
GlobalConfig.__index = GlobalConfig;
|
||||
|
||||
@@ -19,13 +20,24 @@ function GlobalConfig.New()
|
||||
if SpearheadConfig.briefingMessageDuration then
|
||||
self._briefingTime = SpearheadConfig.briefingMessageDuration
|
||||
end
|
||||
|
||||
if SpearheadConfig.debugEnabled ~= nil then
|
||||
self._debugEnabled = SpearheadConfig.debugEnabled
|
||||
else
|
||||
self._debugEnabled = false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function GlobalConfig:getBriefingTime()
|
||||
return self._briefingTime or 30
|
||||
return self._briefingTime or 60
|
||||
end
|
||||
|
||||
function GlobalConfig:isDebugEnabled()
|
||||
return self._debugEnabled or false
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -7,29 +7,47 @@
|
||||
--- @field startingStage integer
|
||||
--- @field maxMissionsPerStage integer
|
||||
--- @field AmountPreactivateStage integer
|
||||
--- @field briefingOnSpawnEnabled boolean
|
||||
local StageConfig = {};
|
||||
StageConfig.__index = StageConfig
|
||||
|
||||
local Logger = require("classes.util.Logger")
|
||||
local _logger = Logger.new("StageConfig", Logger.LogLevel)
|
||||
|
||||
---comment
|
||||
---@return StageConfig
|
||||
function StageConfig:new()
|
||||
local function new()
|
||||
|
||||
if SpearheadConfig == nil then SpearheadConfig = {} end
|
||||
if SpearheadConfig.StageConfig == nil then SpearheadConfig.StageConfig = {} end
|
||||
if SpearheadConfig == nil then
|
||||
_logger:warn("SpearheadConfig is nil, creating default SpearheadConfig")
|
||||
SpearheadConfig = {}
|
||||
end
|
||||
|
||||
---@type StageConfig
|
||||
local o = {
|
||||
isEnabled = SpearheadConfig.StageConfig.enabled or true,
|
||||
isDrawStagesEnabled = SpearheadConfig.StageConfig.drawStages or true,
|
||||
isAutoStages = SpearheadConfig.StageConfig.autoStages or true,
|
||||
startingStage = SpearheadConfig.StageConfig.startingStage or 1,
|
||||
maxMissionsPerStage = SpearheadConfig.StageConfig.maxMissionStage or 10,
|
||||
isDrawPreActivatedEnabled = SpearheadConfig.StageConfig.drawPreActivated or true,
|
||||
AmountPreactivateStage = SpearheadConfig.StageConfig.preactivateStage or 1,
|
||||
}
|
||||
if SpearheadConfig.StageConfig == nil then
|
||||
_logger:warn("SpearheadConfig.StageConfig is nil, creating default StageConfig")
|
||||
SpearheadConfig.StageConfig = {}
|
||||
end
|
||||
|
||||
setmetatable(o, { __index = self })
|
||||
local self = setmetatable({}, StageConfig)
|
||||
self.isEnabled = SpearheadConfig.StageConfig.enabled ~= false
|
||||
self.isDrawStagesEnabled = SpearheadConfig.StageConfig.drawStages ~= false
|
||||
self.isAutoStages = SpearheadConfig.StageConfig.autoStages ~= false
|
||||
self.startingStage = SpearheadConfig.StageConfig.startingStage or 1
|
||||
self.maxMissionsPerStage = SpearheadConfig.StageConfig.maxMissionStage or 10
|
||||
self.isDrawPreActivatedEnabled = SpearheadConfig.StageConfig.drawPreActivated ~= false
|
||||
self.AmountPreactivateStage = SpearheadConfig.StageConfig.preactivateStage or 1
|
||||
self.briefingOnSpawnEnabled = SpearheadConfig.StageConfig.briefingOnSpawn ~= false
|
||||
|
||||
return o;
|
||||
_logger:info("Successfully created StageConfig Object")
|
||||
|
||||
return self;
|
||||
end
|
||||
|
||||
local config = new();
|
||||
|
||||
---@return StageConfig
|
||||
function StageConfig:getInstance()
|
||||
return config
|
||||
end
|
||||
|
||||
return StageConfig
|
||||
@@ -350,18 +350,6 @@ function Database.New(Logger)
|
||||
end
|
||||
end
|
||||
|
||||
for _, missionZone in pairs(self._tables.MissionZones) do
|
||||
if self._tables.MissionZoneData[missionZone] == nil or self._tables.MissionZoneData[missionZone].description == nil then
|
||||
MissionEditorWarnings.Add("Mission with zonename: " .. missionZone .. " does not have a briefing")
|
||||
end
|
||||
end
|
||||
|
||||
for _, missionZone in pairs(self._tables.RandomMissionZones) do
|
||||
if self._tables.MissionZoneData[missionZone] == nil or self._tables.MissionZoneData[missionZone].description == nil then
|
||||
MissionEditorWarnings.Add("Mission with zonename: " .. missionZone .. " does not have a briefing")
|
||||
end
|
||||
end
|
||||
|
||||
for _, farpZoneName in pairs(self._tables.AllFarpZones) do
|
||||
for _, airbase in pairs(world.getAirbases()) do
|
||||
if airbase:getDesc().category == Airbase.Category.HELIPAD then
|
||||
@@ -447,6 +435,21 @@ function Database.New(Logger)
|
||||
end
|
||||
end
|
||||
|
||||
-- Checks for missing briefings in mission zones and random mission zones
|
||||
do
|
||||
for _, missionZone in pairs(self._tables.MissionZones) do
|
||||
if self._tables.MissionZoneData[missionZone] == nil or self._tables.MissionZoneData[missionZone].description == nil then
|
||||
MissionEditorWarnings.Add("Mission with zonename: " .. missionZone .. " does not have a briefing")
|
||||
end
|
||||
end
|
||||
|
||||
for _, missionZone in pairs(self._tables.RandomMissionZones) do
|
||||
if self._tables.MissionZoneData[missionZone] == nil or self._tables.MissionZoneData[missionZone].description == nil then
|
||||
MissionEditorWarnings.Add("Mission with zonename: " .. missionZone .. " does not have a briefing")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if missions == 0 then missions = 1 end
|
||||
|
||||
self._logger:info("initiated the database with amount of zones: ")
|
||||
|
||||
@@ -50,6 +50,19 @@ do
|
||||
table.insert(OnStageNumberChangedHandlers, handler)
|
||||
end
|
||||
|
||||
---@class OnStageNumberChangeCompleteListener
|
||||
---@field OnStageNumberChangeComplete fun(self:OnStageNumberChangeCompleteListener, number:integer)
|
||||
|
||||
local OnStageNumberChangeCompleteListeners = {}
|
||||
---@param listener OnStageNumberChangeCompleteListener
|
||||
SpearheadEvents.AddStageNumberChangeCompleteListener = function(listener)
|
||||
if type(listener) ~= "table" or type(listener.OnStageNumberChangeComplete) ~= "function" then
|
||||
warn("Event handler not of type table/object with function OnStageNumberChangeComplete(self, number)")
|
||||
return
|
||||
end
|
||||
table.insert(OnStageNumberChangeCompleteListeners, listener)
|
||||
end
|
||||
|
||||
---@param newStageNumber number
|
||||
SpearheadEvents.PublishStageNumberChanged = function(newStageNumber)
|
||||
pcall(function ()
|
||||
@@ -71,6 +84,16 @@ do
|
||||
logError(err)
|
||||
end
|
||||
end
|
||||
|
||||
for _, callable in pairs(OnStageNumberChangeCompleteListeners) do
|
||||
local succ, err = pcall(function()
|
||||
callable:OnStageNumberChangeComplete(newStageNumber)
|
||||
end)
|
||||
if err then
|
||||
logError(err)
|
||||
end
|
||||
end
|
||||
|
||||
Logger.new("Events", "INFO"):info("Published stage number changed to: " .. tostring(newStageNumber))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -92,7 +92,7 @@ do --setup route util
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishOnStation, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishOnStation, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ do --setup route util
|
||||
},
|
||||
stopCondition = {
|
||||
duration = durationBefore10,
|
||||
condition = "return Spearhead.DcsUtil.IsBingoFuel(\"" .. groupName .. "\", 0.10)",
|
||||
condition = "return GlobalCapCallBacks.IsBingoFuel(\"" .. groupName .. "\", 0.10)",
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -135,7 +135,7 @@ do --setup route util
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTBInTen, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTBInTen, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ do --setup route util
|
||||
},
|
||||
stopCondition = {
|
||||
duration = durationAfter10,
|
||||
condition = "return Spearhead.DcsUtil.IsBingoFuel(\"" .. groupName .. "\")",
|
||||
condition = "return GlobalCapCallBacks.IsBingoFuel(\"" .. groupName .. "\", 0.10)",
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -169,7 +169,7 @@ do --setup route util
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTB, \"" .. groupName .. "\")"
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTB, \"" .. groupName .. "\")"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,7 +375,7 @@ do --setup route util
|
||||
action = {
|
||||
id = "Script",
|
||||
params = {
|
||||
command = "pcall(Spearhead.Events.PublishRTB, \"" ..
|
||||
command = "pcall(GlobalCapCallBacks.PublishRTB, \"" ..
|
||||
groupName .. "\")"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
local Events = require("classes.spearhead_events")
|
||||
local Util = require("classes.util.Util")
|
||||
local DcsUtil = require("classes.util.DcsUtil")
|
||||
local Logger = require("classes.util.Logger")
|
||||
local MissionEditorWarnings = require("classes.util.MissionEditorWarnings")
|
||||
|
||||
local ExtraStage = require("classes.stageClasses.Stages.ExtraStage")
|
||||
local PrimaryStage = require("classes.stageClasses.Stages.PrimaryStage")
|
||||
local WaitingStage = require("classes.stageClasses.Stages.WaitingStage")
|
||||
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
|
||||
|
||||
local StagesByName = {}
|
||||
|
||||
@@ -20,10 +22,11 @@ local WaitingStagesByIndex = {}
|
||||
|
||||
local currentStage = -99
|
||||
|
||||
---@class GlobalStageManager : StageCompleteListener, OnStageChangedListener
|
||||
---@class GlobalStageManager : StageCompleteListener, OnStageChangedListener, OnStageNumberChangeCompleteListener
|
||||
---@field private database Database
|
||||
---@field private logger Logger
|
||||
---@field private stageConfig StageConfig
|
||||
---@field private _missionCommandsHelper MissionCommandsHelper
|
||||
local GlobalStageManager = {}
|
||||
GlobalStageManager.__index = GlobalStageManager
|
||||
|
||||
@@ -41,6 +44,7 @@ function GlobalStageManager.NewAndStart(database, stageConfig, logLevel, spawnMa
|
||||
local self = setmetatable({}, GlobalStageManager)
|
||||
self.database = database
|
||||
self.stageConfig = stageConfig
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate()
|
||||
|
||||
self.logger = logger
|
||||
if stageConfig.isAutoStages ~= true then
|
||||
@@ -214,14 +218,34 @@ function GlobalStageManager:OnStageNumberChanged(stageNumber)
|
||||
self:UpdateDrawings(stageNumber)
|
||||
end
|
||||
|
||||
function GlobalStageManager:OnStageNumberChangeComplete(stageNumber)
|
||||
self.logger:debug("Stage number change complete to: " .. tostring(stageNumber))
|
||||
|
||||
local groups = {}
|
||||
|
||||
for _, player in pairs(DcsUtil.getAllPlayerUnits()) do
|
||||
local group = player:getGroup()
|
||||
if group then
|
||||
groups[group:getID()] = group
|
||||
end
|
||||
end
|
||||
|
||||
for _, group in pairs(groups) do
|
||||
self._missionCommandsHelper:OverviewToGroup(group:getID())
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
function GlobalStageManager:UpdateDrawings(stageNumber)
|
||||
self.logger:debug("Updating custom drawings for stage number: " .. tostring(stageNumber))
|
||||
local drawings = self.database:getCustomDrawings()
|
||||
for _, drawing in pairs(drawings) do
|
||||
local startStage, stopStage = drawing:GetStartAndStop()
|
||||
if stageNumber >= startStage and stageNumber < stopStage then
|
||||
self.logger:debug("Drawing " .. drawing:GetName() .. " is active for stage number: " .. tostring(stageNumber))
|
||||
drawing:Draw()
|
||||
else
|
||||
self.logger:debug("Drawing " .. drawing:GetName() .. " is not active for stage number: " .. tostring(stageNumber))
|
||||
drawing:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,6 +2,8 @@ local Util = require("classes.util.Util")
|
||||
local DcsUtil = require("classes.util.DcsUtil")
|
||||
local SupplyUnitsTracker = require("classes.stageClasses.helpers.SupplyUnitsTracker")
|
||||
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
|
||||
local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing")
|
||||
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
|
||||
|
||||
---@class SupplyHub
|
||||
---@field private _database Database
|
||||
@@ -12,7 +14,7 @@ local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionComma
|
||||
---@field private _isCommmandAdded table<string, boolean>
|
||||
---@field private _missionCommandsHelper MissionCommandsHelper
|
||||
---@field private _inZone table<string, boolean>
|
||||
---@field private _drawID number
|
||||
---@field private _customDrawing CustomDrawing?
|
||||
---@field private _cargoInUnits table<table<string, number>>
|
||||
---@field private _activeAtStart boolean
|
||||
---@field private _active boolean
|
||||
@@ -30,6 +32,7 @@ function SupplyHub.new(database, logger, zoneName)
|
||||
self._database = database
|
||||
self._logger = logger
|
||||
self._zoneName = zoneName
|
||||
self._customDrawing = nil
|
||||
|
||||
local split = Util.split_string(zoneName, "_")
|
||||
if string.lower(split[2]) == "a" then
|
||||
@@ -40,9 +43,9 @@ function SupplyHub.new(database, logger, zoneName)
|
||||
|
||||
self._zone = DcsUtil.getZoneByName(zoneName)
|
||||
|
||||
self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate(logger.LogLevel)
|
||||
self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate()
|
||||
self._inZone = {}
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(logger.LogLevel)
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate()
|
||||
|
||||
self._logger:debug("Creating Supply Hub zone: " .. self._zoneName)
|
||||
|
||||
@@ -72,13 +75,13 @@ function SupplyHub:Activate()
|
||||
self._logger:debug("Activating Supply Hub zone: " .. self._zoneName)
|
||||
|
||||
local zone = DcsUtil.getZoneByName(self._zoneName)
|
||||
if zone and self._drawID == nil then
|
||||
---@type DrawColor
|
||||
local fillColor = { r=0, g=1, b=0, a=0.2 }
|
||||
---@type DrawColor
|
||||
local lineColor = { r=0, g=1, b=0, a=1}
|
||||
if zone and self._customDrawing == nil then
|
||||
local fillColor = DrawingHelper.ColorTableToColorString({ 0, 1, 0, 0.2 })
|
||||
local lineColor = DrawingHelper.ColorTableToColorString({ 0, 1, 0, 1})
|
||||
local lineStyle = 1
|
||||
self._drawID = DcsUtil.DrawZone(zone, lineColor, fillColor, lineStyle)
|
||||
|
||||
self._customDrawing = CustomDrawing.FromZone(zone, lineColor, fillColor, lineStyle, 6)
|
||||
self._customDrawing:Draw()
|
||||
end
|
||||
|
||||
self._supplyUnitsTracker:RegisterHub(self)
|
||||
|
||||
@@ -11,6 +11,8 @@ local StageBase = require("classes.stageClasses.SpecialZones.StageBase")
|
||||
local BlueSam = require("classes.stageClasses.SpecialZones.BlueSam")
|
||||
local Events = require("classes.spearhead_events")
|
||||
local GlobalCapManager = require("classes.capClasses.GlobalCapManager")
|
||||
local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing")
|
||||
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
|
||||
|
||||
---@alias StageColor
|
||||
---| "RED"
|
||||
@@ -43,17 +45,15 @@ local GlobalCapManager = require("classes.capClasses.GlobalCapManager")
|
||||
--- @field zoneName string
|
||||
--- @field stageName string?
|
||||
--- @field stageNumber number
|
||||
--- @field protected _currentStageState CurrentStageState
|
||||
--- @field protected _missionCommandsHelper MissionCommandsHelper
|
||||
--- @field protected _isActive boolean
|
||||
--- @field protected _isComplete boolean
|
||||
--- @field protected _missionPriority MissionPriority
|
||||
--- @field protected _database Database
|
||||
--- @field protected _db StageData
|
||||
--- @field protected _logger Logger
|
||||
--- @field protected _preActivated boolean
|
||||
--- @field protected _activeStage integer
|
||||
--- @field protected _stageConfig StageConfig
|
||||
--- @field protected _stageDrawingId integer
|
||||
--- @field protected _customDrawing CustomDrawing
|
||||
--- @field protected _spawnedGroups Array<string>
|
||||
--- @field protected _stageCompleteListeners Array<StageCompleteListener>
|
||||
--- @field protected CheckContinuousAsync fun(self:Stage, time:number) : number?
|
||||
@@ -63,13 +63,20 @@ local Stage = {}
|
||||
|
||||
Stage.__index = Stage
|
||||
|
||||
---@enum CurrentStageState
|
||||
Stage.CurrentStageState = {
|
||||
INACTIVE = 0,
|
||||
PREACTIVATED = 1,
|
||||
ACTIVE = 2,
|
||||
BLUE = 3
|
||||
}
|
||||
|
||||
Stage.StageColors = {
|
||||
INVISIBLE = { r=0, g=0, b=0, a=0 },
|
||||
RED_ACTIVE = { r=1, g=0, b=0, a=0.15 },
|
||||
RED_PREACTIVE = { r=1, g=0, b=0, a=0.10},
|
||||
BLUE = { r=0, g=0, b=1, a=0.10},
|
||||
GRAY = { r=80/255, g=80/255, b=80/255, a=0.10 }
|
||||
INVISIBLE = { 0, 0, 0, 0 },
|
||||
RED_ACTIVE = { 1, 0, 0, 0.20 },
|
||||
RED_PREACTIVE = { 1, 0, 0, 0.05},
|
||||
BLUE = { 0, 0, 1, 0.10},
|
||||
GRAY = { 80/255, 80/255, 80/255, 0.10 }
|
||||
}
|
||||
|
||||
---comment
|
||||
@@ -83,12 +90,11 @@ Stage.StageColors = {
|
||||
function Stage:superNew(database, stageConfig, logger, initData, missionPriority, spawnManager)
|
||||
|
||||
logger:debug("[BaseStage] Initiating stage with name: " .. initData.stageZoneName)
|
||||
|
||||
self._currentStageState = Stage.CurrentStageState.INACTIVE
|
||||
self.zoneName = initData.stageZoneName
|
||||
self.stageNumber = initData.stageNumber
|
||||
self._isActive = false
|
||||
self._isComplete = false
|
||||
self.stageName = initData.stageDisplayName
|
||||
self._currentStageState = Stage.CurrentStageState.INACTIVE
|
||||
|
||||
self.OnPostStageComplete = nil
|
||||
self.OnPostBlueActivated = nil
|
||||
@@ -110,13 +116,19 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
|
||||
}
|
||||
|
||||
self._activeStage = -99
|
||||
self._preActivated = false
|
||||
self._stageConfig = stageConfig or {}
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(logger.LogLevel)
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate()
|
||||
|
||||
local zone = DcsUtil.getZoneByName(self.zoneName)
|
||||
if zone then
|
||||
self._stageDrawingId = DcsUtil.DrawZone(zone, Stage.StageColors.INVISIBLE, Stage.StageColors.INVISIBLE, 4)
|
||||
|
||||
local colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.INVISIBLE)
|
||||
local fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.INVISIBLE)
|
||||
|
||||
local customDrawing = CustomDrawing.FromZone(zone, colorString, fillColorString, 1, 5)
|
||||
if customDrawing then
|
||||
self._customDrawing = customDrawing
|
||||
end
|
||||
end
|
||||
|
||||
self._spawnedGroups = {}
|
||||
@@ -253,6 +265,7 @@ function Stage:superNew(database, stageConfig, logger, initData, missionPriority
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Events.AddStageNumberChangedListener(self)
|
||||
|
||||
return self
|
||||
@@ -260,7 +273,7 @@ end
|
||||
|
||||
---@return boolean
|
||||
function Stage:IsComplete()
|
||||
if self._isComplete == true then return true end
|
||||
if self._currentStageState == Stage.CurrentStageState.BLUE then return true end
|
||||
|
||||
for i, mission in pairs(self._db.sams) do
|
||||
local state = mission:getState()
|
||||
@@ -276,13 +289,13 @@ function Stage:IsComplete()
|
||||
end
|
||||
end
|
||||
|
||||
self._isComplete = true
|
||||
self._currentStageState = Stage.CurrentStageState.BLUE
|
||||
return true
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function Stage:IsActive()
|
||||
return self._isActive == true
|
||||
return self._currentStageState == Stage.CurrentStageState.ACTIVE
|
||||
end
|
||||
|
||||
---comment
|
||||
@@ -367,10 +380,9 @@ function Stage:AddStageCompleteListener(listener)
|
||||
end
|
||||
|
||||
---Activates all SAMS, Airbase units etc all at once.
|
||||
---@param draw boolean
|
||||
function Stage:PreActivate(draw)
|
||||
if self._preActivated == false then
|
||||
self._preActivated = true
|
||||
function Stage:PreActivate()
|
||||
if self._currentStageState == Stage.CurrentStageState.INACTIVE then
|
||||
self._currentStageState = Stage.CurrentStageState.PREACTIVATED
|
||||
for key, mission in pairs(self._db.sams) do
|
||||
if mission then
|
||||
mission:SpawnInactive()
|
||||
@@ -382,40 +394,60 @@ function Stage:PreActivate(draw)
|
||||
end
|
||||
end
|
||||
|
||||
if draw == true then
|
||||
self:MarkStage(Stage.StageColors.RED_PREACTIVE)
|
||||
end
|
||||
self:MarkStage()
|
||||
|
||||
end
|
||||
|
||||
---@param stageColor DrawColor
|
||||
function Stage:MarkStage(stageColor)
|
||||
local lineColor = { r=stageColor.r, g=stageColor.g, b=stageColor.b, a=stageColor.a }
|
||||
local fillColor = { r=stageColor.r, g=stageColor.g, b=stageColor.b, a=stageColor.a }
|
||||
function Stage:MarkStage()
|
||||
|
||||
if stageColor.a > 0 then
|
||||
lineColor.a = 1
|
||||
self._logger:debug("Marking stage '" .. Util.toString(self.zoneName) .. "' with state: " .. self._currentStageState)
|
||||
|
||||
if self._customDrawing then
|
||||
self._customDrawing:Remove()
|
||||
end
|
||||
|
||||
if stageColor == Stage.StageColors.RED_PREACTIVE then
|
||||
lineColor.a = 0
|
||||
if self._stageConfig.isDrawStagesEnabled == false then return end
|
||||
if self._stageConfig.isDrawPreActivatedEnabled == false and self._currentStageState == Stage.CurrentStageState.PREACTIVATED then
|
||||
return
|
||||
end
|
||||
|
||||
if self._stageDrawingId and self._stageConfig.isDrawStagesEnabled == true then
|
||||
DcsUtil.SetLineColor(self._stageDrawingId, lineColor)
|
||||
DcsUtil.SetFillColor(self._stageDrawingId, fillColor)
|
||||
if self._customDrawing then
|
||||
self._customDrawing:UpdateDrawingObject(function(drawingObject)
|
||||
local drawing = drawingObject --[[@as Polygon]]
|
||||
if self._currentStageState == Stage.CurrentStageState.ACTIVE then
|
||||
drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_ACTIVE)
|
||||
drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_ACTIVE)
|
||||
drawing.style = "dot dash"
|
||||
elseif self._currentStageState == Stage.CurrentStageState.PREACTIVATED then
|
||||
drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_PREACTIVE)
|
||||
drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.RED_PREACTIVE)
|
||||
drawing.style = "no line"
|
||||
elseif self._currentStageState == Stage.CurrentStageState.BLUE then
|
||||
drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.BLUE)
|
||||
drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.BLUE)
|
||||
drawing.style = "two dash"
|
||||
else
|
||||
drawing.fillColorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.INVISIBLE)
|
||||
drawing.colorString = DrawingHelper.ColorTableToColorString(Stage.StageColors.INVISIBLE)
|
||||
drawing.style = "no line"
|
||||
end
|
||||
|
||||
return drawing
|
||||
end)
|
||||
self._customDrawing:Draw()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Stage:ActivateStage()
|
||||
self._isActive = true;
|
||||
self._currentStageState = Stage.CurrentStageState.ACTIVE
|
||||
|
||||
self:PreActivate()
|
||||
|
||||
pcall(function()
|
||||
self:MarkStage(Stage.StageColors.RED_ACTIVE)
|
||||
self:MarkStage()
|
||||
end)
|
||||
|
||||
self:PreActivate(false)
|
||||
|
||||
self._logger:debug("Activating Misc groups for zone. Count: " .. Util.tableLength(self._db.miscGroups))
|
||||
for _, miscGroup in pairs(self._db.miscGroups) do
|
||||
miscGroup:Spawn()
|
||||
@@ -462,9 +494,9 @@ function Stage:OnStageNumberChanged(number)
|
||||
|
||||
if self.stageNumber - self._activeStage == self._stageConfig.AmountPreactivateStage then
|
||||
self._logger:debug("Pre-activating stage: " .. self.zoneName .. " with number: " .. number)
|
||||
self:PreActivate(true)
|
||||
self:PreActivate()
|
||||
elseif GlobalCapManager.IsCapActiveWhenZoneIsActive(self.zoneName, number) == true then
|
||||
self:PreActivate(false)
|
||||
self:PreActivate()
|
||||
end
|
||||
|
||||
if number == self.stageNumber then
|
||||
@@ -559,7 +591,7 @@ end
|
||||
function Stage:ActivateBlueStage()
|
||||
|
||||
self._logger:debug("Setting stage '" .. Util.toString(self.zoneName) .. "' to blue")
|
||||
|
||||
self._currentStageState = Stage.CurrentStageState.BLUE
|
||||
for _, mission in pairs(self._db.missions) do
|
||||
mission:SpawnPersistedState()
|
||||
end
|
||||
@@ -575,7 +607,7 @@ function Stage:ActivateBlueStage()
|
||||
---@param self Stage
|
||||
local ActivateBlueAsync = function(self)
|
||||
pcall(function()
|
||||
self:MarkStage(Stage.StageColors.BLUE)
|
||||
self:MarkStage()
|
||||
end)
|
||||
|
||||
self:ActivateBlueGroups()
|
||||
|
||||
@@ -23,7 +23,7 @@ function ExtraStage.New(database, stageConfig, logger, initData, spawnManager)
|
||||
|
||||
self.OnPostBlueActivated = function (selfStage)
|
||||
|
||||
selfStage:MarkStage(Stage.StageColors.GRAY)
|
||||
selfStage:MarkStage()
|
||||
end
|
||||
|
||||
self.OnPostStageComplete = function (selfStage)
|
||||
@@ -34,7 +34,7 @@ function ExtraStage.New(database, stageConfig, logger, initData, spawnManager)
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param self Stage
|
||||
---@param self ExtraStage
|
||||
---@param number integer
|
||||
function ExtraStage:OnStageNumberChanged(number)
|
||||
|
||||
@@ -47,16 +47,16 @@ function ExtraStage:OnStageNumberChanged(number)
|
||||
|
||||
if self.stageNumber - self._activeStage == self._stageConfig.AmountPreactivateStage then
|
||||
self._logger:debug("Pre-activating stage: " .. self.zoneName .. " with number: " .. number)
|
||||
self:PreActivate(true)
|
||||
self:PreActivate()
|
||||
elseif GlobalCapManager.IsCapActiveWhenZoneIsActive(self.zoneName, number) == true then
|
||||
self:PreActivate(false)
|
||||
self:PreActivate()
|
||||
end
|
||||
|
||||
if number == self.stageNumber then
|
||||
self:ActivateStage()
|
||||
end
|
||||
|
||||
if self._isComplete == true then
|
||||
if self._currentStageState == Stage.CurrentStageState.BLUE then
|
||||
self:ActivateBlueStage()
|
||||
end
|
||||
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
|
||||
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
|
||||
local Util = require("classes.util.Util")
|
||||
local Logger = require("classes.util.Logger")
|
||||
|
||||
|
||||
local drawingLogger = Logger.new("CustomDrawing")
|
||||
|
||||
---@class CustomDrawing
|
||||
---@field private _id integer?
|
||||
---@field private _drawingObject DrawingObject
|
||||
---@field private _startingStage number
|
||||
---@field private _removeAtStage number
|
||||
---@field private _logger Logger
|
||||
local CustomDrawing = {}
|
||||
CustomDrawing.__index = CustomDrawing
|
||||
|
||||
|
||||
---@param drawingObject DrawingObject
|
||||
---@param id integer?
|
||||
---@return CustomDrawing
|
||||
function CustomDrawing.New(drawingObject, id)
|
||||
function CustomDrawing.New(drawingObject)
|
||||
local self = setmetatable({}, CustomDrawing)
|
||||
self._drawingObject = drawingObject
|
||||
self._id = id
|
||||
self._id = nil -- initiate ID as nil, when drawn it will be set to the ID returned by DrawingHelper.Draw
|
||||
self._logger = drawingLogger
|
||||
|
||||
local name = drawingObject.name
|
||||
local split = Util.split_string(name or "", "_")
|
||||
@@ -28,6 +33,63 @@ function CustomDrawing.New(drawingObject, id)
|
||||
return self
|
||||
end
|
||||
|
||||
---@param zone SpearheadTriggerZone
|
||||
---@param colorString string
|
||||
---@param fillColorString string
|
||||
---@param lineStyle LineType
|
||||
---@param lineThickness number
|
||||
---@return CustomDrawing?
|
||||
function CustomDrawing.FromZone(zone, colorString, fillColorString, lineStyle, lineThickness)
|
||||
if zone == nil then
|
||||
drawingLogger:warn("CustomDrawing.FromZone called with nil zone")
|
||||
return nil
|
||||
end
|
||||
|
||||
if zone.zone_type == "Cilinder" then
|
||||
---@type Circle
|
||||
local drawingObject = {
|
||||
mapX = zone.location.x,
|
||||
mapY = zone.location.y,
|
||||
radius = zone.radius,
|
||||
name = zone.name .. "_drawing",
|
||||
primitiveType = "Polygon",
|
||||
polygonMode = "circle",
|
||||
visible = true,
|
||||
style = DrawingHelper.ToLineStyleString(lineStyle),
|
||||
colorString = colorString,
|
||||
fillColorString = fillColorString,
|
||||
thickness = lineThickness,
|
||||
}
|
||||
|
||||
return CustomDrawing.New(drawingObject)
|
||||
end
|
||||
|
||||
if zone.zone_type == "Polygon" then
|
||||
|
||||
---@type Free
|
||||
local drawingObject = {
|
||||
mapX = 0,
|
||||
mapY = 0,
|
||||
points = zone.verts,
|
||||
name = zone.name .. "_drawing",
|
||||
primitiveType = "Polygon",
|
||||
polygonMode = "free",
|
||||
visible = true,
|
||||
style = DrawingHelper.ToLineStyleString(lineStyle),
|
||||
colorString = colorString,
|
||||
fillColorString = fillColorString,
|
||||
thickness = lineThickness,
|
||||
}
|
||||
|
||||
return CustomDrawing.New(drawingObject)
|
||||
end
|
||||
end
|
||||
|
||||
---@return string
|
||||
function CustomDrawing:GetName()
|
||||
return self._drawingObject.name
|
||||
end
|
||||
|
||||
---@return number start
|
||||
---@return number stop
|
||||
function CustomDrawing:GetStartAndStop()
|
||||
@@ -35,14 +97,26 @@ function CustomDrawing:GetStartAndStop()
|
||||
end
|
||||
|
||||
function CustomDrawing:Draw()
|
||||
self._id = DrawingHelper.Draw(self._drawingObject)
|
||||
self._logger:debug("Drawing custom drawing with ID " .. tostring(self._id))
|
||||
|
||||
if self._id ~= nil then
|
||||
DrawingHelper.Remove(self._id)
|
||||
end
|
||||
|
||||
self._id = DrawingHelper.Draw(self._drawingObject, self._logger)
|
||||
end
|
||||
|
||||
function CustomDrawing:Remove()
|
||||
if self._id ~= nil then
|
||||
self._logger:debug("Removing custom drawing with ID " .. tostring(self._id))
|
||||
DrawingHelper.Remove(self._id)
|
||||
self._id = nil
|
||||
end
|
||||
end
|
||||
|
||||
---@param updateFunc fun(drawingObject:DrawingObject):DrawingObject
|
||||
function CustomDrawing:UpdateDrawingObject(updateFunc)
|
||||
self._drawingObject = updateFunc(self._drawingObject)
|
||||
end
|
||||
|
||||
return CustomDrawing
|
||||
@@ -1,25 +1,49 @@
|
||||
local Util = require("classes.util.Util")
|
||||
local Logger = require("classes.util.Logger")
|
||||
local GlobalConfig = require("classes.configuration.GlobalConfig")
|
||||
|
||||
---@type LogLevel
|
||||
local level = "INFO"
|
||||
if GlobalConfig:isDebugEnabled() then
|
||||
level = "DEBUG"
|
||||
end
|
||||
|
||||
local drawingLogger = Logger.new("DrawingHelper", level)
|
||||
|
||||
---@class DrawingHelper
|
||||
local DrawingHelper = {}
|
||||
DrawingHelper.__index = DrawingHelper
|
||||
|
||||
|
||||
local customDrawingIdIncrementer = 4210
|
||||
|
||||
---@param object DrawingObject
|
||||
---@param logger Logger?
|
||||
---@return integer? id
|
||||
function DrawingHelper.Draw(object)
|
||||
function DrawingHelper.Draw(object, logger)
|
||||
if object == nil then
|
||||
if logger then
|
||||
logger:warn("DrawingHelper.Draw called with nil object")
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local id = DrawingHelper.GetAndAddId()
|
||||
|
||||
if logger then
|
||||
logger:debug("Drawing object with ID " .. tostring(id) .. " and primitive type: " .. tostring(object.primitiveType))
|
||||
end
|
||||
|
||||
if(object.primitiveType == "Polygon") then
|
||||
DrawingHelper.DrawPolygon(object--[[@as Polygon]], id)
|
||||
DrawingHelper.DrawPolygon(object--[[@as Polygon]], id, logger)
|
||||
elseif(object.primitiveType == "Line") then
|
||||
DrawingHelper.DrawLine(object--[[@as Line]], id)
|
||||
DrawingHelper.DrawLine(object--[[@as Line]], id, logger)
|
||||
elseif(object.primitiveType == "TextBox") then
|
||||
DrawingHelper.DrawTextBox(object--[[@as TextBox]], id)
|
||||
else
|
||||
if logger then
|
||||
logger:warn("Unknown primitive type: " .. tostring(object.primitiveType))
|
||||
end
|
||||
end
|
||||
|
||||
return id
|
||||
@@ -36,16 +60,25 @@ end
|
||||
---@param points Array<Vec3>
|
||||
---@param fillColor table
|
||||
---@param lineColor table
|
||||
local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineStyle)
|
||||
---@param lineStyle LineType
|
||||
---@param lineThickness number
|
||||
---@param logger Logger?
|
||||
local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineStyle, lineThickness, logger)
|
||||
|
||||
if lineThickness == nil or lineThickness <= 0 then
|
||||
lineStyle = 0
|
||||
end
|
||||
|
||||
local functionString = "trigger.action.markupToAll(" .. shapeID .. ", -1, " .. drawID .. ","
|
||||
for _, point in ipairs(points) do
|
||||
|
||||
for _, point in pairs(points) do
|
||||
functionString = functionString .. " { x=" .. point.x .. ", y=0,z=" .. point.z .. "},"
|
||||
end
|
||||
functionString = functionString ..
|
||||
"{ " .. lineColor[1] .. "," .. lineColor[2] .. "," .. lineColor[3] .. "," .. lineColor[4] .. "}, " ..
|
||||
"{ " .. fillColor[1] .. "," .. fillColor[2] .. "," .. fillColor[3] .. "," .. fillColor[4] .. "}, " ..
|
||||
lineStyle .. ")"
|
||||
functionString = functionString .. "{0,1,0,1}, {0,1,0,1}, " .. lineStyle .. ")"
|
||||
|
||||
if logger then
|
||||
logger:debug("Drawing complex drawing with ID " .. tostring(drawID) .. " and function string: " .. functionString)
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: deprecated
|
||||
local f, err = loadstring(functionString)
|
||||
@@ -55,12 +88,21 @@ local function MarkupToAll(shapeID, drawID, points, fillColor, lineColor, lineS
|
||||
env.error("Something failed when drawing complex drawing" .. err)
|
||||
end
|
||||
|
||||
if logger then
|
||||
logger:debug("Drawing with fill color: " .. table.concat(fillColor, ",") .. " and line color: " .. table.concat(lineColor, ",") .. " and line style: " .. tostring(lineStyle) .. " and line thickness: " .. tostring(lineThickness))
|
||||
end
|
||||
|
||||
trigger.action.setMarkupColorFill(drawID, fillColor)
|
||||
trigger.action.setMarkupColor(drawID, lineColor)
|
||||
trigger.action.setMarkupTypeLine(drawID, lineStyle)
|
||||
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param object Polygon
|
||||
---@param id integer
|
||||
function DrawingHelper.DrawPolygon(object, id)
|
||||
---@param logger Logger?
|
||||
function DrawingHelper.DrawPolygon(object, id, logger)
|
||||
if object == nil then
|
||||
return
|
||||
end
|
||||
@@ -75,11 +117,12 @@ function DrawingHelper.DrawPolygon(object, id)
|
||||
end
|
||||
|
||||
---@param oval Oval
|
||||
local function DrawOval(oval)
|
||||
---@param logger Logger?
|
||||
local function DrawOval(oval, logger)
|
||||
---@type Array<Vec3>
|
||||
local points = {}
|
||||
local pointsNo = 30
|
||||
local angleStep = (2 * math.pi) / points
|
||||
local angleStep = (2 * math.pi) / pointsNo
|
||||
|
||||
local fillColor = DrawingHelper.ColorToColorTable(oval.fillColorString)
|
||||
local color = DrawingHelper.ColorToColorTable(oval.colorString)
|
||||
@@ -91,20 +134,36 @@ function DrawingHelper.DrawPolygon(object, id)
|
||||
local y = oval.mapY + (oval.r2 * math.sin(angle))
|
||||
table.insert(points, { x = x, y = 0, z = y } )
|
||||
end
|
||||
MarkupToAll(7, id, points, fillColor, color, lineStyle)
|
||||
MarkupToAll(7, id, points, fillColor, color, lineStyle, oval.thickness, logger)
|
||||
end
|
||||
|
||||
---@param free Free
|
||||
local function DrawFree(free)
|
||||
---@param logger Logger?
|
||||
local function DrawFree(free, logger)
|
||||
local fillColor = DrawingHelper.ColorToColorTable(free.fillColorString)
|
||||
local color = DrawingHelper.ColorToColorTable(free.colorString)
|
||||
local lineStyle = DrawingHelper.ToLineStyleInteger(free.style)
|
||||
|
||||
local points = {}
|
||||
for _, point in ipairs(free.points) do
|
||||
table.insert(points, { x = point.x, y = 0, z = point.y } )
|
||||
local keys = {}
|
||||
for k, _ in pairs(free.points) do
|
||||
table.insert(keys, k)
|
||||
end
|
||||
MarkupToAll(7, id, points, fillColor, color, lineStyle)
|
||||
|
||||
table.sort(keys, function(a, b) return a < b end)
|
||||
|
||||
local points = {}
|
||||
for _, k in ipairs(keys) do
|
||||
local point = free.points[k]
|
||||
|
||||
local newPoint = { x = free.mapX + point.x, y = 0, z = free.mapY + point.y }
|
||||
local firstPoint = points[1]
|
||||
|
||||
if firstPoint == nil or newPoint.x ~= firstPoint.x or newPoint.z ~= firstPoint.z then
|
||||
table.insert(points, newPoint)
|
||||
end
|
||||
end
|
||||
|
||||
MarkupToAll(7, id, points, fillColor, color, lineStyle, free.thickness, logger)
|
||||
end
|
||||
|
||||
---@param rect Rect
|
||||
@@ -116,38 +175,49 @@ function DrawingHelper.DrawPolygon(object, id)
|
||||
local pointA = { x = rect.mapX, y = 0, z = rect.mapY }
|
||||
local pointB = { x = rect.mapX + rect.width, y = 0, z = rect.mapY + rect.height }
|
||||
trigger.action.rectToAll(-1, id, pointA, pointB, color, fillColor, lineStyle, true)
|
||||
|
||||
end
|
||||
|
||||
---@param arrow Arrow
|
||||
local function DrawArrow(arrow)
|
||||
---@param logger Logger?
|
||||
local function DrawArrow(arrow, logger)
|
||||
local fillColor = DrawingHelper.ColorToColorTable(arrow.fillColorString)
|
||||
local color = DrawingHelper.ColorToColorTable(arrow.colorString)
|
||||
local lineStyle = DrawingHelper.ToLineStyleInteger(arrow.style)
|
||||
|
||||
local startPoint = { x = arrow.mapX, y = 0, z = arrow.mapY }
|
||||
if logger then
|
||||
logger:debug("Drawing arrow with start point: " .. tostring(arrow.mapX) .. ", " .. tostring(arrow.mapY) .. " and angle: " .. tostring(arrow.angle) .. " and length: " .. tostring(arrow.length))
|
||||
end
|
||||
|
||||
local endPoint = { x = arrow.mapX, y = 0, z = arrow.mapY }
|
||||
local rad = math.rad(arrow.angle or 0)
|
||||
local length = arrow.length or 100
|
||||
local endPoint = { x = arrow.mapX + length * math.cos(rad), y = 0, z = arrow.mapY + length * math.sin(rad) }
|
||||
local startPoint = { x = arrow.mapX - length * math.sin(rad), y = 0, z = arrow.mapY + length * math.cos(rad) }
|
||||
trigger.action.arrowToAll(-1, id, startPoint, endPoint, color, fillColor, lineStyle, true)
|
||||
end
|
||||
|
||||
if logger then
|
||||
logger:debug("Drawing polygon with ID " .. tostring(id) .. " and polygon mode: " .. tostring(object.polygonMode))
|
||||
end
|
||||
|
||||
if object.polygonMode == "circle" then
|
||||
DrawCircle(object--[[@as Circle]])
|
||||
elseif object.polygonMode == "oval" then
|
||||
DrawOval(object--[[@as Oval]])
|
||||
DrawOval(object--[[@as Oval]], logger)
|
||||
elseif object.polygonMode == "free" then
|
||||
DrawFree(object--[[@as Free]])
|
||||
DrawFree(object--[[@as Free]], logger)
|
||||
elseif object.polygonMode == "rect" then
|
||||
DrawRect(object--[[@as Rect]])
|
||||
elseif object.polygonMode == "arrow" then
|
||||
DrawArrow(object--[[@as Arrow]])
|
||||
DrawArrow(object--[[@as Arrow]], logger)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param object Line
|
||||
---@param id integer
|
||||
function DrawingHelper.DrawLine(object, id)
|
||||
---@param logger Logger?
|
||||
function DrawingHelper.DrawLine(object, id, logger)
|
||||
|
||||
---@type Array<Vec3>
|
||||
local points = {}
|
||||
@@ -158,7 +228,7 @@ function DrawingHelper.DrawLine(object, id)
|
||||
|
||||
local color = DrawingHelper.ColorToColorTable(object.colorString)
|
||||
local lineStyle = DrawingHelper.ToLineStyleInteger(object.style)
|
||||
MarkupToAll(1, id, points, color, color, lineStyle)
|
||||
MarkupToAll(1, id, points, color, color, lineStyle, object.thickness, logger)
|
||||
end
|
||||
|
||||
---@private
|
||||
@@ -177,20 +247,41 @@ function DrawingHelper.Remove(id)
|
||||
trigger.action.removeMark(id)
|
||||
end
|
||||
|
||||
|
||||
|
||||
---@param hexStr string
|
||||
---@return table
|
||||
function DrawingHelper.ColorToColorTable(hexStr)
|
||||
|
||||
if hexStr == nil then
|
||||
drawingLogger:warn("ColorToColorTable called with nil hexStr, returning default color {0, 0, 0, 0}")
|
||||
return { 0, 0, 0, 0 }
|
||||
end
|
||||
|
||||
|
||||
hexStr = hexStr:gsub("0x", "")
|
||||
local a = tonumber(hexStr:sub(1, 2), 16) / 255
|
||||
local r = tonumber(hexStr:sub(3, 4), 16) / 255
|
||||
local g = tonumber(hexStr:sub(5, 6), 16) / 255
|
||||
local b = tonumber(hexStr:sub(7, 8), 16) / 255
|
||||
local r = tonumber(hexStr:sub(1, 2), 16) / 255
|
||||
local g = tonumber(hexStr:sub(3, 4), 16) / 255
|
||||
local b = tonumber(hexStr:sub(5, 6), 16) / 255
|
||||
local a = tonumber(hexStr:sub(7, 8), 16) / 255
|
||||
|
||||
return { r, g , b , a }
|
||||
end
|
||||
|
||||
---@param rgba table
|
||||
---@return string
|
||||
function DrawingHelper.ColorTableToColorString(rgba)
|
||||
if rgba == nil or #rgba < 4 or rgba[1] == nil or rgba[2] == nil or rgba[3] == nil or rgba[4] == nil then
|
||||
drawingLogger:warn("ColorTableToColorString called with invalid rgba table, returning default color string '0x00000000'")
|
||||
return "0x00000000"
|
||||
end
|
||||
|
||||
local r = string.format("%02X", math.floor(rgba[1] * 255))
|
||||
local g = string.format("%02X", math.floor(rgba[2] * 255))
|
||||
local b = string.format("%02X", math.floor(rgba[3] * 255))
|
||||
local a = string.format("%02X", math.floor(rgba[4] * 255))
|
||||
|
||||
return "0x" .. r .. g .. b .. a
|
||||
end
|
||||
|
||||
---@param lineStyle string
|
||||
function DrawingHelper.ToLineStyleInteger(lineStyle)
|
||||
lineStyle = lineStyle:lower()
|
||||
@@ -213,6 +304,26 @@ function DrawingHelper.ToLineStyleInteger(lineStyle)
|
||||
end
|
||||
end
|
||||
|
||||
function DrawingHelper.ToLineStyleString(lineStyle)
|
||||
if lineStyle == 0 then
|
||||
return "no line"
|
||||
elseif lineStyle == 1 then
|
||||
return "solid"
|
||||
elseif lineStyle == 2 then
|
||||
return "dashed"
|
||||
elseif lineStyle == 3 then
|
||||
return "dotted"
|
||||
elseif lineStyle == 4 then
|
||||
return "dot dash"
|
||||
elseif lineStyle == 5 then
|
||||
return "long dash"
|
||||
elseif lineStyle == 6 then
|
||||
return "two dash"
|
||||
else
|
||||
return "no line"
|
||||
end
|
||||
end
|
||||
|
||||
---@class ARGB
|
||||
---@field public a number
|
||||
---@field public r number
|
||||
|
||||
@@ -137,10 +137,6 @@ function BattleManager:LetUnitsShoot(groups, targetGroups)
|
||||
}
|
||||
}
|
||||
|
||||
if debugDrawing == true then
|
||||
self:DrawDebugLine(point, unit)
|
||||
end
|
||||
|
||||
local controller = unit:getController()
|
||||
if controller then
|
||||
controller:setTask(shootTask)
|
||||
@@ -245,42 +241,8 @@ function BattleManager:GetRandomPoint(origin, groupHulls)
|
||||
if not hull then return nil end
|
||||
local shootPoints = Util.GetTangentHullPointsFromOrigin(hull, origin)
|
||||
|
||||
if debugDrawing == true then
|
||||
self:DrawDebugZone({ hull })
|
||||
end
|
||||
|
||||
return Util.randomFromList(shootPoints) --[[@as Vec2]]
|
||||
end
|
||||
|
||||
do --DEBUG
|
||||
|
||||
---@param unit Unit
|
||||
---@param target Vec2
|
||||
function BattleManager:DrawDebugLine(target, unit)
|
||||
local color = {r = 1, g = 0, b = 0, a = 1}
|
||||
if unit:getCoalition() == 2 then
|
||||
color = {r = 0, g = 0, b = 1, a = 1}
|
||||
end
|
||||
|
||||
DcsUtil.DrawLine(unit:getPoint(), {x = target.x, y = 0, z = target.y}, color, 1)
|
||||
end
|
||||
|
||||
---@param hulls Array<Array<Vec2>>
|
||||
function BattleManager:DrawDebugZone(hulls)
|
||||
for _, drawHull in pairs(hulls) do
|
||||
|
||||
---@type SpearheadTriggerZone
|
||||
local zone = {
|
||||
name = "temp",
|
||||
zone_type = "Polygon",
|
||||
radius = 0,
|
||||
verts = drawHull,
|
||||
location = { x=drawHull[1].x, y=drawHull[1].y },
|
||||
}
|
||||
|
||||
DcsUtil.DrawZone(zone, {r =0, g=0, b =1, a = 0.5} ,{r =0, g= 0, b =1, a = 0}, 1)
|
||||
end
|
||||
end
|
||||
end --DEBUG
|
||||
|
||||
return BattleManager
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
---@class MaxLoadConfig
|
||||
---@field maxInternalLoad number
|
||||
|
||||
---@type table<string, MaxLoadConfig>
|
||||
local MaxLoadConfig = {
|
||||
["Mi-8MT"] = {
|
||||
maxInternalLoad = 4000,
|
||||
},
|
||||
["CH-47Fbl1"] = {
|
||||
maxInternalLoad = 10000
|
||||
},
|
||||
["Mi-24P"] = {
|
||||
maxInternalLoad = 2000
|
||||
},
|
||||
["UH-1H"] = {
|
||||
maxInternalLoad = 2000
|
||||
}
|
||||
}
|
||||
|
||||
return MaxLoadConfig
|
||||
@@ -4,6 +4,7 @@ local Logger = require("classes.util.Logger")
|
||||
local SpearheadEvents = require("classes.spearhead_events")
|
||||
local SupplyUnitsTracker = require("classes.stageClasses.helpers.SupplyUnitsTracker")
|
||||
local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper")
|
||||
local StageConfig = require("classes.configuration.StageConfig")
|
||||
|
||||
|
||||
---@class MissionCommandsHelper
|
||||
@@ -14,9 +15,9 @@ local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHel
|
||||
---@field updateContinuous fun(self: MissionCommandsHelper, time: number): number @function to update commands continuously
|
||||
---@field pinnedByGroup table<string, Mission> @table of pinned missions by group ID
|
||||
---@field private _stageBriefings table<string, string> @table of stage briefings by stage name
|
||||
---@field private _supplyHubGroups table<string, boolean> @table of supply hub groups by their ID
|
||||
---@field private _logger Logger @logger instance for logging
|
||||
---@field private _supplyUnitsTracker SupplyUnitsTracker @supply units tracker instance
|
||||
---@field private _stageConfig StageConfig
|
||||
local MissionCommandsHelper = {}
|
||||
MissionCommandsHelper.__index = MissionCommandsHelper
|
||||
|
||||
@@ -35,12 +36,11 @@ local id = 0
|
||||
local instance = nil
|
||||
|
||||
---@return MissionCommandsHelper
|
||||
---@param logLevel string @log level for the logger
|
||||
function MissionCommandsHelper.getOrCreate(logLevel)
|
||||
function MissionCommandsHelper.getOrCreate()
|
||||
if instance == nil then
|
||||
instance = setmetatable({}, MissionCommandsHelper)
|
||||
|
||||
instance._logger = Logger.new("MissionCommandsHelper", logLevel)
|
||||
instance._logger = Logger.new("MissionCommandsHelper")
|
||||
|
||||
instance._logger:info("Creating MissionCommandsHelper instance")
|
||||
|
||||
@@ -49,10 +49,29 @@ function MissionCommandsHelper.getOrCreate(logLevel)
|
||||
instance.updateNeeded = false
|
||||
instance.pinnedByGroup = {}
|
||||
instance.lastUpdate = 0
|
||||
instance._supplyHubGroups = {}
|
||||
instance._stageBriefings = {}
|
||||
|
||||
instance._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate(logLevel)
|
||||
instance._stageConfig = StageConfig:getInstance()
|
||||
|
||||
instance._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate()
|
||||
|
||||
instance._supplyUnitsTracker:AddOnSupplyUnitEventListener(
|
||||
{
|
||||
enteredSupplyHub = function(self, unit)
|
||||
if unit == nil then return end
|
||||
instance.updateNeeded = true
|
||||
instance:updateCommandsForGroup(unit:getGroup():getID())
|
||||
end,
|
||||
exitedSupplyHub = function(self, unit)
|
||||
instance.updateNeeded = true
|
||||
instance:updateCommandsForGroup(unit:getGroup():getID())
|
||||
end,
|
||||
supplyUnitSpawned = function(self, unit)
|
||||
instance.updateNeeded = true
|
||||
instance:updateCommandsForGroup(unit:getGroup():getID())
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
---comment
|
||||
---@param selfA MissionCommandsHelper
|
||||
@@ -79,7 +98,6 @@ function MissionCommandsHelper.getOrCreate(logLevel)
|
||||
|
||||
timer.scheduleFunction(instance.updateContinuous, instance, timer.getTime() + 5)
|
||||
SpearheadEvents.AddOnPlayerEnterUnitListener(instance)
|
||||
|
||||
end
|
||||
|
||||
return instance
|
||||
@@ -108,38 +126,16 @@ function MissionCommandsHelper:RemoveMissionToCommands(mission)
|
||||
self.updateNeeded = true
|
||||
end
|
||||
|
||||
---@param groupID number
|
||||
function MissionCommandsHelper:MarkUnitInSupplyHub(groupID)
|
||||
self._logger:debug("Marking unit in supply hub: " .. tostring(groupID))
|
||||
local updateNeeded = false
|
||||
if self._supplyHubGroups[tostring(groupID)] ~= true then
|
||||
updateNeeded = true
|
||||
end
|
||||
|
||||
self._supplyHubGroups[tostring(groupID)] = true
|
||||
if updateNeeded == true then self:updateCommandsForGroup(groupID) end
|
||||
end
|
||||
|
||||
|
||||
---@param groupID number
|
||||
function MissionCommandsHelper:MarkUnitOutsideSupplyHub(groupID)
|
||||
self._logger:debug("Marking unit outide supply hub: " .. tostring(groupID))
|
||||
local updateNeeded = false
|
||||
if self._supplyHubGroups[tostring(groupID)] == true then
|
||||
updateNeeded = true
|
||||
end
|
||||
|
||||
self._supplyHubGroups[tostring(groupID)] = false
|
||||
if updateNeeded == true then self:updateCommandsForGroup(groupID) end
|
||||
end
|
||||
|
||||
|
||||
|
||||
---@param unit Unit
|
||||
function MissionCommandsHelper:OnPlayerEntersUnit(unit)
|
||||
if unit then
|
||||
local group = unit:getGroup()
|
||||
if group then self:updateCommandsForGroup(group:getID()) end
|
||||
if group then
|
||||
self:updateCommandsForGroup(group:getID())
|
||||
if self._stageConfig.briefingOnSpawnEnabled == true then
|
||||
self:OverviewToGroup(group:getID())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -174,14 +170,11 @@ local pinMissionCommand = function(args)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
function MissionCommandsHelper:AddOverviewCommand(groupID)
|
||||
|
||||
local MissionsOverviewToGroup = function (id)
|
||||
|
||||
---@param groupID integer
|
||||
function MissionCommandsHelper:OverviewToGroup(groupID)
|
||||
local text = "Missions Overview\n\n"
|
||||
|
||||
local group = DcsUtil.GetPlayerGroupByGroupID(id)
|
||||
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
|
||||
---@type Vec2
|
||||
local groupPos = { x = 0, y = 0 }
|
||||
if group then
|
||||
@@ -189,11 +182,9 @@ function MissionCommandsHelper:AddOverviewCommand(groupID)
|
||||
groupPos = { x = pos.x, y = pos.z }
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param mission Mission
|
||||
---@return string
|
||||
local function formatLine(mission)
|
||||
|
||||
local distanceText = "?"
|
||||
if group then
|
||||
local lead = group:getUnit(1)
|
||||
@@ -205,16 +196,14 @@ function MissionCommandsHelper:AddOverviewCommand(groupID)
|
||||
end
|
||||
end
|
||||
|
||||
return string.format("[%s]\t%s \t%s \t%s %% \t%s nM\n", mission.code, mission.missionTypeDisplay, mission.name, mission:PercentageComplete(), distanceText)
|
||||
return string.format("[%s]\t%s \t%s \t%s %% \t%s nM\n", mission.code, mission.missionTypeDisplay, mission.name,
|
||||
mission:PercentageComplete(), distanceText)
|
||||
end
|
||||
|
||||
for _, briefing in pairs(self._stageBriefings) do
|
||||
text = text .. briefing .. "\n\n"
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
---Primary missions
|
||||
text = text .. "Primary Missions\n"
|
||||
|
||||
@@ -241,7 +230,6 @@ function MissionCommandsHelper:AddOverviewCommand(groupID)
|
||||
---@type Array<Mission>
|
||||
local secondaryMissions = {}
|
||||
for code, enabled in pairs(self.enabledByCode) do
|
||||
|
||||
if enabled == true then
|
||||
local mission = self.missionsByCode[code]
|
||||
if mission and mission:getState() == "ACTIVE" and mission.priority == "secondary" then
|
||||
@@ -256,29 +244,42 @@ function MissionCommandsHelper:AddOverviewCommand(groupID)
|
||||
end
|
||||
|
||||
|
||||
trigger.action.outTextForGroup(id, text, 20, true)
|
||||
trigger.action.outTextForGroup(groupID, text, 20, true)
|
||||
end
|
||||
|
||||
---@private
|
||||
function MissionCommandsHelper:AddOverviewCommand(groupID)
|
||||
|
||||
---@class OverviewToGroupCommandArgs
|
||||
---@field self MissionCommandsHelper @the MissionCommandsHelper instance
|
||||
---@field groupId integer @the group ID of the player requesting the overview
|
||||
|
||||
---@param args OverviewToGroupCommandArgs
|
||||
local MissionOverViewToGroup = function(args)
|
||||
args.self:OverviewToGroup(args.groupId)
|
||||
end
|
||||
|
||||
---@type OverviewToGroupCommandArgs
|
||||
local overviewToGroupCommandArgs = { self = self, groupId = groupID }
|
||||
|
||||
missionCommands.removeItemForGroup(groupID, { "Overview" })
|
||||
missionCommands.addCommandForGroup(groupID, "Overview", nil, MissionsOverviewToGroup, groupID)
|
||||
missionCommands.addCommandForGroup(groupID, "Overview", nil, MissionOverViewToGroup, overviewToGroupCommandArgs)
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param groupID number
|
||||
function MissionCommandsHelper:AddPinnedMission(groupID)
|
||||
|
||||
local pinndedMission = self.pinnedByGroup[tostring(groupID)]
|
||||
missionCommands.removeItemForGroup(groupID, { "Pinned Mission" })
|
||||
|
||||
if pinndedMission and self.enabledByCode[tostring(pinndedMission.code)] == true then
|
||||
missionCommands.addCommandForGroup(groupID, "Pinned Mission", nil, missionBriefingRequested, { groupId = groupID, mission = pinndedMission })
|
||||
missionCommands.addCommandForGroup(groupID, "Pinned Mission", nil, missionBriefingRequested,
|
||||
{ groupId = groupID, mission = pinndedMission })
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---@param groupID number
|
||||
function MissionCommandsHelper:updateCommandsForGroup(groupID)
|
||||
|
||||
self._logger:debug("Updating commands for group: " .. tostring(groupID))
|
||||
|
||||
self:AddPinnedMission(groupID)
|
||||
@@ -304,7 +305,6 @@ function MissionCommandsHelper:updateCommandsForGroup(groupID)
|
||||
self._logger:debug("Manual refresh of missions for group: " .. tostring(refresh_mission_id))
|
||||
self:updateCommandsForGroup(refresh_mission_id)
|
||||
end, groupID)
|
||||
|
||||
end
|
||||
|
||||
local folderNames = {
|
||||
@@ -327,7 +327,6 @@ function MissionCommandsHelper:PinMission(mission, groupID)
|
||||
end
|
||||
|
||||
function MissionCommandsHelper:AddAllMissionCommandsToGroup(groupID)
|
||||
|
||||
local perFolder = 9
|
||||
|
||||
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
|
||||
@@ -405,9 +404,7 @@ end
|
||||
---@param path Array<string>
|
||||
---@param mission Mission
|
||||
function MissionCommandsHelper:addMissionCommands(groupId, path, mission)
|
||||
|
||||
if path then
|
||||
|
||||
local group = DcsUtil.GetPlayerGroupByGroupID(groupId)
|
||||
local distance = "[?]"
|
||||
if group then
|
||||
@@ -420,13 +417,15 @@ function MissionCommandsHelper:addMissionCommands(groupId, path, mission)
|
||||
end
|
||||
end
|
||||
|
||||
local missionFolderName = "[" .. mission.code .. "]" .. distance .. mission.name .. "( " .. mission.missionTypeDisplay .. " )"
|
||||
local missionFolderName = "[" ..
|
||||
mission.code .. "]" .. distance .. mission.name .. "( " .. mission.missionTypeDisplay .. " )"
|
||||
missionCommands.addSubMenuForGroup(groupId, missionFolderName, path)
|
||||
table.insert(path, missionFolderName)
|
||||
|
||||
---@type MissionBriefingRequestedArgs
|
||||
local missionBriefingRequestedArgs = { groupId = groupId, mission = mission }
|
||||
missionCommands.addCommandForGroup(groupId, "Briefing", path, missionBriefingRequested,missionBriefingRequestedArgs)
|
||||
missionCommands.addCommandForGroup(groupId, "Briefing", path, missionBriefingRequested,
|
||||
missionBriefingRequestedArgs)
|
||||
|
||||
---@type PinMissionCommandArgs
|
||||
local pinMissionCommandArgs = { self = self, groupId = groupId, mission = mission }
|
||||
@@ -437,8 +436,7 @@ end
|
||||
---@private
|
||||
---@param groupID integer
|
||||
function MissionCommandsHelper:AddSupplyHubCommandsIfApplicable(groupID)
|
||||
|
||||
if self._supplyHubGroups[tostring(groupID)] ~= true then return end
|
||||
if self._supplyUnitsTracker:IsGroupLeadInSupplyHub(groupID) ~= true then return end
|
||||
|
||||
self._logger:debug("Adding supply hub commands for group: " .. tostring(groupID))
|
||||
|
||||
@@ -468,28 +466,32 @@ function MissionCommandsHelper:AddSupplyHubCommandsIfApplicable(groupID)
|
||||
local path = { [1] = folderNames.supplyHub }
|
||||
|
||||
---@type LoadCargoCommandParams
|
||||
local farpParams1000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_1000", supplyUnitsTracker = self._supplyUnitsTracker, commandHelper = self }
|
||||
local farpParams1000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_1000", supplyUnitsTracker =
|
||||
self._supplyUnitsTracker, commandHelper = self }
|
||||
missionCommands.addCommandForGroup(groupID, "Load FARP Crate (1000)", path, loadCargoCommand, farpParams1000)
|
||||
|
||||
---@type LoadCargoCommandParams
|
||||
local farpParams2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_2000", supplyUnitsTracker = self._supplyUnitsTracker, commandHelper = self }
|
||||
local farpParams2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "FARP_CRATE_2000", supplyUnitsTracker =
|
||||
self._supplyUnitsTracker, commandHelper = self }
|
||||
missionCommands.addCommandForGroup(groupID, "Load FARP Crate (2000)", path, loadCargoCommand, farpParams2000)
|
||||
|
||||
---@type LoadCargoCommandParams
|
||||
local samParms1000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "SAM_CRATE_2000", supplyUnitsTracker = self._supplyUnitsTracker, commandHelper = self }
|
||||
local samParms1000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "SAM_CRATE_2000", supplyUnitsTracker =
|
||||
self._supplyUnitsTracker, commandHelper = self }
|
||||
missionCommands.addCommandForGroup(groupID, "Load SAM Crate (1000)", path, loadCargoCommand, samParms1000)
|
||||
|
||||
---@type LoadCargoCommandParams
|
||||
local samParms2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "SAM_CRATE_2000", supplyUnitsTracker = self._supplyUnitsTracker, commandHelper = self }
|
||||
local samParms2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "SAM_CRATE_2000", supplyUnitsTracker =
|
||||
self._supplyUnitsTracker, commandHelper = self }
|
||||
missionCommands.addCommandForGroup(groupID, "Load SAM Crate (2000)", path, loadCargoCommand, samParms2000)
|
||||
|
||||
---@type LoadCargoCommandParams
|
||||
local airbaseParms2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "AIRBASE_CRATE_2000", supplyUnitsTracker = self._supplyUnitsTracker, commandHelper = self }
|
||||
local airbaseParms2000 = { unitID = unit:getID(), groupID = group:getID(), crateType = "AIRBASE_CRATE_2000", supplyUnitsTracker =
|
||||
self._supplyUnitsTracker, commandHelper = self }
|
||||
missionCommands.addCommandForGroup(groupID, "Airbase Crate (2000)", path, loadCargoCommand, airbaseParms2000)
|
||||
end
|
||||
|
||||
function MissionCommandsHelper:AddCargoCommands(groupID)
|
||||
|
||||
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
|
||||
if group == nil then return end
|
||||
|
||||
@@ -519,25 +521,23 @@ function MissionCommandsHelper:AddCargoCommands(groupID)
|
||||
for i = 1, amount do
|
||||
local path = { [1] = folderNames.cargo }
|
||||
---@type UnloadCargoCommandParams
|
||||
local params = { unitID = unit:getID(), crateType = cargoType, supplyUnitsTracker = self._supplyUnitsTracker, commandHelper = self }
|
||||
missionCommands.addCommandForGroup(groupID, "Unload " .. cargoConfig.displayName, path, unloadCargoCommand, params)
|
||||
local params = { unitID = unit:getID(), crateType = cargoType, supplyUnitsTracker = self
|
||||
._supplyUnitsTracker, commandHelper = self }
|
||||
missionCommands.addCommandForGroup(groupID, "Unload " .. cargoConfig.displayName, path,
|
||||
unloadCargoCommand, params)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
---@private
|
||||
---@param groupId integer
|
||||
function MissionCommandsHelper:addMissionFolders(groupId)
|
||||
|
||||
missionCommands.addSubMenuForGroup(groupId, folderNames.primary)
|
||||
missionCommands.addSubMenuForGroup(groupId, folderNames.secondary)
|
||||
|
||||
if self._supplyHubGroups[tostring(groupId)] == true then
|
||||
self._logger:debug("Adding supply hub commands folder for group: " .. tostring(groupId))
|
||||
if self._supplyUnitsTracker:IsGroupLeadInSupplyHub(groupId) == true then
|
||||
missionCommands.addSubMenuForGroup(groupId, folderNames.supplyHub)
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
---@class DropZoneSlice
|
||||
---@field centerAngle number Angle in degrees (0=forward, 90=right, 180=rear, 270=left)
|
||||
---@field angleWidth number Total width of the slice in degrees (e.g. 60 = ±30°)
|
||||
---@field minRadius number Minimum search radius in meters (safe distance from helicopter)
|
||||
---@field maxRadius number Maximum search radius in meters
|
||||
---@field spacing number Distance increment when searching outward in meters
|
||||
|
||||
---@class SupplyLoadConfig
|
||||
---@field maxInternalLoad number
|
||||
---@field dropZones Array<DropZoneSlice>
|
||||
|
||||
---@type table<string, SupplyLoadConfig>
|
||||
local SupplyLoadConfig = {
|
||||
["Mi-8MT"] = {
|
||||
maxInternalLoad = 4000,
|
||||
dropZones = {
|
||||
{ centerAngle = 180, angleWidth = 60, minRadius = 20, maxRadius = 50, spacing = 5 },
|
||||
}
|
||||
},
|
||||
["CH-47Fbl1"] = {
|
||||
maxInternalLoad = 10000,
|
||||
dropZones = {
|
||||
{ centerAngle = 180, angleWidth = 30, minRadius = 20, maxRadius = 75, spacing = 5 },
|
||||
}
|
||||
},
|
||||
["Mi-24P"] = {
|
||||
maxInternalLoad = 2000,
|
||||
dropZones = {
|
||||
{ centerAngle = 270, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 },
|
||||
{ centerAngle = 90, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 },
|
||||
}
|
||||
},
|
||||
["UH-1H"] = {
|
||||
maxInternalLoad = 2000,
|
||||
dropZones = {
|
||||
{ centerAngle = 270, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 },
|
||||
{ centerAngle = 90, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SupplyLoadConfig
|
||||
@@ -3,7 +3,7 @@ local Util = require("classes.util.Util")
|
||||
local DcsUtil = require("classes.util.DcsUtil")
|
||||
local SpearheadEvents = require("classes.spearhead_events")
|
||||
local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper")
|
||||
local MaxLoadConfig = require("classes.stageClasses.helpers.MaxLoadConfig")
|
||||
local SupplyLoadConfig = require("classes.stageClasses.helpers.SupplyLoadConfig")
|
||||
|
||||
---@class SupplyUnitEventListener
|
||||
---@field supplyUnitSpawned fun(self:SupplyUnitEventListener, unit:Unit) | nil
|
||||
@@ -26,13 +26,12 @@ SupplyUnitsTracker.__index = SupplyUnitsTracker
|
||||
local singleton = nil
|
||||
|
||||
---comment
|
||||
---@param logLevel LogLevel
|
||||
---@return SupplyUnitsTracker
|
||||
function SupplyUnitsTracker.getOrCreate(logLevel)
|
||||
function SupplyUnitsTracker.getOrCreate()
|
||||
|
||||
if singleton == nil then
|
||||
singleton = setmetatable({}, SupplyUnitsTracker)
|
||||
singleton._logger = Logger.new("SupplyUnitsTracker", logLevel)
|
||||
singleton._logger = Logger.new("SupplyUnitsTracker")
|
||||
singleton._unitPositions = {}
|
||||
singleton._cargoInUnits = {}
|
||||
singleton._supplyUnitsByName = {}
|
||||
@@ -94,7 +93,7 @@ end
|
||||
|
||||
|
||||
---@param listener SupplyUnitEventListener
|
||||
function SupplyUnitsTracker:AddOnSupplyUnitSpawnedListener(listener)
|
||||
function SupplyUnitsTracker:AddOnSupplyUnitEventListener(listener)
|
||||
if listener == nil then return end
|
||||
|
||||
if self._supplyUnitEventsListeners == nil then
|
||||
@@ -104,6 +103,26 @@ function SupplyUnitsTracker:AddOnSupplyUnitSpawnedListener(listener)
|
||||
table.insert(self._supplyUnitEventsListeners, listener)
|
||||
end
|
||||
|
||||
---@param unit Unit
|
||||
---@return boolean
|
||||
function SupplyUnitsTracker:IsUnitInSupplyHub(unit)
|
||||
if unit == nil then return false end
|
||||
local unitIDStr = tostring(unit:getID())
|
||||
return self._unitInSupplyHub[unitIDStr] == true
|
||||
end
|
||||
|
||||
---@param groupID number
|
||||
---@return boolean
|
||||
function SupplyUnitsTracker:IsGroupLeadInSupplyHub(groupID)
|
||||
local group = DcsUtil.GetPlayerGroupByGroupID(groupID)
|
||||
if group == nil then return false end
|
||||
|
||||
local unit = group:getUnit(1)
|
||||
if unit == nil then return false end
|
||||
|
||||
return self:IsUnitInSupplyHub(unit)
|
||||
end
|
||||
|
||||
function SupplyUnitsTracker:Update()
|
||||
local players = DcsUtil.getAllPlayerUnits()
|
||||
for _, player in pairs(players) do
|
||||
@@ -211,7 +230,6 @@ function SupplyUnitsTracker:CheckUnitsInZones()
|
||||
if Util.is3dPointInZone(pos, zone) then
|
||||
if self._unitInSupplyHub[tostring(unit:getID())] ~= true then
|
||||
self._unitInSupplyHub[tostring(unit:getID())] = true
|
||||
|
||||
for _, listener in pairs(self._supplyUnitEventsListeners) do
|
||||
pcall(function()
|
||||
if listener.enteredSupplyHub then
|
||||
@@ -278,14 +296,15 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType, missionCommandsHe
|
||||
self._logger:debug("Unload requested for unit: " .. unitID .. " crateType: " .. crateType)
|
||||
|
||||
local unit = DcsUtil.GetPlayerUnitByID(unitID)
|
||||
if unit == nil or unit:isExist() == false then return end
|
||||
if unit == nil or unit:isExist() == false then
|
||||
self._logger:warn("Unload requested for non-existent unit: " .. unitID)
|
||||
return
|
||||
end
|
||||
local group = unit:getGroup()
|
||||
if group == nil then
|
||||
self._logger:warn("Unload requested for unit with no group: " .. unit:getName())
|
||||
return
|
||||
end
|
||||
|
||||
self:RemoveCargoFromUnit(unitID, crateType)
|
||||
self:UpdateWeightForUnit(unit)
|
||||
|
||||
local cargoConfig = SupplyConfigHelper.getSupplyConfig(crateType)
|
||||
|
||||
@@ -294,7 +313,16 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType, missionCommandsHe
|
||||
return
|
||||
end
|
||||
|
||||
local cargoPos = self:GetCargoPlacePosition(unit)
|
||||
local cargoPos = self:GetCargoPlacePosition(unit, cargoConfig.staticType)
|
||||
|
||||
if cargoPos == nil then
|
||||
self._logger:warn("No valid position found to drop cargo for unit: " .. unit:getName())
|
||||
trigger.action.outTextForUnit(unit:getID(), "No valid position to drop cargo. Unloading area is too crowded.", 10)
|
||||
return
|
||||
end
|
||||
|
||||
self:RemoveCargoFromUnit(unitID, crateType)
|
||||
self:UpdateWeightForUnit(unit)
|
||||
|
||||
cargoCount = cargoCount + 1
|
||||
local cargoSpawnObject = {
|
||||
@@ -304,9 +332,11 @@ function SupplyUnitsTracker:UnloadRequested(unitID, crateType, missionCommandsHe
|
||||
y = cargoPos.z,
|
||||
}
|
||||
|
||||
self._logger:debug("Spawning crate #" .. cargoCount .. " at (" .. string.format("%.2f", cargoPos.x) .. ", " .. string.format("%.2f", cargoPos.y) .. ", " .. string.format("%.2f", cargoPos.z) .. ")")
|
||||
local spawned = coalition.addStaticObject(unit:getCoalition(), cargoSpawnObject)
|
||||
self._droppedCrates[cargoSpawnObject.name] = spawned
|
||||
missionCommandsHelper:updateCommandsForGroup(group:getID())
|
||||
self._logger:debug("Cargo dropped for unit: " .. unit:getName() .. " crateType: " .. crateType)
|
||||
end
|
||||
|
||||
---@return table<string,StaticObject>
|
||||
@@ -394,7 +424,7 @@ function SupplyUnitsTracker:TryLoadCrateInUnit(unit, crateType, commandHelper)
|
||||
end
|
||||
end
|
||||
|
||||
local unitConfig = MaxLoadConfig[unit:getTypeName()]
|
||||
local unitConfig = SupplyLoadConfig[unit:getTypeName()]
|
||||
if unitConfig == nil then
|
||||
trigger.action.outTextForUnit(unit:getID(), "Your unit type is not configured for logistics: " .. crateType, 5)
|
||||
self._logger:error("Invalid unit type: " .. unit:getTypeName())
|
||||
@@ -437,53 +467,234 @@ function SupplyUnitsTracker:UnitRequestCrateSpawn(groupID, crateType)
|
||||
end
|
||||
end
|
||||
|
||||
---@class SupplyUnitsBoundingBox
|
||||
---@field min Vec3 World space minimum
|
||||
---@field max Vec3 World space maximum
|
||||
---@field heading number? Object heading in radians
|
||||
|
||||
---@param foundObject Object
|
||||
---@return SupplyUnitsBoundingBox?
|
||||
function SupplyUnitsTracker:GetBoundingBoxes(foundObject)
|
||||
|
||||
local desc = foundObject:getDesc()
|
||||
if foundObject:getCategory() == Object.Category.SCENERY then
|
||||
desc = SceneryObject.getDescByName(foundObject:getTypeName())
|
||||
end
|
||||
|
||||
if desc == nil or desc.box == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
local objPos = foundObject:getPoint()
|
||||
local box = desc.box
|
||||
local heading = 0
|
||||
|
||||
-- Try to get object heading from position vector's forward direction
|
||||
-- This works for units and other objects that support getPosition
|
||||
pcall(function()
|
||||
local objPosition = foundObject:getPosition()
|
||||
if objPosition and objPosition.x then
|
||||
heading = math.atan2(objPosition.x.z, objPosition.x.x)
|
||||
end
|
||||
end)
|
||||
|
||||
-- For rotated objects, we need to rotate the bounding box
|
||||
local minX = box.min.x
|
||||
local maxX = box.max.x
|
||||
local minZ = box.min.z
|
||||
local maxZ = box.max.z
|
||||
|
||||
-- If object has significant rotation, apply rotation to bbox corners
|
||||
if math.abs(heading) > 0.1 then
|
||||
-- Get all 4 corners of bbox in local space
|
||||
local corners = {
|
||||
{minX, minZ},
|
||||
{minX, maxZ},
|
||||
{maxX, minZ},
|
||||
{maxX, maxZ}
|
||||
}
|
||||
|
||||
-- Rotate corners and find new min/max
|
||||
minX, maxX = math.huge, -math.huge
|
||||
minZ, maxZ = math.huge, -math.huge
|
||||
|
||||
for _, corner in ipairs(corners) do
|
||||
local rotX = corner[1] * math.cos(heading) - corner[2] * math.sin(heading)
|
||||
local rotZ = corner[1] * math.sin(heading) + corner[2] * math.cos(heading)
|
||||
minX = math.min(minX, rotX)
|
||||
maxX = math.max(maxX, rotX)
|
||||
minZ = math.min(minZ, rotZ)
|
||||
maxZ = math.max(maxZ, rotZ)
|
||||
end
|
||||
end
|
||||
|
||||
-- Convert relative bbox to world space by adding object position
|
||||
---@type SupplyUnitsBoundingBox
|
||||
return {
|
||||
min = {
|
||||
x = objPos.x + minX,
|
||||
y = objPos.y + box.min.y,
|
||||
z = objPos.z + minZ
|
||||
},
|
||||
max = {
|
||||
x = objPos.x + maxX,
|
||||
y = objPos.y + box.max.y,
|
||||
z = objPos.z + maxZ
|
||||
},
|
||||
heading = heading
|
||||
}
|
||||
end
|
||||
|
||||
---Check if two axis-aligned bounding boxes collide with safety margin
|
||||
---@param crateBBox SupplyUnitsBoundingBox The crate's bbox in world space
|
||||
---@param objBBox SupplyUnitsBoundingBox The existing object's bbox in world space
|
||||
---@param safetyMargin number Safety margin around objects
|
||||
---@return boolean True if collision detected
|
||||
function SupplyUnitsTracker:CheckBBoxCollision(crateBBox, objBBox, safetyMargin)
|
||||
|
||||
-- Apply safety margin to object bbox
|
||||
local objMin = {
|
||||
x = objBBox.min.x - safetyMargin,
|
||||
y = objBBox.min.y - safetyMargin,
|
||||
z = objBBox.min.z - safetyMargin
|
||||
}
|
||||
local objMax = {
|
||||
x = objBBox.max.x + safetyMargin,
|
||||
y = objBBox.max.y + safetyMargin,
|
||||
z = objBBox.max.z + safetyMargin
|
||||
}
|
||||
|
||||
-- AABB collision detection
|
||||
return crateBBox.min.x <= objMax.x and crateBBox.max.x >= objMin.x and
|
||||
crateBBox.min.y <= objMax.y and crateBBox.max.y >= objMin.y and
|
||||
crateBBox.min.z <= objMax.z and crateBBox.max.z >= objMin.z
|
||||
end
|
||||
|
||||
---@private
|
||||
---@param unit Unit
|
||||
---@return Vec3
|
||||
function SupplyUnitsTracker:GetCargoPlacePosition(unit)
|
||||
---@param crateTypeName string
|
||||
---@return Vec3?
|
||||
function SupplyUnitsTracker:GetCargoPlacePosition(unit, crateTypeName)
|
||||
|
||||
local pos = unit:getPosition()
|
||||
local preferredPos = {
|
||||
x = pos.p.x - 10 * pos.x.x,
|
||||
y = pos.p.y - 10 * pos.x.y,
|
||||
z = pos.p.z - 10 * pos.x.z
|
||||
local unitPos = unit:getPosition()
|
||||
|
||||
-- Get unit's heading from the forward vector (x component)
|
||||
-- Heading is calculated as: atan2(forward.z, forward.x)
|
||||
local unitHeading = math.atan2(unitPos.x.z, unitPos.x.x)
|
||||
|
||||
-- Get crate bbox - relative to placement position
|
||||
local crateDesc = StaticObject.getDescByName(crateTypeName) --[[@as table]]
|
||||
if crateDesc == nil or crateDesc.box == nil then
|
||||
self._logger:error("Could not get bbox for crate type: " .. crateTypeName)
|
||||
return nil
|
||||
end
|
||||
|
||||
local crateRelativeBBox = crateDesc.box
|
||||
|
||||
-- Get drop zone config for this unit
|
||||
local dropZones = {
|
||||
{ centerAngle = 180, angleWidth = 60, minRadius = 15, maxRadius = 50, spacing = 5 }
|
||||
}
|
||||
|
||||
return preferredPos
|
||||
if SupplyLoadConfig[unit:getTypeName()] ~= nil then
|
||||
dropZones = SupplyLoadConfig[unit:getTypeName()].dropZones
|
||||
end
|
||||
|
||||
-- Get occupied objects with their bboxes
|
||||
local searchVolume = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = {
|
||||
x = unitPos.p.x,
|
||||
y = unitPos.p.y,
|
||||
z = unitPos.p.z
|
||||
},
|
||||
radius = 100 -- Search a large area
|
||||
}
|
||||
}
|
||||
|
||||
-- local volume = {
|
||||
-- id = world.VolumeType.SPHERE,
|
||||
-- params = {
|
||||
-- point = preferredPos,
|
||||
-- radius = 10
|
||||
-- }
|
||||
-- }
|
||||
local occupiedObjects = {}
|
||||
local found = function(foundItem, val)
|
||||
local bbox = self:GetBoundingBoxes(foundItem)
|
||||
if bbox then
|
||||
self._logger:debug("Found object: " .. foundItem:getTypeName() .. " at (" .. foundItem:getPoint().x .. ", " .. foundItem:getPoint().z .. ")")
|
||||
table.insert(occupiedObjects, {
|
||||
pos = foundItem:getPoint(),
|
||||
bbox = bbox
|
||||
})
|
||||
else
|
||||
self._logger:debug("Found object without bbox: " .. foundItem:getTypeName())
|
||||
end
|
||||
end
|
||||
|
||||
-- local occupiedPosX = {}
|
||||
-- local occupiedPosZ = {}
|
||||
local searchCategories = {}
|
||||
for key, value in pairs(Object.Category) do
|
||||
self._logger:debug("Adding category to search: " .. tostring(value) .. " (" .. tostring(key) .. ")")
|
||||
table.insert(searchCategories, value)
|
||||
end
|
||||
|
||||
-- ---@param foundItem Object
|
||||
-- local found = function(foundItem, val)
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
world.searchObjects(searchCategories, searchVolume, found)
|
||||
|
||||
-- local foundPos = foundItem:getPoint()
|
||||
local safetyMargin = 3 -- Safety margin around objects
|
||||
|
||||
-- local z = math.floor(foundPos.z)
|
||||
-- for i = z - 3 , z + 3 do
|
||||
-- occupiedPosZ[i] = true
|
||||
-- end
|
||||
-- Search through each slice
|
||||
for _, zone in ipairs(dropZones) do
|
||||
-- Calculate angle range for this slice
|
||||
local minAngle = zone.centerAngle - (zone.angleWidth / 2)
|
||||
local maxAngle = zone.centerAngle + (zone.angleWidth / 2)
|
||||
|
||||
-- local x = math.floor(foundPos.x)
|
||||
-- for i = x - 3 , x + 3 do
|
||||
-- occupiedPosX[i] = true
|
||||
-- end
|
||||
-- end
|
||||
-- Search outward in rings starting from minRadius
|
||||
for distance = zone.minRadius, zone.maxRadius, zone.spacing do
|
||||
-- Check multiple positions within the angular slice
|
||||
local angleStep = math.min(15, zone.angleWidth / 3) -- Divide slice into sections
|
||||
|
||||
-- world.searchObjects(volume.id, volume.params, found)
|
||||
for angle = minAngle, maxAngle, angleStep do
|
||||
local radians = math.rad(angle)
|
||||
|
||||
-- Calculate position at this angle and distance, relative to unit's heading
|
||||
-- Angle 0 = forward, 90 = right, 180 = rear, 270 = left
|
||||
-- Apply unit heading to make angles relative to unit orientation
|
||||
local worldAngle = radians + unitHeading
|
||||
|
||||
local candidateX = unitPos.p.x + distance * math.sin(worldAngle)
|
||||
local candidateZ = unitPos.p.z + distance * math.cos(worldAngle)
|
||||
local candidateY = land.getHeight({ x = candidateX, y = candidateZ })
|
||||
|
||||
-- Convert crate's relative bbox to world space at this position
|
||||
local crateBBoxWorldSpace = {
|
||||
min = {
|
||||
x = candidateX + crateRelativeBBox.min.x,
|
||||
y = candidateY + crateRelativeBBox.min.y,
|
||||
z = candidateZ + crateRelativeBBox.min.z
|
||||
},
|
||||
max = {
|
||||
x = candidateX + crateRelativeBBox.max.x,
|
||||
y = candidateY + crateRelativeBBox.max.y,
|
||||
z = candidateZ + crateRelativeBBox.max.z
|
||||
}
|
||||
}
|
||||
|
||||
-- Check if crate bbox collides with any existing objects
|
||||
local collides = false
|
||||
for _, obj in ipairs(occupiedObjects) do
|
||||
if self:CheckBBoxCollision(crateBBoxWorldSpace, obj.bbox, safetyMargin) then
|
||||
collides = true
|
||||
self._logger:debug("Collision at angle=" .. angle .. ", distance=" .. distance)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not collides then
|
||||
self._logger:debug("Valid position found at angle=" .. angle .. ", distance=" .. distance .. ", pos=(" .. string.format("%.2f", candidateX) .. ", " .. string.format("%.2f", candidateY) .. ", " .. string.format("%.2f", candidateZ) .. ")")
|
||||
return { x = candidateX, y = candidateY, z = candidateZ }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- No free spot found
|
||||
return nil
|
||||
end
|
||||
|
||||
return SupplyUnitsTracker
|
||||
@@ -5,6 +5,8 @@ local SupplyUnitsTracker = require("classes.stageClasses.helpers.SupplyUnitsTrac
|
||||
local MissionCommandsHelper = require("classes.stageClasses.helpers.MissionCommandsHelper")
|
||||
local GlobalConfig = require("classes.configuration.GlobalConfig")
|
||||
local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHelper")
|
||||
local CustomDrawing = require("classes.stageClasses.drawings.CustomDrawing")
|
||||
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
|
||||
|
||||
---@class BuildableMission : Mission, SupplyUnitEventListener
|
||||
---@field private _requiredKilos number
|
||||
@@ -17,8 +19,8 @@ local SupplyConfigHelper = require("classes.stageClasses.helpers.SupplyConfigHel
|
||||
---@field private _supplyUnitsTracker SupplyUnitsTracker
|
||||
---@field private _noLandingZone SpearheadTriggerZone?
|
||||
---@field private _dropOffZone SpearheadTriggerZone?
|
||||
---@field private _noLandingZoneId number
|
||||
---@field private _dropOffZoneId number
|
||||
---@field private _noLandingZoneDrawing CustomDrawing?
|
||||
---@field private _dropOffZoneDrawing CustomDrawing?
|
||||
local BuildableMission = {}
|
||||
BuildableMission.__index = BuildableMission
|
||||
|
||||
@@ -76,7 +78,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
|
||||
self._onCrateDroppedOfListeners = {}
|
||||
self._completeListeners = {}
|
||||
self._markIDsPerGroup = {}
|
||||
self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate(logger.LogLevel)
|
||||
self._supplyUnitsTracker = SupplyUnitsTracker.getOrCreate()
|
||||
self._state = "NEW"
|
||||
|
||||
|
||||
@@ -87,7 +89,7 @@ function BuildableMission.new(database, logger, targetZone, noLandingZone, requi
|
||||
|
||||
self.priority = "secondary"
|
||||
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(self._logger.LogLevel)
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate()
|
||||
|
||||
self._crateType = requiredCrateType
|
||||
|
||||
@@ -164,20 +166,20 @@ function BuildableMission:SpawnActive()
|
||||
return
|
||||
end
|
||||
|
||||
---@type DrawColor
|
||||
local lineColor = { r=230/255, g=93/255, b=49/255, a=1}
|
||||
---@type DrawColor
|
||||
local fillColor = { r=230/255, g=93/255, b=49/255, a=0.2}
|
||||
self._noLandingZoneId = DcsUtil.DrawZone(self._noLandingZone, lineColor, fillColor, 6)
|
||||
local lineColor = DrawingHelper.ColorTableToColorString({ 230/255, 93/255, 49/255, 1})
|
||||
local fillColor = DrawingHelper.ColorTableToColorString({ 230/255, 93/255, 49/255, 0.2})
|
||||
self._noLandingZoneDrawing = CustomDrawing.FromZone(self._noLandingZone, lineColor, fillColor, 2, 6)
|
||||
self._noLandingZoneDrawing:Draw()
|
||||
|
||||
if self._dropOffZone == nil then
|
||||
self._logger:error("No drop off zone found for mission: " .. self.code)
|
||||
return
|
||||
end
|
||||
|
||||
local lineColor2 = { r=0, g=0, b=1, a=1}
|
||||
local fillColor2 = { r=0, g=0, b=1, a=0}
|
||||
self._dropOffZoneId = DcsUtil.DrawZone(self._dropOffZone, lineColor2, fillColor2, 6)
|
||||
local lineColor2 = DrawingHelper.ColorTableToColorString({ 0, 0, 1, 1})
|
||||
local fillColor2 = DrawingHelper.ColorTableToColorString({ 0, 0, 1, 0})
|
||||
self._dropOffZoneDrawing = CustomDrawing.FromZone(self._dropOffZone, lineColor2, fillColor2, 2, 6)
|
||||
self._dropOffZoneDrawing:Draw()
|
||||
|
||||
---@param selfA BuildableMission
|
||||
---@param time number
|
||||
@@ -197,7 +199,7 @@ function BuildableMission:SpawnActive()
|
||||
self._state = "ACTIVE"
|
||||
|
||||
self._missionCommandsHelper:AddMissionToCommands(self)
|
||||
self._supplyUnitsTracker:AddOnSupplyUnitSpawnedListener(self)
|
||||
self._supplyUnitsTracker:AddOnSupplyUnitEventListener(self)
|
||||
|
||||
local units = self._supplyUnitsTracker:GetUnits()
|
||||
if units then
|
||||
@@ -254,8 +256,8 @@ function BuildableMission:CheckCratesInZone()
|
||||
end
|
||||
|
||||
if self._droppedKilos >= self._requiredKilos then
|
||||
DcsUtil.RemoveMark(self._noLandingZoneId)
|
||||
DcsUtil.RemoveMark(self._dropOffZoneId)
|
||||
self._dropOffZoneDrawing:Remove()
|
||||
self._noLandingZoneDrawing:Remove()
|
||||
self:NotifyMissionComplete()
|
||||
self._state = "COMPLETED"
|
||||
end
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
local Mission = require("classes.stageClasses.missions.baseMissions.Mission")
|
||||
local Util = require("classes.util.Util")
|
||||
local DcsUtil = require("classes.util.DcsUtil")
|
||||
local DrawingHelper = require("classes.stageClasses.drawings.helper.DrawingHelper")
|
||||
|
||||
---@class RunwayStrikeMission : Mission
|
||||
---@field runwayBombingTracker RunwayBombingTracker
|
||||
@@ -154,9 +155,22 @@ function RunwayStrikeMission:Draw()
|
||||
if runwaySection.drawID == nil then
|
||||
local zone = self:SectionToSpearheadZone(runwaySection)
|
||||
|
||||
local color = { r=0, g=1, b=0, a=0.5 }
|
||||
---@type Free
|
||||
local drawObject = {
|
||||
primitiveType = "Polygon",
|
||||
polygonMode = "free",
|
||||
mapX = 0,
|
||||
mapY = 0,
|
||||
points = zone.verts,
|
||||
name = zone.name,
|
||||
fillColorString = DrawingHelper.ColorTableToColorString(fillColor),
|
||||
colorString = DrawingHelper.ColorTableToColorString(lineColor),
|
||||
style = "solid",
|
||||
thickness = 1,
|
||||
visible = true,
|
||||
}
|
||||
|
||||
runwaySection.drawID = DcsUtil.DrawZone(zone, color, color, 5)
|
||||
runwaySection.drawID = DrawingHelper.Draw(drawObject)
|
||||
else
|
||||
DcsUtil.SetFillColor(runwaySection.drawID, fillColor)
|
||||
DcsUtil.SetLineColor(runwaySection.drawID, lineColor)
|
||||
|
||||
@@ -350,7 +350,7 @@ function ZoneMission:SpawnPersistedState()
|
||||
end
|
||||
end
|
||||
|
||||
---spawns the mission, but doesn't add
|
||||
---spawns the mission, but doesn't add it to the mission commands.
|
||||
function ZoneMission:SpawnInactive()
|
||||
self._logger:info("PreActivating " .. self.name)
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ function Mission.newSuper(self, zoneName, missionName, missionType, missionBrief
|
||||
self.location = database:GetLocationForMissionZone(zoneName)
|
||||
self.missionTypeDisplay = self.missionType
|
||||
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate(logger.LogLevel)
|
||||
self._missionCommandsHelper = MissionCommandsHelper.getOrCreate()
|
||||
|
||||
return true, "success"
|
||||
end
|
||||
|
||||
@@ -173,10 +173,6 @@ do -- INIT DCS_UTIL
|
||||
verts = enlargedPoints
|
||||
}
|
||||
|
||||
if SpearheadConfig and SpearheadConfig.debugEnabled == true then
|
||||
DCS_UTIL.DrawZone(triggerZone, { r = 0, g = 1, b = 0, a = 1 }, { a = 0, r = 0, g = 1, b = 0 }, 1)
|
||||
end
|
||||
|
||||
DCS_UTIL.__airbaseZonesByName[name] = triggerZone
|
||||
end
|
||||
end
|
||||
@@ -636,71 +632,6 @@ do -- INIT DCS_UTIL
|
||||
---@field b number
|
||||
---@field a number
|
||||
|
||||
local drawID = 400
|
||||
---@param zone SpearheadTriggerZone
|
||||
---@param lineColor DrawColor
|
||||
---@param fillColor DrawColor
|
||||
---@param lineStyle LineType
|
||||
---@return number drawID
|
||||
function DCS_UTIL.DrawZone(zone, lineColor, fillColor, lineStyle)
|
||||
if lineStyle == nil then lineStyle = 4 end
|
||||
drawID = drawID + 1
|
||||
if zone.zone_type == "Cilinder" then
|
||||
trigger.action.circleToAll(-1, drawID, { x = zone.location.x, y = 0, z = zone.location.y }, zone.radius,
|
||||
{ 0, 0, 0, 0 }, { 0, 0, 0, 0 }, lineStyle, true)
|
||||
else
|
||||
local functionString = "trigger.action.markupToAll(7, -1, " .. drawID .. ","
|
||||
for _, vecpoint in pairs(zone.verts) do
|
||||
functionString = functionString .. " { x=" .. vecpoint.x .. ", y=0,z=" .. vecpoint.y .. "},"
|
||||
end
|
||||
functionString = functionString .. "{0,1,0,1}, {0,1,0,1}, " .. lineStyle .. ")"
|
||||
|
||||
---@diagnostic disable-next-line: deprecated
|
||||
local f, err = loadstring(functionString)
|
||||
if f then
|
||||
f()
|
||||
else
|
||||
env.error("Something failed when drawing complex drawing" .. err)
|
||||
end
|
||||
end
|
||||
local fillColorMapped = {
|
||||
fillColor.r or 0,
|
||||
fillColor.g or 0,
|
||||
fillColor.b or 0,
|
||||
fillColor.a or 0.5
|
||||
}
|
||||
|
||||
local lineColorMapped = {
|
||||
lineColor.r or 0,
|
||||
lineColor.g or 0,
|
||||
lineColor.b or 0,
|
||||
lineColor.a or 1
|
||||
}
|
||||
|
||||
trigger.action.setMarkupColorFill(drawID, fillColorMapped)
|
||||
trigger.action.setMarkupColor(drawID, lineColorMapped)
|
||||
|
||||
return drawID
|
||||
end
|
||||
|
||||
---@param start Vec3
|
||||
---@param finish Vec3
|
||||
---@param lineColor DrawColor
|
||||
---@param lineStyle LineType
|
||||
function DCS_UTIL.DrawLine(start, finish, lineColor, lineStyle)
|
||||
if lineStyle == nil then lineStyle = 4 end
|
||||
drawID = drawID + 1
|
||||
|
||||
local lineColorMapped = {
|
||||
lineColor.r or 0,
|
||||
lineColor.g or 0,
|
||||
lineColor.b or 0,
|
||||
lineColor.a or 1
|
||||
}
|
||||
|
||||
trigger.action.lineToAll(-1, drawID, start, finish, lineColorMapped, lineStyle)
|
||||
return drawID
|
||||
end
|
||||
|
||||
---@param groupID number
|
||||
---@param text string
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
|
||||
local Util = require("classes.util.Util")
|
||||
local SpearheadConfig = require("classes.configuration.GlobalConfig")
|
||||
|
||||
|
||||
---@type LogLevel
|
||||
local defaultLogLevel = "INFO"
|
||||
|
||||
if SpearheadConfig then
|
||||
if SpearheadConfig:isDebugEnabled() then
|
||||
defaultLogLevel = "DEBUG"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--- @class Logger
|
||||
--- @field LoggerName string the name of the logger
|
||||
@@ -10,13 +22,13 @@ do
|
||||
|
||||
---comment
|
||||
---@param logger_name any
|
||||
---@param logLevel LogLevel
|
||||
---@param logLevel LogLevel? override the default log level
|
||||
---@return Logger
|
||||
function LOGGER.new(logger_name, logLevel)
|
||||
LOGGER.__index = LOGGER
|
||||
local self = setmetatable({}, LOGGER)
|
||||
self.LoggerName = logger_name or "(loggername not set)"
|
||||
self.LogLevel = logLevel or "INFO"
|
||||
self.LogLevel = logLevel or defaultLogLevel
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -297,6 +297,49 @@ do -- INIT UTIL
|
||||
return false
|
||||
end
|
||||
|
||||
---@param points Array<Vec3>
|
||||
---@return Array<Vec3>
|
||||
function UTIL.getConvexHull3d(points)
|
||||
if #points == 0 then
|
||||
return {}
|
||||
end
|
||||
|
||||
---comment
|
||||
---@param a Vec3
|
||||
---@param b Vec3
|
||||
---@param c Vec3
|
||||
---@return boolean
|
||||
local function ccw(a, b, c)
|
||||
return (b.z - a.z) * (c.x - a.x) > (b.x - a.x) * (c.z - a.z)
|
||||
end
|
||||
|
||||
table.sort(points, function(left, right)
|
||||
return left.z < right.z
|
||||
end)
|
||||
|
||||
local hull = {}
|
||||
-- lower hull
|
||||
for _, point in pairs(points) do
|
||||
while #hull >= 2 and not ccw(hull[#hull - 1], hull[#hull], point) do
|
||||
table.remove(hull, #hull)
|
||||
end
|
||||
table.insert(hull, point)
|
||||
end
|
||||
|
||||
-- upper hull
|
||||
local t = #hull + 1
|
||||
for i = #points, 1, -1 do
|
||||
local point = points[i]
|
||||
while #hull >= t and not ccw(hull[#hull - 1], hull[#hull], point) do
|
||||
table.remove(hull, #hull)
|
||||
end
|
||||
table.insert(hull, point)
|
||||
end
|
||||
table.remove(hull, #hull)
|
||||
return hull
|
||||
end
|
||||
|
||||
|
||||
---comment
|
||||
---@param points Array<Vec2> points
|
||||
---@return Array<Vec2> hullPoints
|
||||
|
||||
+2
-24
@@ -28,10 +28,10 @@ SpearheadEvents.Init(defaultLogLevel)
|
||||
local dbLogger = Logger.new("database", defaultLogLevel)
|
||||
local standardLogger = Logger.new("", defaultLogLevel)
|
||||
local databaseManager = Database.New(dbLogger)
|
||||
MissionCommandsHelper.getOrCreate(defaultLogLevel) -- initiate
|
||||
MissionCommandsHelper.getOrCreate() -- initiate
|
||||
|
||||
local capConfig = CapConfig:new();
|
||||
local stageConfig = StageConfig:new();
|
||||
local stageConfig = StageConfig:getInstance();
|
||||
|
||||
local startingStage = stageConfig.startingStage or 1
|
||||
if SpearheadConfig and SpearheadConfig.Persistence and SpearheadConfig.Persistence.enabled == true then
|
||||
@@ -72,25 +72,3 @@ local missionEditorWarningsLogger = Logger.new("MissionEditorWarnings", defaultL
|
||||
MissionEditorWarnings.WriteAll(missionEditorWarningsLogger)
|
||||
GlobalStageManager:printFullOverview()
|
||||
|
||||
--Check lines of code in directory per file:
|
||||
-- Get-ChildItem . -Include *.lua -Recurse | foreach {""+(Get-Content $_).Count + " => " + $_.name }; GCI . -Include *.lua* -Recurse | foreach{(GC $_).Count} | measure-object -sum | % Sum
|
||||
-- find . -name '*.lua' | xargs wc -l
|
||||
|
||||
--- ==================== DEBUG ORDER OR ZONE VEC ===========================
|
||||
-- local zone = Spearhead.DcsUtil.getZoneByName("MISSIONSTAGE_99")
|
||||
|
||||
-- local count = Spearhead.Util.tableLength(zone.verts)
|
||||
|
||||
-- for i = 1, count - 1 do
|
||||
|
||||
-- local a = zone.verts[i]
|
||||
-- local b = zone.verts[i+1]
|
||||
|
||||
-- local color = {0,0,0,1}
|
||||
|
||||
-- color[i] = 1
|
||||
|
||||
-- trigger.action.textToAll(-1, 46+i , { x= a.x, y = 0, z = a.z } , color, {0,0,0}, 24 , true , "" .. i )
|
||||
-- trigger.action.lineToAll(-1 , 56+i , { x= a.x, y = 0, z = a.z } , { x = b.x, y = 0, z = b.z } , color , 1, true)
|
||||
|
||||
-- end
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.12.1
|
||||
0.13.0
|
||||
Reference in New Issue
Block a user