xcandiottix Posted August 1, 2020 Posted August 1, 2020 Hello, I have a custom mission that I created over two years ago that, since the last patch, is having a game and multiplayer server breaking issue on Open Beta. I reverted all of my code changes from the server to before the last patch and I am still having the same problem. If I launch the EXACT same mission in the stable version of DCS the issue goes away. Therefore, I am certain this new bug is because of the recently and on going changes to how AI ground units follow routes. Additionally, in DCS Open Beta, I went to the Mission Editor and placed a ground unit. Made it move from Waypoint 1 to Waypoint 2, Perform Command, Run Script, env.info("Hello World', true). This works. Therefore, the issue is not able to be replicated via the ME but instead is caused when pushing a mission table via the pushTask function. The way the mission code works is a mission table is created for a unit asking it to drive on road from point 1 to point 2. Upon arriving, run script ground_arrivedAtZone(...). This function should pass the ground unit/group's object (aka self) into my custom function. This no longer works in DCS Open Beta but does work in public release. Additionally, I also have the following functions: helicopter_arrivedAtZone(...), airplane_arrivedAtZone(...), helicopter_arrivedAtZone(...), and ship_arrivedAtZone(...). These all continue to work perfectly both on DCS Open Beta and Stable. Therefore, this issue only affects ground vehicles. Here is what an example of the table my code creates to tell the unit to move: 2020-08-01 07:39:12.991 INFO SCRIPTING: [id] => Mission 2020-08-01 07:39:12.991 INFO SCRIPTING: [params] => table: 000002301471D750 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [route] => table: 000002301471D0C0 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [points] => table: 000002301471D4D0 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [1] => table: 000002301471D840 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [alt] => 0 2020-08-01 07:39:12.991 INFO SCRIPTING: [type] => Turning Point 2020-08-01 07:39:12.991 INFO SCRIPTING: [action] => On Road 2020-08-01 07:39:12.991 INFO SCRIPTING: [alt_type] => BARO 2020-08-01 07:39:12.991 INFO SCRIPTING: [speed] => 20.833349704742 2020-08-01 07:39:12.991 INFO SCRIPTING: [y] => 297241.875 2020-08-01 07:39:12.991 INFO SCRIPTING: [x] => -6594.4604491581 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: [2] => table: 000002301471D840 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [alt] => 0 2020-08-01 07:39:12.991 INFO SCRIPTING: [type] => Turning Point 2020-08-01 07:39:12.991 INFO SCRIPTING: [action] => On Road 2020-08-01 07:39:12.991 INFO SCRIPTING: [alt_type] => BARO 2020-08-01 07:39:12.991 INFO SCRIPTING: [speed] => 20.833349704742 2020-08-01 07:39:12.991 INFO SCRIPTING: [y] => 292523.23468511 2020-08-01 07:39:12.991 INFO SCRIPTING: [task] => table: 000002301471CB70 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [id] => ComboTask 2020-08-01 07:39:12.991 INFO SCRIPTING: [params] => table: 000002301471CBC0 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [tasks] => table: 000002301471D700 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [1] => table: 000002301471DB10 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [enabled] => true 2020-08-01 07:39:12.991 INFO SCRIPTING: [id] => WrappedAction 2020-08-01 07:39:12.991 INFO SCRIPTING: [auto] => false 2020-08-01 07:39:12.991 INFO SCRIPTING: [params] => table: 000002301471CE40 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [action] => table: 000002301471D7A0 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [id] => Script 2020-08-01 07:39:12.991 INFO SCRIPTING: [params] => table: 000002301471DB60 { 2020-08-01 07:39:12.991 INFO SCRIPTING: [command] => ground_arriveAtZone(...) 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: [x] => -7726.8239333925 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } 2020-08-01 07:39:12.991 INFO SCRIPTING: } As you can see, this looks exactly like how the ME creates a table for the same action: ["country"] = { [1] = { ["id"] = 0, ["vehicle"] = { ["group"] = { [1] = { ["visible"] = false, ["tasks"] = { }, -- end of ["tasks"] ["uncontrollable"] = false, ["task"] = "Ground Nothing", ["route"] = { ["spans"] = { [1] = { [1] = { ["y"] = 68125.08748297, ["x"] = -367966.59928559, }, -- end of [1] [2] = { ["y"] = 73187.475237484, ["x"] = -371985.17939363, }, -- end of [2] }, -- end of [1] [2] = { [1] = { ["y"] = 73187.475237484, ["x"] = -371985.17939363, }, -- end of [1] [2] = { ["y"] = 79682.423698286, ["x"] = -373177.61133761, }, -- end of [2] }, -- end of [2] }, -- end of ["spans"] ["points"] = { [1] = { ["alt"] = 5, ["type"] = "Turning Point", ["ETA"] = 0, ["alt_type"] = "BARO", ["formation_template"] = "", ["y"] = 68125.08748297, ["x"] = -367966.59928559, ["name"] = "DictKey_WptName_9586", ["ETA_locked"] = true, ["speed"] = 5.5555555555556, ["action"] = "Off Road", ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] ["speed_locked"] = true, }, -- end of [1] [2] = { ["alt"] = 5, ["type"] = "Turning Point", ["ETA"] = 1163.4289363442, ["alt_type"] = "BARO", ["formation_template"] = "", ["y"] = 73187.475237484, ["x"] = -371985.17939363, ["name"] = "DictKey_WptName_9587", ["ETA_locked"] = false, ["speed"] = 5.5555555555556, ["action"] = "Off Road", ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { [1] = { ["enabled"] = true, ["auto"] = false, ["id"] = "WrappedAction", ["number"] = 1, ["params"] = { ["action"] = { ["id"] = "Script", ["params"] = { ["command"] = "tasking_someFunction(thisObject)", }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [1] }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] ["speed_locked"] = true, }, -- end of [2] }, -- end of ["points"] }, -- end of ["route"] ["groupId"] = 147, ["hidden"] = false, ["units"] = { [1] = { ["type"] = "BTR-80", ["transportable"] = { ["randomTransportable"] = false, }, -- end of ["transportable"] ["unitId"] = 147, ["skill"] = "Average", ["y"] = 68125.08748297, ["x"] = -367966.59928559, ["name"] = "DictKey_UnitName_9585", ["heading"] = 2.2417522028456, ["playerCanDrive"] = true, }, -- end of [1] }, -- end of ["units"] ["y"] = 68125.08748297, ["x"] = -367966.59928559, ["name"] = "DictKey_GroupName_9584", ["start_time"] = 0, }, -- end of [1] }, -- end of ["group"] }, -- end of ["vehicle"] ["name"] = "Russia", }, -- end of [1] However, in game, these do not have the same outcomes. The ME version works while my version does not work in DCS Open Beta but does work in DCS Stable release. In order to make sure my function wasn't the issue, I edited my code to simply pass the following when reaching a waypoint: "env.info('Hello World', true)" This does not work on DCS Open Beta but does work on DCS Stable release. If I had to make a guess as to what is going on, it would be that possibly in the ME, the X and Z coordinates that a unit goes to are rounded or perhaps there is a trigger area that when a unit stops moving, it checks to see if it is in the trigger area and runs the way point commands. However, if using the pushTask function, perhaps whatever rounding or trigger being produced in the ME is not being produced via custom code. This is just a guess, I have no idea though. I am not going to provide a mission file or anything of the sort because flipping through some previous threads it seems that custom missions don't get exported correctly. This mission runs on a fully dedicated server that I have been operating since the start of the year. The mission code itself is about two years old and comprises of over 10,000 lines of code. If you would like to talk with me directly, please let me know. I am on discord as well (xcandiottix on the DCS channel) and I can do a screenshare or explain the situation as needed. I assume I am not the only one with this issue. This bug has bricked my server so I am not happy to be paying to run the server without being able to run the mission so I would like to try and get this resolved as soon as possible. Thanks I created and maintain Operation Candyland, a DCS Open Beta server. Since 2019, Operation Candyland has been one of the best persistent campaigns running on DCS. Featuring ALL modern US and Russian Air, Ground, and Sea forces dynamically controlled by a standalone AI controller. At any given time, there are over 500 units on the map without any lag or desync due to the standalone nature of the system. Experience one of the best multiday campaign experiences in DCS either solo or with a group of other pilots. Both new and veteran DCS pilots will find Operation Candyland a refreshing challenge where no two campaigns are ever the same. Challenge yourself by reaching the top of a custom scoreboard which grades you based on your sortie performance and experience a custom F10 fog of war system which reveals units based on your coalition's current level of command and control. Rescue downed friendly pilots or captured downed enemy pilots in order to extract valuable intel to progress the mission. Learn more at: https://discord.gg/operation-candyland
xcandiottix Posted August 2, 2020 Author Posted August 2, 2020 Continued... To further assist in your troubleshooting efforts I have made a test mission that exactly replicates my issue. First, in the ME I placed a BTR on the map and told it to drive along a road from its start position to waypoint and stop. At that way point, it does an advanced waypoint action, perform command, run script and executes the following causing a pop-up to occur: env.info('ME Unit Arrived',true) The ME's mission table looks like this: [7] = { ["id"] = 0, ["vehicle"] = { ["group"] = { [1] = { ["visible"] = false, ["tasks"] = { }, -- end of ["tasks"] ["uncontrollable"] = false, ["task"] = "Ground Nothing", ["route"] = { ["spans"] = { [1] = { [1] = { ["y"] = 240593.89300325, ["x"] = -4208.8317450602, }, -- end of [1] [2] = { ["y"] = 240596.94540253, ["x"] = -4278.7578212511, }, -- end of [2] [3] = { ["y"] = 240602.28067526, ["x"] = -4343.583444338, }, -- end of [3] [4] = { ["y"] = 240603.38221113, ["x"] = -4348.4698324703, }, -- end of [4] [5] = { ["y"] = 240606.79415006, ["x"] = -4351.6665939047, }, -- end of [5] [6] = { ["y"] = 240611.80472017, ["x"] = -4352.0588226468, }, -- end of [6] [7] = { ["y"] = 240716.62316159, ["x"] = -4346.1820791284, }, -- end of [7] [8] = { ["y"] = 240751.60029399, ["x"] = -4347.3348212997, }, -- end of [8] [9] = { ["y"] = 240893.84139701, ["x"] = -4354.3919448054, }, -- end of [9] }, -- end of [1] [2] = { [1] = { ["y"] = 240894.32182172, ["x"] = -4343.0523642259, }, -- end of [1] [2] = { ["y"] = 240894.32182172, ["x"] = -4343.0523642259, }, -- end of [2] }, -- end of [2] }, -- end of ["spans"] ["points"] = { [1] = { ["alt"] = 39, ["type"] = "Turning Point", ["ETA"] = 0, ["alt_type"] = "BARO", ["formation_template"] = "", ["y"] = 240595.42752279, ["x"] = -4208.7165258643, ["name"] = "DictKey_WptName_8", ["ETA_locked"] = true, ["speed"] = 5.5555555555556, ["action"] = "On Road", ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] ["speed_locked"] = true, }, -- end of [1] [2] = { ["alt"] = 43, ["type"] = "Turning Point", ["ETA"] = 77.785766803555, ["alt_type"] = "BARO", ["formation_template"] = "", ["y"] = 240894.21881934, ["x"] = -4352.8790597107, ["name"] = "DictKey_WptName_9", ["ETA_locked"] = false, ["speed"] = 5.5555555555556, ["action"] = "On Road", ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { [1] = { ["enabled"] = true, ["auto"] = false, ["id"] = "WrappedAction", ["number"] = 1, ["params"] = { ["action"] = { ["id"] = "Script", ["params"] = { ["command"] = "env.info('ME Unit Arrived',true)", }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [1] }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] ["speed_locked"] = true, }, -- end of [2] }, -- end of ["points"] }, -- end of ["route"] ["groupId"] = 1, ["hidden"] = false, ["units"] = { [1] = { ["type"] = "BTR-80", ["transportable"] = { ["randomTransportable"] = false, }, -- end of ["transportable"] ["unitId"] = 1, ["skill"] = "Average", ["y"] = 240595.42752279, ["x"] = -4208.7165258643, ["name"] = "DictKey_UnitName_7", ["heading"] = 3.119924833519, ["playerCanDrive"] = true, }, -- end of [1] }, -- end of ["units"] ["y"] = 240595.42752279, ["x"] = -4208.7165258643, ["name"] = "DictKey_GroupName_6", ["start_time"] = 0, }, -- end of [1] }, -- end of ["group"] }, -- end of ["vehicle"] ["name"] = "Russia", }, -- end of [7] Then, I wrote a custom script to place another BTR at the exact same start position as the first after 5 seconds passes. The code looks like this: --Create the unit dynamically local groupObjectTable = {} groupObjectTable.task = "Ground Nothing" groupObjectTable.route = {} groupObjectTable.route.points = {} groupObjectTable.route.points[1] = {} groupObjectTable.route.points[1].type = "Turning Point" groupObjectTable.route.points[1].x = -4208.7165258643 groupObjectTable.route.points[1].y = 240595.42752279 groupObjectTable.route.points[1].action = "On Road" groupObjectTable.route.points[1].task = {} groupObjectTable.route.points[1].task.id = "ComboTask" groupObjectTable.route.points[1].task.params = {} groupObjectTable.route.points[1].task.params.tasks = {} groupObjectTable.route.points[1].speed_locked = false groupObjectTable.units = {} groupObjectTable.units[1] = {} groupObjectTable.units[1] = {} groupObjectTable.units[1].skill = "Average" groupObjectTable.units[1]["type"] = "BTR-80" groupObjectTable.units[1].x = -4208.7165258643 groupObjectTable.units[1].y = 240595.42752279 groupObjectTable.units[1].name = "Custom Script Unit" groupObjectTable.units[1].heading = 3.119924833519 groupObjectTable.units[1].playerCanDrive = false groupObjectTable.x = -4208.7165258643 groupObjectTable.y = 240595.42752279 groupObjectTable.name = "Custom Script Group" coalition.addGroup(0, Unit.Category["GROUND_UNIT"], groupObjectTable) After another 5 seconds, I trigger a second script to run which passes a mission table to the dynamically spawned unit telling it to drive to the same position as the ME unit and fire a pop up box as well. The script looks like this: --Create a dynamic mission table w/ a wrapped script action local taskTable = {} taskTable.id = 'Mission' taskTable.params = {} taskTable.params.route = {} taskTable.params.route.points = {} taskTable.params.route.points[1] = {} taskTable.params.route.points[1].alt = 0 taskTable.params.route.points[1].type = "Turning Point" taskTable.params.route.points[1].action = "On Road" taskTable.params.route.points[1].alt_type = "BARO" taskTable.params.route.points[1].speed = 5.5555555555556 taskTable.params.route.points[1].x = -4208.7165258643 taskTable.params.route.points[1].y = 240595.42752279 taskTable.params.route.points[2] = {} taskTable.params.route.points[2].alt = 0 taskTable.params.route.points[2].type = "Turning Point" taskTable.params.route.points[2].action = "On Road" taskTable.params.route.points[2].alt_type = "BARO" taskTable.params.route.points[2].speed = 5.5555555555556 taskTable.params.route.points[2].x = -4352.8790597107 taskTable.params.route.points[2].y = 240894.21881934 --Add script tast to waypoint 2 taskTable.params.route.points[2].task = {} taskTable.params.route.points[2].task.id = "ComboTask" taskTable.params.route.points[2].task.params = {} taskTable.params.route.points[2].task.params.tasks = {} taskTable.params.route.points[2].task.params.tasks[1] = {} taskTable.params.route.points[2].task.params.tasks[1].enabled = true taskTable.params.route.points[2].task.params.tasks[1].auto = false taskTable.params.route.points[2].task.params.tasks[1].id = "WrappedAction" taskTable.params.route.points[2].task.params.tasks[1].params = {} taskTable.params.route.points[2].task.params.tasks[1].params.action = {} taskTable.params.route.points[2].task.params.tasks[1].params.action.id = "Script" taskTable.params.route.points[2].task.params.tasks[1].params.action.params = {} taskTable.params.route.points[2].task.params.tasks[1].params.action.params.command = "env.info('Dynamic Unit Arrived',true)" --Pass mission to dynmaically created unit Group.getByName("Custom Script Group"):getController():pushTask(taskTable) If I run this mission in DCS Open Beta, the ME unit fires a pop up box when getting to the waypoint however the dynamically created unit does not. If I run this exact same mission file in DCS stable, both units fire a pop up box. Here is a video of it: Mission File attached.wp_issue.miz I created and maintain Operation Candyland, a DCS Open Beta server. Since 2019, Operation Candyland has been one of the best persistent campaigns running on DCS. Featuring ALL modern US and Russian Air, Ground, and Sea forces dynamically controlled by a standalone AI controller. At any given time, there are over 500 units on the map without any lag or desync due to the standalone nature of the system. Experience one of the best multiday campaign experiences in DCS either solo or with a group of other pilots. Both new and veteran DCS pilots will find Operation Candyland a refreshing challenge where no two campaigns are ever the same. Challenge yourself by reaching the top of a custom scoreboard which grades you based on your sortie performance and experience a custom F10 fog of war system which reveals units based on your coalition's current level of command and control. Rescue downed friendly pilots or captured downed enemy pilots in order to extract valuable intel to progress the mission. Learn more at: https://discord.gg/operation-candyland
xcandiottix Posted August 15, 2020 Author Posted August 15, 2020 Bueller? I created and maintain Operation Candyland, a DCS Open Beta server. Since 2019, Operation Candyland has been one of the best persistent campaigns running on DCS. Featuring ALL modern US and Russian Air, Ground, and Sea forces dynamically controlled by a standalone AI controller. At any given time, there are over 500 units on the map without any lag or desync due to the standalone nature of the system. Experience one of the best multiday campaign experiences in DCS either solo or with a group of other pilots. Both new and veteran DCS pilots will find Operation Candyland a refreshing challenge where no two campaigns are ever the same. Challenge yourself by reaching the top of a custom scoreboard which grades you based on your sortie performance and experience a custom F10 fog of war system which reveals units based on your coalition's current level of command and control. Rescue downed friendly pilots or captured downed enemy pilots in order to extract valuable intel to progress the mission. Learn more at: https://discord.gg/operation-candyland
xcandiottix Posted August 27, 2020 Author Posted August 27, 2020 Well, this may not be fixed. But thankfully the number one requested DCS feature has finally arrived. ME. Added a new country Lebano :sarcasm face: I created and maintain Operation Candyland, a DCS Open Beta server. Since 2019, Operation Candyland has been one of the best persistent campaigns running on DCS. Featuring ALL modern US and Russian Air, Ground, and Sea forces dynamically controlled by a standalone AI controller. At any given time, there are over 500 units on the map without any lag or desync due to the standalone nature of the system. Experience one of the best multiday campaign experiences in DCS either solo or with a group of other pilots. Both new and veteran DCS pilots will find Operation Candyland a refreshing challenge where no two campaigns are ever the same. Challenge yourself by reaching the top of a custom scoreboard which grades you based on your sortie performance and experience a custom F10 fog of war system which reveals units based on your coalition's current level of command and control. Rescue downed friendly pilots or captured downed enemy pilots in order to extract valuable intel to progress the mission. Learn more at: https://discord.gg/operation-candyland
toutenglisse Posted August 28, 2020 Posted August 28, 2020 Maybe nothing to do with your issue, but in your test mission I see for the ME unit that points' altitudes are positive (39 and 43 meters BARO - correspounding to ground level I suppose), while the Dyn unit's points have altitude at sea level (0 meter BARO). Does it change something if you change BARO to RADIO for Dyn unit (so 0 meter is ground level, reachable by dyn unit), or put the according altitude at points' coodinates (like 39 and 43 meters) ?
xcandiottix Posted August 28, 2020 Author Posted August 28, 2020 Maybe nothing to do with your issue, but in your test mission I see for the ME unit that points' altitudes are positive (39 and 43 meters BARO - correspounding to ground level I suppose), while the Dyn unit's points have altitude at sea level (0 meter BARO). Does it change something if you change BARO to RADIO for Dyn unit (so 0 meter is ground level, reachable by dyn unit), or put the according altitude at points' coodinates (like 39 and 43 meters) ? Interesting thought, let me give that shot. I know that all trigger points are spherical so sometimes if you have a ground level trigger air planes won't trigger them because the planes are too far up in the air. However, in the lua documentation it seems to suggest that ground units should be set to zero by default and then placement of that unit on the "z" axis is the properly calculated based on the "x/y" coordinate it is spawning at. I created and maintain Operation Candyland, a DCS Open Beta server. Since 2019, Operation Candyland has been one of the best persistent campaigns running on DCS. Featuring ALL modern US and Russian Air, Ground, and Sea forces dynamically controlled by a standalone AI controller. At any given time, there are over 500 units on the map without any lag or desync due to the standalone nature of the system. Experience one of the best multiday campaign experiences in DCS either solo or with a group of other pilots. Both new and veteran DCS pilots will find Operation Candyland a refreshing challenge where no two campaigns are ever the same. Challenge yourself by reaching the top of a custom scoreboard which grades you based on your sortie performance and experience a custom F10 fog of war system which reveals units based on your coalition's current level of command and control. Rescue downed friendly pilots or captured downed enemy pilots in order to extract valuable intel to progress the mission. Learn more at: https://discord.gg/operation-candyland
Grimes Posted August 28, 2020 Posted August 28, 2020 Appears to work with setTask but not pushTask. Unsure why that would have changed or makes a difference. Will report it. The right man in the wrong place makes all the difference in the world. Current Projects: Grayflag Server, Scripting Wiki Useful Links: Mission Scripting Tools MIST-(GitHub) MIST-(Thread) SLMOD, Wiki wishlist, Mission Editing Wiki!, Mission Building Forum
xcandiottix Posted August 29, 2020 Author Posted August 29, 2020 Appears to work with setTask but not pushTask. Unsure why that would have changed or makes a difference. Will report it. Bless you good sir. I created and maintain Operation Candyland, a DCS Open Beta server. Since 2019, Operation Candyland has been one of the best persistent campaigns running on DCS. Featuring ALL modern US and Russian Air, Ground, and Sea forces dynamically controlled by a standalone AI controller. At any given time, there are over 500 units on the map without any lag or desync due to the standalone nature of the system. Experience one of the best multiday campaign experiences in DCS either solo or with a group of other pilots. Both new and veteran DCS pilots will find Operation Candyland a refreshing challenge where no two campaigns are ever the same. Challenge yourself by reaching the top of a custom scoreboard which grades you based on your sortie performance and experience a custom F10 fog of war system which reveals units based on your coalition's current level of command and control. Rescue downed friendly pilots or captured downed enemy pilots in order to extract valuable intel to progress the mission. Learn more at: https://discord.gg/operation-candyland
Recommended Posts