diff --git a/scripts/lua/backend/OlympusCommand.lua b/scripts/lua/backend/OlympusCommand.lua index 4161a48c..4d3e8146 100644 --- a/scripts/lua/backend/OlympusCommand.lua +++ b/scripts/lua/backend/OlympusCommand.lua @@ -14,6 +14,7 @@ Olympus.missionData = {} Olympus.unitsData = {} Olympus.weaponsData = {} Olympus.drawingsByLayer = {} +Olympus.executionResults = {} -- Units data structures Olympus.unitCounter = 1 -- Counter to generate unique names @@ -662,7 +663,7 @@ end -- loadout: (string, optional) only for air units, must be one of the loadouts defined in unitPayloads.lua or mods.lua -- payload: (table, optional) overrides loadout, specifies directly the loadout of the unit -- liveryID: (string, optional) -function Olympus.spawnUnits(spawnTable) +function Olympus.spawnUnits(spawnTable, requestHash) Olympus.debug("Olympus.spawnUnits " .. Olympus.serializeTable(spawnTable), 2) local unitsTable = nil @@ -710,10 +711,17 @@ function Olympus.spawnUnits(spawnTable) task = 'CAP' } Olympus.debug(Olympus.serializeTable(vars), 2) - mist.dynAdd(vars) + local newGroup = mist.dynAdd(vars) Olympus.unitCounter = Olympus.unitCounter + 1 Olympus.debug("Olympus.spawnUnits completed succesfully", 2) + + if newGroup == nil then + Olympus.notify("Olympus.spawnUnits failed to spawn group: " .. Olympus.serializeTable(spawnTable), 30) + return nil + end + + Olympus.executionResults[requestHash] = newGroup.groupId end -- Generates unit table for air units @@ -1498,6 +1506,11 @@ function Olympus.setWeaponsData(arg, time) return time + 0.25 end +function Olympus.setExecutionResults() + Olympus.OlympusDLL.setExecutionResults() + return timer.getTime() + 1 +end + function Olympus.setMissionData(arg, time) -- Bullseye data local bullseyes = {} @@ -1697,6 +1710,7 @@ world.addEventHandler(handler) timer.scheduleFunction(Olympus.setUnitsData, {}, timer.getTime() + 0.05) timer.scheduleFunction(Olympus.setWeaponsData, {}, timer.getTime() + 0.25) timer.scheduleFunction(Olympus.setMissionData, {}, timer.getTime() + 1) +timer.scheduleFunction(Olympus.setExecutionResults, {}, timer.getTime() + 1) -- Initialize the ME units Olympus.initializeUnits() diff --git a/scripts/python/API/testbed.py b/scripts/python/API/example_disembarked_infantry.py similarity index 90% rename from scripts/python/API/testbed.py rename to scripts/python/API/example_disembarked_infantry.py index 298eb96b..6ff1fd90 100644 --- a/scripts/python/API/testbed.py +++ b/scripts/python/API/example_disembarked_infantry.py @@ -33,7 +33,7 @@ class DisembarkedInfantry(Unit): target = self.pick_random_target() if random_bearing: - # If random_bearing is True or no target is found, use a random bearing + # If random_bearing is True use a random bearing bearing = randrange(0, 100) / 100 * pi * 2 elif target is None: # If no target is found, use the unit's current heading @@ -41,7 +41,7 @@ class DisembarkedInfantry(Unit): else: bearing = self.position.bearing_to(target.position) - # Project the unit's position 30 meters in front of its current heading + # Project the unit's position 30 meters destination = self.position.project_with_bearing_and_distance(30, bearing) # Set the destination for the unit @@ -98,13 +98,13 @@ def on_api_startup(api: API): global units_to_delete logger.info("API started") - # Get all the units from the API + # Get all the units from the API. Force an update to get the latest units. units = api.update_units() # Initialize the list to hold units to delete units_to_delete = [] - # Delete the units + # Delete the AI blue units for unit in units.values(): if unit.alive and not unit.human and unit.coalition == "blue": units_to_delete.append(unit) @@ -122,6 +122,7 @@ def on_api_startup(api: API): ################################################################################################# def on_unit_alive_change(unit: Unit, value: bool): global units_to_delete + if units_to_delete is None: logger.error("units_to_delete is not initialized.") return @@ -144,14 +145,15 @@ def on_api_update(api: API): logger.info("All units have been deleted successfully.") units_to_delete = None + # Get the units from the API logger.info("Spawning a disembarked infantry units.") units = api.get_units() # Find the first human unit that is alive and on the ground for unit in units.values(): if unit.human and unit.alive and not unit.airborne: - for i in range(50): - # Spawn a new unit 10 meters in from of the human + for i in range(10): + # Spawn unit nearby spawn_position = unit.position.project_with_bearing_and_distance(10, unit.heading + pi / 2 + 0.2 * i) spawn_table: UnitSpawnTable = UnitSpawnTable( unit_type="Soldier M4", @@ -161,6 +163,7 @@ def on_api_update(api: API): livery_id="" ) + # Define the callback for when the unit is spawned. This is an asynchronous function but could be synchronous too. async def execution_callback(new_group_ID: int): logger.info(f"New units spawned, groupID: {new_group_ID}") @@ -174,13 +177,20 @@ def on_api_update(api: API): api.spawn_ground_units([spawn_table], unit.coalition, "", True, 0, lambda new_group_ID: execution_callback(new_group_ID)) logger.info(f"Spawned new unit succesfully at {spawn_position} with heading {unit.heading}") - + break + +############################################################################################## +# Main entry point for the script. It registers the callbacks and starts the API. +############################################################################################## if __name__ == "__main__": + # Initialize the API api = API() + # Register the callbacks api.register_on_update_callback(on_api_update) api.register_on_startup_callback(on_api_startup) + # Start the API, this will run forever until stopped api.run() \ No newline at end of file diff --git a/scripts/python/API/unit/unit.py b/scripts/python/API/unit/unit.py index 7ce5a759..f64cdfa5 100644 --- a/scripts/python/API/unit/unit.py +++ b/scripts/python/API/unit/unit.py @@ -668,8 +668,8 @@ class Unit: def delete_unit(self, explosion=False, explosion_type="", immediate=True): return self.api.send_command({"deleteUnit": {"ID": self.ID, "explosion": explosion, "explosionType": explosion_type, "immediate": immediate}}) - def land_at(self, lat: float, lng: float): - return self.api.send_command({"landAt": {"ID": self.ID, "location": {"lat": lat, "lng": lng}}}) + def land_at(self, location: LatLng): + return self.api.send_command({"landAt": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}}}) def change_speed(self, change: str): return self.api.send_command({"changeSpeed": {"ID": self.ID, "change": change}}) @@ -713,26 +713,26 @@ class Unit: def refuel(self): return self.api.send_command({"refuel": {"ID": self.ID}}) - def bomb_point(self, lat: float, lng: float): - return self.api.send_command({"bombPoint": {"ID": self.ID, "location": {"lat": lat, "lng": lng}}}) + def bomb_point(self, location: LatLng): + return self.api.send_command({"bombPoint": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}}}) - def carpet_bomb(self, lat: float, lng: float): - return self.api.send_command({"carpetBomb": {"ID": self.ID, "location": {"lat": lat, "lng": lng}}}) + def carpet_bomb(self, location: LatLng): + return self.api.send_command({"carpetBomb": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}}}) - def bomb_building(self, lat: float, lng: float): - return self.api.send_command({"bombBuilding": {"ID": self.ID, "location": {"lat": lat, "lng": lng}}}) + def bomb_building(self, location: LatLng): + return self.api.send_command({"bombBuilding": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}}}) - def fire_at_area(self, lat: float, lng: float): - return self.api.send_command({"fireAtArea": {"ID": self.ID, "location": {"lat": lat, "lng": lng}}}) + def fire_at_area(self, location: LatLng): + return self.api.send_command({"fireAtArea": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}}}) - def fire_laser(self, lat: float, lng: float, code: int): - return self.api.send_command({"fireLaser": {"ID": self.ID, "location": {"lat": lat, "lng": lng}, "code": code}}) + def fire_laser(self, location: LatLng, code: int): + return self.api.send_command({"fireLaser": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}, "code": code}}) - def fire_infrared(self, lat: float, lng: float): - return self.api.send_command({"fireInfrared": {"ID": self.ID, "location": {"lat": lat, "lng": lng}}}) + def fire_infrared(self, location: LatLng): + return self.api.send_command({"fireInfrared": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}}}) - def simulate_fire_fight(self, lat: float, lng: float, altitude: float): - return self.api.send_command({"simulateFireFight": {"ID": self.ID, "location": {"lat": lat, "lng": lng}, "altitude": altitude}}) + def simulate_fire_fight(self, location: LatLng, altitude: float): + return self.api.send_command({"simulateFireFight": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}, "altitude": altitude}}) def scenic_aaa(self, coalition: str): return self.api.send_command({"scenicAAA": {"ID": self.ID, "coalition": coalition}}) @@ -740,8 +740,8 @@ class Unit: def miss_on_purpose(self, coalition: str): return self.api.send_command({"missOnPurpose": {"ID": self.ID, "coalition": coalition}}) - def land_at_point(self, lat: float, lng: float): - return self.api.send_command({"landAtPoint": {"ID": self.ID, "location": {"lat": lat, "lng": lng}}}) + def land_at_point(self, location: LatLng): + return self.api.send_command({"landAtPoint": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}}}) def set_shots_scatter(self, shots_scatter: int): return self.api.send_command({"setShotsScatter": {"ID": self.ID, "shotsScatter": shots_scatter}}) @@ -749,8 +749,8 @@ class Unit: def set_shots_intensity(self, shots_intensity: int): return self.api.send_command({"setShotsIntensity": {"ID": self.ID, "shotsIntensity": shots_intensity}}) - def set_racetrack(self, lat: float, lng: float, bearing: float, length: float): - return self.api.send_command({"setRacetrack": {"ID": self.ID, "location": {"lat": lat, "lng": lng}, "bearing": bearing, "length": length}}) + def set_racetrack(self, location: LatLng, bearing: float, length: float): + return self.api.send_command({"setRacetrack": {"ID": self.ID, "location": {"lat": location.lat, "lng": location.lng}, "bearing": bearing, "length": length}}) def set_advanced_options(self, is_active_tanker: bool, is_active_awacs: bool, tacan: dict, radio: dict, general_settings: dict): return self.api.send_command({"setAdvancedOptions": {"ID": self.ID, "isActiveTanker": is_active_tanker, "isActiveAWACS": is_active_awacs, "TACAN": tacan, "radio": radio, "generalSettings": general_settings}})