TARGET Scenery & PyBridge

This commit is contained in:
Frank
2026-08-20 18:45:48 +02:00
parent 51bd6150e8
commit f5aef8edb9
4 changed files with 136 additions and 5 deletions
+14 -3
View File
@@ -953,8 +953,18 @@ function TARGET:OnEventUnitDeadOrLost(EventData)
local Name=EventData and EventData.IniUnitName or nil local Name=EventData and EventData.IniUnitName or nil
local isElement=false
local isCasualty=nil
if Name then
isElement=self:IsElement(Name)
isCasualty=self:IsCasualty(Name)
printf("Dead/unit lost event for %s: isElement=%s, isCascualty=%s", tostring(Name), tostring(isElement), tostring(isCasualty))
else
self:E(self.lid..string.format("ERROR: Could not get name of Dead Unit"))
end
-- Check that this is the right group. -- Check that this is the right group.
if self:IsElement(Name) and not self:IsCasualty(Name) then if isElement and not isCasualty then
-- Debug info. -- Debug info.
self:T(self.lid..string.format("EVENT ID=%d: Unit %s dead or lost!", EventData.id, tostring(Name))) self:T(self.lid..string.format("EVENT ID=%d: Unit %s dead or lost!", EventData.id, tostring(Name)))
@@ -1081,6 +1091,7 @@ function TARGET:_AddObject(Object)
target.N0=target.N0+1 target.N0=target.N0+1
printf("FF target adding element %s", tostring(target.Name))
table.insert(self.elements, target.Name) table.insert(self.elements, target.Name)
elseif Object:IsInstanceOf("AIRBASE") then elseif Object:IsInstanceOf("AIRBASE") then
@@ -1957,7 +1968,7 @@ function TARGET:GetTargetByName(ObjectName)
for _,_target in pairs(self.targets) do for _,_target in pairs(self.targets) do
local target=_target --#TARGET.Object local target=_target --#TARGET.Object
if ObjectName==target.Name then if tostring(ObjectName)==tostring(target.Name) then
return target return target
end end
end end
@@ -2165,7 +2176,7 @@ function TARGET:IsElement(Name)
end end
for _,name in pairs(self.elements) do for _,name in pairs(self.elements) do
if name==Name then if tostring(name)==tostring(Name) then
return true return true
end end
end end
@@ -309,7 +309,7 @@ function MOOSE_BRIDGE:_ResolveCoordinateFromInputs(inputs)
local longitude = inputs.longitude ~= nil and tonumber(inputs.longitude) or nil local longitude = inputs.longitude ~= nil and tonumber(inputs.longitude) or nil
if latitude and longitude then if latitude and longitude then
if not coord or not coord.LLtoLO then return nil, "coord.LLtoLO is not available" end if not coord or not coord.LLtoLO then return nil, "coord.LLtoLO is not available" end
local point = coord.LLtoLO({lat=latitude, lon=longitude, alt=0}) local point = coord.LLtoLO(latitude, longitude, 0)
if point then if point then
x = tonumber(point.x) x = tonumber(point.x)
z = tonumber(point.z) z = tonumber(point.z)
@@ -441,6 +441,47 @@ function MOOSE_BRIDGE:_ResolveCoordinateAuftragTarget(inputs)
return self:_ResolveCoordinateFromInputs(inputs) return self:_ResolveCoordinateFromInputs(inputs)
end end
function MOOSE_BRIDGE:_ResolveSceneryAuftragTarget(inputs)
local prefix, name = bridge_split_object_id(inputs.target_id)
if prefix ~= "SCENERY" or not name then return nil, "Invalid SCENERY target id" end
if not SCENERY or not SCENERY.Register then return nil, "MOOSE SCENERY wrapper is not available" end
local scenery_id = tonumber(name) or name
if SCENERY.FindByID then
local existing = SCENERY:FindByID(scenery_id)
local dcs_object = existing and existing.GetDCSObject and existing:GetDCSObject() or nil
if dcs_object then return existing, nil end
end
local coordinate, coordinate_err = self:_ResolveCoordinateFromInputs(inputs)
if not coordinate then return nil, coordinate_err end
if not world or not world.searchObjects or not world.VolumeType then
return nil, "DCS world.searchObjects is not available"
end
if not Object or not Object.Category or Object.Category.SCENERY == nil then
return nil, "DCS scenery object category is not available"
end
local center = coordinate.GetVec3 and coordinate:GetVec3() or nil
if not center then return nil, "SCENERY target coordinate is unavailable" end
local found = nil
local volume = {id=world.VolumeType.SPHERE, params={point=center, radius=150}}
world.searchObjects(Object.Category.SCENERY, volume, function(object)
local object_name = self:_DcsCall(object, "getName")
if object_name ~= nil and bridge_safe_tostring(object_name) == name then
found = object
return false
end
return true
end)
if not found then return nil, "SCENERY target is not live-queryable: " .. name end
local scenery = SCENERY:Register(name, found)
local dcs_object = scenery and scenery.GetDCSObject and scenery:GetDCSObject() or nil
if not dcs_object then return nil, "SCENERY wrapper has no DCS object: " .. name end
return scenery, nil
end
function MOOSE_BRIDGE:_CommonAuftragCommandInputs(cmd) function MOOSE_BRIDGE:_CommonAuftragCommandInputs(cmd)
local p = self:_CommandParams(cmd) local p = self:_CommandParams(cmd)
local legacy_params = type(p.params) == "table" and p.params or {} local legacy_params = type(p.params) == "table" and p.params or {}
@@ -644,6 +685,22 @@ function MOOSE_BRIDGE:_ResolveArtyTarget(inputs)
end end
function MOOSE_BRIDGE:_ResolveStrikeTarget(inputs) function MOOSE_BRIDGE:_ResolveStrikeTarget(inputs)
local prefix = inputs.target_id and bridge_split_object_id(inputs.target_id) or nil
if prefix == "SCENERY" then
local scenery, scenery_err = self:_ResolveSceneryAuftragTarget(inputs)
if scenery then
inputs.target_resolution = "scenery_object"
return scenery, nil
end
local coordinate, coordinate_err = self:_ResolveCoordinateFromInputs(inputs)
if coordinate then
inputs.target_resolution = "coordinate_fallback"
inputs.target_resolution_error = scenery_err
return coordinate, nil
end
return nil, scenery_err or coordinate_err
end
inputs.target_resolution = "coordinate"
return self:_ResolveCoordinateAuftragTarget(inputs) return self:_ResolveCoordinateAuftragTarget(inputs)
end end
@@ -1053,6 +1110,8 @@ function MOOSE_BRIDGE:_BuildAuftragCommandResult(action, auftrag, inputs)
required_assets_max=inputs.required_assets_max, required_assets_max=inputs.required_assets_max,
weapon_type=inputs.weapon_type, weapon_type=inputs.weapon_type,
target=inputs.target_id, target=inputs.target_id,
target_resolution=inputs.target_resolution,
target_resolution_error=inputs.target_resolution_error,
opszone=inputs.opszone_id, opszone=inputs.opszone_id,
capture_coalition=inputs.capture_coalition, capture_coalition=inputs.capture_coalition,
stay_in_zone_time_s=inputs.stay_in_zone_time_s, stay_in_zone_time_s=inputs.stay_in_zone_time_s,
@@ -85,6 +85,21 @@ function MOOSE_BRIDGE:_StartDcsEventForwarding()
self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.Kill self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.Kill
self:_Log("DCS Kill event forwarding enabled") self:_Log("DCS Kill event forwarding enabled")
end end
if bridge_event_available(EVENTS.MarkAdded) then
self:HandleEvent(EVENTS.MarkAdded)
self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.MarkAdded
self:_Log("DCS MarkAdded event forwarding enabled")
end
if bridge_event_available(EVENTS.MarkChange) then
self:HandleEvent(EVENTS.MarkChange)
self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.MarkChange
self:_Log("DCS MarkChange event forwarding enabled")
end
if bridge_event_available(EVENTS.MarkRemoved) then
self:HandleEvent(EVENTS.MarkRemoved)
self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.MarkRemoved
self:_Log("DCS MarkRemoved event forwarding enabled")
end
if bridge_event_available(EVENTS.MissionEnd) then if bridge_event_available(EVENTS.MissionEnd) then
self:HandleEvent(EVENTS.MissionEnd) self:HandleEvent(EVENTS.MissionEnd)
self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.MissionEnd self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.MissionEnd
@@ -297,6 +312,49 @@ function MOOSE_BRIDGE:OnEventKill(EventData)
end end
end end
--- Forward one DCS F10 map-marker event without interpreting its text.
-- Marker commands remain a Python concern so the Lua bridge stays semantic
-- and does not couple mission scripts to verification workflows.
function MOOSE_BRIDGE:_ForwardMapMarker(EventData, event_name, dcs_event_name)
local ok, err = pcall(function()
if type(EventData) ~= "table" then error("Map marker event data is missing") end
local marker_id = EventData.MarkID or EventData.idx
if marker_id == nil then error("Map marker event has no marker ID") end
local point = EventData.MarkVec3 or EventData.pos
local coordinates = point and self:_CoordinatesForPoint(point, "ll") or {}
self:SendEvent(event_name, {
dcs_event_id=EventData.id,
dcs_event_name=dcs_event_name,
dcs_event_time=EventData.time,
marker_id=marker_id,
text=EventData.MarkText or EventData.text,
coalition=self:_CoalitionToName(EventData.MarkCoalition or EventData.coalition),
group_id=EventData.MarkGroupID or EventData.groupID,
player_name=EventData.PlayerName,
x=coordinates.x,
y=coordinates.y,
z=coordinates.z,
latitude=coordinates.latitude,
longitude=coordinates.longitude,
})
end)
if not ok then
self:_Log("Failed to forward " .. tostring(dcs_event_name) .. " event: " .. tostring(err))
end
end
function MOOSE_BRIDGE:OnEventMarkAdded(EventData)
self:_ForwardMapMarker(EventData, "map.marker.added", "S_EVENT_MARK_ADDED")
end
function MOOSE_BRIDGE:OnEventMarkChange(EventData)
self:_ForwardMapMarker(EventData, "map.marker.changed", "S_EVENT_MARK_CHANGE")
end
function MOOSE_BRIDGE:OnEventMarkRemoved(EventData)
self:_ForwardMapMarker(EventData, "map.marker.removed", "S_EVENT_MARK_REMOVED")
end
--- Forward DCS S_EVENT_MISSION_END as the authoritative Python session boundary. --- Forward DCS S_EVENT_MISSION_END as the authoritative Python session boundary.
-- Flush immediately because normal bridge scheduling stops with the mission. -- Flush immediately because normal bridge scheduling stops with the mission.
-- @param Core.Event#EVENTDATA EventData MOOSE-normalized DCS event data. -- @param Core.Event#EVENTDATA EventData MOOSE-normalized DCS event data.
+4 -1
View File
@@ -60,7 +60,10 @@ function SCENERY:Register( SceneryName, SceneryObject, SceneryZone )
end end
if _SCENERY[ID] then return _SCENERY[ID] end if _SCENERY[ID] then
BASE:I("Returning DCS scenery object found in _SCENERY table with ID")
return _SCENERY[ID]
end
local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) ) local self = BASE:Inherit( self, POSITIONABLE:New( SceneryName ) )