Zone Manager Causing CH47 to get stuck?

Hey, sorry for the lengthy message. I am having issues where the CH47 is getting stuck mid-air after dropping its locked crate. I have spent weeks trying to figure out what the problem is. Finally, I have fixed the issue, and it seems to be ZoneManager. I used Visual Studio with the help of the built-in GitHub Copilot and made some changes to ZoneManager. After making the changes, the CH47 finally despawns properly. I could make the changes myself after each update you release, but I thought maybe you could implement in case anyone else has the issue in the future. Here is the error I get when the CH47 gets stuck:

NullReferenceException: Object reference not set to an instance of an object
at RpcTarget.NetworkGroup (System.String funcName, BaseNetworkable entity) [0x00010] in <455f496e536148ebab2f8b303602acdd>:0
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.BaseMountable.DismountPlayer_Patch0(BaseMountable,BasePlayer,bool)
at BasePlayer.EnsureDismounted () [0x0000e] in <455f496e536148ebab2f8b303602acdd>:0
at BasePlayer.OnDied (HitInfo info) [0x000e8] in <455f496e536148ebab2f8b303602acdd>:0
at ScientistNPC.OnDied (HitInfo info) [0x00000] in <455f496e536148ebab2f8b303602acdd>:0
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.BaseCombatEntity.Die_Patch0(BaseCombatEntity,HitInfo)
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.BasePlayer.Die_Patch0(BasePlayer,HitInfo)
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.BaseCombatEntity.Hurt_Patch0(BaseCombatEntity,HitInfo)
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.BasePlayer.Hurt_Patch0(BasePlayer,HitInfo)
at HumanNPC.Hurt (HitInfo info) [0x00018] in <455f496e536148ebab2f8b303602acdd>:0
at BaseCombatEntity.Hurt (System.Single amount, Rust.DamageType type, BaseEntity attacker, System.Boolean useProtection) [0x0002f] in <455f496e536148ebab2f8b303602acdd>:0
at CH47HelicopterAIController.DismountAllPlayers () [0x00040] in <455f496e536148ebab2f8b303602acdd>:0
at BaseMountable.DoServerDestroy () [0x00000] in <455f496e536148ebab2f8b303602acdd>:0
at BaseHelicopter.DoServerDestroy () [0x00007] in <455f496e536148ebab2f8b303602acdd>:0
at BaseNetworkable.DoEntityDestroy () [0x00026] in <455f496e536148ebab2f8b303602acdd>:0
at (wrapper dynamic-method) MonoMod.Utils.DynamicMethodDefinition.BaseNetworkable.Kill_Patch0(BaseNetworkable,BaseNetworkable/DestroyMode)
at CH47HelicopterAIController.DelayedKill () [0x00006] in <455f496e536148ebab2f8b303602acdd>:0
at InvokeHandlerBase`1[T].DoTick () [0x00138] in <bcfd9d22dad547c68fe65bcc93becf9c>:0
at InvokeHandlerBase`1[T].LateUpdate () [0x0001f] in <bcfd9d22dad547c68fe65bcc93becf9c>:0

Here are the changes I made that fixed the problem:

ADD TO HELPERS SECTION:
private static bool TryGetNetId(BaseNetworkable entity, out NetworkableId id)
{
    id = default;
    if (!entity || entity.IsDestroyed)
        return false;

    if (entity.net == null)
        return false;

    id = entity.net.ID;
    return true;
}

private static bool TryGetEntityZones(BaseNetworkable entity, out EntityZones ez)
{
    ez = null;
    if (!TryGetNetId(entity, out var id))
        return false;

    return zonedEntities.TryGetValue(id, out ez);
}

REPLACE:
private void OnEntityKill(BaseEntity baseEntity)
{
    if (!baseEntity || !baseEntity.IsValid() || baseEntity.IsDestroyed)
        return;

    if (!TryGetEntityZones(baseEntity, out EntityZones entityZones))
        return;

    for (int i = entityZones.Zones.Count - 1; i >= 0; i--)
    {
        Zone zone = entityZones.Zones[i];
        if (!zone)
            continue;

        zone.OnEntityExitZone(baseEntity, false, true);
    }

    if (TryGetNetId(baseEntity, out var id))
        zonedEntities.Remove(id);
}

