mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.1.0
Persistence
This commit is contained in:
parent
780797aba3
commit
f741c511a5
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
rndFlags = {}
|
rndFlags = {}
|
||||||
rndFlags.version = "1.3.1"
|
rndFlags.version = "1.3.2"
|
||||||
rndFlags.verbose = false
|
rndFlags.verbose = false
|
||||||
rndFlags.requiredLibs = {
|
rndFlags.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
@ -29,8 +29,10 @@ rndFlags.requiredLibs = {
|
|||||||
- added zonal verbosity
|
- added zonal verbosity
|
||||||
- added 'rndDone!' flag
|
- added 'rndDone!' flag
|
||||||
- rndMethod defaults to "inc"
|
- rndMethod defaults to "inc"
|
||||||
|
1.3.2 - moved flagArrayFromString to dcsCommon
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
rndFlags.rndGen = {}
|
rndFlags.rndGen = {}
|
||||||
|
|
||||||
function rndFlags.addRNDZone(aZone)
|
function rndFlags.addRNDZone(aZone)
|
||||||
@ -38,6 +40,8 @@ function rndFlags.addRNDZone(aZone)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function rndFlags.flagArrayFromString(inString)
|
function rndFlags.flagArrayFromString(inString)
|
||||||
|
return dcsCommon.flagArrayFromString(inString, rndFlags.verbose)
|
||||||
|
--[[--
|
||||||
if string.len(inString) < 1 then
|
if string.len(inString) < 1 then
|
||||||
trigger.action.outText("+++RND: empty flags", 30)
|
trigger.action.outText("+++RND: empty flags", 30)
|
||||||
return {}
|
return {}
|
||||||
@ -88,6 +92,7 @@ function rndFlags.flagArrayFromString(inString)
|
|||||||
trigger.action.outText("+++RND: <" .. #flags .. "> flags total", 30)
|
trigger.action.outText("+++RND: <" .. #flags .. "> flags total", 30)
|
||||||
end
|
end
|
||||||
return flags
|
return flags
|
||||||
|
--]]--
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxCargoReceiver = {}
|
cfxCargoReceiver = {}
|
||||||
cfxCargoReceiver.version = "1.2.1"
|
cfxCargoReceiver.version = "1.2.2"
|
||||||
cfxCargoReceiver.ups = 1 -- once a second
|
cfxCargoReceiver.ups = 1 -- once a second
|
||||||
cfxCargoReceiver.maxDirectionRange = 500 -- in m. distance when cargo manager starts talking to pilots who are carrying that cargo
|
cfxCargoReceiver.maxDirectionRange = 500 -- in m. distance when cargo manager starts talking to pilots who are carrying that cargo
|
||||||
cfxCargoReceiver.requiredLibs = {
|
cfxCargoReceiver.requiredLibs = {
|
||||||
@ -17,6 +17,9 @@ cfxCargoReceiver.requiredLibs = {
|
|||||||
- 1.2.0 method
|
- 1.2.0 method
|
||||||
f!, cargoReceived!
|
f!, cargoReceived!
|
||||||
- 1.2.1 cargoMethod
|
- 1.2.1 cargoMethod
|
||||||
|
- 1.2.2 removed deprecated functions
|
||||||
|
corrected pollFlag bug (not passing zone along)
|
||||||
|
distance to receiver is given as distance to zone boundary
|
||||||
|
|
||||||
|
|
||||||
CargoReceiver is a zone enhancement you use to be automatically
|
CargoReceiver is a zone enhancement you use to be automatically
|
||||||
@ -39,13 +42,15 @@ function cfxCargoReceiver.processReceiverZone(aZone) -- process attribute and ad
|
|||||||
-- isCargoReceiver flag and we are good
|
-- isCargoReceiver flag and we are good
|
||||||
aZone.isCargoReceiver = true
|
aZone.isCargoReceiver = true
|
||||||
-- we can add additional processing here
|
-- we can add additional processing here
|
||||||
aZone.autoRemove = cfxZones.getBoolFromZoneProperty(aZone, "autoRemove", false) -- maybe add a removedelay
|
aZone.autoRemove = cfxZones.getBoolFromZoneProperty(aZone, "autoRemove", false) -- maybe add a removeDelay
|
||||||
|
aZone.removeDelay = cfxZones.getNumberFromZoneProperty(aZone, "removeDelay", 1)
|
||||||
|
if aZone.removeDelay < 1 then aZone.removeDelay = 1 end
|
||||||
aZone.silent = cfxZones.getBoolFromZoneProperty(aZone, "silent", false)
|
aZone.silent = cfxZones.getBoolFromZoneProperty(aZone, "silent", false)
|
||||||
|
|
||||||
--trigger.action.outText("+++rcv: recognized receiver zone: " .. aZone.name , 30)
|
--trigger.action.outText("+++rcv: recognized receiver zone: " .. aZone.name , 30)
|
||||||
|
|
||||||
-- same integration as object destruct detector for flags
|
-- same integration as object destruct detector for flags
|
||||||
|
--[[--
|
||||||
if cfxZones.hasProperty(aZone, "setFlag") then
|
if cfxZones.hasProperty(aZone, "setFlag") then
|
||||||
aZone.setFlag = cfxZones.getStringFromZoneProperty(aZone, "setFlag", "999")
|
aZone.setFlag = cfxZones.getStringFromZoneProperty(aZone, "setFlag", "999")
|
||||||
end
|
end
|
||||||
@ -70,7 +75,7 @@ function cfxCargoReceiver.processReceiverZone(aZone) -- process attribute and ad
|
|||||||
if cfxZones.hasProperty(aZone, "f-1") then
|
if cfxZones.hasProperty(aZone, "f-1") then
|
||||||
aZone.decreaseFlag = cfxZones.getStringFromZoneProperty(aZone, "f-1", "999")
|
aZone.decreaseFlag = cfxZones.getStringFromZoneProperty(aZone, "f-1", "999")
|
||||||
end
|
end
|
||||||
|
--]]--
|
||||||
-- new method support
|
-- new method support
|
||||||
aZone.cargoMethod = cfxZones.getStringFromZoneProperty(aZone, "method", "inc")
|
aZone.cargoMethod = cfxZones.getStringFromZoneProperty(aZone, "method", "inc")
|
||||||
if cfxZones.hasProperty(aZone, "cargoMethod") then
|
if cfxZones.hasProperty(aZone, "cargoMethod") then
|
||||||
@ -79,9 +84,7 @@ function cfxCargoReceiver.processReceiverZone(aZone) -- process attribute and ad
|
|||||||
|
|
||||||
if cfxZones.hasProperty(aZone, "f!") then
|
if cfxZones.hasProperty(aZone, "f!") then
|
||||||
aZone.outReceiveFlag = cfxZones.getStringFromZoneProperty(aZone, "f!", "*<none>")
|
aZone.outReceiveFlag = cfxZones.getStringFromZoneProperty(aZone, "f!", "*<none>")
|
||||||
end
|
elseif cfxZones.hasProperty(aZone, "cargoReceived!") then
|
||||||
|
|
||||||
if cfxZones.hasProperty(aZone, "cargoReceived!") then
|
|
||||||
aZone.outReceiveFlag = cfxZones.getStringFromZoneProperty(aZone, "cargoReceived!", "*<none>")
|
aZone.outReceiveFlag = cfxZones.getStringFromZoneProperty(aZone, "cargoReceived!", "*<none>")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -112,7 +115,25 @@ end
|
|||||||
--
|
--
|
||||||
-- cargo event happened. Called by Cargo Manager
|
-- cargo event happened. Called by Cargo Manager
|
||||||
--
|
--
|
||||||
|
function cfxCargoReceiver.removeCargo(args)
|
||||||
|
-- asynch call
|
||||||
|
if not args then return end
|
||||||
|
local theObject = args.theObject
|
||||||
|
local theZone = args.theZone
|
||||||
|
if not theObject then return end
|
||||||
|
if not theObject:isExist() then
|
||||||
|
-- maybe blew up? anyway, we are done
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if args.theZone.verbose or cfxCargoReceiver.verbose then
|
||||||
|
trigger.action.outText("+++crgR: removed object <" .. theObject.getName() .. "> from cargo zone <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
theObject:destroy()
|
||||||
|
end
|
||||||
|
|
||||||
function cfxCargoReceiver.cargoEvent(event, object, name)
|
function cfxCargoReceiver.cargoEvent(event, object, name)
|
||||||
|
-- usually called from cargomanager
|
||||||
--trigger.action.outText("Cargo Receiver: event <" .. event .. "> for " .. name, 30)
|
--trigger.action.outText("Cargo Receiver: event <" .. event .. "> for " .. name, 30)
|
||||||
if not event then return end
|
if not event then return end
|
||||||
if event == "grounded" then
|
if event == "grounded" then
|
||||||
@ -135,6 +156,7 @@ function cfxCargoReceiver.cargoEvent(event, object, name)
|
|||||||
cfxCargoReceiver.invokeCallback("deliver", object, name, aZone)
|
cfxCargoReceiver.invokeCallback("deliver", object, name, aZone)
|
||||||
|
|
||||||
-- set flags as indicated
|
-- set flags as indicated
|
||||||
|
--[[--
|
||||||
if aZone.setFlag then
|
if aZone.setFlag then
|
||||||
trigger.action.setUserFlag(aZone.setFlag, 1)
|
trigger.action.setUserFlag(aZone.setFlag, 1)
|
||||||
end
|
end
|
||||||
@ -149,16 +171,20 @@ function cfxCargoReceiver.cargoEvent(event, object, name)
|
|||||||
local val = trigger.misc.getUserFlag(aZone.decreaseFlag) - 1
|
local val = trigger.misc.getUserFlag(aZone.decreaseFlag) - 1
|
||||||
trigger.action.setUserFlag(aZone.decreaseFlag, val)
|
trigger.action.setUserFlag(aZone.decreaseFlag, val)
|
||||||
end
|
end
|
||||||
|
--]]--
|
||||||
if aZone.outReceiveFlag then
|
if aZone.outReceiveFlag then
|
||||||
cfxZones.pollFlag(aZone.outReceiveFlag, aZone.cargoMethod)
|
cfxZones.pollFlag(aZone.outReceiveFlag, aZone.cargoMethod, aZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
--trigger.action.outText("+++rcv: " .. name .. " delivered in zone " .. aZone.name, 30)
|
--trigger.action.outText("+++rcv: " .. name .. " delivered in zone " .. aZone.name, 30)
|
||||||
--trigger.action.outSound("Quest Snare 3.wav")
|
--trigger.action.outSound("Quest Snare 3.wav")
|
||||||
if aZone.autoRemove then
|
if aZone.autoRemove then
|
||||||
-- maybe schedule this in a few seconds?
|
-- schedule this for in a few seconds?
|
||||||
object:destroy()
|
local args = {}
|
||||||
|
args.theObject = object
|
||||||
|
args.theZone = aZone
|
||||||
|
timer.scheduleFunction(cfxCargoReceiver.removeCargo, args, timer.getTime() + aZone.removeDelay)
|
||||||
|
--object:destroy()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -177,11 +203,16 @@ function cfxCargoReceiver.update()
|
|||||||
-- new we see if any of these are close to a delivery zone
|
-- new we see if any of these are close to a delivery zone
|
||||||
for idx, aCargo in pairs(liftedCargos) do
|
for idx, aCargo in pairs(liftedCargos) do
|
||||||
local thePoint = aCargo:getPoint()
|
local thePoint = aCargo:getPoint()
|
||||||
local receiver, delta = cfxZones.getClosestZone(
|
local receiver = cfxZones.getClosestZone(
|
||||||
thePoint,
|
thePoint,
|
||||||
cfxCargoReceiver.receiverZones -- must be indexed by name
|
cfxCargoReceiver.receiverZones -- must be indexed by name
|
||||||
)
|
)
|
||||||
-- we now check if we are in 'speaking range' and receiver can talk
|
-- we now check if we are in 'speaking range' and receiver can talk
|
||||||
|
-- modify delta by distance to boundary, not
|
||||||
|
-- center
|
||||||
|
local delta = dcsCommon.distFlat(thePoint, cfxZones.getPoint(receiver))
|
||||||
|
delta = delta - receiver.radius
|
||||||
|
|
||||||
if (receiver.silent == false) and
|
if (receiver.silent == false) and
|
||||||
(delta < cfxCargoReceiver.maxDirectionRange) then
|
(delta < cfxCargoReceiver.maxDirectionRange) then
|
||||||
-- this cargo can be talked down.
|
-- this cargo can be talked down.
|
||||||
@ -195,7 +226,7 @@ function cfxCargoReceiver.update()
|
|||||||
local theUnit = info.unit
|
local theUnit = info.unit
|
||||||
if theUnit:isExist() then
|
if theUnit:isExist() then
|
||||||
local uPoint = theUnit:getPoint()
|
local uPoint = theUnit:getPoint()
|
||||||
local currDelta = dcsCommon.dist(thePoint, uPoint)
|
local currDelta = dcsCommon.distFlat(thePoint, uPoint)
|
||||||
if currDelta < minDelta then
|
if currDelta < minDelta then
|
||||||
minDelta = currDelta
|
minDelta = currDelta
|
||||||
closestUnit = theUnit
|
closestUnit = theUnit
|
||||||
@ -217,7 +248,7 @@ function cfxCargoReceiver.update()
|
|||||||
receiver.point,
|
receiver.point,
|
||||||
thePoint,
|
thePoint,
|
||||||
ownHeading) .. " o'clock"
|
ownHeading) .. " o'clock"
|
||||||
message = receiver.name .. " is " .. math.floor(delta) .. "m at your " .. oclock
|
message = receiver.name .. " (r=" .. receiver.radius .. "m) is " .. math.floor(delta) .. "m at your " .. oclock
|
||||||
end
|
end
|
||||||
-- add agl
|
-- add agl
|
||||||
local agl = dcsCommon.getUnitAGL(aCargo)
|
local agl = dcsCommon.getUnitAGL(aCargo)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
cfxMX = {}
|
cfxMX = {}
|
||||||
cfxMX.version = "1.1.0"
|
cfxMX.version = "1.2.0"
|
||||||
|
cfxMX.verbose = false
|
||||||
--[[--
|
--[[--
|
||||||
Mission data decoder. Access to ME-built mission structures
|
Mission data decoder. Access to ME-built mission structures
|
||||||
|
|
||||||
@ -12,6 +13,10 @@ cfxMX.version = "1.1.0"
|
|||||||
- on start up collects a cross reference table of all
|
- on start up collects a cross reference table of all
|
||||||
original group id
|
original group id
|
||||||
- add linkUnit for statics
|
- add linkUnit for statics
|
||||||
|
1.2.0 - added group name reference table
|
||||||
|
- added group type reference
|
||||||
|
- added references for allFixed, allHelo, allGround, allSea, allStatic
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
@ -19,6 +24,11 @@ cfxMX.groupNamesByID = {}
|
|||||||
cfxMX.groupIDbyName = {}
|
cfxMX.groupIDbyName = {}
|
||||||
cfxMX.groupDataByName = {}
|
cfxMX.groupDataByName = {}
|
||||||
|
|
||||||
|
cfxMX.allFixedByName = {}
|
||||||
|
cfxMX.allHeloByName = {}
|
||||||
|
cfxMX.allGroundByName = {}
|
||||||
|
cfxMX.allSeaByName = {}
|
||||||
|
cfxMX.allStaticByName ={}
|
||||||
|
|
||||||
function cfxMX.getGroupFromDCSbyName(aName, fetchOriginal)
|
function cfxMX.getGroupFromDCSbyName(aName, fetchOriginal)
|
||||||
if not fetchOriginal then fetchOriginal = false end
|
if not fetchOriginal then fetchOriginal = false end
|
||||||
@ -154,7 +164,7 @@ function cfxMX.getStaticFromDCSbyName(aName, fetchOriginal)
|
|||||||
return nil, "<none>", "<none>", "<no group name>"
|
return nil, "<none>", "<none>", "<no group name>"
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxMX.createCrossReference()
|
function cfxMX.createCrossReferences()
|
||||||
for coa_name_miz, coa_data in pairs(env.mission.coalition) do -- iterate all coalitions
|
for coa_name_miz, coa_data in pairs(env.mission.coalition) do -- iterate all coalitions
|
||||||
local coa_name = coa_name_miz
|
local coa_name = coa_name_miz
|
||||||
if string.lower(coa_name_miz) == 'neutrals' then -- remove 's' at neutralS
|
if string.lower(coa_name_miz) == 'neutrals' then -- remove 's' at neutralS
|
||||||
@ -178,7 +188,7 @@ function cfxMX.createCrossReference()
|
|||||||
obj_type_name == "ship" or
|
obj_type_name == "ship" or
|
||||||
obj_type_name == "plane" or
|
obj_type_name == "plane" or
|
||||||
obj_type_name == "vehicle" or
|
obj_type_name == "vehicle" or
|
||||||
obj_type_name == "static"
|
obj_type_name == "static" -- what about "cargo"?
|
||||||
then -- (so it's not id or name)
|
then -- (so it's not id or name)
|
||||||
local category = obj_type_name
|
local category = obj_type_name
|
||||||
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's at least one group!
|
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's at least one group!
|
||||||
@ -188,6 +198,21 @@ function cfxMX.createCrossReference()
|
|||||||
cfxMX.groupNamesByID[aID] = aName
|
cfxMX.groupNamesByID[aID] = aName
|
||||||
cfxMX.groupIDbyName[aName] = aID
|
cfxMX.groupIDbyName[aName] = aID
|
||||||
cfxMX.groupDataByName[aName] = group_data
|
cfxMX.groupDataByName[aName] = group_data
|
||||||
|
-- now make the type-specific xrefs
|
||||||
|
if obj_type_name == "helicopter" then
|
||||||
|
cfxMX.allHeloByName[aName] = group_data
|
||||||
|
elseif obj_type_name == "ship" then
|
||||||
|
cfxMX.allSeaByName[aName] = group_data
|
||||||
|
elseif obj_type_name == "plane" then
|
||||||
|
cfxMX.allFixedByName[aName] = group_data
|
||||||
|
elseif obj_type_name == "vehicle" then
|
||||||
|
cfxMX.allGroundByName[aName] = group_data
|
||||||
|
elseif obj_type_name == "static" then
|
||||||
|
cfxMX.allStaticByName[aName] = group_data
|
||||||
|
else
|
||||||
|
-- should be impossible, but still
|
||||||
|
trigger.action.outText("+++MX: <" .. obj_type_name .. "> unknown type for <" .. aName .. ">", 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end --if has category data
|
end --if has category data
|
||||||
end --if plane, helo etc... category
|
end --if plane, helo etc... category
|
||||||
@ -212,8 +237,10 @@ function cfxMX.catText2ID(inText)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function cfxMX.start()
|
function cfxMX.start()
|
||||||
cfxMX.createCrossReference()
|
cfxMX.createCrossReferences()
|
||||||
trigger.action.outText("cfxMX: "..#cfxMX.groupNamesByID .. " groups processed successfully", 30)
|
if cfxMX.verbose then
|
||||||
|
trigger.action.outText("cfxMX: "..#cfxMX.groupNamesByID .. " groups processed successfully", 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start
|
-- start
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxObjectSpawnZones = {}
|
cfxObjectSpawnZones = {}
|
||||||
cfxObjectSpawnZones.version = "1.2.1"
|
cfxObjectSpawnZones.version = "1.3.0"
|
||||||
cfxObjectSpawnZones.requiredLibs = {
|
cfxObjectSpawnZones.requiredLibs = {
|
||||||
"dcsCommon", -- common is of course needed for everything
|
"dcsCommon", -- common is of course needed for everything
|
||||||
-- pretty stupid to check for this since we
|
-- pretty stupid to check for this since we
|
||||||
@ -26,7 +26,10 @@ cfxObjectSpawnZones.verbose = false
|
|||||||
-- 1.1.5 - spawn?, spawnObjects? synonyms
|
-- 1.1.5 - spawn?, spawnObjects? synonyms
|
||||||
-- 1.2.0 - DML flag upgrade
|
-- 1.2.0 - DML flag upgrade
|
||||||
-- 1.2.1 - config zone
|
-- 1.2.1 - config zone
|
||||||
-- - autoLink bug (zone instead of spaneer accessed)
|
-- - autoLink bug (zone instead of spawner accessed)
|
||||||
|
-- 1.3.0 - better synonym handling
|
||||||
|
-- - useDelicates link to delicate when spawned
|
||||||
|
-- - spawned single and multi-objects can be made delicates
|
||||||
|
|
||||||
-- respawn currently happens after theSpawns is deleted and cooldown seconds have passed
|
-- respawn currently happens after theSpawns is deleted and cooldown seconds have passed
|
||||||
cfxObjectSpawnZones.allSpawners = {}
|
cfxObjectSpawnZones.allSpawners = {}
|
||||||
@ -58,13 +61,9 @@ function cfxObjectSpawnZones.createSpawner(inZone)
|
|||||||
-- connect with ME if a trigger flag is given
|
-- connect with ME if a trigger flag is given
|
||||||
if cfxZones.hasProperty(inZone, "f?") then
|
if cfxZones.hasProperty(inZone, "f?") then
|
||||||
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "f?", "none")
|
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "f?", "none")
|
||||||
end
|
elseif cfxZones.hasProperty(inZone, "spawn?") then
|
||||||
|
|
||||||
if cfxZones.hasProperty(inZone, "spawn?") then
|
|
||||||
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawn?", "none")
|
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawn?", "none")
|
||||||
end
|
elseif cfxZones.hasProperty(inZone, "spawnObjects?") then
|
||||||
|
|
||||||
if cfxZones.hasProperty(inZone, "spawnObjects?") then
|
|
||||||
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawnObjects?", "none")
|
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawnObjects?", "none")
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -116,6 +115,11 @@ function cfxObjectSpawnZones.createSpawner(inZone)
|
|||||||
theSpawner.requestable = cfxZones.getBoolFromZoneProperty(inZone, "requestable", false)
|
theSpawner.requestable = cfxZones.getBoolFromZoneProperty(inZone, "requestable", false)
|
||||||
if theSpawner.requestable then theSpawner.paused = true end
|
if theSpawner.requestable then theSpawner.paused = true end
|
||||||
|
|
||||||
|
-- see if the spawn can be made brittle/delicte
|
||||||
|
if cfxZones.hasProperty(inZone, "useDelicates") then
|
||||||
|
theSpawner.delicateName = cfxZones.getStringFromZoneProperty(inZone, "useDelicates", "<none>")
|
||||||
|
end
|
||||||
|
|
||||||
-- see if it is linked to a ship to set realtive orig headiong
|
-- see if it is linked to a ship to set realtive orig headiong
|
||||||
|
|
||||||
if inZone.linkedUnit then
|
if inZone.linkedUnit then
|
||||||
@ -258,6 +262,16 @@ function cfxObjectSpawnZones.spawnObjectNTimes(aSpawner, theType, n, container)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if aSpawner.delicateName and delicates then
|
||||||
|
-- pass this object to the delicate zone mentioned
|
||||||
|
local theDeli = delicates.getDelicatesByName(aSpawner.delicateName)
|
||||||
|
if theDeli then
|
||||||
|
delicates.addStaticObjectToInventoryForZone(theDeli, theObject)
|
||||||
|
else
|
||||||
|
trigger.action.outText("+++oSpwn: spawner <" .. aZone.name .. "> can't find delicates <" .. aSpawner.delicateName .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -302,6 +316,17 @@ function cfxObjectSpawnZones.spawnObjectNTimes(aSpawner, theType, n, container)
|
|||||||
cfxCargoManager.addCargo(theObject)
|
cfxCargoManager.addCargo(theObject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if aSpawner.delicateName and delicates then
|
||||||
|
-- pass this object to the delicate zone mentioned
|
||||||
|
local theDeli = delicates.getDelicatesByName(aSpawner.delicateName)
|
||||||
|
if theDeli then
|
||||||
|
delicates.addStaticObjectToInventoryForZone(theDeli, theObject)
|
||||||
|
else
|
||||||
|
trigger.action.outText("+++oSpwn: spawner <" .. aZone.name .. "> can't find delicates <" .. aSpawner.delicateName .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- update rotation
|
-- update rotation
|
||||||
currDegree = currDegree + degreeIncrement
|
currDegree = currDegree + degreeIncrement
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxZones = {}
|
cfxZones = {}
|
||||||
cfxZones.version = "2.8.3"
|
cfxZones.version = "2.8.4"
|
||||||
|
|
||||||
-- cf/x zone management module
|
-- cf/x zone management module
|
||||||
-- reads dcs zones and makes them accessible and mutable
|
-- reads dcs zones and makes them accessible and mutable
|
||||||
@ -88,6 +88,7 @@ cfxZones.version = "2.8.3"
|
|||||||
- 2.8.3 - new verifyMethod()
|
- 2.8.3 - new verifyMethod()
|
||||||
- changed extractPropertyFromDCS() to also match attributes with blanks like "the Attr" to "theAttr"
|
- changed extractPropertyFromDCS() to also match attributes with blanks like "the Attr" to "theAttr"
|
||||||
- new expandFlagName()
|
- new expandFlagName()
|
||||||
|
- 2.8.4 - fixed bug in setFlagValue()
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
cfxZones.verbose = false
|
cfxZones.verbose = false
|
||||||
@ -867,11 +868,12 @@ end
|
|||||||
-- get closest zone returns the zone that is closest to point
|
-- get closest zone returns the zone that is closest to point
|
||||||
function cfxZones.getClosestZone(point, theZones)
|
function cfxZones.getClosestZone(point, theZones)
|
||||||
if not theZones then theZones = cfxZones.zones end
|
if not theZones then theZones = cfxZones.zones end
|
||||||
|
local lPoint = {x=point.x, y=0, z=point.z}
|
||||||
local currDelta = math.huge
|
local currDelta = math.huge
|
||||||
local closestZone = nil
|
local closestZone = nil
|
||||||
for zName, zData in pairs(theZones) do
|
for zName, zData in pairs(theZones) do
|
||||||
local zPoint = cfxZones.getPoint(zData)
|
local zPoint = cfxZones.getPoint(zData)
|
||||||
local delta = dcsCommon.dist(point, zPoint)
|
local delta = dcsCommon.dist(lPoint, zPoint) -- emulate flag compare
|
||||||
if (delta < currDelta) then
|
if (delta < currDelta) then
|
||||||
currDelta = delta
|
currDelta = delta
|
||||||
closestZone = zData
|
closestZone = zData
|
||||||
@ -1276,7 +1278,7 @@ end
|
|||||||
function cfxZones.setFlagValue(theFlag, theValue, theZone)
|
function cfxZones.setFlagValue(theFlag, theValue, theZone)
|
||||||
local zoneName = "<dummy>"
|
local zoneName = "<dummy>"
|
||||||
if not theZone then
|
if not theZone then
|
||||||
trigger.action.outText("+++Zne: no zone on setFlagValue")
|
trigger.action.outText("+++Zne: no zone on setFlagValue", 30) -- mod me for detector
|
||||||
else
|
else
|
||||||
zoneName = theZone.name -- for flag wildcards
|
zoneName = theZone.name -- for flag wildcards
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
dcsCommon = {}
|
dcsCommon = {}
|
||||||
dcsCommon.version = "2.6.6"
|
dcsCommon.version = "2.6.8"
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
2.2.6 - compassPositionOfARelativeToB
|
2.2.6 - compassPositionOfARelativeToB
|
||||||
- clockPositionOfARelativeToB
|
- clockPositionOfARelativeToB
|
||||||
@ -82,7 +82,9 @@ dcsCommon.version = "2.6.6"
|
|||||||
- new stringRemainsStartingWith()
|
- new stringRemainsStartingWith()
|
||||||
- new stripLF()
|
- new stripLF()
|
||||||
- new removeBlanks()
|
- new removeBlanks()
|
||||||
|
2.6.7 - new menu2text()
|
||||||
|
2.6.8 - new getMissionName()
|
||||||
|
- new flagArrayFromString()
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
-- dcsCommon is a library of common lua functions
|
-- dcsCommon is a library of common lua functions
|
||||||
@ -1882,6 +1884,21 @@ dcsCommon.version = "2.6.6"
|
|||||||
return catNum
|
return catNum
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function dcsCommon.menu2text(inMenu)
|
||||||
|
if not inMenu then return "<nil>" end
|
||||||
|
local s = ""
|
||||||
|
for n, v in pairs(inMenu) do
|
||||||
|
if type(v) == "string" then
|
||||||
|
if s == "" then s = "[" .. v .. "]" else
|
||||||
|
s = s .. " | [" .. type(v) .. "]" end
|
||||||
|
else
|
||||||
|
if s == "" then s = "[<" .. type(v) .. ">]" else
|
||||||
|
s = s .. " | [<" .. type(v) .. ">]" end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
-- recursively show the contents of a variable
|
-- recursively show the contents of a variable
|
||||||
function dcsCommon.dumpVar(key, value, prefix, inrecursion)
|
function dcsCommon.dumpVar(key, value, prefix, inrecursion)
|
||||||
if not inrecursion then
|
if not inrecursion then
|
||||||
@ -2361,6 +2378,68 @@ function dcsCommon.latLon2Text(lat, lon)
|
|||||||
return lat, lon
|
return lat, lon
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- get mission name. If mission file name without ".miz"
|
||||||
|
function dcsCommon.getMissionName()
|
||||||
|
local mn = net.dostring_in("gui", "return DCS.getMissionName()")
|
||||||
|
return mn
|
||||||
|
end
|
||||||
|
|
||||||
|
function dcsCommon.flagArrayFromString(inString, verbose)
|
||||||
|
if not verbose then verbose = false end
|
||||||
|
|
||||||
|
if verbose then
|
||||||
|
trigger.action.outText("+++flagArray: processing <" .. inString .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
if string.len(inString) < 1 then
|
||||||
|
trigger.action.outText("+++flagArray: empty flags", 30)
|
||||||
|
return {}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local flags = {}
|
||||||
|
local rawElements = dcsCommon.splitString(inString, ",")
|
||||||
|
-- go over all elements
|
||||||
|
for idx, anElement in pairs(rawElements) do
|
||||||
|
if dcsCommon.stringStartsWithDigit(anElement) and dcsCommon.containsString(anElement, "-") then
|
||||||
|
-- interpret this as a range
|
||||||
|
local theRange = dcsCommon.splitString(anElement, "-")
|
||||||
|
local lowerBound = theRange[1]
|
||||||
|
lowerBound = tonumber(lowerBound)
|
||||||
|
local upperBound = theRange[2]
|
||||||
|
upperBound = tonumber(upperBound)
|
||||||
|
if lowerBound and upperBound then
|
||||||
|
-- swap if wrong order
|
||||||
|
if lowerBound > upperBound then
|
||||||
|
local temp = upperBound
|
||||||
|
upperBound = lowerBound
|
||||||
|
lowerBound = temp
|
||||||
|
end
|
||||||
|
-- now add add numbers to flags
|
||||||
|
for f=lowerBound, upperBound do
|
||||||
|
table.insert(flags, f)
|
||||||
|
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- bounds illegal
|
||||||
|
trigger.action.outText("+++flagArray: ignored range <" .. anElement .. "> (range)", 30)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- single number
|
||||||
|
f = dcsCommon.trim(anElement) -- DML flag upgrade: accept strings tonumber(anElement)
|
||||||
|
if f then
|
||||||
|
table.insert(flags, f)
|
||||||
|
|
||||||
|
else
|
||||||
|
trigger.action.outText("+++flagArray: ignored element <" .. anElement .. "> (single)", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if verbose then
|
||||||
|
trigger.action.outText("+++flagArray: <" .. #flags .. "> flags total", 30)
|
||||||
|
end
|
||||||
|
return flags
|
||||||
|
end
|
||||||
--
|
--
|
||||||
--
|
--
|
||||||
-- INIT
|
-- INIT
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
delicates = {}
|
delicates = {}
|
||||||
delicates.version = "1.0.0"
|
delicates.version = "1.1.0"
|
||||||
delicates.verbose = false
|
delicates.verbose = false
|
||||||
delicates.ups = 1
|
delicates.ups = 1
|
||||||
delicates.requiredLibs = {
|
delicates.requiredLibs = {
|
||||||
@ -12,6 +12,11 @@ delicates.inventory = {}
|
|||||||
--[[--
|
--[[--
|
||||||
Version History
|
Version History
|
||||||
1.0.0 - initial version
|
1.0.0 - initial version
|
||||||
|
1.1.0 - better synonym handling for f! and out!
|
||||||
|
- addStaticObjectInventoryForZone
|
||||||
|
- blowAll?
|
||||||
|
- safetyMargin - safety margin. defaults to 10%
|
||||||
|
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
function delicates.adddDelicates(theZone)
|
function delicates.adddDelicates(theZone)
|
||||||
@ -68,7 +73,7 @@ function delicates.makeZoneInventory(theZone)
|
|||||||
for idy, anObject in pairs(collector) do
|
for idy, anObject in pairs(collector) do
|
||||||
local oName = anObject:getName()
|
local oName = anObject:getName()
|
||||||
if type(oName) == 'number' then oName = tostring(oName) end
|
if type(oName) == 'number' then oName = tostring(oName) end
|
||||||
local oLife = anObject:getLife()
|
local oLife = anObject:getLife() - anObject:getLife() * theZone.safetyMargin
|
||||||
if theZone.verbose or delicates.verbose then
|
if theZone.verbose or delicates.verbose then
|
||||||
trigger.action.outText("+++deli: cat=".. aCat .. ":<" .. oName .. "> Life=" .. oLife, 30)
|
trigger.action.outText("+++deli: cat=".. aCat .. ":<" .. oName .. "> Life=" .. oLife, 30)
|
||||||
end
|
end
|
||||||
@ -91,25 +96,47 @@ function delicates.makeZoneInventory(theZone)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function delicates.addStaticObjectToInventoryForZone(theZone, theStatic)
|
||||||
|
if not theZone then return end
|
||||||
|
if not theStatic then return end
|
||||||
|
|
||||||
|
local desc = {}
|
||||||
|
desc.cat = theStatic:getCategory()
|
||||||
|
desc.oLife = theStatic:getLife() - theStatic:getLife() * theZone.safetyMargin
|
||||||
|
if desc.oLife < 0 then desc.oLife = 0 end
|
||||||
|
desc.theZone = theZone
|
||||||
|
desc.oName = theStatic:getName()
|
||||||
|
delicates.inventory[desc.oName] = desc
|
||||||
|
|
||||||
|
if theZone.verbose or delicates.verbose then
|
||||||
|
trigger.action.outText("+++deli: added static <" .. desc.oName .. "> to <" .. theZone.name .. "> with minimal life = <" .. desc.oLife .. "/" .. theStatic:getLife() .. "> = safety margin of " .. theZone.safetyMargin * 100 .. "%", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function delicates.createDelicatesWithZone(theZone)
|
function delicates.createDelicatesWithZone(theZone)
|
||||||
theZone.power = cfxZones.getNumberFromZoneProperty(theZone, "power", 10)
|
theZone.power = cfxZones.getNumberFromZoneProperty(theZone, "power", 10)
|
||||||
|
|
||||||
if cfxZones.hasProperty(theZone, "delicatesHit!") then
|
if cfxZones.hasProperty(theZone, "delicatesHit!") then
|
||||||
theZone.delicateHit = cfxZones.getStringFromZoneProperty(theZone, "delicatesHit!", "*<none>")
|
theZone.delicateHit = cfxZones.getStringFromZoneProperty(theZone, "delicatesHit!", "*<none>")
|
||||||
end
|
elseif cfxZones.hasProperty(theZone, "f!") then
|
||||||
if cfxZones.hasProperty(theZone, "f!") then
|
|
||||||
theZone.delicateHit = cfxZones.getStringFromZoneProperty(theZone, "f!", "*<none>")
|
theZone.delicateHit = cfxZones.getStringFromZoneProperty(theZone, "f!", "*<none>")
|
||||||
end
|
elseif cfxZones.hasProperty(theZone, "out!") then
|
||||||
if cfxZones.hasProperty(theZone, "out!") then
|
|
||||||
theZone.delicateHit = cfxZones.getStringFromZoneProperty(theZone, "out!", "*<none>")
|
theZone.delicateHit = cfxZones.getStringFromZoneProperty(theZone, "out!", "*<none>")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- safety margin
|
||||||
|
theZone.safetyMargin = cfxZones.getNumberFromZoneProperty(theZone, "safetyMargin", 0)
|
||||||
|
|
||||||
-- DML Method
|
-- DML Method
|
||||||
theZone.delicateHitMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
|
theZone.delicateHitMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
|
||||||
if cfxZones.hasProperty(theZone, "delicateMethod") then
|
if cfxZones.hasProperty(theZone, "delicateMethod") then
|
||||||
theZone.delicateHitMethod = cfxZones.getStringFromZoneProperty(theZone, "delicatesMethod", "inc")
|
theZone.delicateHitMethod = cfxZones.getStringFromZoneProperty(theZone, "delicatesMethod", "inc")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
theZone.delicateTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "thriggerMethod", "change")
|
||||||
|
if cfxZones.hasProperty(theZone, "delicateTriggerMethod") then
|
||||||
|
theZone.delicateTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "delicatesMethod", "change")
|
||||||
|
end
|
||||||
|
|
||||||
theZone.delicateRemove = cfxZones.getBoolFromZoneProperty(theZone, "remove", true)
|
theZone.delicateRemove = cfxZones.getBoolFromZoneProperty(theZone, "remove", true)
|
||||||
|
|
||||||
@ -117,6 +144,11 @@ function delicates.createDelicatesWithZone(theZone)
|
|||||||
-- may want to filter by objects, can be passed in delicates
|
-- may want to filter by objects, can be passed in delicates
|
||||||
delicates.makeZoneInventory(theZone)
|
delicates.makeZoneInventory(theZone)
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "blowAll?") then
|
||||||
|
theZone.blowAll = cfxZones.getStringFromZoneProperty(theZone, "blowAll?", "*<none>")
|
||||||
|
theZone.lastBlowAll = cfxZones.getFlagValue(theZone.blowAll, theZone)
|
||||||
|
end
|
||||||
|
|
||||||
if delicates.verbose or theZone.verbose then
|
if delicates.verbose or theZone.verbose then
|
||||||
trigger.action.outText("+++deli: new delicates zone <".. theZone.name ..">", 30)
|
trigger.action.outText("+++deli: new delicates zone <".. theZone.name ..">", 30)
|
||||||
end
|
end
|
||||||
@ -185,14 +217,42 @@ function delicates:onEvent(theEvent)
|
|||||||
local oName = theObj:getName()
|
local oName = theObj:getName()
|
||||||
local desc = delicates.inventory[oName]
|
local desc = delicates.inventory[oName]
|
||||||
if desc then
|
if desc then
|
||||||
-- trigger.action.outText("+++deli: REGISTERED HIT -- removing!", 30)
|
-- see if damage exceeds maximum
|
||||||
delicates.blowUpObject(desc)
|
local cLife = theObj:getLife()
|
||||||
-- remove it from further searches
|
if cLife < desc.oLife then
|
||||||
delicates.inventory[oName] = nil
|
if desc.theZone.verbose or delicates.verbose then
|
||||||
|
trigger.action.outText("+++deli: BRITTLE TRIGGER: life <" .. cLife .. "> below safety margin <" .. oDesc.oLife .. ">", 30)
|
||||||
|
end
|
||||||
|
delicates.blowUpObject(desc)
|
||||||
|
-- remove it from further searches
|
||||||
|
delicates.inventory[oName] = nil
|
||||||
|
else
|
||||||
|
if desc.theZone.verbose or delicates.verbose then
|
||||||
|
trigger.action.outText("+++deli: CLOSE CALL, but life <" .. cLife .. "> within safety margin <" .. oDesc.oLife .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- trigger.action.outText("+++deli: we hit " .. oName, 30)
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- blow entire zone
|
||||||
|
--
|
||||||
|
function delicates.blowZone(theZone)
|
||||||
|
if not theZone then return end
|
||||||
|
local zName = theZone.name
|
||||||
|
local newInventory = {}
|
||||||
|
local delay = 0.7
|
||||||
|
for oName, oDesc in pairs (delicates.inventory) do
|
||||||
|
if oDesc.theZone.name == zName then
|
||||||
|
delicates.blowUpObject(oDesc, delay)
|
||||||
|
delay = delay + 0.2 -- stagger explosions
|
||||||
|
else
|
||||||
|
newInventory[oName] = oDesc
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
delicates.inventory = newInventory
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -228,12 +288,12 @@ function delicates.update()
|
|||||||
if theObj then
|
if theObj then
|
||||||
local cLife = theObj:getLife()
|
local cLife = theObj:getLife()
|
||||||
if cLife >= oDesc.oLife then
|
if cLife >= oDesc.oLife then
|
||||||
-- transfer to next iter
|
-- all well, transfer to next iter
|
||||||
newInventory[oName] = oDesc
|
newInventory[oName] = oDesc
|
||||||
else
|
else
|
||||||
-- blow stuff up
|
-- health beneath min. blow stuff up
|
||||||
if oDesc.theZone.verbose or delicates.verbose then
|
if oDesc.theZone.verbose or delicates.verbose then
|
||||||
trigger.action.outText(oName .. " was hit, will blow up, new health is at " .. oDesc.oLife .. ".", 30)
|
trigger.action.outText(oName .. " was hit, will blow up, current health is <" .. cLife .. ">, min health was " .. oDesc.oLife .. ".", 30)
|
||||||
end
|
end
|
||||||
delicates.blowUpObject(oDesc)
|
delicates.blowUpObject(oDesc)
|
||||||
end
|
end
|
||||||
@ -245,6 +305,13 @@ function delicates.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
delicates.inventory = newInventory
|
delicates.inventory = newInventory
|
||||||
|
|
||||||
|
-- now scan all zones for signals
|
||||||
|
for idx, theZone in pairs(delicates.theDelicates) do
|
||||||
|
if theZone.blowAll and cfxZones.testZoneFlag(theZone, theZone.blowAll, theZone.delicateTriggerMethod, "lastBlowAll") then
|
||||||
|
delicates.blowZone(theZone)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|||||||
@ -566,5 +566,5 @@ end
|
|||||||
To do
|
To do
|
||||||
- reset? flag: will reset all to MX locationS
|
- reset? flag: will reset all to MX locationS
|
||||||
- add a zone's follow ability to impostors by allowing linkedUnit to work with impostors
|
- add a zone's follow ability to impostors by allowing linkedUnit to work with impostors
|
||||||
|
- impostor on idle option. when task of group goes to idle, the group turns into impostors
|
||||||
--]]--
|
--]]--
|
||||||
584
modules/persistence.lua
Normal file
584
modules/persistence.lua
Normal file
@ -0,0 +1,584 @@
|
|||||||
|
persistence = {}
|
||||||
|
persistence.version = "1.0.0"
|
||||||
|
persistence.ups = 1 -- once every 1 seconds
|
||||||
|
persistence.verbose = false
|
||||||
|
persistence.active = false
|
||||||
|
persistence.saveFileName = nil -- "mission data.txt"
|
||||||
|
persistence.sharedDir = nil -- not yet implemented
|
||||||
|
persistence.missionDir = nil -- set at start
|
||||||
|
persistence.saveDir = nil -- set at start
|
||||||
|
|
||||||
|
persistence.missionData = {} -- loaded from file
|
||||||
|
persistence.requiredLibs = {
|
||||||
|
"dcsCommon", -- always
|
||||||
|
"cfxZones", -- Zones, of course
|
||||||
|
}
|
||||||
|
--[[--
|
||||||
|
Version History
|
||||||
|
1.0.0 - initial version
|
||||||
|
|
||||||
|
PROVIDES LOAD/SAVE ABILITY TO MODULES
|
||||||
|
PROVIDES STANDALONE/HOSTED SERVER COMPATIOBILITY
|
||||||
|
|
||||||
|
--]]--
|
||||||
|
|
||||||
|
-- in order to work, Host must desanitize lfs and io
|
||||||
|
-- only works when run as server
|
||||||
|
|
||||||
|
--
|
||||||
|
-- flags to save. can be added to by saveFlags attribute
|
||||||
|
--
|
||||||
|
persistence.flagsToSave = {} -- simple table
|
||||||
|
persistence.callbacks = {} -- cbblocks, dictionary
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- modules register here
|
||||||
|
--
|
||||||
|
function persistence.registerModule(name, callbacks)
|
||||||
|
-- callbacks is a table with the following entries
|
||||||
|
-- callbacks.persistData - method that returns a table
|
||||||
|
-- note that name is also what the data is saved under
|
||||||
|
-- and must be the one given when you retrieve it later
|
||||||
|
persistence.callbacks[name] = callbacks
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: module <" .. name .. "> registred itself", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.registerFlagsToSave(flagNames, theZone)
|
||||||
|
-- name can be single flag name or anything that
|
||||||
|
-- a zone definition has to offer, including local
|
||||||
|
-- flags.
|
||||||
|
-- flags can be passed like this: "a, 4-19, 99, kills, *lcl"
|
||||||
|
-- if you pass a local flag, you must pass the zone
|
||||||
|
-- or "persisTEMP" will be used
|
||||||
|
|
||||||
|
if not theZone then theZone = cfxZones.createSimpleZone("persisTEMP") end
|
||||||
|
local newFlags = dcsCommon.flagArrayFromString(flagNames, persistence.verbose)
|
||||||
|
|
||||||
|
-- mow process all new flags and add them to the list of flags
|
||||||
|
-- to save
|
||||||
|
for idx, flagName in pairs(newFlags) do
|
||||||
|
if dcsCommon.stringStartsWith(flagName, "*") then
|
||||||
|
flagName = theZone.name .. flagName
|
||||||
|
end
|
||||||
|
table.insert(persistence.flagsToSave, flagName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
-- registered modules call this to get their data
|
||||||
|
--
|
||||||
|
function persistence.getSavedDataForModule(name)
|
||||||
|
if not persistence.active then return nil end
|
||||||
|
if not persistence.hasData then return nil end
|
||||||
|
if not persistence.missionData then return end
|
||||||
|
|
||||||
|
return persistence.missionData[name] -- simply get the modules data block
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Shared Data API
|
||||||
|
--
|
||||||
|
function persistence.getSharedDataFor(name, item) -- not yet finalized
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.putSharedDataFor(data, name, item) -- not yet finalized
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- helper meths
|
||||||
|
--
|
||||||
|
|
||||||
|
function persistence.hasFile(path) --check if file exists at path
|
||||||
|
-- will also return true for a directory, follow up with isDir
|
||||||
|
|
||||||
|
local attr = lfs.attributes(path)
|
||||||
|
if attr then
|
||||||
|
return true, attr.mode
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("isFile: attributes not found for <" .. path .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
return false, "<err>"
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.isDir(path) -- check if path is a directory
|
||||||
|
local success, mode = persistence.hasFile(path)
|
||||||
|
if success then
|
||||||
|
success = (mode == "directory")
|
||||||
|
end
|
||||||
|
return success
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Main save meths
|
||||||
|
--
|
||||||
|
function persistence.saveText(theString, fileName, shared, append)
|
||||||
|
if not persistence.active then return false end
|
||||||
|
if not fileName then return false end
|
||||||
|
if not shared then shared = flase end
|
||||||
|
if not theString then theString = "" end
|
||||||
|
|
||||||
|
local path = persistence.missionDir .. fileName
|
||||||
|
if shared then
|
||||||
|
-- we would now change the path
|
||||||
|
trigger.action.outText("+++persistence: NYI: shared", 30)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local theFile = nil
|
||||||
|
|
||||||
|
if append then
|
||||||
|
theFile = io.open(path, "a")
|
||||||
|
else
|
||||||
|
theFile = io.open(path, "w")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not theFile then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
theFile:write(theString)
|
||||||
|
|
||||||
|
theFile:close()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.saveTable(theTable, fileName, shared, append)
|
||||||
|
if not persistence.active then return false end
|
||||||
|
if not fileName then return false end
|
||||||
|
if not theTable then return false end
|
||||||
|
if not shared then shared = false end
|
||||||
|
|
||||||
|
local theString = net.lua2json(theTable)
|
||||||
|
|
||||||
|
if not theString then theString = "" end
|
||||||
|
|
||||||
|
local path = persistence.missionDir .. fileName
|
||||||
|
if shared then
|
||||||
|
-- we would now change the path
|
||||||
|
trigger.action.outText("+++persistence: NYI: shared", 30)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local theFile = nil
|
||||||
|
|
||||||
|
if append then
|
||||||
|
theFile = io.open(path, "a")
|
||||||
|
else
|
||||||
|
theFile = io.open(path, "w")
|
||||||
|
end
|
||||||
|
|
||||||
|
if not theFile then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
theFile:write(theString)
|
||||||
|
|
||||||
|
theFile:close()
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function persistence.loadText(fileName) -- load file as text
|
||||||
|
if not persistence.active then return nil end
|
||||||
|
if not fileName then return nil end
|
||||||
|
|
||||||
|
local path = persistence.missionDir .. fileName
|
||||||
|
local theFile = io.open(path, "r")
|
||||||
|
if not theFile then return nil end
|
||||||
|
|
||||||
|
local t = theFile:read("*a")
|
||||||
|
|
||||||
|
theFile:close()
|
||||||
|
|
||||||
|
return t
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.loadTable(fileName) -- load file as table
|
||||||
|
if not persistence.active then return nil end
|
||||||
|
if not fileName then return nil end
|
||||||
|
|
||||||
|
local t = persistence.loadText(fileName)
|
||||||
|
|
||||||
|
if not t then return nil end
|
||||||
|
|
||||||
|
local tab = net.json2lua(t)
|
||||||
|
|
||||||
|
return tab
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Data Load on Start
|
||||||
|
--
|
||||||
|
function persistence.initFlagsFromData(theFlags)
|
||||||
|
-- assumes that theFlags is a dictionary containing
|
||||||
|
-- flag names
|
||||||
|
local flagLog = ""
|
||||||
|
local flagCount = 0
|
||||||
|
for flagName, value in pairs(theFlags) do
|
||||||
|
local val = tonumber(value) -- ensure number
|
||||||
|
if not val then val = 0 end
|
||||||
|
trigger.action.setUserFlag(flagName, val)
|
||||||
|
if flagLog ~= "" then
|
||||||
|
flagLog = flagLog .. ", " .. flagName .. "=" .. val
|
||||||
|
else
|
||||||
|
flagLog = flagName .. "=" .. val
|
||||||
|
end
|
||||||
|
flagCount = flagCount + 1
|
||||||
|
end
|
||||||
|
if persistence.verbose and flagCount > 0 then
|
||||||
|
trigger.action.outText("+++persistence: loaded " .. flagCount .. " flags from storage:\n" .. flagLog .. "", 30)
|
||||||
|
elseif persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: no flags loaded, commencing mission data load", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.missionStartDataLoad()
|
||||||
|
-- check one: see if we have mission data
|
||||||
|
local theData = persistence.loadTable(persistence.saveFileName)
|
||||||
|
|
||||||
|
if not theData then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: no saved data, fresh start.", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end -- there was no data to load
|
||||||
|
|
||||||
|
if theData["freshMaker"] then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: detected fresh start.", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- when we get here, we got at least some data. check it
|
||||||
|
if theData["versionID"] or persistence.versionID then
|
||||||
|
local vid = theData.versionID -- note: either may be nil!
|
||||||
|
if vid ~= persistence.versionID then
|
||||||
|
-- we pretend load never happened.
|
||||||
|
-- simply return
|
||||||
|
if persistence.verbose then
|
||||||
|
local curvid = persistence.versionID
|
||||||
|
if not curvid then curvid = "<NIL>" end
|
||||||
|
if not vid then vid = "<NIL>" end
|
||||||
|
trigger.action.outText("+++persistence: version mismatch\n(saved = <" .. vid .. "> vs current = <" .. curvid .. ">) - fresh start.", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we have valid data, and modules, after signing up
|
||||||
|
-- can init from by data
|
||||||
|
persistence.missionData = theData
|
||||||
|
persistence.hasData = true
|
||||||
|
|
||||||
|
-- init my flags from last save
|
||||||
|
local theFlags = theData["persistence.flagData"]
|
||||||
|
if theFlags then
|
||||||
|
persistence.initFlagsFromData(theFlags)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we are done for now. modules check in
|
||||||
|
-- after persistence and load their own data
|
||||||
|
-- when they detect that there is data to load
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: basic import complete.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- MAIN DATA WRITE
|
||||||
|
--
|
||||||
|
function persistence.collectFlagData()
|
||||||
|
local flagData = {}
|
||||||
|
for idx, flagName in pairs (persistence.flagsToSave) do
|
||||||
|
local theNum = trigger.misc.getUserFlag(flagName)
|
||||||
|
flagData[flagName] = theNum
|
||||||
|
|
||||||
|
end
|
||||||
|
return flagData
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.saveMissionData()
|
||||||
|
local myData = {}
|
||||||
|
|
||||||
|
-- first, handle versionID and freshMaker
|
||||||
|
if persistence.freshMaker then
|
||||||
|
myData["freshMaker"] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.versionID then
|
||||||
|
myData["versionID"] = persistence.versionID
|
||||||
|
end
|
||||||
|
|
||||||
|
-- now handle flags
|
||||||
|
myData["persistence.flagData"] = persistence.collectFlagData()
|
||||||
|
|
||||||
|
-- now handle all other modules
|
||||||
|
for moduleName, callbacks in pairs(persistence.callbacks) do
|
||||||
|
local moduleData = callbacks.persistData()
|
||||||
|
if moduleData then
|
||||||
|
myData[moduleName] = moduleData
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: gathered data from <" .. moduleName .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- now save data to file
|
||||||
|
persistence.saveTable(myData, persistence.saveFileName)
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- UPDATE
|
||||||
|
--
|
||||||
|
function persistence.doSaveMission()
|
||||||
|
-- main save entry, also from API
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: starting save", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.active then
|
||||||
|
persistence.saveMissionData()
|
||||||
|
else
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: not actice. skipping save", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: mission saved", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.noteCleanRestart()
|
||||||
|
persistence.freshMaker = true
|
||||||
|
persistence.doSaveMission()
|
||||||
|
trigger.action.outText("\n\nYou can re-start the mission for a fresh start.\n\n",30)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.update()
|
||||||
|
-- call me in a second to poll triggers
|
||||||
|
timer.scheduleFunction(persistence.update, {}, timer.getTime() + 1/persistence.ups)
|
||||||
|
|
||||||
|
-- check my trigger flag
|
||||||
|
if persistence.saveMission and cfxZones.testZoneFlag(persistence, persistence.saveMission, "change", "lastSaveMission") then
|
||||||
|
persistence.doSaveMission()
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.cleanRestart and cfxZones.testZoneFlag(persistence, persistence.cleanRestart, "change", "lastCleanRestart") then
|
||||||
|
persistence.noteCleanRestart()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check my timer
|
||||||
|
if persistence.saveTime and persistence.saveTime < timer.getTime() then
|
||||||
|
persistence.doSaveMission()
|
||||||
|
-- start next cycle
|
||||||
|
persistence.saveTime = persistence.saveInterval * 60 + timer.getTime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
-- config & start
|
||||||
|
--
|
||||||
|
|
||||||
|
function persistence.collectFlagsFromZone(theZone)
|
||||||
|
local theFlags = cfxZones.getStringFromZoneProperty(theZone, "saveFlags", "*dummy")
|
||||||
|
persistence.registerFlagsToSave(theFlags, theZone)
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.readConfigZone()
|
||||||
|
local theZone = cfxZones.getZoneByName("persistenceConfig")
|
||||||
|
local hasConfig = true
|
||||||
|
if not theZone then
|
||||||
|
hasConfig = false
|
||||||
|
theZone = cfxZones.createSimpleZone("persistenceConfig")
|
||||||
|
end
|
||||||
|
|
||||||
|
-- serverDir is the path from the server save directory, usually "Missions/".
|
||||||
|
-- will be added to lfs.writedir().
|
||||||
|
persistence.serverDir = cfxZones.getStringFromZoneProperty(theZone, "serverDir", "Missions\\")
|
||||||
|
|
||||||
|
if hasConfig then
|
||||||
|
if cfxZones.hasProperty(theZone, "saveDir") then
|
||||||
|
persistence.saveDir = cfxZones.getStringFromZoneProperty(theZone, "saveDir", "")
|
||||||
|
else
|
||||||
|
-- local missname = net.dostring_in("gui", "return DCS.getMissionName()") .. " (data)"
|
||||||
|
persistence.saveDir = dcsCommon.getMissionName() .. " (data)"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
persistence.saveDir = "" -- save dir is to main mission
|
||||||
|
-- so that when no config is present (standalone debugger)
|
||||||
|
-- this will not cause a separate save folder
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.saveDir == "" and persistence.verbose then
|
||||||
|
trigger.action.outText("*** WARNING: persistence is set to write to main mission directory!", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "saveFileName") then
|
||||||
|
persistence.saveFileName = cfxZones.getStringFromZoneProperty(theZone, "saveFileName", dcsCommon.getMissionName() .. " Data.txt")
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "versionID") then
|
||||||
|
persistence.versionID = cfxZones.getStringFromZoneProperty(theZone, "versionID", "") -- to check for full restart
|
||||||
|
end
|
||||||
|
|
||||||
|
persistence.saveInterval = cfxZones.getNumberFromZoneProperty(theZone, "saveInterval", -1) -- default to manual save
|
||||||
|
if persistence.saveInterval > 0 then
|
||||||
|
persistence.saveTime = persistence.saveInterval * 60 + timer.getTime()
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "cleanRestart?") then
|
||||||
|
persistence.cleanRestart = cfxZones.getStringFromZoneProperty(theZone, "cleanRestart?", "*<none>")
|
||||||
|
persistence.lastCleanRestart = cfxZones.getFlagValue(persistence.cleanRestart, theZone)
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "saveMission?") then
|
||||||
|
persistence.saveMission = cfxZones.getStringFromZoneProperty(theZone, "saveMission?", "*<none>")
|
||||||
|
persistence.lastSaveMission = cfxZones.getFlagValue(persistence.saveMission, theZone)
|
||||||
|
end
|
||||||
|
|
||||||
|
persistence.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
|
||||||
|
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: read config", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.start()
|
||||||
|
-- lib check
|
||||||
|
if not dcsCommon.libCheck then
|
||||||
|
trigger.action.outText("persistence requires dcsCommon", 30)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not dcsCommon.libCheck("persistence", persistence.requiredLibs) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- read config
|
||||||
|
persistence.saveFileName = dcsCommon.getMissionName() .. " Data.txt"
|
||||||
|
persistence.readConfigZone()
|
||||||
|
|
||||||
|
-- let's see it lfs and io are online
|
||||||
|
persistence.active = false
|
||||||
|
if not _G["lfs"] then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence requires 'lfs'", 30)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not _G["io"] then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence requires 'io'", 30)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local mainDir = lfs.writedir() .. persistence.serverDir
|
||||||
|
if not dcsCommon.stringEndsWith(mainDir, "\\") then
|
||||||
|
mainDir = mainDir .. "\\"
|
||||||
|
end
|
||||||
|
-- lets see if we can access the server's mission directory and
|
||||||
|
-- save directory
|
||||||
|
-- we first try to access server's main mission directory, called "mainDir" which is usually <writeDir>/Missions/>
|
||||||
|
|
||||||
|
if persistence.isDir(mainDir) then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("persistence: main dir is <" .. mainDir .. ">", 30)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: Main directory <" .. mainDir .. "> not found or not a directory", 30)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
persistence.mainDir = mainDir
|
||||||
|
|
||||||
|
local missionDir = mainDir .. persistence.saveDir
|
||||||
|
if not dcsCommon.stringEndsWith(missionDir, "\\") then
|
||||||
|
missionDir = missionDir .. "\\"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if mission dir exists already
|
||||||
|
local success, mode = persistence.hasFile(missionDir)
|
||||||
|
if success and mode == "directory" then
|
||||||
|
-- has been allocated, and is dir
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: saving mission data to <" .. missionDir .. ">", 30)
|
||||||
|
end
|
||||||
|
elseif success then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: <" .. missionDir .. "> is not a directory", 30)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
-- does not exist, try to allocate it
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: will now create <" .. missionDir .. ">", 30)
|
||||||
|
end
|
||||||
|
local ok, mkErr = lfs.mkdir(missionDir)
|
||||||
|
if not ok then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: unable to create <" .. missionDir .. ">: <" .. mkErr .. ">", 30)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: created <" .. missionDir .. "> successfully, will save mission data here", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
persistence.missionDir = missionDir
|
||||||
|
|
||||||
|
persistence.active = true -- we can load and save data
|
||||||
|
persistence.hasData = false -- we do not have save data
|
||||||
|
|
||||||
|
-- from here on we can read and write files in the missionDir
|
||||||
|
-- read persistence attributes from all zones
|
||||||
|
local attrZones = cfxZones.getZonesWithAttributeNamed("saveFlags")
|
||||||
|
for k, aZone in pairs(attrZones) do
|
||||||
|
persistence.collectFlagsFromZone(aZone) -- process attributes
|
||||||
|
-- we do not retain the zone, it's job is done
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence is active", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we now see if we can and need load data
|
||||||
|
persistence.missionStartDataLoad()
|
||||||
|
|
||||||
|
-- and start updating
|
||||||
|
persistence.update()
|
||||||
|
|
||||||
|
|
||||||
|
return persistence.active
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- go!
|
||||||
|
--
|
||||||
|
|
||||||
|
if not persistence.start() then
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++ persistence not available", 30)
|
||||||
|
end
|
||||||
|
-- we do NOT remove the methods so we don't crash
|
||||||
|
end
|
||||||
|
|
||||||
|
-- add zones for saveFlags so authors can easily save flag values
|
||||||
@ -1,5 +1,5 @@
|
|||||||
radioMenu = {}
|
radioMenu = {}
|
||||||
radioMenu.version = "1.0.1"
|
radioMenu.version = "1.1.0"
|
||||||
radioMenu.verbose = false
|
radioMenu.verbose = false
|
||||||
radioMenu.ups = 1
|
radioMenu.ups = 1
|
||||||
radioMenu.requiredLibs = {
|
radioMenu.requiredLibs = {
|
||||||
@ -12,6 +12,9 @@ radioMenu.menus = {}
|
|||||||
Version History
|
Version History
|
||||||
1.0.0 Initial version
|
1.0.0 Initial version
|
||||||
1.0.1 spelling corrections
|
1.0.1 spelling corrections
|
||||||
|
1.1.0 removeMenu
|
||||||
|
addMenu
|
||||||
|
menuVisible
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
function radioMenu.addRadioMenu(theZone)
|
function radioMenu.addRadioMenu(theZone)
|
||||||
@ -32,17 +35,60 @@ end
|
|||||||
--
|
--
|
||||||
-- read zone
|
-- read zone
|
||||||
--
|
--
|
||||||
|
function radioMenu.installMenu(theZone)
|
||||||
|
if theZone.coalition == 0 then
|
||||||
|
theZone.rootMenu = missionCommands.addSubMenu(theZone.rootName, nil)
|
||||||
|
else
|
||||||
|
theZone.rootMenu = missionCommands.addSubMenuForCoalition(theZone.coalition, theZone.rootName, nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
local menuA = cfxZones.getStringFromZoneProperty(theZone, "itemA", "<no A submenu>")
|
||||||
|
if theZone.coalition == 0 then
|
||||||
|
theZone.menuA = missionCommands.addCommand(menuA, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "A"})
|
||||||
|
else
|
||||||
|
theZone.menuA = missionCommands.addCommandForCoalition(theZone.coalition, menuA, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "A"})
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "itemB") then
|
||||||
|
local menuB = cfxZones.getStringFromZoneProperty(theZone, "itemB", "<no B submenu>")
|
||||||
|
if theZone.coalition == 0 then
|
||||||
|
theZone.menuB = missionCommands.addCommand(menuB, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "B"})
|
||||||
|
else
|
||||||
|
theZone.menuB = missionCommands.addCommandForCoalition(theZone.coalition, menuB, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "B"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "itemC") then
|
||||||
|
local menuC = cfxZones.getStringFromZoneProperty(theZone, "itemC", "<no C submenu>")
|
||||||
|
if theZone.coalition == 0 then
|
||||||
|
theZone.menuC = missionCommands.addCommand(menuC, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "C"})
|
||||||
|
else
|
||||||
|
theZone.menuC = missionCommands.addCommandForCoalition(theZone.coalition, menuC, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "C"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "itemD") then
|
||||||
|
local menuD = cfxZones.getStringFromZoneProperty(theZone, "itemD", "<no D submenu>")
|
||||||
|
if theZone.coalition == 0 then
|
||||||
|
theZone.menuD = missionCommands.addCommand(menuD, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "D"})
|
||||||
|
else
|
||||||
|
theZone.menuD = missionCommands.addCommandForCoalition(theZone.coalition, menuD, theZone.rootMenu, radioMenu.redirectMenuX, {theZone, "D"})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function radioMenu.createRadioMenuWithZone(theZone)
|
function radioMenu.createRadioMenuWithZone(theZone)
|
||||||
local rootName = cfxZones.getStringFromZoneProperty(theZone, "radioMenu", "<No Name>")
|
theZone.rootName = cfxZones.getStringFromZoneProperty(theZone, "radioMenu", "<No Name>")
|
||||||
|
|
||||||
theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, "coalition", 0)
|
theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, "coalition", 0)
|
||||||
|
|
||||||
if theZone.coalition == 0 then
|
theZone.menuVisible = cfxZones.getBoolFromZoneProperty(theZone, "menuVisible", true)
|
||||||
theZone.rootMenu = missionCommands.addSubMenu(rootName, nil)
|
|
||||||
else
|
|
||||||
theZone.rootMenu = missionCommands.addSubMenuForCoalition(theZone.coalition, rootName, nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
-- install menu if not hidden
|
||||||
|
if theZone.menuVisible then
|
||||||
|
radioMenu.installMenu(theZone)
|
||||||
|
end
|
||||||
|
--[[--
|
||||||
-- now do the two options
|
-- now do the two options
|
||||||
local menuA = cfxZones.getStringFromZoneProperty(theZone, "itemA", "<no A submenu>")
|
local menuA = cfxZones.getStringFromZoneProperty(theZone, "itemA", "<no A submenu>")
|
||||||
if theZone.coalition == 0 then
|
if theZone.coalition == 0 then
|
||||||
@ -78,6 +124,7 @@ function radioMenu.createRadioMenuWithZone(theZone)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--]]--
|
||||||
|
|
||||||
-- get the triggers & methods here
|
-- get the triggers & methods here
|
||||||
theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
|
theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
|
||||||
@ -85,6 +132,8 @@ function radioMenu.createRadioMenuWithZone(theZone)
|
|||||||
theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, "radioMethod", "inc")
|
theZone.radioMethod = cfxZones.getStringFromZoneProperty(theZone, "radioMethod", "inc")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
theZone.radioTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "radioTriggerMethod", "change")
|
||||||
|
|
||||||
theZone.itemAChosen = cfxZones.getStringFromZoneProperty(theZone, "A!", "*<none>")
|
theZone.itemAChosen = cfxZones.getStringFromZoneProperty(theZone, "A!", "*<none>")
|
||||||
theZone.cooldownA = cfxZones.getNumberFromZoneProperty(theZone, "cooldownA", 0)
|
theZone.cooldownA = cfxZones.getNumberFromZoneProperty(theZone, "cooldownA", 0)
|
||||||
theZone.mcdA = 0
|
theZone.mcdA = 0
|
||||||
@ -105,6 +154,16 @@ function radioMenu.createRadioMenuWithZone(theZone)
|
|||||||
theZone.mcdD = 0
|
theZone.mcdD = 0
|
||||||
theZone.busyD = cfxZones.getStringFromZoneProperty(theZone, "busyD", "Please stand by (<s> seconds)")
|
theZone.busyD = cfxZones.getStringFromZoneProperty(theZone, "busyD", "Please stand by (<s> seconds)")
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "removeMenu?") then
|
||||||
|
theZone.removeMenu = cfxZones.getStringFromZoneProperty(theZone, "removeMenu?", "*<none>")
|
||||||
|
theZone.lastRemoveMenu = cfxZones.getFlagValue(theZone.removeMenu, theZone)
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxZones.hasProperty(theZone, "addMenu?") then
|
||||||
|
theZone.addMenu = cfxZones.getStringFromZoneProperty(theZone, "addMenu?", "*<none>")
|
||||||
|
theZone.lastAddMenu = cfxZones.getFlagValue(theZone.addMenu, theZone)
|
||||||
|
end
|
||||||
|
|
||||||
if radioMenu.verbose or theZone.verbose then
|
if radioMenu.verbose or theZone.verbose then
|
||||||
trigger.action.outText("+++radioMenu: new radioMenu zone <".. theZone.name ..">", 30)
|
trigger.action.outText("+++radioMenu: new radioMenu zone <".. theZone.name ..">", 30)
|
||||||
end
|
end
|
||||||
@ -189,13 +248,44 @@ end
|
|||||||
--
|
--
|
||||||
-- Update -- required when we can enable/disable a zone's menu
|
-- Update -- required when we can enable/disable a zone's menu
|
||||||
--
|
--
|
||||||
--[[--
|
|
||||||
function radioMenu.update()
|
function radioMenu.update()
|
||||||
-- call me in a second to poll triggers
|
-- call me in a second to poll triggers
|
||||||
timer.scheduleFunction(radioMenu.update, {}, timer.getTime() + 1/radioMenu.ups)
|
timer.scheduleFunction(radioMenu.update, {}, timer.getTime() + 1/radioMenu.ups)
|
||||||
|
|
||||||
|
-- iterate all menus
|
||||||
|
for idx, theZone in pairs(radioMenu.menus) do
|
||||||
|
if theZone.removeMenu
|
||||||
|
and cfxZones.testZoneFlag(theZone, theZone.removeMenu, theZone.radioTriggerMethod, "lastRemoveMenu")
|
||||||
|
and theZone.menuVisible
|
||||||
|
then
|
||||||
|
if theZone.verbose or radioMenu.verbose then
|
||||||
|
trigger.action.outText("+++menu: removing <" .. dcsCommon.menu2text(theZone.rootMenu) .. "> for <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
if theZone.coalition == 0 then
|
||||||
|
missionCommands.removeItem(theZone.rootMenu)
|
||||||
|
else
|
||||||
|
missionCommands.removeItemForCoalition(theZone.coalition, theZone.rootMenu)
|
||||||
|
end
|
||||||
|
|
||||||
|
theZone.menuVisible = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if theZone.addMenu
|
||||||
|
and cfxZones.testZoneFlag(theZone, theZone.addMenu, theZone.radioTriggerMethod, "lastAddMenu")
|
||||||
|
and (not theZone.menuVisible)
|
||||||
|
then
|
||||||
|
if theZone.verbose or radioMenu.verbose then
|
||||||
|
trigger.action.outText("+++menu: adding menu from <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
radioMenu.installMenu(theZone) -- auto-handles coalition
|
||||||
|
theZone.menuVisible = true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
--]]--
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Config & Start
|
-- Config & Start
|
||||||
@ -238,7 +328,7 @@ function radioMenu.start()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- start update
|
-- start update
|
||||||
--radioMenu.update()
|
radioMenu.update()
|
||||||
|
|
||||||
trigger.action.outText("cfx radioMenu v" .. radioMenu.version .. " started.", 30)
|
trigger.action.outText("cfx radioMenu v" .. radioMenu.version .. " started.", 30)
|
||||||
return true
|
return true
|
||||||
@ -251,7 +341,5 @@ if not radioMenu.start() then
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
to do: turn on/off via flags
|
|
||||||
callbacks for the menus
|
callbacks for the menus
|
||||||
one-shot items
|
|
||||||
--]]--
|
--]]--
|
||||||
@ -1,13 +1,15 @@
|
|||||||
-- theDebugger
|
-- theDebugger
|
||||||
debugger = {}
|
debugger = {}
|
||||||
debugger.version = "1.0.1"
|
debugger.version = "1.1.1"
|
||||||
debugDemon = {}
|
debugDemon = {}
|
||||||
debugDemon.version = "1.0.0"
|
debugDemon.version = "1.1.1"
|
||||||
|
|
||||||
debugger.verbose = false
|
debugger.verbose = false
|
||||||
debugger.ups = 4 -- every 0.25 second
|
debugger.ups = 4 -- every 0.25 second
|
||||||
debugger.name = "DML Debugger" -- for compliance with cfxZones
|
debugger.name = "DML Debugger" -- for compliance with cfxZones
|
||||||
|
|
||||||
|
debugger.log = ""
|
||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
Version History
|
Version History
|
||||||
1.0.0 - Initial version
|
1.0.0 - Initial version
|
||||||
@ -15,14 +17,67 @@ debugger.name = "DML Debugger" -- for compliance with cfxZones
|
|||||||
- changed 'on' to 'active' in config zone
|
- changed 'on' to 'active' in config zone
|
||||||
- merged debugger and debugDemon
|
- merged debugger and debugDemon
|
||||||
- QoL check for 'debug' attribute (no '?')
|
- QoL check for 'debug' attribute (no '?')
|
||||||
1.0.2 - contested! flag
|
1.1.0 - logging
|
||||||
|
- trigger.action --> debugger for outText
|
||||||
|
- persistence of logs
|
||||||
|
- save <name>
|
||||||
|
1.1.1 - warning when trying to set a flag to a non-int
|
||||||
|
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
debugger.requiredLibs = {
|
debugger.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
"cfxZones", -- Zones, of course
|
"cfxZones", -- Zones, of course
|
||||||
}
|
}
|
||||||
|
-- note: saving logs requires persistence module
|
||||||
|
-- will auto-abort saving if not present
|
||||||
|
|
||||||
|
|
||||||
debugger.debugZones = {}
|
debugger.debugZones = {}
|
||||||
|
debugger.debugUnits = {}
|
||||||
|
debugger.debugGroups = {}
|
||||||
|
debugger.debugObjects = {}
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Logging & saving
|
||||||
|
--
|
||||||
|
|
||||||
|
function debugger.outText(message, seconds, cls)
|
||||||
|
if not message then message = "" end
|
||||||
|
if not seconds then seconds = 20 end
|
||||||
|
if not cls then cls = false end
|
||||||
|
|
||||||
|
-- append message to log, and add a lf
|
||||||
|
if not debugger.log then debugger.log = "" end
|
||||||
|
debugger.log = debugger.log .. message .. "\n"
|
||||||
|
|
||||||
|
-- now hand up to trigger
|
||||||
|
trigger.action.outText(message, seconds, cls)
|
||||||
|
end
|
||||||
|
|
||||||
|
function debugger.saveLog(name)
|
||||||
|
if not _G["persistence"] then
|
||||||
|
debugger.outText("+++debug: persistence module required to save log")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not persistence.active then
|
||||||
|
debugger.outText("+++debug: persistence module can't write. ensur you desanitize lfs and io")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if persistence.saveText(debugger.log, name) then
|
||||||
|
debugger.outText("+++debug: log saved to <" .. persistence.missionDir .. name .. ">")
|
||||||
|
else
|
||||||
|
debugger.outText("+++debug: unable to save log to <" .. persistence.missionDir .. name .. ">")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- tracking flags
|
||||||
|
--
|
||||||
|
|
||||||
function debugger.addDebugger(theZone)
|
function debugger.addDebugger(theZone)
|
||||||
table.insert(debugger.debugZones, theZone)
|
table.insert(debugger.debugZones, theZone)
|
||||||
@ -33,7 +88,7 @@ function debugger.getDebuggerByName(aName)
|
|||||||
if aName == aZone.name then return aZone end
|
if aName == aZone.name then return aZone end
|
||||||
end
|
end
|
||||||
if debugger.verbose then
|
if debugger.verbose then
|
||||||
trigger.action.outText("+++debug: no debug zone with name <" .. aName ..">", 30)
|
debugger.outText("+++debug: no debug zone with name <" .. aName ..">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -65,7 +120,7 @@ function debugger.createDebuggerWithZone(theZone)
|
|||||||
|
|
||||||
-- say who we are and what we are monitoring
|
-- say who we are and what we are monitoring
|
||||||
if debugger.verbose or theZone.verbose then
|
if debugger.verbose or theZone.verbose then
|
||||||
trigger.action.outText("---debug: adding zone <".. theZone.name .."> to look for <value " .. theZone.debugInputMethod .. "> in flag(s):", 30)
|
debugger.outText("---debug: adding zone <".. theZone.name .."> to look for <value " .. theZone.debugInputMethod .. "> in flag(s):", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- read main debug array
|
-- read main debug array
|
||||||
@ -77,7 +132,7 @@ function debugger.createDebuggerWithZone(theZone)
|
|||||||
for idx, aFlag in pairs(flagArray) do
|
for idx, aFlag in pairs(flagArray) do
|
||||||
local fVal = cfxZones.getFlagValue(aFlag, theZone)
|
local fVal = cfxZones.getFlagValue(aFlag, theZone)
|
||||||
if debugger.verbose or theZone.verbose then
|
if debugger.verbose or theZone.verbose then
|
||||||
trigger.action.outText(" monitoring flag <" .. aFlag .. ">, inital value is <" .. fVal .. ">", 30)
|
debugger.outText(" monitoring flag <" .. aFlag .. ">, inital value is <" .. fVal .. ">", 30)
|
||||||
end
|
end
|
||||||
valueArray[aFlag] = fVal
|
valueArray[aFlag] = fVal
|
||||||
end
|
end
|
||||||
@ -226,7 +281,7 @@ function debugger.debugZone(theZone)
|
|||||||
-- generate the ouput message
|
-- generate the ouput message
|
||||||
local msg = theZone.debugMsg
|
local msg = theZone.debugMsg
|
||||||
msg = debugger.processDebugMsg(msg, theZone, aFlag, oldVal, newValue)
|
msg = debugger.processDebugMsg(msg, theZone, aFlag, oldVal, newValue)
|
||||||
trigger.action.outText(msg, 30)
|
debugger.outText(msg, 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -239,7 +294,7 @@ function debugger.resetObserver(theZone)
|
|||||||
for idf, aFlag in pairs(theZone.flagArray) do
|
for idf, aFlag in pairs(theZone.flagArray) do
|
||||||
local fVal = cfxZones.getFlagValue(aFlag, theZone)
|
local fVal = cfxZones.getFlagValue(aFlag, theZone)
|
||||||
if debugger.verbose or theZone.verbose then
|
if debugger.verbose or theZone.verbose then
|
||||||
trigger.action.outText("---debug: resetting flag <" .. aFlag .. ">, to <" .. fVal .. "> for zone <" .. theZone.name .. ">", 30)
|
debugger.outText("---debug: resetting flag <" .. aFlag .. ">, to <" .. fVal .. "> for zone <" .. theZone.name .. ">", 30)
|
||||||
end
|
end
|
||||||
theZone.valueArray[aFlag] = fVal
|
theZone.valueArray[aFlag] = fVal
|
||||||
end
|
end
|
||||||
@ -256,39 +311,39 @@ function debugger.showObserverState(theZone)
|
|||||||
for idf, aFlag in pairs(theZone.flagArray) do
|
for idf, aFlag in pairs(theZone.flagArray) do
|
||||||
local fVal = cfxZones.getFlagValue(aFlag, theZone)
|
local fVal = cfxZones.getFlagValue(aFlag, theZone)
|
||||||
if debugger.verbose or theZone.verbose then
|
if debugger.verbose or theZone.verbose then
|
||||||
trigger.action.outText(" state of flag <" .. aFlag .. ">: <" .. theZone.valueArray[aFlag] .. ">", 30)
|
debugger.outText(" state of flag <" .. aFlag .. ">: <" .. theZone.valueArray[aFlag] .. ">", 30)
|
||||||
end
|
end
|
||||||
theZone.valueArray[aFlag] = fVal
|
theZone.valueArray[aFlag] = fVal
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.showState()
|
function debugger.showState()
|
||||||
trigger.action.outText("---debug: CURRENT STATE <" .. dcsCommon.nowString() .. "> --- ", 30)
|
debugger.outText("---debug: CURRENT STATE <" .. dcsCommon.nowString() .. "> --- ", 30)
|
||||||
for idx, theZone in pairs(debugger.debugZones) do
|
for idx, theZone in pairs(debugger.debugZones) do
|
||||||
-- show this zone's state
|
-- show this zone's state
|
||||||
if #theZone.flagArray > 0 then
|
if #theZone.flagArray > 0 then
|
||||||
trigger.action.outText(" state of observer <" .. theZone.name .. "> looking for <value " .. theZone.debugInputMethod .. ">:", 30)
|
debugger.outText(" state of observer <" .. theZone.name .. "> looking for <value " .. theZone.debugInputMethod .. ">:", 30)
|
||||||
debugger.showObserverState(theZone)
|
debugger.showObserverState(theZone)
|
||||||
else
|
else
|
||||||
if theZone.verbose or debugger.verbose then
|
if theZone.verbose or debugger.verbose then
|
||||||
trigger.action.outText(" (empty observer <" .. theZone.name .. ">)", 30)
|
debugger.outText(" (empty observer <" .. theZone.name .. ">)", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
trigger.action.outText("---debug: end of state --- ", 30)
|
debugger.outText("---debug: end of state --- ", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.doActivate()
|
function debugger.doActivate()
|
||||||
debugger.active = true
|
debugger.active = true
|
||||||
if debugger.verbose or true then
|
if debugger.verbose or true then
|
||||||
trigger.action.outText("+++ DM Debugger is now active", 30)
|
debugger.outText("+++ DM Debugger is now active", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugger.doDeactivate()
|
function debugger.doDeactivate()
|
||||||
debugger.active = false
|
debugger.active = false
|
||||||
if debugger.verbose or true then
|
if debugger.verbose or true then
|
||||||
trigger.action.outText("+++ debugger deactivated", 30)
|
debugger.outText("+++ debugger deactivated", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -339,7 +394,7 @@ function debugger.readConfigZone()
|
|||||||
local theZone = cfxZones.getZoneByName("debuggerConfig")
|
local theZone = cfxZones.getZoneByName("debuggerConfig")
|
||||||
if not theZone then
|
if not theZone then
|
||||||
if debugger.verbose then
|
if debugger.verbose then
|
||||||
trigger.action.outText("+++debug: NO config zone!", 30)
|
debugger.outText("+++debug: NO config zone!", 30)
|
||||||
end
|
end
|
||||||
theZone = cfxZones.createSimpleZone("debuggerConfig")
|
theZone = cfxZones.createSimpleZone("debuggerConfig")
|
||||||
end
|
end
|
||||||
@ -371,7 +426,7 @@ function debugger.readConfigZone()
|
|||||||
debugger.ups = cfxZones.getNumberFromZoneProperty(theZone, "ups", 4)
|
debugger.ups = cfxZones.getNumberFromZoneProperty(theZone, "ups", 4)
|
||||||
|
|
||||||
if debugger.verbose then
|
if debugger.verbose then
|
||||||
trigger.action.outText("+++debug: read config", 30)
|
debugger.outText("+++debug: read config", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -398,22 +453,22 @@ function debugger.start()
|
|||||||
|
|
||||||
local attrZones = cfxZones.getZonesWithAttributeNamed("debug")
|
local attrZones = cfxZones.getZonesWithAttributeNamed("debug")
|
||||||
for k, aZone in pairs(attrZones) do
|
for k, aZone in pairs(attrZones) do
|
||||||
trigger.action.outText("***Warning: Zone <" .. aZone.name .. "> has a 'debug' flag. Are you perhaps missing a '?'", 30)
|
debugger.outText("***Warning: Zone <" .. aZone.name .. "> has a 'debug' flag. Are you perhaps missing a '?'", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- say if we are active
|
-- say if we are active
|
||||||
if debugger.verbose then
|
if debugger.verbose then
|
||||||
if debugger.active then
|
if debugger.active then
|
||||||
trigger.action.outText("+++debugger loaded and active", 30)
|
debugger.outText("+++debugger loaded and active", 30)
|
||||||
else
|
else
|
||||||
trigger.action.outText("+++ debugger: standing by for activation", 30)
|
debugger.outText("+++ debugger: standing by for activation", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start update
|
-- start update
|
||||||
debugger.update()
|
debugger.update()
|
||||||
|
|
||||||
trigger.action.outText("cfx debugger v" .. debugger.version .. " started.", 30)
|
debugger.outText("cfx debugger v" .. debugger.version .. " started.", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -441,6 +496,7 @@ debugDemon.verbose = false
|
|||||||
--[[--
|
--[[--
|
||||||
Version History
|
Version History
|
||||||
1.0.0 - initial version
|
1.0.0 - initial version
|
||||||
|
1.1.0 - save command, requires persistence
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -559,7 +615,7 @@ function debugDemon.executeCommand(theCommands, event)
|
|||||||
local success = theInvoker(arguments, event)
|
local success = theInvoker(arguments, event)
|
||||||
return success
|
return success
|
||||||
else
|
else
|
||||||
trigger.action.outText("***error: unknown command <".. cmd .. ">", 30)
|
debugger.outText("***error: unknown command <".. cmd .. ">", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -592,7 +648,7 @@ end
|
|||||||
-- COMMANDS
|
-- COMMANDS
|
||||||
--
|
--
|
||||||
function debugDemon.processHelpCommand(args, event)
|
function debugDemon.processHelpCommand(args, event)
|
||||||
trigger.action.outText("*** debugger: commands are:" ..
|
debugger.outText("*** debugger: commands are:" ..
|
||||||
"\n " .. debugDemon.markOfDemon .. "show <flagname/observername> -- show current values for flag or observer" ..
|
"\n " .. debugDemon.markOfDemon .. "show <flagname/observername> -- show current values for flag or observer" ..
|
||||||
"\n " .. debugDemon.markOfDemon .. "set <flagname> <number> -- set flag to value <number>" ..
|
"\n " .. debugDemon.markOfDemon .. "set <flagname> <number> -- set flag to value <number>" ..
|
||||||
"\n " .. debugDemon.markOfDemon .. "inc <flagname> -- increase flag by 1, changing it" ..
|
"\n " .. debugDemon.markOfDemon .. "inc <flagname> -- increase flag by 1, changing it" ..
|
||||||
@ -614,6 +670,8 @@ trigger.action.outText("*** debugger: commands are:" ..
|
|||||||
"\n\n " .. debugDemon.markOfDemon .. "start -- starts debugger" ..
|
"\n\n " .. debugDemon.markOfDemon .. "start -- starts debugger" ..
|
||||||
"\n " .. debugDemon.markOfDemon .. "stop -- stop debugger" ..
|
"\n " .. debugDemon.markOfDemon .. "stop -- stop debugger" ..
|
||||||
|
|
||||||
|
"\n\n " .. debugDemon.markOfDemon .. "save [<filename>] -- saves debugger log to storage" ..
|
||||||
|
|
||||||
"\n\n " .. debugDemon.markOfDemon .. "? or -help -- this text", 30)
|
"\n\n " .. debugDemon.markOfDemon .. "? or -help -- this text", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -622,14 +680,14 @@ function debugDemon.processNewCommand(args, event)
|
|||||||
-- syntax new <observername> [[for] <condition>]
|
-- syntax new <observername> [[for] <condition>]
|
||||||
local observerName = args[1]
|
local observerName = args[1]
|
||||||
if not observerName then
|
if not observerName then
|
||||||
trigger.action.outText("*** new: missing observer name.", 30)
|
debugger.outText("*** new: missing observer name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
-- see if this observer already existst
|
-- see if this observer already existst
|
||||||
local theObserver = debugger.getDebuggerByName(observerName)
|
local theObserver = debugger.getDebuggerByName(observerName)
|
||||||
if theObserver then
|
if theObserver then
|
||||||
trigger.action.outText("*** new: observer <" .. observerName .. "> already exists.", 30)
|
debugger.outText("*** new: observer <" .. observerName .. "> already exists.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -638,7 +696,7 @@ function debugDemon.processNewCommand(args, event)
|
|||||||
local remainderName = event.remainder
|
local remainderName = event.remainder
|
||||||
local rObserver = debugger.getDebuggerByName(remainderName)
|
local rObserver = debugger.getDebuggerByName(remainderName)
|
||||||
if rObserver then
|
if rObserver then
|
||||||
trigger.action.outText("*** new: observer <" .. remainderName .. "> already exists.", 30)
|
debugger.outText("*** new: observer <" .. remainderName .. "> already exists.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -655,14 +713,14 @@ function debugDemon.processNewCommand(args, event)
|
|||||||
if condition == "for" then condition = args[3] end
|
if condition == "for" then condition = args[3] end
|
||||||
if condition then
|
if condition then
|
||||||
if not cfxZones.verifyMethod(condition, theZone) then
|
if not cfxZones.verifyMethod(condition, theZone) then
|
||||||
trigger.action.outText("*** new: illegal trigger condition <" .. condition .. "> for observer <" .. observerName .. ">", 30)
|
debugger.outText("*** new: illegal trigger condition <" .. condition .. "> for observer <" .. observerName .. ">", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
theZone.debugInputMethod = condition
|
theZone.debugInputMethod = condition
|
||||||
end
|
end
|
||||||
|
|
||||||
debugger.addDebugger(theZone)
|
debugger.addDebugger(theZone)
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debugger: new observer <" .. observerName .. "> for <" .. theZone.debugInputMethod .. ">", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debugger: new observer <" .. observerName .. "> for <" .. theZone.debugInputMethod .. ">", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -670,14 +728,14 @@ function debugDemon.processUpdateCommand(args, event)
|
|||||||
-- syntax update <observername> [[to] <condition>]
|
-- syntax update <observername> [[to] <condition>]
|
||||||
local observerName = args[1]
|
local observerName = args[1]
|
||||||
if not observerName then
|
if not observerName then
|
||||||
trigger.action.outText("*** update: missing observer name.", 30)
|
debugger.outText("*** update: missing observer name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
-- see if this observer already existst
|
-- see if this observer already existst
|
||||||
local theZone = debugger.getDebuggerByName(observerName)
|
local theZone = debugger.getDebuggerByName(observerName)
|
||||||
if not theZone then
|
if not theZone then
|
||||||
trigger.action.outText("*** update: observer <" .. observerName .. "> does not exist exists.", 30)
|
debugger.outText("*** update: observer <" .. observerName .. "> does not exist exists.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -685,13 +743,13 @@ function debugDemon.processUpdateCommand(args, event)
|
|||||||
if condition == "to" then condition = args[3] end
|
if condition == "to" then condition = args[3] end
|
||||||
if condition then
|
if condition then
|
||||||
if not cfxZones.verifyMethod(condition, theZone) then
|
if not cfxZones.verifyMethod(condition, theZone) then
|
||||||
trigger.action.outText("*** update: illegal trigger condition <" .. condition .. "> for observer <" .. observerName .. ">", 30)
|
debugger.outText("*** update: illegal trigger condition <" .. condition .. "> for observer <" .. observerName .. ">", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
theZone.debugInputMethod = condition
|
theZone.debugInputMethod = condition
|
||||||
end
|
end
|
||||||
|
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debugger: updated observer <" .. observerName .. "> to <" .. theZone.debugInputMethod .. ">", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debugger: updated observer <" .. observerName .. "> to <" .. theZone.debugInputMethod .. ">", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -699,21 +757,21 @@ function debugDemon.processDropCommand(args, event)
|
|||||||
-- syntax drop <observername>
|
-- syntax drop <observername>
|
||||||
local observerName = event.remainder -- remainder
|
local observerName = event.remainder -- remainder
|
||||||
if not observerName then
|
if not observerName then
|
||||||
trigger.action.outText("*** drop: missing observer name.", 30)
|
debugger.outText("*** drop: missing observer name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
-- see if this observer already existst
|
-- see if this observer already existst
|
||||||
local theZone = debugger.getDebuggerByName(observerName)
|
local theZone = debugger.getDebuggerByName(observerName)
|
||||||
if not theZone then
|
if not theZone then
|
||||||
trigger.action.outText("*** drop: observer <" .. observerName .. "> does not exist exists.", 30)
|
debugger.outText("*** drop: observer <" .. observerName .. "> does not exist exists.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
-- now simply and irrevocable remove the observer, unless it's home,
|
-- now simply and irrevocable remove the observer, unless it's home,
|
||||||
-- in which case it's simply reset
|
-- in which case it's simply reset
|
||||||
if theZone == debugDemon.observer then
|
if theZone == debugDemon.observer then
|
||||||
trigger.action.outText("*** drop: <" .. observerName .. "> is MY PRECIOUS and WILL NOT be dropped.", 30)
|
debugger.outText("*** drop: <" .. observerName .. "> is MY PRECIOUS and WILL NOT be dropped.", 30)
|
||||||
-- can't really happen since it contains blanks, but
|
-- can't really happen since it contains blanks, but
|
||||||
-- we've seen stranger things
|
-- we've seen stranger things
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
@ -721,7 +779,7 @@ function debugDemon.processDropCommand(args, event)
|
|||||||
|
|
||||||
debugger.removeDebugger(theZone)
|
debugger.removeDebugger(theZone)
|
||||||
|
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debugger: dropped observer <" .. observerName .. ">", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debugger: dropped observer <" .. observerName .. ">", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
-- observe command: add a new flag to observe
|
-- observe command: add a new flag to observe
|
||||||
@ -730,7 +788,7 @@ function debugDemon.processObserveCommand(args, event)
|
|||||||
-- args[1] is the name of the flag
|
-- args[1] is the name of the flag
|
||||||
local flagName = args[1]
|
local flagName = args[1]
|
||||||
if not flagName then
|
if not flagName then
|
||||||
trigger.action.outText("*** observe: missing flag name.", 30)
|
debugger.outText("*** observe: missing flag name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -738,7 +796,7 @@ function debugDemon.processObserveCommand(args, event)
|
|||||||
if args[2] == "with" then
|
if args[2] == "with" then
|
||||||
local aName = args[3]
|
local aName = args[3]
|
||||||
if not aName then
|
if not aName then
|
||||||
trigger.action.outText("*** observe: missing <observer name> after 'with'.", 30)
|
debugger.outText("*** observe: missing <observer name> after 'with'.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
aName = dcsCommon.stringRemainsStartingWith(event.remainder, aName)
|
aName = dcsCommon.stringRemainsStartingWith(event.remainder, aName)
|
||||||
@ -746,12 +804,12 @@ function debugDemon.processObserveCommand(args, event)
|
|||||||
if not withTracker then
|
if not withTracker then
|
||||||
-- withTracker = debugDemon.createObserver(aName)
|
-- withTracker = debugDemon.createObserver(aName)
|
||||||
-- debugger.addDebugger(withTracker)
|
-- debugger.addDebugger(withTracker)
|
||||||
trigger.action.outText("*** observe: no observer <" .. aName .. "> exists", 30)
|
debugger.outText("*** observe: no observer <" .. aName .. "> exists", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
else -- not with as arg 2
|
else -- not with as arg 2
|
||||||
if #args > 1 then
|
if #args > 1 then
|
||||||
trigger.action.outText("*** observe: unknown command after flag name '" .. flagName .. "'.", 30)
|
debugger.outText("*** observe: unknown command after flag name '" .. flagName .. "'.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
-- use own observer
|
-- use own observer
|
||||||
@ -759,13 +817,13 @@ function debugDemon.processObserveCommand(args, event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if debugger.isObservingWithObserver(flagName, withTracker) then
|
if debugger.isObservingWithObserver(flagName, withTracker) then
|
||||||
trigger.action.outText("*** observe: already observing " .. flagName .. " with <" .. withTracker.name .. ">" , 30)
|
debugger.outText("*** observe: already observing " .. flagName .. " with <" .. withTracker.name .. ">" , 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- we add flag to tracker and init value
|
-- we add flag to tracker and init value
|
||||||
debugger.addFlagToObserver(flagName, withTracker)
|
debugger.addFlagToObserver(flagName, withTracker)
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debugger: now observing <" .. flagName .. "> for value " .. withTracker.debugInputMethod .. " with <" .. withTracker.name .. ">.", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debugger: now observing <" .. flagName .. "> for value " .. withTracker.debugInputMethod .. " with <" .. withTracker.name .. ">.", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -774,7 +832,7 @@ function debugDemon.processShowCommand(args, event)
|
|||||||
-- observer has precendce over flag
|
-- observer has precendce over flag
|
||||||
local theName = args[1]
|
local theName = args[1]
|
||||||
if not theName then
|
if not theName then
|
||||||
trigger.action.outText("*** show: missing observer/flag name.", 30)
|
debugger.outText("*** show: missing observer/flag name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -785,12 +843,12 @@ function debugDemon.processShowCommand(args, event)
|
|||||||
if not theObserver then
|
if not theObserver then
|
||||||
-- we directly use trigger.misc
|
-- we directly use trigger.misc
|
||||||
local fVal = trigger.misc.getUserFlag(theName)
|
local fVal = trigger.misc.getUserFlag(theName)
|
||||||
trigger.action.outText("[" .. dcsCommon.nowString() .. "] flag <" .. theName .. "> : value <".. fVal .. ">", 30)
|
debugger.outText("[" .. dcsCommon.nowString() .. "] flag <" .. theName .. "> : value <".. fVal .. ">", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if we get here, we want to show an entire observer
|
-- if we get here, we want to show an entire observer
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] flags observed by <" .. theName .. "> looking for <value ".. theObserver.debugInputMethod .. ">:", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] flags observed by <" .. theName .. "> looking for <value ".. theObserver.debugInputMethod .. ">:", 30)
|
||||||
local flags = theObserver.flagArray
|
local flags = theObserver.flagArray
|
||||||
local values = theObserver.valueArray
|
local values = theObserver.valueArray
|
||||||
for idx, flagName in pairs(flags) do
|
for idx, flagName in pairs(flags) do
|
||||||
@ -804,7 +862,7 @@ function debugDemon.processShowCommand(args, event)
|
|||||||
theMark = " ! "
|
theMark = " ! "
|
||||||
trailer = ", HIT!"
|
trailer = ", HIT!"
|
||||||
end
|
end
|
||||||
trigger.action.outText(theMark .. "f:<" .. flagName .. "> = <".. fVal .. "> [current, state = <" .. values[flagName] .. ">" .. trailer .. "]", 30)
|
debugger.outText(theMark .. "f:<" .. flagName .. "> = <".. fVal .. "> [current, state = <" .. values[flagName] .. ">" .. trailer .. "]", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -836,7 +894,7 @@ function debugDemon.processSnapCommand(args, event)
|
|||||||
theName = dcsCommon.stringRemainsStartingWith(event.remainder, theName)
|
theName = dcsCommon.stringRemainsStartingWith(event.remainder, theName)
|
||||||
theObserver = debugger.getDebuggerByName(theName)
|
theObserver = debugger.getDebuggerByName(theName)
|
||||||
if not theObserver then
|
if not theObserver then
|
||||||
trigger.action.outText("*** snap: unknown observer name <" .. theName .. ">.", 30)
|
debugger.outText("*** snap: unknown observer name <" .. theName .. ">.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -861,26 +919,26 @@ function debugDemon.processSnapCommand(args, event)
|
|||||||
|
|
||||||
local sz = dcsCommon.getSizeOfTable(snapshot)
|
local sz = dcsCommon.getSizeOfTable(snapshot)
|
||||||
debugDemon.snapshot = snapshot
|
debugDemon.snapshot = snapshot
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debug: new snapshot created, " .. sz .. " flags.", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: new snapshot created, " .. sz .. " flags.", 30)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugDemon.processCompareCommand(args, event)
|
function debugDemon.processCompareCommand(args, event)
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debug: comparing snapshot with current flag values", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: comparing snapshot with current flag values", 30)
|
||||||
for flagName, val in pairs (debugDemon.snapshot) do
|
for flagName, val in pairs (debugDemon.snapshot) do
|
||||||
local cVal = trigger.misc.getUserFlag(flagName)
|
local cVal = trigger.misc.getUserFlag(flagName)
|
||||||
local mark = ' '
|
local mark = ' '
|
||||||
if cVal ~= val then mark = ' ! ' end
|
if cVal ~= val then mark = ' ! ' end
|
||||||
trigger.action.outText(mark .. "<" .. flagName .. "> snap = <" .. val .. ">, now = <" .. cVal .. "> " .. mark, 30)
|
debugger.outText(mark .. "<" .. flagName .. "> snap = <" .. val .. ">, now = <" .. cVal .. "> " .. mark, 30)
|
||||||
end
|
end
|
||||||
trigger.action.outText("*** END", 30)
|
debugger.outText("*** END", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function debugDemon.processNoteCommand(args, event)
|
function debugDemon.processNoteCommand(args, event)
|
||||||
local n = event.remainder
|
local n = event.remainder
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "]: " .. n, 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "]: " .. n, 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -888,7 +946,7 @@ function debugDemon.processSetCommand(args, event)
|
|||||||
-- syntax set <flagname> <value>
|
-- syntax set <flagname> <value>
|
||||||
local theName = args[1]
|
local theName = args[1]
|
||||||
if not theName then
|
if not theName then
|
||||||
trigger.action.outText("*** set: missing flag name.", 30)
|
debugger.outText("*** set: missing flag name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -900,13 +958,21 @@ function debugDemon.processSetCommand(args, event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not theVal or not (tonumber(theVal)) then
|
if not theVal or not (tonumber(theVal)) then
|
||||||
trigger.action.outText("*** set: missing or illegal value for flag <" .. theName .. ">.", 30)
|
debugger.outText("*** set: missing or illegal value for flag <" .. theName .. ">.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
-- we set directly, no cfxZones procing
|
theVal = tonumber(theVal)
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debug: set flag <" .. theName .. "> to <" .. theVal .. ">", 30)
|
|
||||||
trigger.action.setUserFlag(theName, theVal)
|
trigger.action.setUserFlag(theName, theVal)
|
||||||
|
-- we set directly, no cfxZones proccing
|
||||||
|
local note =""
|
||||||
|
-- flags are ints only?
|
||||||
|
if theVal ~= math.floor(theVal) then
|
||||||
|
note = " [int! " .. math.floor(theVal) .. "]"
|
||||||
|
end
|
||||||
|
|
||||||
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: set flag <" .. theName .. "> to <" .. theVal .. ">" .. note, 30)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -914,7 +980,7 @@ function debugDemon.processIncCommand(args, event)
|
|||||||
-- syntax inc <flagname>
|
-- syntax inc <flagname>
|
||||||
local theName = args[1]
|
local theName = args[1]
|
||||||
if not theName then
|
if not theName then
|
||||||
trigger.action.outText("*** inc: missing flag name.", 30)
|
debugger.outText("*** inc: missing flag name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -922,7 +988,7 @@ function debugDemon.processIncCommand(args, event)
|
|||||||
local nVal = cVal + 1
|
local nVal = cVal + 1
|
||||||
|
|
||||||
-- we set directly, no cfxZones procing
|
-- we set directly, no cfxZones procing
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debug: inc flag <" .. theName .. "> from <" .. cVal .. "> to <" .. nVal .. ">", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: inc flag <" .. theName .. "> from <" .. cVal .. "> to <" .. nVal .. ">", 30)
|
||||||
trigger.action.setUserFlag(theName, nVal)
|
trigger.action.setUserFlag(theName, nVal)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -931,7 +997,7 @@ function debugDemon.processFlipCommand(args, event)
|
|||||||
-- syntax flip <flagname>
|
-- syntax flip <flagname>
|
||||||
local theName = args[1]
|
local theName = args[1]
|
||||||
if not theName then
|
if not theName then
|
||||||
trigger.action.outText("*** flip: missing flag name.", 30)
|
debugger.outText("*** flip: missing flag name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -939,7 +1005,7 @@ function debugDemon.processFlipCommand(args, event)
|
|||||||
if cVal == 0 then nVal = 1 else nVal = 0 end
|
if cVal == 0 then nVal = 1 else nVal = 0 end
|
||||||
|
|
||||||
-- we set directly, no cfxZones procing
|
-- we set directly, no cfxZones procing
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debug: flipped flag <" .. theName .. "> from <" .. cVal .. "> to <" .. nVal .. ">", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: flipped flag <" .. theName .. "> from <" .. cVal .. "> to <" .. nVal .. ">", 30)
|
||||||
trigger.action.setUserFlag(theName, nVal)
|
trigger.action.setUserFlag(theName, nVal)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -952,9 +1018,9 @@ function debugDemon.processListCommand(args, event)
|
|||||||
prefix = event.remainder -- dcsCommon.stringRemainsStartingWith(event.text, prefix)
|
prefix = event.remainder -- dcsCommon.stringRemainsStartingWith(event.text, prefix)
|
||||||
end
|
end
|
||||||
if prefix then
|
if prefix then
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] listing observers whose name contains <" .. prefix .. ">:", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] listing observers whose name contains <" .. prefix .. ">:", 30)
|
||||||
else
|
else
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] listing all observers:", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] listing all observers:", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
local allObservers = debugger.debugZones
|
local allObservers = debugger.debugZones
|
||||||
@ -966,7 +1032,7 @@ function debugDemon.processListCommand(args, event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if doList then
|
if doList then
|
||||||
trigger.action.outText(" <" .. theName .. "> for <value " .. theZone.debugInputMethod .. "> (" .. #theZone.flagArray .. " flags)", 30)
|
debugger.outText(" <" .. theName .. "> for <value " .. theZone.debugInputMethod .. "> (" .. #theZone.flagArray .. " flags)", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
@ -976,20 +1042,20 @@ function debugDemon.processWhoCommand(args, event)
|
|||||||
-- syntax: who <flagname>
|
-- syntax: who <flagname>
|
||||||
local flagName = event.remainder -- args[1]
|
local flagName = event.remainder -- args[1]
|
||||||
if not flagName or flagName:len()<1 then
|
if not flagName or flagName:len()<1 then
|
||||||
trigger.action.outText("*** who: missing flag name.", 30)
|
debugger.outText("*** who: missing flag name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
local observers = debugger.isObserving(flagName)
|
local observers = debugger.isObserving(flagName)
|
||||||
|
|
||||||
if not observers or #observers < 1 then
|
if not observers or #observers < 1 then
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] flag <" .. flagName .. "> is currently not observed", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] flag <" .. flagName .. "> is currently not observed", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] flag <" .. flagName .. "> is currently observed by", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] flag <" .. flagName .. "> is currently observed by", 30)
|
||||||
for idx, theZone in pairs(observers) do
|
for idx, theZone in pairs(observers) do
|
||||||
trigger.action.outText(" <" .. theZone.name .. "> looking for <value " .. theZone.debugInputMethod .. ">", 30)
|
debugger.outText(" <" .. theZone.name .. "> looking for <value " .. theZone.debugInputMethod .. ">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -1001,7 +1067,7 @@ function debugDemon.processForgetCommand(args, event)
|
|||||||
|
|
||||||
local flagName = args[1]
|
local flagName = args[1]
|
||||||
if not flagName then
|
if not flagName then
|
||||||
trigger.action.outText("*** forget: missing flag name.", 30)
|
debugger.outText("*** forget: missing flag name.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1009,19 +1075,19 @@ function debugDemon.processForgetCommand(args, event)
|
|||||||
if args[2] == "with" or args[2] == "from" then -- we also allow 'from'
|
if args[2] == "with" or args[2] == "from" then -- we also allow 'from'
|
||||||
local aName = args[3]
|
local aName = args[3]
|
||||||
if not aName then
|
if not aName then
|
||||||
trigger.action.outText("*** forget: missing <observer name> after 'with'.", 30)
|
debugger.outText("*** forget: missing <observer name> after 'with'.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
aName = dcsCommon.stringRemainsStartingWith(event.remainder, aName)
|
aName = dcsCommon.stringRemainsStartingWith(event.remainder, aName)
|
||||||
withTracker = debugger.getDebuggerByName(aName)
|
withTracker = debugger.getDebuggerByName(aName)
|
||||||
if not withTracker then
|
if not withTracker then
|
||||||
trigger.action.outText("*** forget: no observer named <" .. aName .. ">", 30)
|
debugger.outText("*** forget: no observer named <" .. aName .. ">", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
else -- not with as arg 2
|
else -- not with as arg 2
|
||||||
if #args > 1 then
|
if #args > 1 then
|
||||||
trigger.action.outText("*** forget: unknown command after flag name '" .. flagName .. "'.", 30)
|
debugger.outText("*** forget: unknown command after flag name '" .. flagName .. "'.", 30)
|
||||||
return false -- allows correction
|
return false -- allows correction
|
||||||
end
|
end
|
||||||
-- use own observer
|
-- use own observer
|
||||||
@ -1029,13 +1095,13 @@ function debugDemon.processForgetCommand(args, event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not debugger.isObservingWithObserver(flagName, withTracker) then
|
if not debugger.isObservingWithObserver(flagName, withTracker) then
|
||||||
trigger.action.outText("*** forget: observer <" .. withTracker.name .. "> does not observe flag <" .. flagName .. ">", 30)
|
debugger.outText("*** forget: observer <" .. withTracker.name .. "> does not observe flag <" .. flagName .. ">", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
-- we add flag to tracker and init value
|
-- we add flag to tracker and init value
|
||||||
debugger.removeFlagFromObserver(flagName, withTracker)
|
debugger.removeFlagFromObserver(flagName, withTracker)
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debugger: no longer observing " .. flagName .. " with <" .. withTracker.name .. ">.", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debugger: no longer observing " .. flagName .. " with <" .. withTracker.name .. ">.", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1057,23 +1123,35 @@ function debugDemon.processResetCommand(args, event)
|
|||||||
local obsName = args[1]
|
local obsName = args[1]
|
||||||
if not obsName then
|
if not obsName then
|
||||||
debugger.reset() -- reset all
|
debugger.reset() -- reset all
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debug: reset complete.", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: reset complete.", 30)
|
||||||
return true -- allows correction
|
return true -- allows correction
|
||||||
end
|
end
|
||||||
|
|
||||||
local withTracker = nil
|
local withTracker = nil
|
||||||
--if args[2] == "with" then
|
local aName = event.remainder
|
||||||
local aName = args[1]
|
|
||||||
aName = event.remainder -- dcsCommon.stringRemainsStartingWith(event.text, aName)
|
|
||||||
withTracker = debugger.getDebuggerByName(aName)
|
withTracker = debugger.getDebuggerByName(aName)
|
||||||
if not withTracker then
|
if not withTracker then
|
||||||
trigger.action.outText("*** reset: no observer <" .. aName .. ">", 30)
|
debugger.outText("*** reset: no observer <" .. aName .. ">", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
debugger.resetObserver(withTracker)
|
debugger.resetObserver(withTracker)
|
||||||
|
|
||||||
trigger.action.outText("*** [" .. dcsCommon.nowString() .. "] debugger:reset observer <" .. withTracker.name .. ">", 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debugger:reset observer <" .. withTracker.name .. ">", 30)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function debugDemon.processSaveCommand(args, event)
|
||||||
|
-- save log to file, requires persistence module
|
||||||
|
-- syntax: -save [<fileName>]
|
||||||
|
local aName = event.remainder
|
||||||
|
if not aName or aName:len() < 1 then
|
||||||
|
aName = "DML Debugger Log"
|
||||||
|
end
|
||||||
|
if not dcsCommon.stringEndsWith(aName, ".txt") then
|
||||||
|
aName = aName .. ".txt"
|
||||||
|
end
|
||||||
|
debugger.saveLog(aName)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
--
|
--
|
||||||
@ -1084,7 +1162,7 @@ function debugDemon.readConfigZone()
|
|||||||
local theZone = cfxZones.getZoneByName("debugDemonConfig")
|
local theZone = cfxZones.getZoneByName("debugDemonConfig")
|
||||||
if not theZone then
|
if not theZone then
|
||||||
if debugDemon.verbose then
|
if debugDemon.verbose then
|
||||||
trigger.action.outText("+++debug: NO config zone!", 30)
|
debugger.outText("+++debug (daemon): NO config zone!", 30)
|
||||||
end
|
end
|
||||||
theZone = cfxZones.createSimpleZone("debugDemonConfig")
|
theZone = cfxZones.createSimpleZone("debugDemonConfig")
|
||||||
end
|
end
|
||||||
@ -1099,7 +1177,7 @@ function debugDemon.readConfigZone()
|
|||||||
|
|
||||||
|
|
||||||
if debugger.verbose then
|
if debugger.verbose then
|
||||||
trigger.action.outText("+++debug (deamon): read config", 30)
|
debugger.outText("+++debug (deamon): read config", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1140,6 +1218,8 @@ function debugDemon.init()
|
|||||||
debugDemon.addCommndProcessor("stop", debugDemon.processStopCommand)
|
debugDemon.addCommndProcessor("stop", debugDemon.processStopCommand)
|
||||||
debugDemon.addCommndProcessor("reset", debugDemon.processResetCommand)
|
debugDemon.addCommndProcessor("reset", debugDemon.processResetCommand)
|
||||||
|
|
||||||
|
debugDemon.addCommndProcessor("save", debugDemon.processSaveCommand)
|
||||||
|
|
||||||
debugDemon.addCommndProcessor("?", debugDemon.processHelpCommand)
|
debugDemon.addCommndProcessor("?", debugDemon.processHelpCommand)
|
||||||
debugDemon.addCommndProcessor("help", debugDemon.processHelpCommand)
|
debugDemon.addCommndProcessor("help", debugDemon.processHelpCommand)
|
||||||
|
|
||||||
@ -1159,7 +1239,11 @@ function debugDemon.start()
|
|||||||
debugDemon.snapshot = debugDemon.createSnapshot(debugger.debugZones)
|
debugDemon.snapshot = debugDemon.createSnapshot(debugger.debugZones)
|
||||||
debugDemon.demonID = world.addEventHandler(debugDemon)
|
debugDemon.demonID = world.addEventHandler(debugDemon)
|
||||||
|
|
||||||
trigger.action.outText("interactive debugDemon v" .. debugDemon.version .. " started" .. "\n enter " .. debugDemon.markOfDemon .. "? in a map mark for help", 30)
|
debugger.outText("interactive debugDemon v" .. debugDemon.version .. " started" .. "\n enter " .. debugDemon.markOfDemon .. "? in a map mark for help", 30)
|
||||||
|
|
||||||
|
if not _G["persistence"] then
|
||||||
|
debugger.outText("\n note: '-save' disabled, no persistence module found", 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if debugDemon.init() then
|
if debugDemon.init() then
|
||||||
@ -1170,6 +1254,11 @@ else
|
|||||||
end
|
end
|
||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
- track units/groups: health changes
|
- track units/groups/objects: health changes
|
||||||
- track players: unit change
|
- track players: unit change, enter, exit
|
||||||
|
- inspect objects, dumping category, life, if it's tasking, latLon, alt, speed, direction
|
||||||
|
|
||||||
|
- exec files. save all commands and then run them from script
|
||||||
|
- remove units via delete and explode
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|||||||
276
modules/unitPersistence.lua
Normal file
276
modules/unitPersistence.lua
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
unitPersistence = {}
|
||||||
|
unitPersistence.version = '1.0.0'
|
||||||
|
unitPersistence.verbose = false
|
||||||
|
unitPersistence.requiredLibs = {
|
||||||
|
"dcsCommon", -- always
|
||||||
|
"cfxZones", -- Zones, of course
|
||||||
|
"persistence",
|
||||||
|
"cfxMX",
|
||||||
|
}
|
||||||
|
--[[--
|
||||||
|
Version History
|
||||||
|
1.0.0 - initial version
|
||||||
|
|
||||||
|
REQUIRES PERSISTENCE AND MX
|
||||||
|
|
||||||
|
Persist ME-placed ground units
|
||||||
|
|
||||||
|
--]]--
|
||||||
|
unitPersistence.groundTroops = {} -- local buffered copy that we
|
||||||
|
-- maintain from save to save
|
||||||
|
unitPersistence.statics = {} -- locally unpacked and buffered static objects
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Save -- Callback
|
||||||
|
--
|
||||||
|
function unitPersistence.saveData()
|
||||||
|
local theData = {}
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
trigger.action.outText("+++unitPersistence: enter saveData", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- theData contains last save
|
||||||
|
-- we save GROUND units placed by ME on. we access a copy of MX data
|
||||||
|
-- for ground troups, iterate through all groups, and create
|
||||||
|
-- a replacement group here and now that is used to replace the one
|
||||||
|
-- that is there when it was spawned
|
||||||
|
for groupName, groupData in pairs(unitPersistence.groundTroops) do
|
||||||
|
-- we update this record live and save it to file
|
||||||
|
if not groupData.isDead then
|
||||||
|
local gotALiveOne = false
|
||||||
|
local allUnits = groupData.units
|
||||||
|
for idx, theUnitData in pairs(allUnits) do
|
||||||
|
if not theUnitData.isDead then
|
||||||
|
local uName = theUnitData.name
|
||||||
|
local gUnit = Unit.getByName(uName)
|
||||||
|
if gUnit and gUnit:isExist() then
|
||||||
|
-- got a live one!
|
||||||
|
gotALiveOne = true
|
||||||
|
-- update x and y and heading
|
||||||
|
theUnitData.heading = dcsCommon.getUnitHeading(gUnit)
|
||||||
|
pos = gUnit:getPoint()
|
||||||
|
theUnitData.x = pos.x
|
||||||
|
theUnitData.y = pos.z -- (!!)
|
||||||
|
-- ground units do not use alt
|
||||||
|
else
|
||||||
|
theUnitData.isDead = true
|
||||||
|
end -- is alive and exists?
|
||||||
|
end -- unit not dead
|
||||||
|
end -- iterate units in group
|
||||||
|
groupData.isDead = not gotALiveOne
|
||||||
|
end -- if group is not dead
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
trigger.action.outText("unitPersistence: save - processed group <" .. groupName .. ">.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- process all static objects placed with ME
|
||||||
|
for oName, oData in pairs(unitPersistence.statics) do
|
||||||
|
if not oData.isDead then
|
||||||
|
-- fetch the object and see if it's still alive
|
||||||
|
local theObject = StaticObject.getByName(oName)
|
||||||
|
if theObject and theObject:isExist() then
|
||||||
|
oData.heading = dcsCommon.getUnitHeading(theObject)
|
||||||
|
pos = theObject:getPoint()
|
||||||
|
oData.x = pos.x
|
||||||
|
oData.y = pos.z -- (!!)
|
||||||
|
oData.isDead = theObject:getLife() < 1
|
||||||
|
-- trigger.action.outText("deadcheck: " .. oName .. " has health=" .. theObject:getLife(), 30)
|
||||||
|
oData.dead = oData.isDead
|
||||||
|
else
|
||||||
|
oData.isDead = true
|
||||||
|
oData.dead = true
|
||||||
|
-- trigger.action.outText("deadcheck: " .. oName .. " certified dead", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
local note = "(ok)"
|
||||||
|
if oData.isDead then note = "(dead)" end
|
||||||
|
trigger.action.outText("unitPersistence: save - processed group <" .. oName .. ">. " .. note, 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
theData.version = unitPersistence.version
|
||||||
|
theData.ground = unitPersistence.groundTroops
|
||||||
|
theData.statics = unitPersistence.statics
|
||||||
|
return theData
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Load Mission Data
|
||||||
|
--
|
||||||
|
function unitPersistence.loadMission()
|
||||||
|
local theData = persistence.getSavedDataForModule("unitPersistence")
|
||||||
|
if not theData then
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
trigger.action.outText("unitPersistence: no save date received, skipping.", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if theData.version ~= unitPersistence.version then
|
||||||
|
trigger.action.outText("\nWARNING!\nUnit data was saved with a different (older) version!\nProceed with caution, fresh start is recommended.\n", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- we just loaded an updated version of unitPersistence.groundTroops
|
||||||
|
-- now iterate all groups, update their positions and
|
||||||
|
-- delete all dead groups or units
|
||||||
|
-- because they currently should exist is the game
|
||||||
|
-- note: if they don't exist in-game that is because mission was
|
||||||
|
-- edited after last save
|
||||||
|
local mismatchWarning = false
|
||||||
|
if theData.ground then
|
||||||
|
for groupName, groupData in pairs(theData.ground) do
|
||||||
|
local theGroup = Group.getByName(groupName)
|
||||||
|
if not theGroup then
|
||||||
|
mismatchWarning = true
|
||||||
|
elseif groupData.isDead then
|
||||||
|
theGroup:destroy()
|
||||||
|
else
|
||||||
|
local newGroup = dcsCommon.clone(groupData)
|
||||||
|
local newUnits = {}
|
||||||
|
for idx, theUnitData in pairs(groupData.units) do
|
||||||
|
-- filter all dead groups
|
||||||
|
if theUnitData.isDead then
|
||||||
|
-- skip it
|
||||||
|
|
||||||
|
else
|
||||||
|
-- add it to new group
|
||||||
|
table.insert(newUnits, theUnitData)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- replace old unit setup with new
|
||||||
|
newGroup.units = newUnits
|
||||||
|
|
||||||
|
local cty = groupData.cty
|
||||||
|
local cat = groupData.cat
|
||||||
|
|
||||||
|
-- destroy the old group
|
||||||
|
--theGroup:destroy() -- will be replaced
|
||||||
|
|
||||||
|
-- spawn new one
|
||||||
|
theGroup = coalition.addGroup(cty, cat, newGroup)
|
||||||
|
if not theGroup then
|
||||||
|
trigger.action.outText("+++ failed to add modified group <" .. groupName .. ">")
|
||||||
|
end
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
trigger.action.outText("+++unitPersistence: updated group <" .. groupName .. "> of cat <" .. cat .. "> for cty <" .. cty .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
trigger.action.outText("+++unitPersistence: no ground unit data.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- and now the same for static objects
|
||||||
|
if theData.statics then
|
||||||
|
for name, staticData in pairs(theData.statics) do
|
||||||
|
local theStatic = StaticObject.getByName(name)
|
||||||
|
if not theStatic then
|
||||||
|
mismatchWarning = true
|
||||||
|
else
|
||||||
|
local newStatic = dcsCommon.clone(staticData)
|
||||||
|
local cty = staticData.cty
|
||||||
|
local cat = staticData.cat
|
||||||
|
-- spawn new one, replacing same.named old, dead if required
|
||||||
|
gStatic = coalition.addStaticObject(cty, newStatic)
|
||||||
|
if not gStatic then
|
||||||
|
trigger.action.outText("+++ failed to add modified static <" .. name .. ">")
|
||||||
|
end
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
local note = ""
|
||||||
|
if newStatic.dead then note = " (dead)" end
|
||||||
|
trigger.action.outText("+++unitPersistence: updated static <" .. name .. "> for cty <" .. cty .. ">" .. note, 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if mismatchWarning then
|
||||||
|
trigger.action.outText("\n+++WARNING: \nSaved data does not match mission. You should re-start from scratch\n", 30)
|
||||||
|
end
|
||||||
|
-- set mission according to data received from last save
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
trigger.action.outText("unitPersistence: units set from save data.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Start
|
||||||
|
--
|
||||||
|
function unitPersistence.start()
|
||||||
|
-- lib check
|
||||||
|
if (not dcsCommon) or (not dcsCommon.libCheck) then
|
||||||
|
trigger.action.outText("unit persistence requires dcsCommon", 30)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not dcsCommon.libCheck("unit persistence", unitPersistence.requiredLibs) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- see if we even need to persist
|
||||||
|
if not persistence.active then
|
||||||
|
return true -- WARNING: true, but not really
|
||||||
|
end
|
||||||
|
|
||||||
|
-- sign up for save callback
|
||||||
|
callbacks = {}
|
||||||
|
callbacks.persistData = unitPersistence.saveData
|
||||||
|
persistence.registerModule("unitPersistence", callbacks)
|
||||||
|
|
||||||
|
-- create a local copy of the entire groundForces data that
|
||||||
|
-- we maintain internally. It's fixed, and we work on our
|
||||||
|
-- own copy for speed
|
||||||
|
for gname, data in pairs(cfxMX.allGroundByName) do
|
||||||
|
local gd = dcsCommon.clone(data) -- copy the record
|
||||||
|
gd.isDead = false -- init new field to alive
|
||||||
|
-- coalition and country
|
||||||
|
gd.cat = cfxMX.catText2ID("vehicle")
|
||||||
|
local gGroup = Group.getByName(gname)
|
||||||
|
if not gGroup then
|
||||||
|
trigger.action.outText("+++warning: group <" .. gname .. "> does not exist in-game!?", 30)
|
||||||
|
else
|
||||||
|
local firstUnit = gGroup:getUnit(1)
|
||||||
|
gd.cty = firstUnit:getCountry()
|
||||||
|
unitPersistence.groundTroops[gname] = gd
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make local copies of all static MX objects
|
||||||
|
-- that we also maintain internally, and convert them to game
|
||||||
|
-- spawnable objects
|
||||||
|
for name, mxData in pairs(cfxMX.allStaticByName) do
|
||||||
|
-- statics in MX are built like groups, so we have to strip
|
||||||
|
-- the outer shell and extract all 'units' which are actually
|
||||||
|
-- objects. And there is usually only one
|
||||||
|
for idx, staticData in pairs(mxData.units) do
|
||||||
|
local theStatic = dcsCommon.clone(staticData)
|
||||||
|
theStatic.isDead = false
|
||||||
|
theStatic.groupId = mxData.groupId
|
||||||
|
theStatic.cat = cfxMX.catText2ID("static")
|
||||||
|
local gameOb = StaticObject.getByName(theStatic.name)
|
||||||
|
if not gameOb then
|
||||||
|
trigger.action.outText("+++warning: static object <" .. theStatic.name .. "> does not exist in-game!?", 30)
|
||||||
|
else
|
||||||
|
theStatic.cty = gameOb:getCountry()
|
||||||
|
unitPersistence.statics[theStatic.name] = theStatic
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- when we run, persistence has run and may have data ready for us
|
||||||
|
if persistence.hasData then
|
||||||
|
unitPersistence.loadMission()
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not unitPersistence.start() then
|
||||||
|
if unitPersistence.verbose then
|
||||||
|
trigger.action.outText("+++ unit persistence not available", 30)
|
||||||
|
end
|
||||||
|
unitPersistence = nil
|
||||||
|
end
|
||||||
BIN
tutorial & demo missions/demo - Being persistent.miz
Normal file
BIN
tutorial & demo missions/demo - Being persistent.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user