winstxnhdw / lc-hax

A powerful, feature-rich and highly performant internal cheat for the co-op indie horror video game, Lethal Company.
77 stars 25 forks source link

[Bug]: Nutcracker + Snareflea Possession / Movement #386

Closed D1GQ closed 4 months ago

D1GQ commented 4 months ago

What happened?

Nutcracker:

Is there a way to make it where the Nutcracker doesn't try to go in Sentry mode at all when possessed, the way is right now the AI sometimes still tries to go in Sentry mode it makes it look very buggy.

Snareflea:

Snarefleas are currently bugged out right now for possession, you can go off this ceiling just fine but when you try to go back on the ceiling it completely breaks the Snareflea.

Off topic:

also this is completely off topic but do you think we can Implement a system to adjust the enemies movement speed depending on which enemy is possessed like the abilities?

Current Commit Hash

none

Injector

If you selected "Others" above, please specify the injector you are using.

No response

Log output

No response

Acknowledgement

winstxnhdw commented 4 months ago

I think we can ping @xAstroBoy and ask him what he thinks about this.

xAstroBoy commented 4 months ago

Yeah, the best way would to be allowing PossessionMod to completely disable the AI under a toggle as well restoring the AI control when needed, which ControlCompany Does, and PossessionMod just uses Update() to override the enemy behaviour.

also digging into each enemy , syncing the speed + the boosts from the sprint, would be a amazing idea.

We won't skid it, but this is how ControlCompany controls the enemy itself, including opening doors and such, would be awesome if we can incorporate it's feature including a way to sync the enemy speed with each animation and such and fix the camera better

And digging into each inherited enemies, they use Update() to lock it into a behaviour, not to the end of a frame.


using System;
using ControlCompany.Core.Config;
using ControlCompany.Core.Extentions;
using UnityEngine;
using UnityEngine.AI;

namespace ControlCompany.Core
{
    internal class EnemyController : CustomPlayerController
    {
        public bool IsAIControlled
        {
            get
            {
                return this.isAIControlled;
            }
        }

        public EnemyAI EnemyAI
        {
            get
            {
                return this.enemyAI;
            }
        }

        public virtual void InitializeEnemyController(PlayerActions playerActions, GameObject enemyGameObject)
        {
            bool isInitialized = this.isInitialized;
            if (!isInitialized)
            {
                base.Initialize(playerActions, CustomPlayerController.CameraMode.THIRD_PERSON);
                CharacterController characterController = this.characterController;
                characterController.excludeLayers &= ~Constants.ITERACTABLE_OBJ_LAYER;
                this.enemyAI = this.GetEnemyAIFromEnemyGameObject(enemyGameObject);
                bool flag = this.enemyAI == null;
                if (flag)
                {
                    throw new Exception("Enemy gameobject does not have EnemyAI script attacked.");
                }
                this.enemyAI.gameObject.LogLayer();
                enemyGameObject.transform.position = base.transform.position;
                enemyGameObject.transform.rotation = base.transform.rotation;
                this.enemyGameObject = enemyGameObject;
                this.enemyAIAgent = enemyGameObject.GetComponentInChildren<NavMeshAgent>();
                this.originalAgentAngularSpeed = this.enemyAIAgent.angularSpeed;
                this.originalAgentSpeed = this.enemyAIAgent.speed;
                this.ConfigureEnemyAttributes(this.enemyAI);
                this.EnableAIControl(false);
            }
        }

        protected EnemyAI GetEnemyAIFromEnemyGameObject(GameObject enemyObj)
        {
            return enemyObj.GetComponentInChildren<EnemyAI>();
        }

        private void ConfigureEnemyAttributes(EnemyAI enemyAI)
        {
            EnemyAttributes enemyAttributes = enemyAI.GetEnemyAttributes();
            base.WalkSpeed = enemyAttributes.WalkSpeed;
            base.RunSpeed = enemyAttributes.RunSpeed;
            base.SetCamDistance(enemyAttributes.CamDistance);
            base.SetCamHeight(enemyAttributes.CamHeight);
            this.controlEnemyRotation = enemyAttributes.PlayerControlsRotation;
            this.controlEnemyMovement = true;
        }

        protected virtual void ConfigureEnemyHandicap(EnemyAI enemyAI)
        {
        }

        protected override void Update()
        {
            bool flag = !this.isInitialized;
            if (!flag)
            {
                base.Update();
                bool flag2 = !this.isAIControlled;
                if (flag2)
                {
                    bool flag3 = !this.enemyAI.isEnemyDead;
                    if (flag3)
                    {
                        bool flag4 = this.controlEnemyMovement;
                        if (flag4)
                        {
                            this.enemyGameObject.transform.position = base.transform.position;
                        }
                        bool flag5 = this.controlEnemyRotation && !this.lockEnemyRotationInput;
                        if (flag5)
                        {
                            this.enemyGameObject.transform.rotation = base.transform.rotation;
                        }
                    }
                }
                else
                {
                    base.transform.position = this.enemyGameObject.transform.position;
                }
            }
        }

        protected override void Move()
        {
            bool flag = !this.enemyAI.isEnemyDead;
            if (flag)
            {
                base.Move();
            }
        }

        public void SetLockEnemyRotation(bool lockEnemyRotationInput)
        {
            this.lockEnemyRotationInput = lockEnemyRotationInput;
        }

        public virtual void UsePrimarySkill()
        {
            this.CheckInitialized();
            bool flag = this.isAIControlled;
            if (flag)
            {
            }
        }

        public virtual void ReleasePrimarySkill()
        {
            this.CheckInitialized();
            bool flag = this.isAIControlled;
            if (flag)
            {
            }
        }

        public virtual void UseSecondarySkill()
        {
            this.CheckInitialized();
            bool flag = this.isAIControlled;
            if (!flag)
            {
                this.enemyAI.SwitchToBehaviourState(1);
            }
        }

        public virtual void ReleaseSecondarySkill()
        {
            this.CheckInitialized();
            bool flag = this.isAIControlled;
            if (flag)
            {
            }
        }

        public void SwitchAIState(int stateIndex)
        {
            this.CheckInitialized();
            bool flag = this.isAIControlled;
            if (!flag)
            {
                this.enemyAI.SwitchToBehaviourState(stateIndex);
            }
        }

        protected virtual void EnableAIControl(bool enabled)
        {
            this.CheckInitialized();
            this.isAIControlled = enabled;
            ControlCompanyPlugin.Instance.logger.LogMessage(string.Format("Enable AI control: {0}", enabled));
            bool flag = this.IsAIControlled;
            if (flag)
            {
                this.enemyAIAgent.angularSpeed = this.originalAgentAngularSpeed;
                this.enemyAIAgent.speed = this.originalAgentSpeed;
                this.enemyAIAgent.isStopped = false;
            }
            else
            {
                this.enemyAI.ChangeOwnershipOfEnemy(ControlCenter.Instance.GetHostPlayer().actualClientId);
                this.enemyAIAgent.angularSpeed = 0f;
                this.enemyAIAgent.speed = 0f;
                this.enemyAIAgent.isStopped = true;
                base.transform.SetParent(null);
            }
            this.canMove = !this.isAIControlled;
        }

        public void ToggleAIControl()
        {
            this.CheckInitialized();
            this.isAIControlled = !this.isAIControlled;
            this.EnableAIControl(this.isAIControlled);
        }

        public virtual void DestroyAndCleanUp()
        {
            bool flag = !this.enemyAI.isEnemyDead;
            if (flag)
            {
                UnityEngine.Object.Destroy(this.enemyGameObject);
            }
            UnityEngine.Object.Destroy(base.gameObject);
        }

        public virtual string GetPrimarySkillName()
        {
            return "";
        }

        public virtual string GetSecondarySkillName()
        {
            return "Secondary Skill";
        }

        protected void CheckInitialized()
        {
            bool flag = !this.isInitialized;
            if (flag)
            {
                throw new Exception("Not initialized yet.");
            }
        }

        protected virtual void OnControllerColliderHit(ControllerColliderHit hit)
        {
            DoorLock component = hit.gameObject.GetComponent<DoorLock>();
            bool flag = component != null;
            if (flag)
            {
                this.doorOpener.OpenDoor(component);
            }
        }

        protected GameObject enemyGameObject;

        private EnemyAI enemyAI;

        private NavMeshAgent enemyAIAgent;

        private float originalAgentAngularSpeed;

        private float originalAgentSpeed;

        private float rotationSpeed = 5f;

        protected bool isAIControlled = false;

        protected bool controlEnemyRotation = false;

        protected bool controlEnemyMovement = true;

        protected bool lockEnemyRotationInput = false;
    }
}
xAstroBoy commented 4 months ago

@winstxnhdw using agent.speed would do the trick, as well you need to fix the collision system, why you dont use the enemy collider itself?

winstxnhdw commented 4 months ago

because anything to do with agents suck. you can't even reliably disable it: https://docs.unity3d.com/ScriptReference/AI.NavMeshAgent.html

xAstroBoy commented 4 months ago

because anything to do with agents suck. you can't even reliably disable it: https://docs.unity3d.com/ScriptReference/AI.NavMeshAgent.html

Actually you can, controlcompany sets isStopped , that completely disables the NavMeshAgent but still leave it’s functionalities available

xAstroBoy commented 4 months ago

‘’’

    protected virtual void EnableAIControl(bool enabled)
    {
        this.CheckInitialized();
        this.isAIControlled = enabled;
        ControlCompanyPlugin.Instance.logger.LogMessage(string.Format("Enable AI control: {0}", enabled));
        bool flag = this.IsAIControlled;
        if (flag)
        {
            this.enemyAIAgent.angularSpeed = this.originalAgentAngularSpeed;
            this.enemyAIAgent.speed = this.originalAgentSpeed;
            this.enemyAIAgent.isStopped = false;
        }
        else
        {
            this.enemyAI.ChangeOwnershipOfEnemy(ControlCenter.Instance.GetHostPlayer().actualClientId);
            this.enemyAIAgent.angularSpeed = 0f;
            this.enemyAIAgent.speed = 0f;
            this.enemyAIAgent.isStopped = true;
            base.transform.SetParent(null);
        }
        this.canMove = !

‘’’

winstxnhdw commented 4 months ago

Yeah, I have tried that. It's not working for me for some reason.

xAstroBoy commented 4 months ago

Yeah, I have tried that. It's not working for me for some reason.

Works well for me, try again? , either way instead of using charactercontroller blank collider just parent it into the enemy itself when is being run?

winstxnhdw commented 4 months ago

CharacterController will always have its own collider though?

xAstroBoy commented 4 months ago

CharacterController will always have its own collider though?

Before parenting it, strip it from that charactercontroller?

winstxnhdw commented 4 months ago

Sure, I'll give it a try.

xAstroBoy commented 4 months ago

i was able to sync the charactercontroller speed by exposing the speed variable and putting a line in update to use that variable in charactercontroller.Speed = agent.speed, also i am working on a spring controller as well

xAstroBoy commented 4 months ago

392 @winstxnhdw @D1GQ i took my time and actually implemented a bunch of features for PossessionMod, have a look.

Managed to preserve all the colliders and adjust perfectly the CharacterController's collision and make it ignore the enemy's one.

D1GQ commented 4 months ago

I'll definitely check it out when I can.

xAstroBoy commented 4 months ago

I'll definitely check it out when I can.

just figured did not need the collider calculation, not disabling the enemy colliders might be enough, and just a big enough collider for the controller to not phase thru the various map structure would work.

winstxnhdw commented 4 months ago

Let me know how it goes. I won’t have time to try it out for a while.

D1GQ commented 4 months ago

Let me know how it goes. I won’t have time to try it out for a while.

Seems pretty nice so far, do you think you can also make it where the Nutcracker has to reload after shooting two times?

D1GQ commented 4 months ago

But there seems to be a bug where you're not able to move when entering and leaving the factory, also would be nice if you have to use the trigger mod too leave an enter instead of it randomly just dragging you.

xAstroBoy commented 4 months ago

But there seems to be a bug where you're not able to move when entering and leaving the factory, also would be nice if you have to use the trigger mod too leave an enter instead of it randomly just dragging you.

I fixed it a hour ago, try with the latest changes

D1GQ commented 4 months ago

I fixed it a hour ago, try with the latest changes

I just downloaded it not even 30 minutes ago it was happening to me with the puffer

xAstroBoy commented 4 months ago

I fixed it a hour ago, try with the latest changes

I just downloaded it not even 30 minutes ago it was happening to me with the puffer

weird, i was 3h trying to fix it , i thought i did, try redownloading or ill try to fix it tomorrow

D1GQ commented 4 months ago

Controlling enemies seems to work fine until you run into another player, it seems that when the AI tries to take over, you pause randomly when you try to move.

xAstroBoy commented 4 months ago

Controlling enemies seems to work fine until you run into another player, it seems that when the AI tries to take over, you pause randomly when you try to move.

That’s spring behaviour, im working on overriding the locks

winstxnhdw commented 4 months ago

Completed in latest.