private static void OnFuelChanged( IStaticWorldObject objectManufacturer, FuelBurningState state, CraftingQueue byproductsCraftQueue, ManufacturingConfig config) { if (!config.IsProduceByproducts) { return; } var currentByproductRecipe = byproductsCraftQueue.QueueItems.FirstOrDefault()?.Recipe as Recipe.RecipeForManufacturingByproduct; var newByproductRecipe = config.MatchRecipeForByproduct(state.CurrentFuelItemType); if (currentByproductRecipe == newByproductRecipe) { return; } byproductsCraftQueue.Clear(); if (newByproductRecipe != null) { CraftingMechanics.ServerStartCrafting( objectManufacturer, null, byproductsCraftQueue, newByproductRecipe, // unlimited count countToCraft: ushort.MaxValue); } }
/// <summary> /// Refreshes best matching recipe, auto-select it if needed by config. /// </summary> private static void RefreshRecipe( ManufacturingState state, ManufacturingConfig config, IStaticWorldObject objectManufacturer) { var selectedRecipe = state.SelectedRecipe; var bestRecipe = SharedMatchBestRecipe(state, config, objectManufacturer); if (bestRecipe is not null && config.IsAutoSelectRecipe) { // auto-select the best recipe selectedRecipe = state.SelectedRecipe = bestRecipe; bestRecipe = null; state.CraftingQueue.Clear(); } if (selectedRecipe is null) { return; } // refresh selected recipe var isSelectedRecipeCanBeCrafted = selectedRecipe.CanBeCrafted( character: null, objectManufacturer, state.CraftingQueue, countToCraft: 1); if (isSelectedRecipeCanBeCrafted) { var currentCraftingRecipe = state.CraftingQueue.QueueItems.FirstOrDefault(); if (currentCraftingRecipe is null || currentCraftingRecipe.RecipeEntry?.Recipe != selectedRecipe) { // there is nothing crafting or something different is crafting - start crafting the new selected recipe Logger.Info($"Manufacturing of recipe {selectedRecipe} started at {objectManufacturer}"); CraftingMechanics.ServerStartCrafting( objectManufacturer, null, state.CraftingQueue, new RecipeWithSkin(selectedRecipe), countToCraft: ushort.MaxValue); } } else if (state.CraftingQueue.QueueItems.Count > 0) { // the selected recipe cannot be crafted // clear current queue (progress is lost!) // nothing will be crafted now Logger.Info($"Manufacturing stopped at {objectManufacturer} - the recipe cannot be crafted anymore"); state.CraftingQueue.Clear(); } }
/// <summary> /// Updates fuel burning state. /// </summary> /// <param name="objectManufacturer">Instance of world object performing manufacturing.</param> /// <param name="state">Instance of fuel burning state.</param> /// <param name="byproductsCraftQueue"></param> /// <param name="config">Manufacturing config.</param> /// <param name="deltaTime">Delta time to progress on.</param> /// <param name="isNeedFuelNow">The new fuel item will be not burned if the fuel is not needed now.</param> public static void Update( IStaticWorldObject objectManufacturer, FuelBurningState state, CraftingQueue byproductsCraftQueue, ManufacturingConfig config, double deltaTime, double byproductsQueueRate, bool isNeedFuelNow, bool forceRefreshFuel = false) { if (isNeedFuelNow && (state.ContainerFuel.StateHash != state.ContainerFuelLastStateHash || forceRefreshFuel)) { RefreshFuel(state, byproductsCraftQueue, config, objectManufacturer, isNeedFuelNow); state.ContainerFuelLastStateHash = state.ContainerFuel.StateHash; } var fuelUseTimeRemainsSeconds = state.FuelUseTimeRemainsSeconds + state.FuelUseTimeAccumulatedRemainder - deltaTime; if (fuelUseTimeRemainsSeconds <= 0) { // fuel is burned state.FuelUseTimeAccumulatedRemainder += state.FuelUseTimeRemainsSeconds; state.FuelUseTimeRemainsSeconds = 0; if (isNeedFuelNow) { // refresh fuel RefreshFuel(state, byproductsCraftQueue, config, objectManufacturer, isNeedFuelNow); return; } return; } // subtract fuel burn time state.FuelUseTimeAccumulatedRemainder = 0; state.FuelUseTimeRemainsSeconds = fuelUseTimeRemainsSeconds; if (config.IsProduceByproducts) { if (byproductsCraftQueue is null) { throw new Exception("No byproductsCraftQueue"); } CraftingMechanics.ServerUpdate(byproductsCraftQueue, deltaTime * byproductsQueueRate); } }
private void ServerRemote_CancelQueueItem(ushort localId) { var character = ServerRemoteContext.Character; var characterServerState = PlayerCharacter.GetPrivateState(character); var queue = characterServerState.CraftingQueue.QueueItems; for (var index = 0; index < queue.Count; index++) { var item = queue[index]; if (item.LocalId == localId) { CraftingMechanics.ServerCancelCraftingQueueItem(character, item); return; } } Logger.Warning("Cannot find crafting queue entry with localId=" + localId); }
/// <summary> /// Updates only crafting queue recipe - please be sure to call <see cref="UpdateRecipeOnly" /> before that. /// </summary> /// <param name="state">Instance of manufacturing state.</param> /// <param name="deltaTime">Delta time to progress on.</param> public static void UpdateCraftingQueueOnly(ManufacturingState state, double deltaTime) { CraftingMechanics.ServerUpdate(state.CraftingQueue, deltaTime); }
public bool ServerRemote_CraftRecipe(RecipeWithSkin recipeEntry, ushort countToCraft) { recipeEntry.Validate(); var character = ServerRemoteContext.Character; var characterServerState = PlayerCharacter.GetPrivateState(character); if (recipeEntry.ProtoItemSkinOverride is IProtoItemWithSkinData protoItemSkin) { if (!Server.Items.IsSkinOwned(character, (ushort)protoItemSkin.SkinId)) { throw new Exception("The skin is not owned: " + protoItemSkin + " for " + character); } } IStaticWorldObject station; var craftingQueue = characterServerState.CraftingQueue; switch (recipeEntry.Recipe) { case Recipe.RecipeForHandCrafting: // simply craft by character station = null; break; case Recipe.RecipeForStationCrafting recipeForStation: station = SharedFindNearbyStationOfTypes(recipeForStation.StationTypes, character); if (station is null) { Logger.Error( $"No crafting stations of types {recipeForStation.StationTypes.GetJoinedString()} found nearby character {character} at position {character.Position}"); return(false); } break; default: throw new Exception("Incorrect recipe for in-hand or station crafting: " + recipeEntry); } // extra check (it's also done in the recipe itself) if (!recipeEntry.Recipe.SharedIsTechUnlocked(character)) { // locked recipe return(false); } var maxCraftingQueueEntriesCount = SharedGetMaxCraftingQueueEntriesCount(character); if (recipeEntry.Recipe.OutputItems.Items[0].ProtoItem.IsStackable) { // stackable items if (!SharedValidateQueueIsNotFull(character, recipeEntry, countToCraft, maxCraftingQueueEntriesCount)) { return(false); } CraftingMechanics.ServerStartCrafting(station, character, craftingQueue, recipeEntry, countToCraft, maxQueueSize: maxCraftingQueueEntriesCount); } else { // non-stackable items countToCraft = MathHelper.Clamp(countToCraft, min: (ushort)1, max: maxCraftingQueueEntriesCount); for (var i = 0; i < countToCraft; i++) { if (!SharedValidateQueueIsNotFull(character, recipeEntry, countToCraft: 1, maxCraftingQueueEntriesCount)) { return(false); } CraftingMechanics.ServerStartCrafting(station, character, craftingQueue, recipeEntry, countToCraft: 1, maxQueueSize: maxCraftingQueueEntriesCount); } } return(true); }
public bool ServerRemote_CraftRecipe(Recipe recipe, ushort countToCraft) { var character = ServerRemoteContext.Character; var characterServerState = PlayerCharacter.GetPrivateState(character); IStaticWorldObject station; var craftingQueue = characterServerState.CraftingQueue; if (recipe.RecipeType == RecipeType.Hand) { // simply craft by character station = null; } else { var recipeForStation = (Recipe.BaseRecipeForStation)recipe; station = SharedFindNearbyStationOfTypes(recipeForStation.StationTypes, character); if (station == null) { Logger.Error( $"No crafting stations of types {recipeForStation.StationTypes.GetJoinedString()} found nearby character {character} at position {character.Position}"); return(false); } if (recipeForStation is Recipe.RecipeForManufacturing) { // manufacture on station throw new Exception("Cannot craft in hand recipe for station manufacturing"); } } var maxCraftingQueueEntriesCount = SharedGetMaxCraftingQueueEntriesCount(character); if (recipe.OutputItems.Items[0].ProtoItem.IsStackable) { // stackable items if (!SharedValidateQueueIsNotFull(character, recipe, countToCraft, maxCraftingQueueEntriesCount)) { return(false); } CraftingMechanics.ServerStartCrafting(station, character, craftingQueue, recipe, countToCraft, maxQueueSize: maxCraftingQueueEntriesCount); } else { // non-stackable items countToCraft = MathHelper.Clamp(countToCraft, min: (ushort)1, max: maxCraftingQueueEntriesCount); for (var i = 0; i < countToCraft; i++) { if (!SharedValidateQueueIsNotFull(character, recipe, countToCraft: 1, maxCraftingQueueEntriesCount)) { return(false); } CraftingMechanics.ServerStartCrafting(station, character, craftingQueue, recipe, countToCraft: 1, maxQueueSize: maxCraftingQueueEntriesCount); } } return(true); }