REPLACE:
private void OnEntityEnterZone(BaseEntity baseEntity, Zone zone)
{
    if (!baseEntity || !baseEntity.IsValid())
        return;

    if (zone.HasFlag(ZoneFlags.KeepVehiclesOut) && !zone.entities.Contains(baseEntity) && zone.TryReverseVelocity(baseEntity))
    {
        BasePlayer player = (baseEntity as BaseVehicle)?.GetDriver();
        if (player)
            SendMessage(player, Message("novehiclesenter", player.UserIDString));
        return;
    }

    if (!TryGetNetId(baseEntity, out var id))
        return;

    if (!zonedEntities.TryGetValue(id, out EntityZones entityZones))
        zonedEntities[id] = entityZones = new EntityZones();

    if (!entityZones.EnterZone(zone))
        return;

    if (zone.parent)
        entityZones.UpdateFlags();
    else
        entityZones.AddFlags(zone.definition.Flags);

    zone.OnEntityEnterZone(baseEntity);

    Interface.CallHook("OnEntityEnterZone", zone.definition.Id, baseEntity);
}

private void OnEntityExitZone(BaseEntity baseEntity, Zone zone)
{
    if (!baseEntity || !baseEntity.IsValid())
        return;

    if (zone.HasFlag(ZoneFlags.KeepVehiclesOut) && zone.entities.Contains(baseEntity) && zone.TryReverseVelocity(baseEntity))
    {
        BasePlayer player = (baseEntity as BaseVehicle)?.GetDriver();
        if (player)
            SendMessage(player, Message("novehiclesleave", player.UserIDString));
        return;
    }

    if (!TryGetEntityZones(baseEntity, out EntityZones entityZones))
        return;

    entityZones.LeaveZone(zone);

    if (entityZones.ShouldRemove())
    {
        if (TryGetNetId(baseEntity, out var id))
            zonedEntities.Remove(id);
    }
    else
    {
        entityZones.UpdateFlags();
    }

    zone.OnEntityExitZone(baseEntity, !entityZones.HasFlag(ZoneFlags.NoDecay));

    Interface.CallHook("OnEntityExitZone", zone.definition.Id, baseEntity);
}

REPLACE:
public void OnEntityEnterZone(BaseEntity baseEntity)
{
    entities.Add(baseEntity);

    if (ZoneManager.TryGetNetId(baseEntity, out var id) && ZoneManager.zonedEntities.TryGetValue(id, out EntityZones entityZone))
        entityZones[id.Value] = entityZone;

    if (HasFlag(ZoneFlags.NoDecay))
    {
        DecayEntity decayEntity = baseEntity.GetComponentInParent<DecayEntity>();
        if (decayEntity)
            decayEntity.decay = null;
    }

    if (HasFlag(ZoneFlags.NoStability))
    {
        if (baseEntity is StabilityEntity entity)
            entity.grounded = true;
    }

    if (HasFlag(ZoneFlags.NpcFreeze) && baseEntity.IsNpc)
    {
        if (baseEntity is BaseAnimalNPC animalNpc) { animalNpc.brain.SetEnabled(false); return; }
        if (baseEntity is global::HumanNPC humanNpc) { humanNpc.Brain.SetEnabled(false); return; }
        if (baseEntity is ScarecrowNPC scarecrowNpc) { scarecrowNpc.Brain.SetEnabled(false); return; }
        if (baseEntity is BaseNpc npc) { npc.CancelInvoke(npc.TickAi); return; }
    }

    if (baseEntity is SmartSwitch or ElectricSwitch or RFReceiver)
    {
        ioEntities.Add((IOEntity)baseEntity);

        if (HasFlag(ZoneFlags.PoweredSwitches))
        {
            ((IOEntity)baseEntity).SetFlag(BaseEntity.Flags.Reserved8, true);
            ((IOEntity)baseEntity).currentEnergy = int.MaxValue;
        }
    }

    if (HasFlag(ZoneFlags.AlwaysLights) || (HasFlag(ZoneFlags.AutoLights) && isLightsOn))
    {
        if (baseEntity is BaseOven or SearchLight)
            ToggleLight(baseEntity, true, Configuration.AutoLights.RequiresFuel);
    }
}

