protected virtual void ServerUpdateInstalledImplant(ServerUpdateData data) { }
protected override void ServerUpdate(ServerUpdateData data) { this.ServerTryConsumeInputItem(data.PrivateState); base.ServerUpdate(data); }
protected override void ServerUpdate(ServerUpdateData data) { var worldObject = data.GameObject; var privateState = data.PrivateState; var objectDepletedDeposit = ObjectDepletedDeposit.SharedGetDepletedDepositWorldObject(worldObject.OccupiedTile); var objectDeposit = this.SharedGetDepositWorldObject(worldObject.OccupiedTile); var fuelBurningState = privateState.FuelBurningState; if (objectDepletedDeposit is not null) { // this is a depleted deposit - stop extraction data.PublicState.IsActive = false; privateState.LiquidContainerState.Amount = 0; if (fuelBurningState is not null) { fuelBurningState.FuelUseTimeRemainsSeconds = 0; } return; } var isActive = false; var isFull = privateState.LiquidContainerState.Amount >= this.LiquidContainerConfig.Capacity; if (fuelBurningState is null) { // no fuel burning state if (this.ElectricityConsumptionPerSecondWhenActive <= 0) { // no fuel burning and no electricity consumption - always active isActive = true; } else { // Consuming electricity. // Active only if electricity state is on and has active recipe. var publicState = data.PublicState; if (publicState.ElectricityConsumerState == ElectricityConsumerState.PowerOnActive) { isActive = !isFull; } } } else { // Please note: fuel is used only to produce oil. // Fuel is not used for "petroleum canister" crafting. FuelBurningMechanic.Update( worldObject, fuelBurningState, byproductsCraftQueue: null, this.ManufacturingConfig, data.DeltaTime * FuelBurningSpeedMultiplier, byproductsQueueRate: 1, isNeedFuelNow: !isFull); var isFuelBurning = fuelBurningState.FuelUseTimeRemainsSeconds > 0; isActive = isFuelBurning; } data.PublicState.IsActive = isActive; LiquidContainerSystem.UpdateWithManufacturing( worldObject, data.PrivateState.LiquidContainerState, this.LiquidContainerConfig, data.PrivateState.ManufacturingState, this.ManufacturingConfig, data.DeltaTime * SharedGetSpeedMultiplier(objectDeposit), // the pump produce petroleum only when active isProduceLiquid: data.PublicState.IsActive, forceUpdateRecipe: true); }
protected override void ServerUpdate(ServerUpdateData data) { //var character = data.GameObject; //this.SharedApplyInput(character, data.PrivateState); }
protected override void ServerUpdate(ServerUpdateData data) { var worldObject = data.GameObject; var deltaTime = data.DeltaTime; var privateState = data.PrivateState; var manufacturingStateRawPetroleum = data.PrivateState.ManufacturingState; var manufacturingStateProcessedGasoline = data.PrivateState.ManufacturingStateGasoline; var manufacturingStateProcessedMineralOil = data.PrivateState.ManufacturingStateMineralOil; var liquidStateRawPetroleum = privateState.LiquidStateRawPetroleum; var liquidStateProcessedGasoline = privateState.LiquidStateGasoline; var liquidStateProcessedMineralOil = privateState.LiquidStateMineralOil; // Force update all recipes: // it will auto-detect and verify current recipes for every crafting queue. var isLiquidStatesChanged = privateState.IsLiquidStatesChanged; ManufacturingMechanic.UpdateRecipeOnly( worldObject, manufacturingStateRawPetroleum, this.ManufacturingConfig, force: isLiquidStatesChanged); ManufacturingMechanic.UpdateRecipeOnly( worldObject, manufacturingStateProcessedGasoline, this.ManufacturingConfigGasoline, force: isLiquidStatesChanged); ManufacturingMechanic.UpdateRecipeOnly( worldObject, manufacturingStateProcessedMineralOil, this.ManufacturingConfigMineralOil, force: isLiquidStatesChanged); privateState.IsLiquidStatesChanged = false; // Update fuel state: // need fuel when any of the output liquids capacity are not full // or any of the manufacturing states has active recipe. var isOutputLiquidCapacityFull = liquidStateProcessedGasoline.Amount >= this.LiquidConfigGasoline.Capacity || liquidStateProcessedMineralOil.Amount >= this.LiquidConfigMineralOil.Capacity; var isNeedElectricityNow = !isOutputLiquidCapacityFull && liquidStateRawPetroleum.Amount > 0; // Consuming electricity. // Active only if electricity state is on and has active recipe. var isActive = false; var publicState = data.PublicState; if (publicState.ElectricityConsumerState == ElectricityConsumerState.PowerOnActive) { isActive = isNeedElectricityNow; } // set IsActive flag in public state - this is used to play sound and animation on client data.PublicState.IsActive = isActive; // Update crafting queue for raw petroleum: // on complete it will consume petroleum canister (if available), increase oil level, produce empty canister. ManufacturingMechanic.UpdateCraftingQueueOnly(manufacturingStateRawPetroleum, deltaTime); if (isActive) // process liquids (consume raw petroleum and produce gasoline and mineral oil) { // apply extraction rate multiplier (it applies to oil refinery production rate) var deltaTimeLiquidProcessing = deltaTime; deltaTimeLiquidProcessing *= StructureConstants.ManufacturingSpeedMultiplier; // active, we can "transfer" liquids and progress crafting queues for processed liquids // try transfer ("use") raw petroleum bar LiquidContainerSystem.UpdateWithoutManufacturing( liquidStateRawPetroleum, this.LiquidConfigRawPetroleum, deltaTimeLiquidProcessing, // petroleum is not produced via this system (it's produced on recipe completion) isProduceLiquid: false, // use petroleum liquid if other capacities are not full isUseRequested: !isOutputLiquidCapacityFull, wasUsed: out var wasUsedPetroleum, resetAmountToZeroWhenNotEnoughToUse: true); if (wasUsedPetroleum) { // increase gasoline level (if possible) LiquidContainerSystem.UpdateWithoutManufacturing( liquidStateProcessedGasoline, this.LiquidConfigGasoline, deltaTimeLiquidProcessing, isProduceLiquid: true, isUseRequested: false, wasUsed: out _); // increase mineral oil level (if possible) LiquidContainerSystem.UpdateWithoutManufacturing( liquidStateProcessedMineralOil, this.LiquidConfigMineralOil, deltaTimeLiquidProcessing, isProduceLiquid: true, isUseRequested: false, wasUsed: out _); // this flag is required to force recipes checking on next iteration privateState.IsLiquidStatesChanged = true; } } // progress crafting queues for processed liquids (craft canisters with according liquids) ManufacturingMechanic.UpdateCraftingQueueOnly(manufacturingStateProcessedGasoline, deltaTime); ManufacturingMechanic.UpdateCraftingQueueOnly(manufacturingStateProcessedMineralOil, deltaTime); }
protected override void ServerUpdate(ServerUpdateData data) { var worldObject = data.GameObject; var deltaTime = data.DeltaTime; var privateState = data.PrivateState; var fuelBurningState = privateState.FuelBurningState; var manufacturingStateRawPetroleum = data.PrivateState.ManufacturingState; var manufacturingStateProcessedGasoline = data.PrivateState.ManufacturingStateGasoline; var manufacturingStateProcessedMineralOil = data.PrivateState.ManufacturingStateMineralOil; var liquidStateRawPetroleum = privateState.LiquidStateRawPetroleum; var liquidStateProcessedGasoline = privateState.LiquidStateGasoline; var liquidStateProcessedMineralOil = privateState.LiquidStateMineralOil; // Force update all recipes: // it will auto-detect and verify current recipes for every crafting queue. var isLiquidStatesChanged = privateState.IsLiquidStatesChanged; ManufacturingMechanic.UpdateRecipeOnly( worldObject, manufacturingStateRawPetroleum, this.ManufacturingConfig, force: isLiquidStatesChanged); ManufacturingMechanic.UpdateRecipeOnly( worldObject, manufacturingStateProcessedGasoline, this.ManufacturingConfigGasoline, force: isLiquidStatesChanged); ManufacturingMechanic.UpdateRecipeOnly( worldObject, manufacturingStateProcessedMineralOil, this.ManufacturingConfigMineralOil, force: isLiquidStatesChanged); privateState.IsLiquidStatesChanged = false; // Update fuel state: // need fuel when processed liquids capacities are not full // or any of the manufacturing states has active recipe. var isLiquidsCapacitiesFull = liquidStateProcessedGasoline.Amount >= this.LiquidConfigGasoline.Capacity && liquidStateProcessedMineralOil.Amount >= this.LiquidConfigMineralOil.Capacity; var isNeedFuelNow = (!isLiquidsCapacitiesFull && liquidStateRawPetroleum.Amount > 0) || manufacturingStateProcessedGasoline.HasActiveRecipe || manufacturingStateProcessedMineralOil.HasActiveRecipe; // update fuel burning progress FuelBurningMechanic.Update( worldObject, fuelBurningState, privateState.FuelBurningByproductsQueue, this.ManufacturingConfig, data.DeltaTime, isNeedFuelNow, forceRefreshFuel: isLiquidStatesChanged); var isFuelBurning = fuelBurningState.FuelUseTimeRemainsSeconds > 0; // set IsActive flag in public state - this is used to play sound and animation on client data.PublicState.IsManufacturingActive = isFuelBurning; // Update crafting queue for raw petroleum: // on complete it will consume petroleum canister (if available), increase oil level, produce empty canister. ManufacturingMechanic.UpdateCraftingQueueOnly(manufacturingStateRawPetroleum, deltaTime); if (!isFuelBurning) { // cannot progress while fuel is not burning return; } // fuel is burning, we can "transfer" liquids and progress crafting queues for processed liquids // try transfer ("use") raw petroleum bar LiquidContainerSystem.UpdateWithoutManufacturing( liquidStateRawPetroleum, this.LiquidConfigRawPetroleum, deltaTime, // petroleum is not produced via this system (it's produced on recipe completion) isProduceLiquid: false, // use petroleum liquid if other capacities are not full isUseRequested: !isLiquidsCapacitiesFull, wasUsed: out var wasUsedPetroleum, resetAmountToZeroWhenNotEnoughToUse: true); if (wasUsedPetroleum) { // increase gasoline level (if possible) LiquidContainerSystem.UpdateWithoutManufacturing( liquidStateProcessedGasoline, this.LiquidConfigGasoline, deltaTime, isProduceLiquid: true, isUseRequested: false, wasUsed: out _); // increase mineral oil level (if possible) LiquidContainerSystem.UpdateWithoutManufacturing( liquidStateProcessedMineralOil, this.LiquidConfigMineralOil, deltaTime, isProduceLiquid: true, isUseRequested: false, wasUsed: out _); // this flag is required to force recipes checking on next iteration privateState.IsLiquidStatesChanged = true; } // progress crafting queues for processed liquids (craft canisters with according liquids) ManufacturingMechanic.UpdateCraftingQueueOnly(manufacturingStateProcessedGasoline, deltaTime); ManufacturingMechanic.UpdateCraftingQueueOnly(manufacturingStateProcessedMineralOil, deltaTime); }
protected override void ServerUpdate(ServerUpdateData data) { var worldObject = data.GameObject; var publicState = data.PublicState; var itemsContainer = publicState.ItemsContainer; var hasItems = itemsContainer.OccupiedSlotsCount > 0; var isTimedOut = false; if (hasItems) { var timeNow = Server.Game.FrameTime; if (publicState.ItemsContainerLastHash != publicState.ItemsContainer.StateHash) { // items container updated - try to extend the timeout publicState.DestroyAtTime = Math.Max(publicState.DestroyAtTime, timeNow + AutoDestroyTimeoutSeconds); publicState.ItemsContainerLastHash = publicState.ItemsContainer.StateHash; } else { // there are items - check timeout isTimedOut = timeNow >= publicState.DestroyAtTime; if (isTimedOut) { // should destroy because timed out if (Server.World.IsObservedByAnyPlayer(worldObject)) { // cannot destroy - there are players observing it isTimedOut = false; publicState.DestroyAtTime = timeNow + AutoDestroyPostponeSeconds; } } } if (!isTimedOut) { return; } } // don't have items or timeout reached Logger.Important( "Destroying ground container at " + worldObject.TilePosition + (isTimedOut ? " - timed out" : " - contains no items")); if (data.PrivateState.ServerLastInteractCharacter != null) { // notify other players that the ground items were picked up using (var scopedBy = Api.Shared.GetTempList <ICharacter>()) { Server.World.GetScopedByPlayers(worldObject, scopedBy); scopedBy.Remove(data.PrivateState.ServerLastInteractCharacter); this.CallClient(scopedBy, _ => _.ClientRemote_OtherPlayerPickedUp(worldObject.TilePosition)); } } // actually destroy it publicState.ItemsContainer = null; Server.World.DestroyObject(worldObject); }
public override double ServerUpdateIntervalSeconds => 0; // every frame protected override void ServerUpdate(ServerUpdateData data) { Instance.ServerUpdate(); }
protected override void ServerUpdate(ServerUpdateData data) { var privateState = data.PrivateState; var manufacturingState = privateState.ManufacturingState; var worldObject = data.GameObject; // update active recipe ManufacturingMechanic.UpdateRecipeOnly( worldObject, manufacturingState, this.ManufacturingConfig); var hasActiveRecipe = manufacturingState.HasActiveRecipe; var isActive = false; var fuelBurningState = privateState.FuelBurningState; if (fuelBurningState == null) { // no fuel burning state if (this.ElectricityConsumptionPerSecondWhenActive <= 0) { // no fuel burning and no electricity consumption - always active isActive = true; } else { // Consuming electricity. // Active only if electricity state is on and has active recipe. var publicState = data.PublicState; if (publicState.ElectricityConsumerState == ElectricityConsumerState.PowerOn) { isActive = hasActiveRecipe && !manufacturingState.CraftingQueue.IsContainerOutputFull; } } } else { // progress fuel burning FuelBurningMechanic.Update( worldObject, fuelBurningState, privateState.FuelBurningByproductsQueue, this.ManufacturingConfig, deltaTime: data.DeltaTime, byproductsQueueRate: StructureConstants.ManufacturingSpeedMultiplier, isNeedFuelNow: hasActiveRecipe && !manufacturingState.CraftingQueue.IsContainerOutputFull); // active only when fuel is burning isActive = fuelBurningState.FuelUseTimeRemainsSeconds > 0; } data.PublicState.IsActive = isActive; if (isActive && hasActiveRecipe) { // progress crafting ManufacturingMechanic.UpdateCraftingQueueOnly( manufacturingState, deltaTime: data.DeltaTime * StructureConstants.ManufacturingSpeedMultiplier * this.ManufacturingSpeedMultiplier); // it's important to synchronize this property here // (because rollback might happen due to unable to spawn output items and container hash will be changed) // TODO: this is hack and we need a better way to track whether the container was actually changed or a better way to update the last state hash. manufacturingState.ContainerOutputLastStateHash = manufacturingState.CraftingQueue.ContainerOutputLastStateHash; } }
protected virtual void ServerUpdateMob(ServerUpdateData data) { }
protected override void ServerUpdate(ServerUpdateData data) { base.ServerUpdate(data); var objectDrone = data.GameObject; var privateState = data.PrivateState; var publicState = data.PublicState; if (privateState.AssociatedItem is null) { // incorrectly configured drone Server.World.DestroyObject(objectDrone); return; } if (privateState.IsDespawned) { return; } UpdateWeaponCooldown(); Vector2D destinationCoordinate; var characterOwner = privateState.CharacterOwner; var hasMiningTargets = publicState.TargetObjectPosition.HasValue; if (hasMiningTargets && !(CharacterDroneControlSystem.SharedIsValidDroneOperationDistance(objectDrone.TilePosition, characterOwner.TilePosition) && objectDrone.Tile.Height == characterOwner.Tile.Height)) { Logger.Info("The drone is beyond operation distance or has different tile height and will be recalled: " + objectDrone); CharacterDroneControlSystem.ServerRecallDrone(objectDrone); hasMiningTargets = false; } if (hasMiningTargets) { // go to the next waypoint destinationCoordinate = publicState.TargetDronePosition ?? publicState.TargetObjectPosition.Value.ToVector2D(); if (!CharacterDroneControlSystem.ServerIsMiningAllowed( publicState.TargetObjectPosition.Value, objectDrone)) { // cannot mine as it's already mined by another drone publicState.ResetTargetPosition(); return; } } else { // should return to the player to despawn if (characterOwner is null || characterOwner.GetPublicState <ICharacterPublicState>().IsDead || CharacterDroneControlSystem.SharedIsBeyondDroneAbandonDistance( objectDrone.TilePosition, characterOwner.TilePosition)) { CharacterDroneControlSystem.ServerDeactivateDrone(objectDrone); return; } destinationCoordinate = characterOwner.Position; } RefreshMovement(isToMineral: hasMiningTargets, destinationCoordinate, out var isDestinationReached); if (!isDestinationReached) { return; } if (hasMiningTargets) { PerformMining(); } else { // we were going to the player and reached its location, despawn ServerOnDroneReturnedToPlayer(objectDrone); } void RefreshMovement( bool isToMineral, Vector2D toPosition, out bool isDestinationReached) { var positionDelta = toPosition - objectDrone.Position; var positionDeltaLength = positionDelta.Length; double targetVelocity; if (positionDeltaLength > (isToMineral ? DistanceThresholdToMineral : DistanceThresholdToPlayer)) { // fly towards that object targetVelocity = this.StatMoveSpeed; isDestinationReached = false; // reduce speed when too close to the target var distanceCoef = positionDeltaLength / (0.5 * targetVelocity); if (distanceCoef < 1) { targetVelocity *= Math.Pow(distanceCoef, 0.5); // ensure it cannot drop lower than 5% of the original move speed targetVelocity = Math.Max(0.05 * this.StatMoveSpeed, targetVelocity); } } else { isDestinationReached = true; // stop if (Server.World.GetDynamicObjectMoveSpeed(objectDrone) == 0) { // already stopped return; } targetVelocity = 0; } var movementDirectionNormalized = positionDelta.Normalized; var moveAcceleration = movementDirectionNormalized * this.PhysicsBodyAccelerationCoef * targetVelocity; Server.World.SetDynamicObjectMoveSpeed(objectDrone, targetVelocity); Server.World.SetDynamicObjectPhysicsMovement(objectDrone, moveAcceleration, targetVelocity: targetVelocity); objectDrone.PhysicsBody.Friction = this.PhysicsBodyFriction; } void PerformMining() { var targetObject = CharacterDroneControlSystem.SharedGetCompatibleTarget( characterOwner, publicState.TargetObjectPosition.Value, out _, out _); if (targetObject is null || !WorldObjectClaimSystem.SharedIsAllowInteraction(characterOwner, targetObject, showClientNotification: false)) { // nothing to mine there, or finished mining, or cannot mine CharacterDroneControlSystem.ServerUnregisterCurrentMining( publicState.TargetObjectPosition.Value, objectDrone); publicState.ResetTargetPosition(); return; } if (privateState.WeaponCooldownSecondsRemains > 0) { return; } if (!CharacterDroneControlSystem.ServerTryRegisterCurrentMining( publicState.TargetObjectPosition.Value, objectDrone)) { // cannot mine as it's already mined by another drone publicState.ResetTargetPosition(); return; } publicState.IsMining = true; var protoMiningTool = this.ProtoItemMiningTool; privateState.WeaponCooldownSecondsRemains += Api.Shared.RoundDurationByServerFrameDuration(protoMiningTool.FireInterval); var characterFinalStatsCache = characterOwner.SharedGetFinalStatsCache(); var weaponFinalCache = privateState.WeaponFinalCache; if (weaponFinalCache is null || !privateState.LastCharacterOwnerFinalStatsCache.CustomEquals(characterFinalStatsCache)) { weaponFinalCache = ServerCreateWeaponFinalCacheForDrone(characterOwner, protoMiningTool, objectDrone); privateState.WeaponFinalCache = weaponFinalCache; privateState.LastCharacterOwnerFinalStatsCache = characterFinalStatsCache; } var protoWorldObject = (IDamageableProtoWorldObject)targetObject.ProtoGameObject; protoWorldObject.SharedOnDamage( weaponFinalCache, targetObject, damagePreMultiplier: 1, damagePostMultiplier: 1, obstacleBlockDamageCoef: out _, damageApplied: out var damageApplied); // reduce drone durability on 1 unit (reflected as HP when it's a world object) // but ensure the new HP cannot drop to exact 0 (to prevent destruction while mining) var newHP = publicState.StructurePointsCurrent - 1 * LazyProtoItemDrone.Value.DurabilityToStructurePointsConversionCoefficient; publicState.StructurePointsCurrent = Math.Max(float.Epsilon, (float)newHP); if (damageApplied <= 0) { // cannot mine there for whatever reason, recall the drone publicState.ResetTargetPosition(); } this.ServerSendMiningSoundCue(objectDrone, characterOwner); } void UpdateWeaponCooldown() { if (privateState.WeaponCooldownSecondsRemains <= 0) { return; } // process weapon cooldown var deltaTime = data.DeltaTime; if (deltaTime > 0.4) { // too large delta time probably due to a frame skip deltaTime = 0.4; } if (privateState.WeaponCooldownSecondsRemains > 0) { privateState.WeaponCooldownSecondsRemains -= deltaTime; if (privateState.WeaponCooldownSecondsRemains < -0.2) { // clamp the remaining cooldown in case of a frame skip privateState.WeaponCooldownSecondsRemains = -0.2; } } } }
/// <summary> /// Return metadata for updates /// </summary> /// <param name="request">The request; contains IDs for updates to retrieve metadata for</param> /// <returns>Update metadata for requested updates</returns> public Task <ServerUpdateData> GetUpdateDataAsync(GetUpdateDataRequest request) { var response = new ServerUpdateData(); // Make sure the request is not larger than the config says var updateRequestCount = request.GetUpdateData.updateIds.Count(); if (updateRequestCount > ServiceConfiguration.MaxNumberOfUpdatesPerRequest) { return(null); } var returnUpdatesList = new List <ServerSyncUpdateData>(); var returnFilesList = new List <ServerSyncUrlData>(); foreach (var rawIdentity in request.GetUpdateData.updateIds) { var updateIdentity = new Identity(rawIdentity); // Find the update; it can be either category or update Update update; if (!FilteredUpdates.TryGetValue(updateIdentity, out update)) { if ((update = Categories.First(c => c.Identity.Equals(updateIdentity))) == null) { throw new Exception("Update not found"); } } if (update.HasFiles) { // if update contains files, we must also gather file information foreach (var updateFile in update.Files) { returnFilesList.Add( new ServerSyncUrlData() { FileDigest = Convert.FromBase64String(updateFile.Digests[0].DigestBase64), MUUrl = updateFile.Urls[0].MuUrl, UssUrl = $"Content/{updateFile.GetContentDirectoryName()}/{updateFile.FileName}" }); } } var rawUpdateData = new ServerSyncUpdateData(); rawUpdateData.Id = rawIdentity; using (var metadataReader = new StreamReader(MetadataSource.GetUpdateMetadataStream(update.Identity))) { rawUpdateData.XmlUpdateBlob = metadataReader.ReadToEnd(); } returnUpdatesList.Add(rawUpdateData); } response.updates = returnUpdatesList.ToArray(); // Deduplicate list of files response.fileUrls = returnFilesList.GroupBy(f => f.MUUrl).Select(k => k.First()).ToArray(); return(Task.FromResult(response)); }
protected override void ServerUpdate(ServerUpdateData data) { var item = data.GameObject; var privateState = data.PrivateState; var character = item.Container.OwnerAsCharacter; if (!IsItemSelectedByPlayer(character, item)) { // not a selected player item this.ServerSetUpdateRate(item, isRare: true); return; } privateState.ServerTimeToPing -= data.DeltaTime; if (privateState.ServerTimeToPing > 0) { return; } privateState.ServerTimeToPing = ServerScanInterval; if (!CharacterEnergySystem.ServerDeductEnergyCharge( character, requiredEnergyAmount: this.EnergyConsumptionPerSecond * ServerScanInterval)) { // no power this.CallClient(character, _ => _.ClientRemote_NoPower()); return; } ItemDurabilitySystem.ServerModifyDurability( item, delta: -(int)Math.Round(this.DurabilityDecreasePerSecond * ServerScanInterval)); if (item.IsDestroyed) { // zero durability reached return; } // update signal strength using var tempSignalStrength = Api.Shared.GetTempList <byte>(); this.ServerCalculateStrengthToTheClosestPragmiumSpires(character, tempSignalStrength.AsList(), MaxNumberOfPongsPerScan); var previousSignalStrength = -1; foreach (var signalStrength in tempSignalStrength.AsList()) { if (signalStrength == previousSignalStrength) { // don't send multiple pongs for the signals of the same strength continue; } previousSignalStrength = signalStrength; var serverTimeToPong = SharedCalculateTimeToPong(signalStrength); ServerTimersSystem.AddAction( serverTimeToPong, () => { var currentCharacter = item.Container.OwnerAsCharacter; if (IsItemSelectedByPlayer(currentCharacter, item)) { this.CallClient(currentCharacter, _ => _.ClientRemote_OnSignal(item, PragmiumSensorSignalKind.Pong)); } }); //Logger.Dev(string.Format("Pragmium scanner signal: {0} strength. Time to send pong: {1} ms.", // signalStrength, // (int)(serverTimeToPong * 1000))); } this.CallClient(character, _ => _.ClientRemote_OnSignal(item, PragmiumSensorSignalKind.Ping)); bool IsItemSelectedByPlayer(ICharacter c, IItem i) => c is not null && ReferenceEquals(i, c.SharedGetPlayerSelectedHotbarItem()); }
protected override void ServerUpdate(ServerUpdateData data) { ItemFreshnessSystem.ServerUpdateFreshness(data.GameObject, data.DeltaTime); }
protected sealed override void ServerUpdate(ServerUpdateData data) { }
protected override void ServerUpdate(ServerUpdateData data) { PowerGridSystem.ServerUpdateGrid(data.GameObject, data.PublicState, data.DeltaTime); }
protected override void ServerUpdateMob(ServerUpdateData data) { var character = data.GameObject; var publicState = data.PublicState; if (publicState.IsDead) { return; } var privateState = data.PrivateState; var lastTargetCharacter = privateState.CurrentTargetCharacter; var deltaTime = data.DeltaTime; // Regenerate the health points a bit on every frame // if there was no damage dealt to boss recently. // Please note: the difficulty coefficient doesn't apply there // as the boss HP doesn't change with difficulty - only damage // to it is modified by the difficulty coefficient. if (Server.Game.FrameTime >= privateState.LastDamageTime + RegenerationDelaySeconds) { publicState.CurrentStats.ServerSetHealthCurrent( (float)(publicState.CurrentStats.HealthCurrent + HealthRegenerationPerSecond * deltaTime)); } var weaponList = this.ServerSelectWeaponsList(privateState, deltaTime, out var isSwitchingToNovaAttack); ServerCharacterAiHelper.ProcessBossAi( character, weaponList, distanceEnemyTooClose: 7.5, distanceEnemyTooFar: 15.5, movementDirection: out var movementDirection, rotationAngleRad: out var rotationAngleRad); if (movementDirection != default && !ServerCanMoveInDirection(character.TilePosition.ToVector2D(), movementDirection, privateState.HoldPosition.ToVector2D())) { // cannot move in desired direction - too far from the position to hold movementDirection = default; } this.ServerSetMobInput(character, movementDirection, rotationAngleRad); if (lastTargetCharacter is null && privateState.CurrentTargetCharacter != null // is the last attack happened not too recently? && privateState.TimeToNextNovaAttack < NovaAttackInterval.Max - 8) { //Logger.Dev("Boss acquired target! Will use a nova attack in the next 2-4 seconds!"); privateState.TimeToNextNovaAttack = RandomHelper.Next(2, 4); } if (isSwitchingToNovaAttack) { privateState.WeaponState.SharedSetInputIsFiring(false); } }
protected override void ServerUpdate(ServerUpdateData data) { var privateState = data.PrivateState; var publicState = data.PublicState; var liquidContainerState = privateState.LiquidState; var isFull = liquidContainerState.Amount >= this.LiquidContainerConfig.Capacity; ManufacturingMechanic.UpdateRecipeOnly( data.GameObject, privateState.ManufacturingState, this.ManufacturingConfig, force: !isFull); ManufacturingMechanic.UpdateCraftingQueueOnly( privateState.ManufacturingState, deltaTime: data.DeltaTime); // refill liquid LiquidContainerSystem.UpdateWithoutManufacturing( liquidContainerState, this.LiquidContainerConfig, data.DeltaTime, isProduceLiquid: false, wasUsed: out _, isUseRequested: privateState.CurrentTemperature >= SteamTemperatureGenerationStart, resetAmountToZeroWhenNotEnoughToUse: true); var isActive = privateState.LiquidState.Amount > 0; var fuelBurningState = privateState.FuelBurningState; if (fuelBurningState != null) { // progress fuel burning FuelBurningMechanic.Update( data.GameObject, fuelBurningState, privateState.FuelBurningByproductsQueue, this.ManufacturingConfig, data.DeltaTime * FuelBurningSpeedMultiplier, byproductsQueueRate: 1, isNeedFuelNow: publicState.ElectricityProducerState == ElectricityProducerState.PowerOnActive && privateState.LiquidState.Amount > 0); // active only when fuel is burning isActive = fuelBurningState.FuelUseTimeRemainsSeconds > 0; } publicState.IsActive = isActive; // update the temperature var temperature = privateState.CurrentTemperature; var delta = isActive ? (float)(SteamTemperatureIncreasePerSecond * data.DeltaTime) : -(float)(SteamTemperatureDecreasePerSecond * data.DeltaTime); // apply some variance in temperature gain delta *= RandomHelper.Range(0.8f, 1.2f); temperature += delta; privateState.CurrentTemperature = MathHelper.Clamp(temperature, SteamTemperatureMin, SteamTemperatureMax); }
protected override void ServerUpdate(ServerUpdateData data) { base.ServerUpdate(data); TradingStationsSystem.ServerUpdate(data.GameObject); }
protected override void ServerUpdate(ServerUpdateData data) { base.ServerUpdate(data); data.PublicState.LiquidType = data.PrivateState.LiquidType; }
protected override void ServerUpdate(ServerUpdateData data) { FoodSpoilageSystem.ServerUpdateFoodFreshness(data.GameObject, data.DeltaTime); }