public override void ServerOnDestroy(IStaticWorldObject gameObject) { base.ServerOnDestroy(gameObject); LandClaimSystem.ServerOnObjectLandClaimDestroyed(gameObject); }
/// <summary> /// Enqueue crafting selected recipe. /// </summary> /// <param name="craftingQueue">Crafting queue instance.</param> /// <param name="recipeEntry">Recipe instance.</param> /// <param name="countToCraft">Count to craft - must be greater than zero.</param> public static void ServerStartCrafting( [CanBeNull] IStaticWorldObject station, [CanBeNull] ICharacter character, [NotNull] CraftingQueue craftingQueue, [NotNull] RecipeWithSkin recipeEntry, ushort countToCraft, ushort?maxQueueSize = null) { if (station is null && character is null) { throw new NullReferenceException("Character AND station cannot be null simultaneously"); } if (countToCraft == 0) { throw new Exception("Are you really want to craft zero items?"); } var isAdminMode = character is not null && CreativeModeSystem.SharedIsInCreativeMode(character); if (!isAdminMode && recipeEntry.Recipe.RecipeType != RecipeType.ManufacturingByproduct && !recipeEntry.Recipe.CanBeCrafted(character, station, craftingQueue, countToCraft: recipeEntry.Recipe.RecipeType == RecipeType.Manufacturing ? (ushort)1 : countToCraft)) { Logger.Error($"Recipe cannot be crafted - check failed: {recipeEntry} at {station}.", character); return; } var queueCount = craftingQueue.QueueItems.Count; if (queueCount > 0) { foreach (var existingQueueItem in craftingQueue.QueueItems) { if (!existingQueueItem.CanCombineWith(recipeEntry)) { continue; } // try to increase the count to craft var lastQueueItemCountBefore = existingQueueItem.CountToCraftRemains; var maxCountToCraft = ushort.MaxValue; var isManufacturingRecipe = recipeEntry.Recipe.RecipeType != RecipeType.Hand && recipeEntry.Recipe.RecipeType != RecipeType.StationCrafting; if (!isManufacturingRecipe) { maxCountToCraft = recipeEntry.Recipe.OutputItems.Items[0].ProtoItem.MaxItemsPerStack; } var originalRequestedCountToCraft = countToCraft; var lastQueueItemCountNew = (ushort)Math.Min(maxCountToCraft, lastQueueItemCountBefore + countToCraft); var canAddCount = lastQueueItemCountNew - lastQueueItemCountBefore; if (canAddCount > 0) { existingQueueItem.CountToCraftRemains = lastQueueItemCountNew; Logger.Info( $"Recipe count extended for crafting: {recipeEntry} at {station}: from x{lastQueueItemCountBefore} to x{countToCraft}", character); ServerDestroyInputItems(craftingQueue, recipeEntry.Recipe, countToCraft: (ushort)canAddCount, isAdminMode); if (isManufacturingRecipe) { return; } var remainingCountToCraft = originalRequestedCountToCraft - canAddCount; if (remainingCountToCraft <= 0) { // the last queue item took all the requested items count to craft return; } // last queue item cannot accomodate all the requested count to craft // let's try to add to previous queue item or a new queue item countToCraft = (ushort)remainingCountToCraft; } } } if (maxQueueSize.HasValue && craftingQueue.QueueItems.Count >= maxQueueSize.Value) { Logger.Info( $"Recipe cannot be queue for crafting due to max queue size limitation: {recipeEntry} at {station} with max queue size {maxQueueSize.Value}.", character); return; } var queueItem = new CraftingQueueItem(recipeEntry, countToCraft, craftingQueue.ServerLastQueueItemLocalId++); ServerDestroyInputItems(craftingQueue, recipeEntry.Recipe, countToCraft: queueItem.CountToCraftRemains, isAdminMode); craftingQueue.QueueItems.Add(queueItem); if (craftingQueue.QueueItems.Count == 1) { // the added recipe is first in queue - so we will craft it right now craftingQueue.SetDurationFromCurrentRecipe(); } Logger.Info($"Recipe queued for crafting: {recipeEntry} at {station}.", character); }
IObjectElectricityStructurePrivateState IProtoObjectElectricityConsumer.GetPrivateState( IStaticWorldObject worldObject) { return(GetPrivateState(worldObject)); }
public override float StructurePointsMax => 0; // non-damageable public override void ServerApplyDecay(IStaticWorldObject worldObject, double deltaTime) { // cannot decay }
public virtual double ServerGetDamageToTree(IStaticWorldObject targetObject) { return(this.DamageToTree); }
public DestroyWallRequest(IStaticWorldObject wallObject, bool isForce) { this.WallObject = wallObject; this.IsForce = isForce; }
public ObjectMulchboxPrivateState GetMulchboxPrivateState(IStaticWorldObject objectMulchbox) { return(GetPrivateState(objectMulchbox)); }
void IInteractableProtoStaticWorldObject.ServerOnMenuClosed(ICharacter who, IStaticWorldObject worldObject) { }
protected virtual IReadOnlyDropItemsList ServerGetLootDroplist(IStaticWorldObject worldObject) { return(this.LootDroplist); }
BaseUserControlWithWindow IInteractableProtoStaticWorldObject.ClientOpenUI(IStaticWorldObject worldObject) { var privateState = GetPrivateState(worldObject); return(this.ClientOpenUI(worldObject, privateState)); }
void IInteractableProtoStaticWorldObject.ServerOnClientInteract(ICharacter who, IStaticWorldObject worldObject) { }
protected override bool TestObject(IStaticWorldObject staticWorldObject) { return(staticWorldObject.ProtoGameObject is IProtoObjectGatherable protoGatherable && protoGatherable.SharedIsCanGather(staticWorldObject) && protoGatherable.SharedCanInteract(CurrentCharacter, staticWorldObject, false)); }
protected override void ServerOnLiquidAmountChanged(IStaticWorldObject objectManufacturer) { // do nothing }
protected override LiquidContainerState GetLiquidState(IStaticWorldObject objectManufacturer) { return(ProtoObjectWell.GetPrivateState(objectManufacturer) .LiquidStateWater); }
public override bool SharedCanInteract(ICharacter character, IStaticWorldObject worldObject, bool writeToLog) { return(this.SharedIsInsideCharacterInteractionArea(character, worldObject, writeToLog)); }
protected virtual BaseUserControlWithWindow ClientOpenUI( IStaticWorldObject worldObject, PrivateState privateState) { return(WindowTrashCan.Show(privateState)); }
public ViewModelManufacturingState( IStaticWorldObject worldObjectManufacturer, ManufacturingState manufacturingState, ManufacturingConfig manufacturingConfig) { this.worldObjectManufacturer = worldObjectManufacturer; this.ManufacturingState = manufacturingState; this.ManufacturingConfig = manufacturingConfig; this.ContainerInput = (IClientItemsContainer)manufacturingState.ContainerInput; this.ContainerOutput = (IClientItemsContainer)manufacturingState.ContainerOutput; this.CommandBrowseRecipes = new ActionCommand(this.ExecuteCommandBrowseRecipes); this.CommandCloseRecipesBrowser = new ActionCommand(this.CloseRecipesBrowser); this.CommandSelectRecipeFromBrowser = new ActionCommandWithParameter(this.ExecuteCommandSelectRecipeFromBrowser); this.CommandApplyBestMatchingRecipe = new ActionCommand(this.ExecuteCommandApplyBestMatchingRecipe); this.VisibilityRecipesSelection = manufacturingConfig.IsAutoSelectRecipe ? Visibility.Collapsed : Visibility.Visible; this.SelectedRecipe = manufacturingState.SelectedRecipe; //this.BestMatchingRecipe = manufacturingState.BestMatchingRecipe; this.RefreshCraftingProgressPercents(); this.ManufacturingState.ClientSubscribe( _ => _.SelectedRecipe, recipe => this.SelectedRecipe = recipe, this); //this.ManufacturingState.ClientSubscribe( // _ => _.BestMatchingRecipe, // recipe => this.BestMatchingRecipe = recipe, // this); this.ManufacturingState.CraftingQueue.ClientSubscribe( _ => _.IsContainerOutputFull, _ => this.NotifyPropertyChanged(nameof(this.IsContainerOutputFull)), this); this.craftingQueue = this.ManufacturingState.CraftingQueue.QueueItems; this.craftingQueue.ClientAnyModification += this.CraftingQueueAnyModificationHandler; this.ManufacturingState.CraftingQueue.ClientSubscribe( _ => _.TimeRemainsToComplete, time => this.RefreshCraftingProgressPercents(), this); // register containers exchange var character = Client.Characters.CurrentPlayerCharacter; ClientContainersExchangeManager.Register( this, this.ManufacturingState.ContainerOutput, allowedTargets: new[] { character.SharedGetPlayerContainerInventory(), character.SharedGetPlayerContainerHotbar() }); ClientContainersExchangeManager.Register( this, this.ManufacturingState.ContainerInput, allowedTargets: new[] { character.SharedGetPlayerContainerInventory(), character.SharedGetPlayerContainerHotbar() }); this.ContainerInput.StateHashChanged += this.ContainerInputStateChangedHandler; this.RefreshIsInputMatchSelectedRecipe(); this.RefreshBestMatchingRecipe(); }
/// <summary> /// Bomberman-style explosion penetrating the walls in a cross. /// </summary> public static void ServerProcessExplosionBomberman( Vector2D positionEpicenter, IPhysicsSpace physicsSpace, int damageDistanceFullDamage, int damageDistanceMax, double damageDistanceDynamicObjectsOnly, WeaponFinalCache weaponFinalCache, Func <double, double> callbackCalculateDamageCoefByDistanceForStaticObjects, Func <double, double> callbackCalculateDamageCoefByDistanceForDynamicObjects) { var protoObjectExplosive = weaponFinalCache.ProtoObjectExplosive; Api.Assert(protoObjectExplosive != null, "Weapon final cache should contain the exploded object"); Api.Assert(damageDistanceMax >= damageDistanceFullDamage, $"{nameof(damageDistanceMax)} must be >= {nameof(damageDistanceFullDamage)}"); var world = Api.Server.World; var damagedObjects = new HashSet <IWorldObject>(); ProcessExplosionDirection(-1, 0); // left ProcessExplosionDirection(0, 1); // top ProcessExplosionDirection(1, 0); // right ProcessExplosionDirection(0, -1); // bottom ServerProcessExplosionCircle(positionEpicenter, physicsSpace, damageDistanceDynamicObjectsOnly, weaponFinalCache, damageOnlyDynamicObjects: true, callbackCalculateDamageCoefByDistance: callbackCalculateDamageCoefByDistanceForDynamicObjects); void ProcessExplosionDirection(int xOffset, int yOffset) { var fromPosition = positionEpicenter.ToVector2Ushort(); for (var offsetIndex = 1; offsetIndex <= damageDistanceMax; offsetIndex++) { var tile = world.GetTile(fromPosition.X + offsetIndex * xOffset, fromPosition.Y + offsetIndex * yOffset, logOutOfBounds: false); if (!tile.IsValidTile || tile.IsCliff) { return; } var tileStaticObjects = tile.StaticObjects; IStaticWorldObject damagedObject = null; foreach (var staticWorldObject in tileStaticObjects) { if (staticWorldObject.ProtoGameObject is IProtoObjectWall || staticWorldObject.ProtoGameObject is IProtoObjectDoor) { // damage only walls and doors damagedObject = staticWorldObject; break; } } if (damagedObject == null) { // no wall or door there if (offsetIndex > damageDistanceFullDamage) { // stop damage propagation return; } continue; } if (!damagedObjects.Add(damagedObject)) { // the object is already damaged // (from another direction which might be theoretically possible in some future cases) continue; } var distanceToDamagedObject = offsetIndex; var damageMultiplier = callbackCalculateDamageCoefByDistanceForStaticObjects(distanceToDamagedObject); damageMultiplier = MathHelper.Clamp(damageMultiplier, 0, 1); var damageableProto = (IDamageableProtoWorldObject)damagedObject.ProtoGameObject; damageableProto.SharedOnDamage( weaponFinalCache, damagedObject, damageMultiplier, out _, out _); } } }
protected override void ClientDeinitializeStructure(IStaticWorldObject gameObject) { base.ClientDeinitializeStructure(gameObject); this.clientBlendHelper.Update(gameObject.OccupiedTile); }
public override string ClientGetTitle(IStaticWorldObject worldObject) { return(this.Name); }
protected override ITextureResource ClientGetTextureResource( IStaticWorldObject gameObject, StaticObjectPublicState publicState) { return(this.DefaultTexture); }
public virtual void ServerOnBuilt(IStaticWorldObject structure, ICharacter byCharacter) { }
public override bool SharedCanInteract(ICharacter character, IStaticWorldObject worldObject, bool writeToLog) { return(false); }
public virtual float SharedGetStructurePointsMax(IStaticWorldObject worldObject) => this.StructurePointsMax;
public override bool SharedIsCanGather(IStaticWorldObject staticWorldObject) { return(GetPublicState(staticWorldObject).HasHarvest); }
protected virtual void ClientDeinitializeStructure(IStaticWorldObject gameObject) { }
private static void TeleportToBed(ICharacter character, IStaticWorldObject bedObject) { var bedPosition = bedObject.TilePosition.ToVector2D() + bedObject.ProtoStaticWorldObject.Layout.Center; var neighborTiles = bedObject.OccupiedTiles .SelectMany(t => t.EightNeighborTiles) .Concat(bedObject.OccupiedTiles) .Distinct() .ToList(); neighborTiles.Shuffle(); var bedTileHeight = bedObject.OccupiedTile.Height; neighborTiles.SortBy(t => t.Position.ToVector2D() .DistanceSquaredTo(bedPosition)); var physicsSpace = Server.World.GetPhysicsSpace(); foreach (var neighborTile in neighborTiles) { if (neighborTile.Height != bedTileHeight) { continue; } var spawnPosition = neighborTile.Position.ToVector2D() + (0.5, 0.5); using (var objectsNearby = physicsSpace.TestCircle( spawnPosition, radius: 0.5, collisionGroup: CollisionGroups.Default)) { if (objectsNearby.Count > 0) { // invalid tile - obstacles continue; } } if (!LandClaimSystem.SharedIsPositionInsideOwnedOrFreeArea(neighborTile.Position, character, requireFactionPermission: false)) { // invalid tile - it's claimed by another player continue; } // valid tile found - respawn here // ensure the character has quit the current vehicle VehicleSystem.ServerCharacterExitCurrentVehicle(character, force: true); if (PlayerCharacter.GetPublicState(character).CurrentVehicle is not null) { Logger.Important($"{character} cannot be teleported to bed as it cannot exit the current vehicle"); return; } Server.World.SetPosition(character, spawnPosition); Logger.Important($"{character} teleported to bed {bedObject}"); return; } Logger.Important($"{character} cannot be teleported to bed {bedObject}"); }
public void Setup(IStaticWorldObject worldObjectMeteorite) { this.lastWorldObjectMeteorite = worldObjectMeteorite; this.RefreshViewModel(); }
IObjectElectricityConsumerPublicState IProtoObjectElectricityConsumer.GetPublicState( IStaticWorldObject worldObject) { return(GetPublicState(worldObject)); }
public sealed override void ServerOnBuilt(IStaticWorldObject structure, ICharacter byCharacter) { base.ServerOnBuilt(structure, byCharacter); LandClaimSystem.ServerOnObjectLandClaimBuilt(byCharacter, structure); }