public void OnEntityExitZone(BaseEntity baseEntity, bool resetDecay, bool isDead = false)
{
    entities.Remove(baseEntity);

    if (ZoneManager.TryGetNetId(baseEntity, out var id))
        entityZones.Remove(id.Value);

    if (isDead)
        return;

    if (resetDecay && HasFlag(ZoneFlags.NoDecay))
    {
        DecayEntity decayEntity = baseEntity.GetComponentInParent<DecayEntity>();
        if (decayEntity)
            decayEntity.decay = PrefabAttribute.server.Find<Decay>(decayEntity.prefabID);
    }

    if (HasFlag(ZoneFlags.NpcFreeze) && baseEntity.IsNpc)
    {
        if (baseEntity is BaseAnimalNPC animalNpc) { animalNpc.brain.SetEnabled(true); return; }
        if (baseEntity is global::HumanNPC humanNpc) { humanNpc.Brain.SetEnabled(true); return; }
        if (baseEntity is ScarecrowNPC scarecrowNpc) { scarecrowNpc.Brain.SetEnabled(true); return; }
        if (baseEntity is BaseNpc npc) { npc.InvokeRandomized(npc.TickAi, 0.1f, 0.1f, 0.00500000035f); return; }
    }

    if (baseEntity is SmartSwitch or ElectricSwitch or RFReceiver)
    {
        IOEntity ioEntity = (IOEntity)baseEntity;
        ioEntities.Remove(ioEntity);

        if (HasFlag(ZoneFlags.PoweredSwitches))
        {
            ioEntity.SetFlag(BaseEntity.Flags.Reserved8, false);
            ioEntity.currentEnergy = 0;

            for (int i = 0; i < ioEntity.inputs.Length; i++)
            {
                IOEntity fromEntity = ioEntity.inputs[i].connectedTo.Get();
                if (fromEntity)
                    fromEntity.MarkDirtyForceUpdateOutputs();
            }
        }
    }

    if (!HasFlag(ZoneFlags.AlwaysLights) && (!HasFlag(ZoneFlags.AutoLights) || !isLightsOn))
        return;

    if (baseEntity is BaseOven or SearchLight)
        ToggleLight(baseEntity, false, false);
}

REPLACE:
private bool HasEntityFlag(BaseEntity baseEntity, int flag)
{
    if (!baseEntity.IsValid())
        return false;

    return TryGetEntityZones(baseEntity, out EntityZones entityZones) && entityZones.HasFlag(flag);
}

private string[] GetEntityZoneIDs(BaseEntity entity)
{
    if (!TryGetEntityZones(entity, out EntityZones entityZones))
        return Array.Empty<string>();

    string[] array = new string[entityZones.Zones.Count];
    for (int i = 0; i < entityZones.Zones.Count; i++)
        array[i] = entityZones.Zones[i].definition.Id;

    return array;
}

private void GetEntityZoneIDsNoAlloc(BaseEntity entity, List<string> list)
{
    if (!TryGetEntityZones(entity, out EntityZones entityZones))
        return;

    foreach (Zone zone in entityZones.Zones)
        list.Add(zone.definition.Id);
}​

Nvm. It worked for awhile, now its getting stuck again

{
NullReferenceException: Object reference not set to an instance of an object
NullReferenceException: Object reference not set to an instance of an object
NullReferenceException: Object reference not set to an instance of an object
NullReferenceException: Object reference not set to an instance of an object
  at BuriedItem.Create (Item item, UnityEngine.Vector3 worldPosition, System.Int64 expiryTime) [0x000db] in <455f496e536148ebab2f8b303602acdd>:0 fps 97gc 48m39s
  at BuriedItems.Register (Item item, UnityEngine.Vector3 worldPosition) [0x0006d] in <455f496e536148ebab2f8b303602acdd>:0
  at DroppedItemContainer.BuryLeftoverItems () [0x00050] in <455f496e536148ebab2f8b303602acdd>:0
  at DroppedItemContainer.RemoveMe () [0x00010] in <455f496e536148ebab2f8b303602acdd>:0
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
DroppedItemContainer:RemoveMe()
InvokeHandlerBase`1:DoTick()
InvokeHandlerBase`1:LateUpdate()
}
{
Scarecrow[5993692] was killed by Scientist[2376732] at (-577.48, 40.96, -1668.51)
Scarecrow[5993692] was killed by Scientist[2376732] at (-577.48, 40.96, -1668.51)
Scarecrow[5993692] was killed by Scientist[2376732] at (-577.48, 40.96, -1668.51)
Scarecrow[5993692] was killed by Scientist[2376732] at (-577.48, 40.96, -1668.51)
NullReferenceException: Object reference not set to an instance of an object
NullReferenceException: Object reference not set to an instance of an object
NullReferenceException: Object reference not set to an instance of an object
NullReferenceException: Object reference not set to an instance of an object
  at BuriedItem.Create (Item item, UnityEngine.Vector3 worldPosition, System.Int64 expiryTime) [0x000db] in <455f496e536148ebab2f8b303602acdd>:0 fps 112gc 10h23m3s
  at BuriedItems.Register (Item item, UnityEngine.Vector3 worldPosition) [0x0006d] in <455f496e536148ebab2f8b303602acdd>:0
  at DroppedItemContainer.BuryLeftoverItems () [0x00050] in <455f496e536148ebab2f8b303602acdd>:0
  at DroppedItemContainer.RemoveMe () [0x00010] in <455f496e536148ebab2f8b303602acdd>:0
UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
UnityEngine.DebugLogHandler:LogException(Exception, Object)
UnityEngine.Logger:LogException(Exception, Object)
UnityEngine.Debug:LogException(Exception)
DroppedItemContainer:RemoveMe()
}

