public static void GenerateGungeoneerMimicBoss(AssetBundle expandSharedAssets1, GameObject aiActorObject, PlayerController sourcePlayer = null)
        {
            if (sourcePlayer == null)
            {
                sourcePlayer = GameManager.Instance.PrimaryPlayer;
            }
            if (sourcePlayer == null)
            {
                return;
            }

            tk2dSprite playerSprite = aiActorObject.AddComponent <tk2dSprite>();

            ExpandUtility.DuplicateSprite(playerSprite, (sourcePlayer.sprite as tk2dSprite));

            // If Player sprite was flipped (aka, player aiming/facing towards the left), then this could cause sprite being shifted left on AIActor.
            // Always set false to ensure this doesn't happen.
            playerSprite.FlipX = false;

            ExpandUtility.GenerateAIActorTemplate(aiActorObject, out m_CorpseObject, aiActorObject.name, System.Guid.NewGuid().ToString(), GunAttachOffset: new Vector3(0.3f, 0.25f, 0), StartingGunID: 472);

            AIActor CachedEnemyActor = aiActorObject.GetComponent <AIActor>();

            if (!aiActorObject | !CachedEnemyActor)
            {
                return;
            }

            if (ExpandStats.debugMode)
            {
                ETGModConsole.Log("Spawning '" + CachedEnemyActor.ActorName + "' with GUID: " + CachedEnemyActor.EnemyGuid + " .", false);
            }

            GameObject m_NewHandObject = new GameObject("PlayerMimicHand");
            tk2dSprite m_HandSprite    = m_NewHandObject.AddComponent <tk2dSprite>();

            ExpandUtility.DuplicateSprite(m_HandSprite, sourcePlayer.primaryHand.gameObject.GetComponent <tk2dSprite>());
            PlayerHandController m_HandController = m_NewHandObject.AddComponent <PlayerHandController>();

            m_HandController.ForceRenderersOff = false;
            m_HandController.handHeightFromGun = 0.05f;

            CachedEnemyActor.aiShooter.handObject = m_HandController;

            // Generate BossCard based on current Player.
            Texture2D BossCardForeground = ExpandUtility.FlipTexture(Instantiate(sourcePlayer.BosscardSprites[0]));
            // Mirror thing will be used as static background. (will be the same for all possible boss cards)
            Texture2D BossCardBackground = expandSharedAssets1.LoadAsset <Texture2D>("MimicInMirror_BossCardBackground");
            // Combine foreground boss card generated from PlayerController onto the static background image loased in earlier. Resolutions must match!
            Texture2D BossCardTexture = ExpandUtility.CombineTextures(BossCardBackground, BossCardForeground);



            GenericIntroDoer miniBossIntroDoer = aiActorObject.AddComponent <GenericIntroDoer>();

            aiActorObject.AddComponent <ExpandGungeoneerMimicIntroDoer>();
            miniBossIntroDoer.triggerType              = GenericIntroDoer.TriggerType.PlayerEnteredRoom;
            miniBossIntroDoer.initialDelay             = 0.15f;
            miniBossIntroDoer.cameraMoveSpeed          = 14;
            miniBossIntroDoer.specifyIntroAiAnimator   = null;
            miniBossIntroDoer.BossMusicEvent           = "Play_MUS_Boss_Theme_Beholster";
            miniBossIntroDoer.PreventBossMusic         = false;
            miniBossIntroDoer.InvisibleBeforeIntroAnim = false;
            miniBossIntroDoer.preIntroAnim             = string.Empty;
            miniBossIntroDoer.preIntroDirectionalAnim  = string.Empty;
            miniBossIntroDoer.introAnim                  = "idle";
            miniBossIntroDoer.introDirectionalAnim       = string.Empty;
            miniBossIntroDoer.continueAnimDuringOutro    = false;
            miniBossIntroDoer.cameraFocus                = null;
            miniBossIntroDoer.roomPositionCameraFocus    = Vector2.zero;
            miniBossIntroDoer.restrictPlayerMotionToRoom = false;
            miniBossIntroDoer.fusebombLock               = false;
            miniBossIntroDoer.AdditionalHeightOffset     = 0;
            miniBossIntroDoer.portraitSlideSettings      = new PortraitSlideSettings()
            {
                bossNameString          = "Dopplegunner",
                bossSubtitleString      = "Imposter!",
                bossQuoteString         = "Clone gone rogue...",
                bossSpritePxOffset      = IntVector2.Zero,
                topLeftTextPxOffset     = IntVector2.Zero,
                bottomRightTextPxOffset = IntVector2.Zero,
                bgColor = new Color(0, 0, 1, 1)
            };
            if (BossCardTexture)
            {
                miniBossIntroDoer.portraitSlideSettings.bossArtSprite = BossCardTexture;
                miniBossIntroDoer.SkipBossCard             = false;
                CachedEnemyActor.healthHaver.bossHealthBar = HealthHaver.BossBarType.MainBar;
            }
            else
            {
                miniBossIntroDoer.SkipBossCard             = true;
                CachedEnemyActor.healthHaver.bossHealthBar = HealthHaver.BossBarType.SubbossBar;
            }
            miniBossIntroDoer.HideGunAndHand        = true;
            miniBossIntroDoer.SkipFinalizeAnimation = true;
            miniBossIntroDoer.RegenerateCache();


            CachedEnemyActor.BaseMovementSpeed = 8f;
            CachedEnemyActor.MovementSpeed     = 8f;

            CachedEnemyActor.healthHaver.SetHealthMaximum(1000);
            CachedEnemyActor.healthHaver.ForceSetCurrentHealth(1000);
            CachedEnemyActor.healthHaver.overrideBossName = "Dopplegunner";
            CachedEnemyActor.healthHaver.RegenerateCache();

            CachedEnemyActor.EnemyId             = Random.Range(2000, 9999);
            CachedEnemyActor.EnemyGuid           = System.Guid.NewGuid().ToString();
            CachedEnemyActor.OverrideDisplayName = ("Dopplegunner");
            CachedEnemyActor.ActorName           = ("Dopplegunner");
            CachedEnemyActor.name = ("Dopplegunner");

            CachedEnemyActor.CanTargetEnemies = false;
            CachedEnemyActor.CanTargetPlayers = true;

            if (sourcePlayer.characterIdentity == PlayableCharacters.Bullet)
            {
                CachedEnemyActor.EnemySwitchState = "Metal_Bullet_Man";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Convict)
            {
                CachedEnemyActor.EnemySwitchState = "Convict";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.CoopCultist)
            {
                CachedEnemyActor.EnemySwitchState = "Cultist";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Cosmonaut)
            {
                CachedEnemyActor.EnemySwitchState = "Cosmonaut";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Guide)
            {
                CachedEnemyActor.EnemySwitchState = "Guide";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Gunslinger)
            {
                CachedEnemyActor.EnemySwitchState = "Gunslinger";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Ninja)
            {
                CachedEnemyActor.EnemySwitchState = "Ninja";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Pilot)
            {
                CachedEnemyActor.EnemySwitchState = "Rogue";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Robot)
            {
                CachedEnemyActor.EnemySwitchState = "Robot";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Soldier)
            {
                CachedEnemyActor.EnemySwitchState = "Marine";
            }
            else if (sourcePlayer.characterIdentity == PlayableCharacters.Eevee)
            {
                CachedEnemyActor.EnemySwitchState = "Convict";
                ExpandShaders.ApplyParadoxPlayerShader(CachedEnemyActor.sprite);
            }
            else
            {
                CachedEnemyActor.EnemySwitchState = "Gun Cultist";
            }


            ExpandGungeoneerMimicBossController playerMimicController = aiActorObject.AddComponent <ExpandGungeoneerMimicBossController>();

            playerMimicController.m_Player = sourcePlayer;

            aiActorObject.AddComponent <ExpandGungeoneerMimicDeathController>();

            if (CachedEnemyActor.GetComponent <ExpandGungeoneerMimicIntroDoer>())
            {
                GenericIntroDoer genericIntroDoer = CachedEnemyActor.gameObject.GetComponent <GenericIntroDoer>();
                FieldInfo        field            = typeof(GenericIntroDoer).GetField("m_specificIntroDoer", BindingFlags.Instance | BindingFlags.NonPublic);
                field.SetValue(genericIntroDoer, CachedEnemyActor.GetComponent <ExpandGungeoneerMimicIntroDoer>());
            }

            CachedEnemyActor.aiAnimator.enabled = false;
            CachedEnemyActor.spriteAnimator.Stop();
            CachedEnemyActor.spriteAnimator.DefaultClipId     = 0;
            CachedEnemyActor.spriteAnimator.playAutomatically = false;

            List <tk2dSpriteAnimationClip> m_AnimationClips = new List <tk2dSpriteAnimationClip>();

            foreach (tk2dSpriteAnimationClip clip in sourcePlayer.spriteAnimator.Library.clips)
            {
                if (!string.IsNullOrEmpty(clip.name))
                {
                    if (clip.name.ToLower() == "dodge")
                    {
                        m_AnimationClips.Add(clip);
                        if (clip.frames != null && clip.frames.Length > 0)
                        {
                            if (!sourcePlayer.UseArmorlessAnim)
                            {
                                CachedEnemyActor.sprite.SetSprite(clip.frames[0].spriteId);
                            }
                        }
                    }
                    else if (clip.name.ToLower() == "dodge_armorless")
                    {
                        m_AnimationClips.Add(clip);
                        if (clip.frames != null && clip.frames.Length > 0)
                        {
                            if (sourcePlayer.UseArmorlessAnim)
                            {
                                CachedEnemyActor.sprite.SetSprite(clip.frames[0].spriteId);
                            }
                        }
                    }
                    else if (clip.name.ToLower() == "run_down")
                    {
                        m_AnimationClips.Add(clip);
                    }
                    else if (clip.name.ToLower() == "run_down_armorless")
                    {
                        m_AnimationClips.Add(clip);
                    }
                    else if (clip.name.ToLower() == "death_shot")
                    {
                        m_AnimationClips.Add(clip);
                    }
                    else if (clip.name.ToLower() == "death_shot_armorless")
                    {
                        m_AnimationClips.Add(clip);
                    }
                }
            }

            if (m_AnimationClips.Count > 0)
            {
                if (!CachedEnemyActor.spriteAnimator.Library)
                {
                    CachedEnemyActor.spriteAnimator.Library = aiActorObject.AddComponent <tk2dSpriteAnimation>();
                }
                CachedEnemyActor.spriteAnimator.Library.clips = m_AnimationClips.ToArray();
            }

            CachedEnemyActor.healthHaver.RegenerateCache();

            BehaviorSpeculator customBehaviorSpeculator = aiActorObject.AddComponent <BehaviorSpeculator>();

            customBehaviorSpeculator.OverrideBehaviors               = new List <OverrideBehaviorBase>(0);
            customBehaviorSpeculator.TargetBehaviors                 = new List <TargetBehaviorBase>(0);
            customBehaviorSpeculator.MovementBehaviors               = new List <MovementBehaviorBase>(0);
            customBehaviorSpeculator.AttackBehaviors                 = new List <AttackBehaviorBase>(0);
            customBehaviorSpeculator.OtherBehaviors                  = new List <BehaviorBase>(0);
            customBehaviorSpeculator.InstantFirstTick                = false;
            customBehaviorSpeculator.TickInterval                    = 0.1f;
            customBehaviorSpeculator.PostAwakenDelay                 = 0.5f;
            customBehaviorSpeculator.RemoveDelayOnReinforce          = false;
            customBehaviorSpeculator.OverrideStartingFacingDirection = false;
            customBehaviorSpeculator.StartingFacingDirection         = -90f;
            customBehaviorSpeculator.SkipTimingDifferentiator        = false;
            customBehaviorSpeculator.RegenerateCache();

            // BehaviorSpeculator is a serialized object. You must build these lists (or create new empty lists) and save them before the game can instantiate it correctly!
            ISerializedObject m_TargetBehaviorSpeculatorSeralized = customBehaviorSpeculator;

            m_TargetBehaviorSpeculatorSeralized.SerializedObjectReferences = new List <Object>(0);
            m_TargetBehaviorSpeculatorSeralized.SerializedStateKeys        = new List <string>()
            {
                "OverrideBehaviors", "TargetBehaviors", "MovementBehaviors", "AttackBehaviors", "OtherBehaviors"
            };
            m_TargetBehaviorSpeculatorSeralized.SerializedStateValues = new List <string>()
            {
                "[]", "[]", "[]", "[]", "[]"
            };

            CachedEnemyActor.RegenerateCache();
            return;
        }
        private void DoInitialConfiguration(PlayerController player)
        {
            m_AIActor.sprite.SetSprite(player.sprite.Collection, player.sprite.GetCurrentSpriteDef().name);

            tk2dSprite m_HandSprite = m_AIActor.aiShooter.handObject.gameObject.AddComponent <tk2dSprite>();

            ExpandUtility.DuplicateSprite(m_HandSprite, player.primaryHand.gameObject.GetComponent <tk2dSprite>());
            m_AIActor.aiShooter.handObject.sprite.SetSprite(player.primaryHand.sprite.Collection, player.primaryHand.sprite.GetCurrentSpriteDef().name);

            // Generate BossCard based on current Player.
            Texture2D BossCardForeground = ExpandUtility.FlipTexture(Instantiate(player.BosscardSprites[0]));
            // Mirror thing will be used as static background. (will be the same for all possible boss cards)
            Texture2D BossCardBackground = ExpandAssets.LoadAsset <Texture2D>("MimicInMirror_BossCardBackground");
            // Combine foreground boss card generated from PlayerController onto the static background image loased in earlier. Resolutions must match!
            Texture2D BossCardTexture = ExpandUtility.CombineTextures(BossCardBackground, BossCardForeground);

            GenericIntroDoer miniBossIntroDoer = gameObject.GetComponent <GenericIntroDoer>();

            if (BossCardTexture)
            {
                miniBossIntroDoer.portraitSlideSettings.bossArtSprite = BossCardTexture;
            }

            if (player.characterIdentity == PlayableCharacters.Bullet)
            {
                m_AIActor.EnemySwitchState = "Metal_Bullet_Man";
            }
            else if (player.characterIdentity == PlayableCharacters.Convict)
            {
                m_AIActor.EnemySwitchState = "Convict";
            }
            else if (player.characterIdentity == PlayableCharacters.CoopCultist)
            {
                m_AIActor.EnemySwitchState = "Cultist";
            }
            else if (player.characterIdentity == PlayableCharacters.Cosmonaut)
            {
                m_AIActor.EnemySwitchState = "Cosmonaut";
            }
            else if (player.characterIdentity == PlayableCharacters.Guide)
            {
                m_AIActor.EnemySwitchState = "Guide";
            }
            else if (player.characterIdentity == PlayableCharacters.Gunslinger)
            {
                m_AIActor.EnemySwitchState = "Gunslinger";
            }
            else if (player.characterIdentity == PlayableCharacters.Ninja)
            {
                m_AIActor.EnemySwitchState = "Ninja";
            }
            else if (player.characterIdentity == PlayableCharacters.Pilot)
            {
                m_AIActor.EnemySwitchState = "Rogue";
            }
            else if (player.characterIdentity == PlayableCharacters.Robot)
            {
                m_AIActor.EnemySwitchState = "Robot";
            }
            else if (player.characterIdentity == PlayableCharacters.Soldier)
            {
                m_AIActor.EnemySwitchState = "Marine";
            }
            else if (player.characterIdentity == PlayableCharacters.Eevee)
            {
                m_AIActor.EnemySwitchState = "Convict";
                ExpandShaders.ApplyParadoxPlayerShader(m_AIActor.sprite);
            }
            else
            {
                m_AIActor.EnemySwitchState = "Gun Cultist";
            }
            List <tk2dSpriteAnimationClip> m_AnimationClips = new List <tk2dSpriteAnimationClip>();

            foreach (tk2dSpriteAnimationClip clip in player.spriteAnimator.Library.clips)
            {
                if (!string.IsNullOrEmpty(clip.name))
                {
                    if (clip.name.ToLower() == "dodge")
                    {
                        m_AnimationClips.Add(clip);
                        if (clip.frames != null && clip.frames.Length > 0)
                        {
                            if (!player.UseArmorlessAnim)
                            {
                                m_AIActor.sprite.SetSprite(clip.frames[0].spriteId);
                            }
                        }
                    }
                    else if (clip.name.ToLower() == "dodge_armorless")
                    {
                        m_AnimationClips.Add(clip);
                        if (clip.frames != null && clip.frames.Length > 0)
                        {
                            if (player.UseArmorlessAnim)
                            {
                                m_AIActor.sprite.SetSprite(clip.frames[0].spriteId);
                            }
                        }
                    }
                    else if (clip.name.ToLower() == "run_down")
                    {
                        m_AnimationClips.Add(clip);
                    }
                    else if (clip.name.ToLower() == "run_down_armorless")
                    {
                        m_AnimationClips.Add(clip);
                    }
                    else if (clip.name.ToLower() == "death_shot")
                    {
                        m_AnimationClips.Add(clip);
                    }
                    else if (clip.name.ToLower() == "death_shot_armorless")
                    {
                        m_AnimationClips.Add(clip);
                    }
                }
            }

            if (m_AnimationClips.Count > 0)
            {
                if (!m_AIActor.spriteAnimator.Library)
                {
                    m_AIActor.spriteAnimator.Library = m_AIActor.gameObject.AddComponent <tk2dSpriteAnimation>();
                }
                m_AIActor.spriteAnimator.Library.clips = m_AnimationClips.ToArray();
            }

            MirrorController mirror = ExpandPrefabs.CurrsedMirror.GetComponent <MirrorController>();

            MirrorBase    = Instantiate(ExpandPrefabs.DoppelgunnerMirror, gameObject.transform.position - new Vector3(0.25f, 1), Quaternion.identity);
            ShatterSystem = Instantiate(mirror.ShatterSystem, MirrorBase.transform.position, Quaternion.identity);
            ShatterSystem.SetActive(false);
            ShatterSystem.transform.parent = MirrorBase.transform;

            MirrorShatterFX = Instantiate(ExpandPrefabs.DoppelgunnerMirrorFX, (MirrorBase.transform.position - Vector3.one), Quaternion.identity);
            MirrorShatterFX.SetActive(false);
        }