This commit is contained in:
Frank
2026-08-17 18:08:43 +02:00
parent 049aca91aa
commit d711172984
5 changed files with 184 additions and 26 deletions
+1 -1
View File
@@ -418,7 +418,7 @@ do -- Zones and Pathlines
---
self:I(string.format("Register ZONE: %s (Polygon, Quad)", ZoneName))
Zone=ZONE_POLYGON:NewFromPointsArray(ZoneName, ZoneData.verticies)
--for i,vec2 in pairs(ZoneData.verticies) do
+1 -1
View File
@@ -1180,7 +1180,7 @@ function ZONE_RADIUS:Scan( ObjectCategories, UnitCategories )
local function EvaluateZone( ZoneObject )
--if ZoneObject:isExist() then --FF: isExist always returns false for SCENERY objects since DCS 2.2 and still in DCS 2.5
if ZoneObject and self:IsVec3InZone(ZoneObject:getPoint()) then
-- Get object category.
+160 -21
View File
@@ -454,6 +454,30 @@ function MOOSE_BRIDGE:_DcsPoint(object)
return self:_DcsCall(object, "getPoint")
end
function MOOSE_BRIDGE:_ScenerySnapshot(object, fallback_point, fallback_name, fallback_type_name, resolution_source)
local point = self:_DcsPoint(object) or fallback_point
if not point then return nil end
local coordinates = self:_CoordinatesForPoint(point, "ll")
local descriptor = self:_DcsCall(object, "getDesc")
local name = self:_DcsCall(object, "getName") or fallback_name
local type_name = self:_DcsCall(object, "getTypeName") or fallback_type_name
return {
object_id="SCENERY:" .. safe_tostring(name),
name=name and safe_tostring(name) or nil,
type_name=type_name and safe_tostring(type_name) or nil,
display_name=type(descriptor) == "table" and descriptor.displayName or nil,
life=tonumber(self:_DcsCall(object, "getLife")),
exists=self:_DcsCall(object, "isExist"),
queryable=object ~= nil,
resolution_source=resolution_source or (object and "world_search" or "reference"),
x=coordinates.x,
y=coordinates.y,
z=coordinates.z,
latitude=coordinates.latitude,
longitude=coordinates.longitude,
}
end
function MOOSE_BRIDGE:_PointFromMooseObject(object)
if not object then return nil end
local coordinate = self:_SafeCall(object, "GetCoordinate")
@@ -757,6 +781,34 @@ function MOOSE_BRIDGE:_MarkPoint(point, text)
return {x=point.x, y=point.y or 0, z=point.z, text=mark_text}
end
function MOOSE_BRIDGE:_CreateMapMarker(params)
if not trigger or not trigger.action or not trigger.action.markToAll then
error("DCS trigger.action.markToAll is not available")
end
local point = self:_DebugMarkupPoint(params.point or params)
local text = self:_OptionalString(params.text) or "MOOSE Bridge marker"
if #text > 180 then error("map.marker.create text accepts at most 180 characters") end
local coalition_id = self:_DebugMarkupCoalition(params.coalition or "all")
local read_only = params.read_only == true
local mark_id = self:_NextMarkId()
if coalition_id == -1 then
trigger.action.markToAll(mark_id, text, point, read_only, "")
else
if not trigger.action.markToCoalition then error("DCS trigger.action.markToCoalition is not available") end
trigger.action.markToCoalition(mark_id, text, point, coalition_id, read_only, "")
end
return {
action="map.marker.create",
mark_id=mark_id,
text=text,
coalition=coalition_id,
read_only=read_only,
x=point.x,
y=point.y or 0,
z=point.z,
}
end
function MOOSE_BRIDGE:_CountTable(value)
if type(value) ~= "table" then return 0 end
local count = 0
@@ -1175,6 +1227,20 @@ function MOOSE_BRIDGE:_ZonePolygonVertices(zone)
return vertices
end
function MOOSE_BRIDGE:_ZoneProperties(zone)
local source = zone and zone.Properties
if type(source) ~= "table" then return nil end
local properties = {}
for key, value in pairs(source) do
local value_type = type(value)
if value_type == "string" or value_type == "number" or value_type == "boolean" then
properties[safe_tostring(key)] = value
end
end
if next(properties) == nil then return nil end
return properties
end
function MOOSE_BRIDGE:_BuildZoneSnapshotItem(zone_name, zone, source)
local name = self:_ZoneName(zone_name, zone)
if not name then return nil end
@@ -1187,7 +1253,7 @@ function MOOSE_BRIDGE:_BuildZoneSnapshotItem(zone_name, zone, source)
local vertices = self:_ZonePolygonVertices(zone)
local radius = nil
if not vertices then radius = self:_SafeCall(zone, "GetRadius") or zone.radius end
local item = {object_id="ZONE:"..safe_tostring(name),dcs_name=safe_tostring(name),object_type="ZONE",category="ZONE",class_name=zone.ClassName,shape=vertices and "polygon" or "circle",source=source,radius=radius,vertices=vertices}
local item = {object_id="ZONE:"..safe_tostring(name),dcs_name=safe_tostring(name),object_type="ZONE",category="ZONE",class_name=zone.ClassName,shape=vertices and "polygon" or "circle",source=source,radius=radius,vertices=vertices,properties=self:_ZoneProperties(zone)}
if point then self:_AddPointFields(item, point) end
return item
end
@@ -1972,6 +2038,10 @@ function MOOSE_BRIDGE:RegisterDefaultCommands()
return self:_MarkPoint(point, p.text or "MOOSE Bridge mark")
end)
self:RegisterCommand("map.marker.create", function(cmd)
return self:_CreateMapMarker(cmd.params or {})
end)
self:RegisterCommand("map.overlay.draw", function(cmd)
return self:_DrawDebugOverlay(cmd.params or {})
end)
@@ -2035,26 +2105,8 @@ function MOOSE_BRIDGE:RegisterDefaultCommands()
truncated = true
return false
end
local point = self:_DcsPoint(object)
if point then
local coordinates = self:_CoordinatesForPoint(point, "ll")
local descriptor = self:_DcsCall(object, "getDesc")
local name = self:_DcsCall(object, "getName")
local type_name = self:_DcsCall(object, "getTypeName")
objects[#objects + 1] = {
object_id="SCENERY:" .. safe_tostring(name or (#objects + 1)),
name=name and safe_tostring(name) or nil,
type_name=type_name and safe_tostring(type_name) or nil,
display_name=type(descriptor) == "table" and descriptor.displayName or nil,
life=tonumber(self:_DcsCall(object, "getLife")),
exists=self:_DcsCall(object, "isExist"),
x=coordinates.x,
y=coordinates.y,
z=coordinates.z,
latitude=coordinates.latitude,
longitude=coordinates.longitude,
}
end
local snapshot = self:_ScenerySnapshot(object)
if snapshot then objects[#objects + 1] = snapshot end
return true
end)
local center_coordinates = self:_CoordinatesForPoint(center, "ll")
@@ -2069,6 +2121,93 @@ function MOOSE_BRIDGE:RegisterDefaultCommands()
}
end)
self:RegisterCommand("scenery.resolve", function(cmd)
local p = cmd.params or {}
if not world or not world.searchObjects or not world.VolumeType then
error("DCS world.searchObjects is not available")
end
if not Object or not Object.Category or Object.Category.SCENERY == nil then
error("DCS scenery object category is not available")
end
if type(p.references) ~= "table" then error("scenery.resolve requires references") end
if #p.references > 500 then error("scenery.resolve accepts at most 500 references") end
local radius = tonumber(p.search_radius_m) or 150
if radius <= 0 or radius > 500 then error("search_radius_m must be in range 0..500") end
local objects = {}
local unresolved = {}
for index, reference in ipairs(p.references) do
if type(reference) ~= "table" then error("Invalid scenery reference at index " .. safe_tostring(index)) end
local object_id = self:_OptionalString(reference.object_id)
local prefix, expected_name = self:_SplitObjectId(object_id)
if prefix ~= "SCENERY" or not expected_name or expected_name == "" then
error("Invalid scenery object_id at index " .. safe_tostring(index))
end
local zone_name = self:_OptionalString(reference.zone_name)
local center = nil
local zone = nil
local assigned_type_name = nil
if zone_name then
zone = ZONE and ZONE.FindByName and ZONE:FindByName(zone_name) or nil
center = self:_PointFromMooseObject(zone)
assigned_type_name = zone and self:_SafeCallArg(zone, "GetProperty", "NAME") or nil
else
local ok, point = pcall(function() return self:_DebugMarkupPoint(reference) end)
if ok then center = point end
end
local found = nil
if center then
local volume = {id=world.VolumeType.SPHERE, params={point=center, radius=radius}}
world.searchObjects(Object.Category.SCENERY, volume, function(object)
local name = self:_DcsCall(object, "getName")
if name ~= nil and safe_tostring(name) == expected_name then
found = object
return false
end
return true
end)
end
local snapshot = nil
if found then
snapshot = self:_ScenerySnapshot(
found,
center,
expected_name,
assigned_type_name,
zone_name and "mission_editor_assignment" or "saved_position"
)
elseif zone_name and center then
-- Some fixed map models can be assigned in the Mission Editor but are
-- omitted by world.searchObjects. Keep the authoritative assignment as
-- baseline evidence while leaving its live state explicitly unknown.
snapshot = self:_ScenerySnapshot(
nil,
center,
expected_name,
assigned_type_name,
"mission_editor_assignment_unqueryable"
)
end
if snapshot then
objects[#objects + 1] = snapshot
end
if not found then
unresolved[#unresolved + 1] = {
object_id=object_id,
zone_name=zone_name,
reason=(zone_name and center) and "assigned_object_not_queryable"
or (center and "not_found_near_reference" or "reference_position_unavailable"),
}
end
end
return {
action="scenery.resolve",
count=#objects,
unresolved_count=#unresolved,
objects=objects,
unresolved=unresolved,
}
end)
self:RegisterCommand("terrain.closest_road_points", function(cmd)
local p = cmd.params or {}
if not land or not land.getClosestPointOnRoads then error("DCS land.getClosestPointOnRoads is not available") end
@@ -304,7 +304,21 @@ function MOOSE_BRIDGE:_ResolveCoordinateFromInputs(inputs)
local z = inputs.z ~= nil and tonumber(inputs.z) or nil
local y = inputs.y ~= nil and tonumber(inputs.y) or 0
if not x or not z then return nil, "Coordinate target requires numeric x and z" end
if not x or not z then
local latitude = inputs.latitude ~= nil and tonumber(inputs.latitude) or nil
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})
if point then
x = tonumber(point.x)
z = tonumber(point.z)
y = tonumber(point.y) or y
end
end
end
if not x or not z then return nil, "Coordinate target requires numeric x/z or latitude/longitude" end
if not COORDINATE or not COORDINATE.New then return nil, "COORDINATE:New is not available" end
return COORDINATE:New(x, y, z), nil
@@ -456,6 +470,8 @@ function MOOSE_BRIDGE:_CommonAuftragCommandInputs(cmd)
x=p.x or legacy_params.x,
y=p.y or legacy_params.y,
z=p.z or legacy_params.z,
latitude=p.latitude or legacy_params.latitude,
longitude=p.longitude or legacy_params.longitude,
dropoff_x=p.dropoff_x or legacy_params.dropoff_x,
dropoff_y=p.dropoff_y or legacy_params.dropoff_y,
dropoff_z=p.dropoff_z or legacy_params.dropoff_z,
+5 -2
View File
@@ -50,7 +50,7 @@ _SCENERY = {}
--@param Core.Zone#ZONE_POLYGON SceneryZone (optional) The zone object.
--@return #SCENERY Scenery object.
function SCENERY:Register( SceneryName, SceneryObject, SceneryZone )
local ID = (SceneryObject and SceneryObject.getID) and SceneryObject:getID() or SceneryName
if _SCENERY[ID] and _SCENERY[ID].SceneryObject == nil then
@@ -322,7 +322,10 @@ function SCENERY:FindByName(Name, Coordinate, Radius, Role, Zone)
scenery = SceneryScan(Coordinate, radius, name)
end
if not scenery then scenery = SCENERY:Register(Name,nil,Zone) end
if not scenery then
self:I(string.format("No scenery object %s found ==> Registering MOOSE SCENERY Object without DCS object", tostring(Name)))
scenery = SCENERY:Register(Name,nil,Zone)
end
return scenery
end