It reveals multiple problems.
As usual. Custom servers: always have problems somewhere.

RustEdit is full of items that can no longer be used. If an item breaks?
It's not announced. And what if you use that Christmas_ball or that single-sided train tunnel in your folder?
Or one of the many other items that have been rendered unusable after an update? Sorry,
it's too much for me to list them all here. Then suddenly annoying errors.
It seems they know exactly what you're using in your beautiful, custom-built server.
And then with every periodic update, they change one of the items, but only in its use.
The item isn't removed, but rendered unusable. You, as a creative developer,
then have to constantly figure out what the problem is? And then also fix it for the time it works.
As I've seen, you're very handy. But it sometimes takes an awful lot of time.
Enjoying your server becomes increasingly less enjoyable. At some point,
enjoyment quickly turns into: I have to fix this. Later, it becomes a constant problem-solving,
and valuable time comes at the expense of your social life.
Whereas starting a 5m server or a Minecraft B-rock Java cs server is a lot of work,
but it doesn't take days of bug-fixing.
Rust doesn't use NULL, as other servers do. This makes Rust unnecessarily difficult,
but especially prone to bugs and errors. Moreover, Rust servers are vulnerable.
Servers are quite easy to crash, like with Kali Linux, etc.
But hey, you're that creative, patient developer who therefore has a busy server.
Every so often, after a major update, your custom server stops running.
That's your disadvantage. Because what do people do who can't access your server?
Because it's not running? Exactly, they then visit another server that's fairly full.
If you don't want problems with your server, so you want a well-running server,
you'll have to find a website that rents servers?
Reputable websites like the link at the bottom of the Rust main menu.
Mostpeoplegiveinwhentheirhomeserverisn'trunningwellandarehappytodo
everything they can for a Rust server. The rest give up completely.
Of course, you can also just ignore the errors until more errors appear and the server stops running.
But you're that go-getter who sinks their teeth into something.
And once you sink your teeth into something, you never let go.
Success is your priority. I also believe you'll manage to solve it.
Sooner or later.

Anyway, here are some points you might be able to work with:

1) RustEdit or Generated map? Use existing save data .sav for each newly generated .map?
Or modified Edit .map? Change the .sav patch to match the update? Sometimes it works for a while,
but will eventually give errors. Perhaps this is something you can do, given your error code.

2) RustEdit, asItypedmystoryabove, there's a chance you'reusingyourownprefabsfromEdit
that have been modified without your knowledge. Readable, but no longer usable in the server.
This causes collision and NULL issues, etc. So, figure out which object it is? Always make a backup.
Delete the suspected object (prefab) and restart the server until you find it.
Downloaded custom prefabs seem harmless. They are precisely the ones that pose a major risk.
When creating a prefab with Unity, RustEdit, or Blender, etc.,
it's easy to immediately save disruptive objects invisibly. An example, but currently a real bug-causing one:
the Christmas_ball. Suppose someone creates a prefab in RustEdit and adds the Christmas_ball,
onlytohaveitburiedmilesoutofsightinthegroundonthecoast?Thenyou'll see the prefab object,
butnottheChristmas_ball. Additionally, youmightdeletetheobjectbutstillbeunable
to remove the Christmas_ball and no longer be able to find it in your RustEdit folder.

3) Update problem. Update SteamCMD and Oxide? If that doesn't help, don't blame yourself and just ignore it.
The next update will definitely solve that problem, and another one will appear. But then this problem will be solved.

4) Check your save.cfg. If you don't know how to trace obscure commands,
I'll tell you how. All the lines in the save.cfg and rust_server_start.bat should also work in your serverCMD.
Copy each line from your server.cfg one by one and enter it in your serverCMD.
However, if it says (NOT FOUND), you can remove it and try if it works in your console.
Sometimes changes are made, but then it still works in the console.
But if it doesn't work in both, then it's useless, just possible errors.

Always keep in mind that jealousy, even among developers,
is the biggest problem, and one that's rarely discussed.
Some developers briefly visit servers and are clever enough to introduce a bug.
Kali Linux is used for this. Therefore, monitor your server as closely as possible.
Checkwho's coming in and out, and for how long. And if any errors arise afterward.
Icanhonestlysayfromexperiencethatit's possible for a hacker to wipe your server or make it unusable.
Itmightseemharmless, butit's still possible for your save data to be corrupted.
This is much easier on a Rust server than on other servers.