From f5aef8edb96879dafbef6c160e3001c022817ee0 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 20 Aug 2026 18:45:48 +0200 Subject: [PATCH] TARGET Scenery & PyBridge --- Moose Development/Moose/Ops/Target.lua | 17 +++++- .../MooseBridgeAuftragExecutionExtension.lua | 61 ++++++++++++++++++- .../Python/MooseBridgeDcsEventsExtension.lua | 58 ++++++++++++++++++ Moose Development/Moose/Wrapper/Scenery.lua | 5 +- 4 files changed, 136 insertions(+), 5 deletions(-) diff --git a/Moose Development/Moose/Ops/Target.lua b/Moose Development/Moose/Ops/Target.lua index 53a183137..23bc1c42f 100644 --- a/Moose Development/Moose/Ops/Target.lua +++ b/Moose Development/Moose/Ops/Target.lua @@ -952,9 +952,19 @@ end function TARGET:OnEventUnitDeadOrLost(EventData) 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. - if self:IsElement(Name) and not self:IsCasualty(Name) then + if isElement and not isCasualty then -- Debug info. 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 + printf("FF target adding element %s", tostring(target.Name)) table.insert(self.elements, target.Name) elseif Object:IsInstanceOf("AIRBASE") then @@ -1957,7 +1968,7 @@ function TARGET:GetTargetByName(ObjectName) for _,_target in pairs(self.targets) do local target=_target --#TARGET.Object - if ObjectName==target.Name then + if tostring(ObjectName)==tostring(target.Name) then return target end end @@ -2165,7 +2176,7 @@ function TARGET:IsElement(Name) end for _,name in pairs(self.elements) do - if name==Name then + if tostring(name)==tostring(Name) then return true end end diff --git a/Moose Development/Moose/Python/MooseBridgeAuftragExecutionExtension.lua b/Moose Development/Moose/Python/MooseBridgeAuftragExecutionExtension.lua index 318e28da5..cabe05ece 100644 --- a/Moose Development/Moose/Python/MooseBridgeAuftragExecutionExtension.lua +++ b/Moose Development/Moose/Python/MooseBridgeAuftragExecutionExtension.lua @@ -309,7 +309,7 @@ function MOOSE_BRIDGE:_ResolveCoordinateFromInputs(inputs) local longitude = inputs.longitude ~= nil and tonumber(inputs.longitude) or nil if latitude and longitude then 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 x = tonumber(point.x) z = tonumber(point.z) @@ -441,6 +441,47 @@ function MOOSE_BRIDGE:_ResolveCoordinateAuftragTarget(inputs) return self:_ResolveCoordinateFromInputs(inputs) 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) local p = self:_CommandParams(cmd) local legacy_params = type(p.params) == "table" and p.params or {} @@ -644,6 +685,22 @@ function MOOSE_BRIDGE:_ResolveArtyTarget(inputs) end 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) end @@ -1053,6 +1110,8 @@ function MOOSE_BRIDGE:_BuildAuftragCommandResult(action, auftrag, inputs) required_assets_max=inputs.required_assets_max, weapon_type=inputs.weapon_type, target=inputs.target_id, + target_resolution=inputs.target_resolution, + target_resolution_error=inputs.target_resolution_error, opszone=inputs.opszone_id, capture_coalition=inputs.capture_coalition, stay_in_zone_time_s=inputs.stay_in_zone_time_s, diff --git a/Moose Development/Moose/Python/MooseBridgeDcsEventsExtension.lua b/Moose Development/Moose/Python/MooseBridgeDcsEventsExtension.lua index 890a9f514..1414330bd 100644 --- a/Moose Development/Moose/Python/MooseBridgeDcsEventsExtension.lua +++ b/Moose Development/Moose/Python/MooseBridgeDcsEventsExtension.lua @@ -85,6 +85,21 @@ function MOOSE_BRIDGE:_StartDcsEventForwarding() self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.Kill self:_Log("DCS Kill event forwarding enabled") 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 self:HandleEvent(EVENTS.MissionEnd) self.DcsRegisteredEvents[#self.DcsRegisteredEvents + 1] = EVENTS.MissionEnd @@ -297,6 +312,49 @@ function MOOSE_BRIDGE:OnEventKill(EventData) 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. -- Flush immediately because normal bridge scheduling stops with the mission. -- @param Core.Event#EVENTDATA EventData MOOSE-normalized DCS event data. diff --git a/Moose Development/Moose/Wrapper/Scenery.lua b/Moose Development/Moose/Wrapper/Scenery.lua index 858a3df0a..0a32ebd4f 100644 --- a/Moose Development/Moose/Wrapper/Scenery.lua +++ b/Moose Development/Moose/Wrapper/Scenery.lua @@ -60,7 +60,10 @@ function SCENERY:Register( SceneryName, SceneryObject, SceneryZone ) 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 ) )