Results 1 to 7 of 7

Thread: How to delete all ground vehicles, ships, artillery, other statics in CLOD

  1. #1
    Ace
    Join Date
    May 2015
    Location
    Kansas City, Missouri area
    Posts
    515
    Post Thanks / Like
    Total Downloaded
    130.02 MB

    How to delete all ground vehicles, ships, artillery, other statics in CLOD

    One somewhat difficult issue in scripting missions etc for CLOD, is sometimes you need to get rid of old ground actors--artillery, ships, vehicles, whatever.

    Getting the full list of these objects doesn't seem to be as easy as it is for aircraft.

    Here is my (somewhat/very) kludgy solution. It has quite a bit of overkill built into it, but it does GET RID of any/all ground objects, ship, artillery, etc. It doesn't try to be smooth--most likely there would be a rather large freeze for the player while you run this things. But, it does work in the sense of zapping ground targets--any and all.

    Note that this doesn't check whether a player is in any of the items, so you might want to add that little check (if you don't, players working artillery, for example, will just be unceremoniously dumped out).

    I'm posting this partly in the hope that some kind person might have the truly elegant solution to this problem.

    FWIW the two key elements of this code:
    Code:
    GamePlay.gpGroundStationarys(x, y, distance) //gets a list of all stationaries within a certain distance of a certain point
    GamePlay.gpActorByName(name) as AiGroundActor //gets actor by name
    The "by name" thing is pretty powerful, because you can see a list of object names by right-clicking in CLOD and "view aircraft" "view vehicle" "view ship" "view misc" etc - and see the name there. Pretty soon you see they are named like "1:12_Chief0" and such, so it become easy to make a list of all (possible) names.

    Another possible approach would be to keep a list of all actors as they spawn in, using "OnActorCreated". However I believe that still leaves you with "sub-Actors" of the group, which are like "1:12_Chief1", "1:12_Chief2", "1:12_Chief3", etc.


    Code:
        public bool DEBUG = false;
    
        private void destroyAllGroundActors(int missionNumber = -1)
        {
            //TODO: Make it list only the actors in that mission by prefixing "XX:" if missionNumber is included.
            try
            {
                //if (!DEBUG) return;
                if (DEBUG) GamePlay.gpLogServer(null, "Destroying all ground actors:", new object[] { });
    
                int group_count = 0;
                if (GamePlay.gpArmies() != null && GamePlay.gpArmies().Length > 0)
                {
                    foreach (int army in GamePlay.gpArmies())
                    {
                        //List a/c in player army if "inOwnArmy" == true; otherwise lists a/c in all armies EXCEPT the player's own army
                        if (GamePlay.gpGroundGroups(army) != null && GamePlay.gpGroundGroups(army).Length > 0)
                        {
                            foreach (AiGroundGroup group in GamePlay.gpGroundGroups(army))
                            {
                                destroyAGVGroundGroup(group);
                            }
                        }
                    }
                }
            }
            catch (Exception e) { System.Console.WriteLine("laa: " + e.ToString()); }
    
    
    
        }
    
        
        //Destroys a given Ground Group, along with any stationaries within the given area
        //you can set distance to be quite close to your given group or leave it large (50000 meters) to basically collect all stationaries on the map
        //maxSubItems catches all the chief1 chief2 chief3 chief4 type things.  If you happen to have more than chief99 then you'll need to
        //increase maxSubItems
        
        private bool destroyAGVGroundGroup(AiGroundGroup group, bool destroyElements = true, bool destroyGroup = true, bool destroyNearbyGroundStationaries = true, bool destroyStatics = true, double distance = 500000, int maxSubItems=20, int maxStatics=500)
        {
            try
            {
                bool success = false;
    
    
                if (group != null)
                {
    
                    //first, we get rid of any stationaries associated with this mission
                    string missionNumber = group.Name().Split(':')[0];
    
    
                    //string subStatName = missionNumber + ":" + i.ToString() + "_Static";
                    string subStatPrefix = missionNumber + ":";
    
                    if (DEBUG) GamePlay.gpLogServer(null, "DEBUG: Destroying Stationaries associated with Mission "
                            + subStatPrefix, new object[] { });
    
                    //Ok, this part is a bit belt&suspenders, just searching by a (potentially very LARGE) area for any ground stationaries that are in the same
                    //mission as our object:
                    if (destroyNearbyGroundStationaries && GamePlay.gpGroundStationarys() != null)
                    {
                        foreach (GroundStationary gg in GamePlay.gpGroundStationarys(group.Pos().x, group.Pos().y, distance)) //all stationaries w/i 500000 or whatever meters of this object
                        {
                            if (gg.Name.StartsWith(subStatPrefix))
                            {
                                gg.Destroy();
                                if (DEBUG) GamePlay.gpLogServer(null, "DEBUG: Destroyed " + gg.Name, new object[] { });
                            }
    
                        }
                    }
    
    
                    //Now we destroy any Actors or sub-Actors of this group
                    //The issue is that we don't know how many sub-actors a particular group might have
                    //Going up to 100 should get them all but if there are some left over in specific cases,
                    //just increase maxSubItems in the method call
                    //These are like trailers & various vehicles within a single convoy (I believe)
                    if (destroyElements)
                    {
                        for (int i = 0; i < maxSubItems; i++)
                        {
                            string subName = group.Name() + (i).ToString();
                            if (DEBUG) GamePlay.gpLogServer(null, "DEBUG: Destroying group element: "
                                    + subName, new object[] { });
                            AiGroundActor subActor = GamePlay.gpActorByName(subName) as AiGroundActor;
                            if (subActor != null)
                            {
                                if (DEBUG) GamePlay.gpLogServer(null, "DEBUG: Destroyed : "
                                    + subActor.Name(), new object[] { });
    
                                //destroyGroundGroup(subActor as AiGroundGroup);
                                (subActor as AiCart).Destroy();
                            }
                        }
                    }
    
                    //Now we destroy any Statics within the same mission as the group.
                    //The issue is that we don't know how many statics a particular mission might have
                    //Going up to say 500 should get them all but if there are some left over in specific cases,
                    //just increase maxStatics in the method call
                    if (destroyStatics)
                    {
                        for (int i = 0; i < maxStatics; i++)
                        {
                            string subName = subStatPrefix + "Static" + (i).ToString();
                            if (DEBUG) GamePlay.gpLogServer(null, "DEBUG: Destroying group element: "
                                    + subName, new object[] { });
                            AiGroundActor subActor = GamePlay.gpActorByName(subName) as AiGroundActor;
                            if (subActor != null)
                            {
                                if (DEBUG) GamePlay.gpLogServer(null, "DEBUG: Destroyed : "
                                    + subActor.Name(), new object[] { });
    
                                //destroyGroundGroup(subActor as AiGroundGroup);
                                (subActor as AiCart).Destroy();
                            }
                        }
                    }
    
    
                    if (destroyGroup)
                    {
                        if (DEBUG) GamePlay.gpLogServer(null, "DEBUG: Finished destroying group: "
                            + group.Name() + " "
                        //+ group.CallSign() + " " 
                        //+ group.Type() + " " 
                        //+ group.TypedName() + " " 
                        //+ group.AirGroup().ID()
                        //+ group.GroupType() + " "
                        //+ group.ID() + " "
                        , new object[] { });
    
    
                        //group.Destroy();
    
                        if ((group as AiGroundActor) != null) (group as AiGroundActor).Destroy();
                        success = true;
    
                    }
    
                }
    
                return success;
            }
            catch (Exception e) { System.Console.WriteLine("dag2: " + e.ToString()); return false; }
        }
    Last edited by TWC_Flug; Jan-06-2017 at 18:46. Reason: slight code edits

  2. Likes Wolf liked this post
  3. #2
    Ace
    Join Date
    May 2015
    Location
    Kansas City, Missouri area
    Posts
    515
    Post Thanks / Like
    Total Downloaded
    130.02 MB

    Re: How to list all ground actors in IL2 CLOD

    Here is a bonus - how to list all ground actors.

    Like the code above, I am not guaranteeing that it is the most elegant OR that it actually lists all ground actors. I think it misses some (trailers, 2nd, 3rd, 4th vehicles in convoys, etc).

    Anyway, it might be helpful for someone and also if anyone has a better approach, I would love to see it!
    Code:
        private void listAllGroundActors(int missionNumber = -1)
        {
            //TODO: Make it list only the actors in that mission by prefixing "XX:" if missionNumber is included.
            try
            {
                if (!DEBUG) return;
                if (DEBUG) GamePlay.gpLogServer(null, "Listing all ground actors:", new object[] { });
    
                int group_count = 0;
                if (GamePlay.gpArmies() != null && GamePlay.gpArmies().Length > 0)
                {
                    foreach (int army in GamePlay.gpArmies())
                    {
                        //List a/c in player army if "inOwnArmy" == true; otherwise lists a/c in all armies EXCEPT the player's own army
                        if (GamePlay.gpGroundGroups(army) != null && GamePlay.gpGroundGroups(army).Length > 0)
                        {
                            foreach (AiGroundGroup group in GamePlay.gpGroundGroups(army))
                            {
                                group_count++;
                                if (group.GetItems() != null && group.GetItems().Length > 0)
                                {
                                    //poscount = group.NOfAirc;
                                    foreach (AiActor actor in group.GetItems())
                                    {
                                        if (actor != null)
                                        {
                                            if (DEBUG) GamePlay.gpLogServer(null, actor.Name(), new object[] { });
                                            AiGroundGroup actorSubGroup = actor as AiGroundGroup;
                                            if (actorSubGroup != null && (actorSubGroup).GetItems() != null && actorSubGroup.GetItems().Length > 0)
                                            {
                                                foreach (AiActor a in actorSubGroup.GetItems())
                                                {
                                                    if (DEBUG) GamePlay.gpLogServer(null, a.Name(), new object[] { });
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e) { System.Console.WriteLine("laa: " + e.ToString()); }
        }

  4. Likes Wolf liked this post
  5. #3
    Ace
    Join Date
    May 2013
    Location
    Stamford, Lincs, UK
    Posts
    1,033
    Post Thanks / Like
    Blog Entries
    8
    Total Downloaded
    7.46 MB

    Re: How to delete all ground vehicles, ships, artillery, other statics in CLOD

    I'm not sure why you want to do this. Or what a "sub actor" is.

  6. #4
    Ace
    Join Date
    May 2015
    Location
    Kansas City, Missouri area
    Posts
    515
    Post Thanks / Like
    Total Downloaded
    130.02 MB

    Re: How to delete all ground vehicles, ships, artillery, other statics in CLOD

    Quote Originally Posted by SoW Reddog View Post
    I'm not sure why you want to do this. Or what a "sub actor" is.
    Well, the specific reason is that in the TWC Practice Server new submission are loaded every 20 minutes via gpPostMissionLoad() in order to keep a fresh supply of targets. This continues over a 10 hour period so you need to clear out old actors periodically or it just gets too cluttered etc.

    This is easy to do with aircraft because you can just use onActorCreated() and set a 20 minute timeout before destroying them (or making them do whatever you want at that point). But not all ground actors come through OnActorCreated, so that creates a problem. (Also FYI not all aircraft come through onActorCreated--if the callsign of the group is set higher than 50 or so, they just never appear.)

    In addition, in the Practice Server there is an admin command to allow the server to be used as a dogfight or practice server. To do that you remove all AI aircraft. There is another command to turn over all the ai aircraft/drones/ground targets immediately, and that requires removing all existing aircraft & ground targets.

    Where I discovered the "sub-actor" issue was in programming the Ground Vehicles Script that sends tenders for every aircraft when the aircraft spawns in or lands, sends emergency vehicles when an aircraft crashes etc. The original concept was to have tenders stationed here & there and have them run out to a certain aircraft when something happened and then run back, continually re-using a relatively small number of ground vehicles. But I soon got tired of trying to work around the more-or-less braindead & buggy routing system for ground vehicles in CLOD. So the solution was just to spawn in the vehicles near the aircraft (just a little bit distant, like over a nearby hill) have them drive up to the aircraft, do their thing, then drive off two or three minutes later, drive over the crest of a nearby hill, and spawn out.

    But when I spawned out every single actor that had come through onActorCreated() I discovered that there were a bunch of things left over. Typically trailers or maybe the things that are loaded into the back of a pickup truck. I think convoys are the same way--only one member of the convoy comes through onActorCreated.

    So the result was that even though I was destroying ever single ground actor that came through onActorCreated(), after a while certain areas were littered with leftover trails, cargo loads, etc etc etc. Since many times these areas were near airports, people would crash into them, die, and get quite mad. So I needed some way to get rid of these extra little "attachments" to various ground actors.

    I don't know what these little extra "actors" are called officially but I called them "sub-actors" because they are like little items that are attached to actors but don't come through onActorCreated. The way CloD names them makes it appear that they consider them attached or subservient to the main actor in some way.

    Also, to answer your question "why?" on a larger level--in this particular instance, I want to destroy certain ground targets. But destroying them is the easy part--the hard part is getting a complete LIST of all ground targets, ships, etc etc etc in the mission at any given time.

    In servers with outside views turned on, you can see a complete list of all aircraft, ships, vehicles, artillery etc just using right-click. So CloD obviously has internal lists of these items somewhere. Is there some easy/simple way to access those lists of actors and objects?
    Last edited by TWC_Flug; Jan-07-2017 at 15:24.

  7. #5
    Ace
    Join Date
    May 2013
    Location
    Stamford, Lincs, UK
    Posts
    1,033
    Post Thanks / Like
    Blog Entries
    8
    Total Downloaded
    7.46 MB

    Re: How to delete all ground vehicles, ships, artillery, other statics in CLOD

    Ah Ok.

    For reference SoW has around 8k objects in our mission file, every time. I would be surprised even if by loading objects mid mission every 20mins that you exceeded that amount?

    Anyway, on to your problem. I think maybe there is something in Salmo's extension class for some of this stuff http://theairtacticalassaultgroup.co...ad.php?t=23542. Certainly GamePlay.gpGetActors() and GamePlay.gpRemoveGroundStationarys( x, y, radius) look like they may hold some value for you.

    Regarding the sub actors (nice name) I'm not sure. If they don't fire OnActorCreated then they don't appear to be visible to the API we have. Its possible Salmo might be able to help you in this regard as it's something I've never come across and haven't had to deal with.

  8. #6
    Team Fusion Salmo's Avatar
    Join Date
    Nov 2011
    Posts
    2,332
    Post Thanks / Like
    Total Downloaded
    191.25 MB

    Re: How to delete all ground vehicles, ships, artillery, other statics in CLOD

    Here's an IGameplay extension method, just drop the TF_GamePlay extension class into your mission script:

    Code:
    public static class TF_GamePlay : IGamePlay  // extends IGamePlay functionality
    {
           public static void gpDestroyAllActors(this IGamePlay IG)
            {   // Purpose: removes all the AiActors from the game.
                // Use: GamePlay.gpDestroyAllActors();
                List<AiActor> actors = new List<AiActor>(IG.gpGetActors());
                for (int i = 0; i < actors.Count; i++)
                {
                    AiActor actor = actors[i];
                    if (actor is AiAircraft) (actor as AiAircraft).Destroy();
                    if (actor is AiGroundActor) (actor as AiGroundActor).Destroy();
                }
            }
    
            public static AiActor[] gpGetActors(this IGamePlay IG)
            {   // Purpose: Returns an array of all the AiActors in the game.
                // Use: GamePlay.gpGetActors();
                List<AiActor> result = new List<AiActor>();
                List<int> armies = new List<int>(IG.gpArmies());
                for (int i = 0; i < armies.Count; i++)
                {
                    // ground actors
                    List<AiGroundGroup> gg = new List<AiGroundGroup>(IG.gpGroundGroups(armies[i]));
                    for (int j = 0; j < gg.Count; j++)
                    {
                        List<AiActor> act = new List<AiActor>(gg[j].GetItems());
                        for (int k = 0; k < act.Count; k++) result.Add(act[k] as AiActor);
                    }
                    // air actors
                    List<AiAirGroup> airgroups = new List<AiAirGroup>(IG.gpAirGroups(armies[i]));
                    for (int j = 0; j < airgroups.Count; j++)
                    {
                        List<AiActor> act = new List<AiActor>(airgroups[j].GetItems());
                        for (int k = 0; k < act.Count; k++) result.Add(act[k] as AiActor);
                    }
                }
                return result.ToArray();
            }
    }
    called from the OnBattleStopped event like this ....

    Code:
            public override void  OnBattleStoped()
            {
     	        base.OnBattleStoped();
                    GamePlay.gpDestroyAllActors();
            }
    Last edited by Salmo; Jan-09-2017 at 01:36.

  9. #7
    Ace
    Join Date
    May 2015
    Location
    Kansas City, Missouri area
    Posts
    515
    Post Thanks / Like
    Total Downloaded
    130.02 MB

    Re: How to delete all ground vehicles, ships, artillery, other statics in CLOD

    Salmo,

    That is amazing. Thank you!

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •