Пример #1
0
        /// <summary>
        /// Shared (current chararacter on client, server) update of
        /// player character's stamina (every frame, called directly from PlayerCharacter).
        /// </summary>
        public static void SharedUpdate(
            ICharacter character,
            PlayerCharacterPublicState publicState,
            PlayerCharacterPrivateState privateState,
            float deltaTime)
        {
            if (!character.ServerIsOnline ||
                publicState.IsDead)
            {
                return;
            }

            var stats = publicState.CurrentStatsExtended;

            // restore stamina slower when no food or water
            var staminaRestoreMultiplier = stats.FoodCurrent == 0f || stats.WaterCurrent == 0f
                                               ? 0.33f
                                               : 1f;

            var finalStatsCache         = privateState.FinalStatsCache;
            var statStaminaRegeneration = finalStatsCache[StatName.StaminaRegenerationPerSecond];

            // update character stats
            if (publicState.AppliedInput.MoveModes != CharacterMoveModes.None)
            {
                if ((publicState.AppliedInput.MoveModes & CharacterMoveModes.ModifierRun) != 0)
                {
                    // character is running - consume stamina
                    var staminaConsumption = finalStatsCache[StatName.RunningStaminaConsumptionPerSecond]
                                             * deltaTime;
                    if (staminaConsumption > 0)
                    {
                        stats.SharedSetStaminaCurrent((float)(stats.StaminaCurrent - staminaConsumption),
                                                      notifyClient: false);
                    }

                    if (Api.IsServer)
                    {
                        // TODO: check if character really moved and not running into a wall
                        privateState.Skills.ServerAddSkillExperience <SkillAthletics>(
                            SkillAthletics.ExperienceAddWhenRunningPerSecond * deltaTime);
                    }
                }
                else // if (!privateState.Input.MoveModes.HasFlag(CharacterMoveModes.ModifierRun))
                {
                    // character is moving but not running (and client is not requested running) - restore stamina at special rate
                    var staminaRestore = StaminaRegenerationWhenMovingMultiplier
                                         * statStaminaRegeneration
                                         * staminaRestoreMultiplier
                                         * deltaTime;
                    stats.SharedSetStaminaCurrent((float)(stats.StaminaCurrent + staminaRestore), notifyClient: false);
                }
            }
            else
            {
                // character is staying - restore stamina
                var staminaRestore = statStaminaRegeneration * staminaRestoreMultiplier * deltaTime;
                stats.SharedSetStaminaCurrent((float)(stats.StaminaCurrent + staminaRestore), notifyClient: false);
            }
        }
        private static void GameInit(ICharacter character)
        {
            foreach (var child in Api.Client.UI.LayoutRootChildren)
            {
                if (child is HUDLayoutControl layoutControl)
                {
                    hudLayoutControl = layoutControl;
                }
            }
            if (hudLayoutControl != null)
            {
                hudLayoutControl.Loaded += LayoutControl_Loaded;
            }
            else
            {
                Api.Logger.Error("LPNotifications: HUDLayoutControl not found.");
            }

            stateSubscriptionStorage = new StateSubscriptionStorage();
            privateState             = PlayerCharacter.GetPrivateState(character);
            lp = privateState.Technologies.LearningPoints;
            privateState.Technologies.ClientSubscribe(
                t => t.LearningPoints,
                OnLPChanged,
                stateSubscriptionStorage);
        }
Пример #3
0
        private void SharedApplyInput(ICharacter character, PlayerCharacterPrivateState privateState)
        {
            var input = privateState.Input;

            // apply input
            privateState.Input.SetChanged(false);

            var moveModes = input.MoveModes;

            double directionX = 0, directionY = 0;

            if ((moveModes & CharacterMoveModes.Up) != 0)
            {
                directionY = 1;
            }

            if ((moveModes & CharacterMoveModes.Down) != 0)
            {
                directionY = -1;
            }

            if ((moveModes & CharacterMoveModes.Left) != 0)
            {
                directionX = -1;
            }

            if ((moveModes & CharacterMoveModes.Right) != 0)
            {
                directionX = 1;
            }

            var moveSpeed = IsServer
                                ? Server.World.GetDynamicObjectMoveSpeed(character)
                                : Client.World.GetDynamicObjectMoveSpeed(character);

            if (directionX == 0 &&
                directionY == 0)
            {
                moveSpeed = 0;
            }

            Vector2D directionVector  = (directionX, directionY);
            var      moveAcceleration = this.PhysicsBodyAccelerationCoef * moveSpeed * directionVector.Normalized;

            if (IsServer)
            {
                Server.World.SetDynamicObjectPhysicsMovement(character,
                                                             moveAcceleration,
                                                             targetVelocity: moveSpeed);
            }
            else
            {
                Client.World.SetDynamicObjectPhysicsMovement(character,
                                                             moveAcceleration,
                                                             targetVelocity: moveSpeed);
            }
        }
 /// <summary>
 /// Checks if current hotbar item is different
 /// </summary>
 public static void SharedRefreshSelectedHotbarItem(
     ICharacter character,
     PlayerCharacterPrivateState privateState)
 {
     if ((IsServer || character.IsCurrentClientCharacter) &&
         privateState.ContainerHotbar.StateHash
         != privateState.ContainerHotbarLastStateHash)
     {
         // need to refresh the selected hotbar item
         SharedSelectHotbarSlotId(character, privateState.SelectedHotbarSlotId);
     }
 }
Пример #5
0
        public void Setup(PlayerCharacterPrivateState privateState)
        {
            this.privateState     = privateState;
            this.skillsDictionary = privateState.Skills.Skills;
            this.skillsDictionary.ClientPairSet     += this.SkillsDictionaryPairSetHandler;
            this.skillsDictionary.ClientPairRemoved += this.SkillsDictionaryClientPairRemoved;

            foreach (var pair in this.skillsDictionary)
            {
                this.RegisterSkill(pair.Key, pair.Value, isInitial: true);
            }
        }
        public static void Init(ICharacter character)
        {
            ClientCurrentCharacterFinalStatsHelper.character = ClientCurrentCharacterHelper.Character;
            privateState = PlayerCharacter.GetPrivateState(character);

            subscriptionStorage?.Dispose();
            subscriptionStorage = new StateSubscriptionStorage();
            privateState.ClientSubscribe(_ => _.FinalStatsCache,
                                         _ => Api.SafeInvoke(FinalStatsCacheChanged),
                                         subscriptionStorage);

            Api.SafeInvoke(FinalStatsCacheChanged);
        }
Пример #7
0
        public ClientWorldMapBedVisualizer(WorldMapController worldMapController)
            : base(worldMapController)
        {
            this.stateSubscriptionOwner      = new StateSubscriptionStorage();
            this.playerCharacterPrivateState = ClientCurrentCharacterHelper.PrivateState;

            this.playerCharacterPrivateState.ClientSubscribe(
                _ => _.CurrentBedObjectPosition,
                _ => this.Refresh(),
                this.stateSubscriptionOwner);

            this.Refresh();
        }
Пример #8
0
        public ClientWorldMapBedVisualizer(WorldMapController worldMapController)
        {
            this.stateSubscriptionOwner      = new StateSubscriptionStorage();
            this.worldMapController          = worldMapController;
            this.playerCharacterPrivateState = Api.Client.Characters.CurrentPlayerCharacter
                                               .GetPrivateState <PlayerCharacterPrivateState>();

            this.playerCharacterPrivateState.ClientSubscribe(
                _ => _.CurrentBedObjectPosition,
                _ => this.Refresh(),
                this.stateSubscriptionOwner);

            this.Refresh();
        }
Пример #9
0
        private int GetGroundSlotCount(PlayerCharacterPrivateState playerPrivateState)
        {
            int nb = 0;

            for (byte i = PlayerConstants.InventorySlotsCount; i < playerPrivateState.ContainerInventory.SlotsCount; i++)
            {
                IItem itemToDrop = playerPrivateState.ContainerInventory.GetItemAtSlot(i);
                if (itemToDrop is not null)
                {
                    nb++;
                }
            }

            return(nb);
        }
        private void SharedApplyInput(ICharacter character, PlayerCharacterPrivateState privateState)
        {
            var input = privateState.Input;

            // apply input
            privateState.Input.SetChanged(false);

            var moveModes = input.MoveModes;

            double directionX = 0, directionY = 0;

            if ((moveModes & CharacterMoveModes.Up) != 0)
            {
                directionY = 1;
            }

            if ((moveModes & CharacterMoveModes.Down) != 0)
            {
                directionY = -1;
            }

            if ((moveModes & CharacterMoveModes.Left) != 0)
            {
                directionX = -1;
            }

            if ((moveModes & CharacterMoveModes.Right) != 0)
            {
                directionX = 1;
            }

            Vector2D directionVector = (directionX, directionY);

            var moveSpeed = IsServer
                                ? Server.Characters.GetMoveSpeed(character)
                                : Client.Characters.GetCurrentCharacterMoveSpeed();

            var moveVelocity = directionVector.Normalized * moveSpeed;

            if (IsServer)
            {
                Server.Characters.SetVelocity(character, moveVelocity);
            }
            else
            {
                Client.Characters.SetVelocity(character, moveVelocity);
            }
        }
Пример #11
0
        protected override void OnEnable()
        {
            this.Reset();

            this.subscriptionStorage = new StateSubscriptionStorage();

            this.characterPrivateState = ClientCurrentCharacterHelper.PrivateState;
            this.characterPrivateState.ClientSubscribe(_ => _.LastDismountedVehicleMapMark,
                                                       _ => this.Refresh(),
                                                       this.subscriptionStorage);

            this.characterPublicState = ClientCurrentCharacterHelper.PublicState;
            this.characterPublicState.ClientSubscribe(_ => _.CurrentVehicle,
                                                      _ => this.Refresh(),
                                                      this.subscriptionStorage);

            this.Refresh();
        }
Пример #12
0
        /// <summary>
        /// Checks if current hotbar item is different
        /// </summary>
        public static void SharedRefreshSelectedHotbarItem(
            ICharacter character,
            PlayerCharacterPrivateState privateState)
        {
            if (IsClient &&
                !character.IsCurrentClientCharacter)
            {
                // don't refresh hotbar items for other characters on client
                return;
            }

            var itemsContainer = TryGetVehicleHotbarContainer(character, out _, out _, out _)
                                 ?? privateState.ContainerHotbar;

            if (itemsContainer.StateHash != privateState.ContainerHotbarLastStateHash)
            {
                // need to refresh the selected hotbar item
                SharedForceRefreshCurrentItem(character, privateState);
            }
        }
Пример #13
0
        public void Setup(PlayerCharacterPrivateState privateState)
        {
            TechGroupsChanged = null;
            TechNodesChanged  = null;

            this.technologies = privateState.Technologies;
            this.techGroups   = this.technologies.Groups;
            this.techNodes    = this.technologies.Nodes;

            this.technologies.ClientSubscribe(
                _ => _.LearningPoints,
                _ => LearningPointsChanged?.Invoke(),
                this);

            this.techGroups.ClientAnyModification += this.TechGroupsClientAnyModificationHandler;
            this.techNodes.ClientAnyModification  += this.TechNodesClientAnyModificationHandler;

            instance = this;

            CurrentTechnologiesChanged?.Invoke();
            TechGroupsChanged?.Invoke();
            TechNodesChanged?.Invoke();
            LearningPointsChanged?.Invoke();
        }
        protected void SharedApplyInput(
            ICharacter character,
            PlayerCharacterPrivateState privateState,
            PlayerCharacterPublicState publicState)
        {
            var characterIsOffline = !character.IsOnline;

            if (characterIsOffline)
            {
                privateState.Input = default;
            }

            // please note - input is a structure so actually we're implicitly copying it here
            var input = privateState.Input;
            // please note - applied input is a class and we're getting it by reference here
            var appliedInput   = publicState.AppliedInput;
            var hasRunningFlag = (input.MoveModes & CharacterMoveModes.ModifierRun) != 0;
            var isRunning      = hasRunningFlag;

            if (isRunning)
            {
                var stats          = publicState.CurrentStatsExtended;
                var wasRunning     = (appliedInput.MoveModes & CharacterMoveModes.ModifierRun) != 0;
                var staminaCurrent = stats.StaminaCurrent;

                if (!wasRunning)
                {
                    // can start running only when the current energy is at least on 10%
                    isRunning = staminaCurrent >= 0.1 * stats.StaminaMax;
                }
                else // if was running
                {
                    // can continue to run while has energy
                    isRunning = staminaCurrent > 0;
                }

                //Logger.WriteDev($"Was running: {wasRunning}; now running: {isRunning}; stamina: {staminaCurrent}");
            }

            double moveSpeed;

            if (characterIsOffline)
            {
                moveSpeed = 0;
                isRunning = false;
            }
            else
            {
                var characterFinalStateCache = privateState.FinalStatsCache;
                moveSpeed  = characterFinalStateCache[StatName.MoveSpeed];
                moveSpeed *= ProtoTile.SharedGetTileMoveSpeedMultiplier(character.Tile);

                if (isRunning)
                {
                    var moveSpeedMultiplier = characterFinalStateCache[StatName.MoveSpeedRunMultiplier];
                    if (moveSpeedMultiplier > 0)
                    {
                        moveSpeed = moveSpeed * moveSpeedMultiplier;
                    }
                    else
                    {
                        isRunning = false;
                    }
                }
            }

            if (!isRunning)
            {
                // cannot run - remove running flag
                input.MoveModes &= ~CharacterMoveModes.ModifierRun;
            }

            if (appliedInput.MoveModes == input.MoveModes &&
                appliedInput.RotationAngleRad == input.RotationAngleRad &&
                publicState.AppliedInput.MoveSpeed == moveSpeed)
            {
                // input is not changed
                return;
            }

            // apply new input
            appliedInput.Set(input, moveSpeed);

            var moveModes = input.MoveModes;

            double directionX = 0, directionY = 0;

            if ((moveModes & CharacterMoveModes.Up) != 0)
            {
                directionY = 1;
            }

            if ((moveModes & CharacterMoveModes.Down) != 0)
            {
                directionY = -1;
            }

            if ((moveModes & CharacterMoveModes.Left) != 0)
            {
                directionX = -1;
            }

            if ((moveModes & CharacterMoveModes.Right) != 0)
            {
                directionX = 1;
            }

            Vector2D directionVector = (directionX, directionY);
            var      moveVelocity    = directionVector.Normalized * moveSpeed;

            if (IsServer)
            {
                Server.Characters.SetVelocity(character, moveVelocity);
            }
            else // if client
            {
                if (ClientCurrentCharacterLagPredictionManager.IsLagPredictionEnabled)
                {
                    Client.Characters.SetVelocity(character, moveVelocity);
                }
            }
        }
 public void Setup(PlayerCharacterPrivateState setPrivateState)
 {
     this.privateState = setPrivateState;
     this.Setup();
 }
Пример #16
0
 protected BaseActionState(ICharacter character)
 {
     this.Character             = character;
     this.CharacterPrivateState = PlayerCharacter.GetPrivateState(character);
     this.CharacterPublicState  = PlayerCharacter.GetPublicState(character);
 }
Пример #17
0
 private static void SharedForceRefreshCurrentItem(
     ICharacter character,
     PlayerCharacterPrivateState privateState)
 {
     SharedSelectHotbarSlotId(character, privateState.SelectedHotbarSlotId, isByPlayer: false);
 }
Пример #18
0
        protected void SharedApplyInput(
            ICharacter character,
            PlayerCharacterPrivateState privateState,
            PlayerCharacterPublicState publicState)
        {
            var characterIsOffline = !character.ServerIsOnline;

            if (characterIsOffline)
            {
                privateState.Input = default;
            }

            var vehicle = publicState.CurrentVehicle;

            if (vehicle is not null)
            {
                if (!vehicle.IsInitialized)
                {
                    return;
                }

                var protoVehicle = (IProtoVehicle)vehicle.ProtoGameObject;
                protoVehicle.SharedApplyInput(vehicle,
                                              character,
                                              privateState,
                                              publicState);
                return;
            }

            // please note - input is a structure so actually we're implicitly copying it here
            var input = privateState.Input;
            // please note - applied input is a class and we're getting it by reference here
            var appliedInput   = publicState.AppliedInput;
            var hasRunningFlag = (input.MoveModes & CharacterMoveModes.ModifierRun) != 0;
            var isRunning      = hasRunningFlag;

            if (isRunning)
            {
                var stats          = publicState.CurrentStatsExtended;
                var wasRunning     = (appliedInput.MoveModes & CharacterMoveModes.ModifierRun) != 0;
                var staminaCurrent = stats.StaminaCurrent;

                if (!wasRunning)
                {
                    // can start running only when the current energy is at least on 10%
                    isRunning = staminaCurrent >= 0.1 * stats.StaminaMax;
                }
                else // if was running
                {
                    // can continue to run while has energy
                    isRunning = staminaCurrent > 0;
                }

                //Logger.WriteDev($"Was running: {wasRunning}; now running: {isRunning}; stamina: {staminaCurrent}");
            }

            double moveSpeed;

            if (characterIsOffline ||
                (privateState.CurrentActionState?.IsBlockingMovement ?? false))
            {
                // offline or current action blocks movement
                moveSpeed       = 0;
                isRunning       = false;
                input.MoveModes = CharacterMoveModes.None;
            }
            else
            {
                var characterFinalStateCache = privateState.FinalStatsCache;
                moveSpeed  = characterFinalStateCache[StatName.MoveSpeed];
                moveSpeed *= ProtoTile.SharedGetTileMoveSpeedMultiplier(character.Tile);

                if (isRunning)
                {
                    if (characterFinalStateCache.HasPerk(StatName.PerkCannotRun))
                    {
                        isRunning = false;
                    }
                    else
                    {
                        var moveSpeedMultiplier = characterFinalStateCache[StatName.MoveSpeedRunMultiplier];
                        if (moveSpeedMultiplier > 0)
                        {
                            moveSpeed = moveSpeed * moveSpeedMultiplier;
                        }
                        else
                        {
                            isRunning = false;
                        }
                    }
                }
            }

            if (!isRunning)
            {
                // cannot run - remove running flag
                input.MoveModes &= ~CharacterMoveModes.ModifierRun;
            }

            if (appliedInput.MoveModes == input.MoveModes &&
                appliedInput.RotationAngleRad == input.RotationAngleRad &&
                publicState.AppliedInput.MoveSpeed == moveSpeed)
            {
                // input is not changed
                return;
            }

            // apply new input
            appliedInput.Set(input, moveSpeed);

            var moveModes = input.MoveModes;

            double directionX = 0, directionY = 0;

            if ((moveModes & CharacterMoveModes.Up) != 0)
            {
                directionY = 1;
            }

            if ((moveModes & CharacterMoveModes.Down) != 0)
            {
                directionY = -1;
            }

            if ((moveModes & CharacterMoveModes.Left) != 0)
            {
                directionX = -1;
            }

            if ((moveModes & CharacterMoveModes.Right) != 0)
            {
                directionX = 1;
            }

            if (directionX == 0 &&
                directionY == 0)
            {
                moveSpeed = 0;
            }

            Vector2D directionVector  = (directionX, directionY);
            var      moveAcceleration = directionVector.Normalized * this.PhysicsBodyAccelerationCoef * moveSpeed;

            if (IsServer)
            {
                Server.World.SetDynamicObjectPhysicsMovement(character,
                                                             moveAcceleration,
                                                             targetVelocity: moveSpeed);
                character.PhysicsBody.Friction = this.PhysicsBodyFriction;
            }
            else // if client
            {
                if (ClientCurrentCharacterLagPredictionManager.IsLagPredictionEnabled)
                {
                    Client.World.SetDynamicObjectPhysicsMovement(character,
                                                                 moveAcceleration,
                                                                 targetVelocity: moveSpeed);
                    character.PhysicsBody.Friction = this.PhysicsBodyFriction;
                }
            }
        }