public static CraftingSlotResponse CancelCraftingJob(string playerId, int slot) { var job = craftingJobs[playerId][slot]; var nextStreamId = GenericUtils.GetNextStreamVersion(); var resp = new CraftingSlotResponse { result = new CraftingSlotInfo(), updates = new Updates() }; foreach (InputItem item in job.escrow) { InventoryUtils.AddItemToInv(playerId, item.itemId, item.quantity); } job.nextCompletionUtc = null; job.available = 0; job.completed = 0; job.recipeId = null; job.sessionId = null; job.state = "Empty"; job.total = 0; job.boostState = null; job.totalCompletionUtc = null; job.unlockPrice = null; job.output = null; job.streamVersion = nextStreamId; UtilityBlockUtils.UpdateUtilityBlocks(playerId, slot, job); Log.Debug($"[{playerId}]: Cancelled crafting job in slot {slot}."); resp.updates.crafting = nextStreamId; return(resp); }
public static CraftingUpdates RemoveBoost(string playerId, string boostInstanceId) { var nextStreamId = GenericUtils.GetNextStreamVersion(); var baseBoosts = ReadBoosts(playerId); var potionToRemove = baseBoosts.result.potions.Find(match => match.instanceId == boostInstanceId); var boostToRemove = catalog.result.items.Find(match => match.id == potionToRemove.itemId); baseBoosts.result.scenarioBoosts.death?.RemoveAll(match => match.instanceId == boostInstanceId); baseBoosts.result.potions.Remove(potionToRemove); baseBoosts.result.activeEffects.RemoveAll(match => boostToRemove.item.boostMetadata.effects.Contains(match.effect) && match.expiration == potionToRemove.expiration); baseBoosts.result.statusEffects = CalculateStatusEffects(baseBoosts); WriteBoosts(playerId, baseBoosts); var updates = new CraftingUpdates { updates = new Updates() }; updates.updates.boosts = nextStreamId; return(updates); }
public static CraftingSlotResponse GetCraftingJobInfo(string playerId, int slot) { try { var job = craftingJobs[playerId][slot]; var recipe = recipeList.result.crafting.Find(match => match.id == job.recipeId & !match.deprecated); var updates = new Updates(); var nextStreamId = GenericUtils.GetNextStreamVersion(); job.streamVersion = nextStreamId; if (job.totalCompletionUtc != null && DateTime.Compare(job.totalCompletionUtc.Value, DateTime.UtcNow) < 0 && job.recipeId != null) { job.available = job.total - job.completed; job.completed += job.available; job.nextCompletionUtc = null; job.state = "Completed"; job.escrow = new InputItem[0]; } /*else * { * * job.available++; * //job.completed++; * job.state = "Available"; * job.streamVersion = nextStreamId; * job.nextCompletionUtc = job.nextCompletionUtc.Value.Add(recipe.duration.TimeOfDay); * * for (int i = 0; i < job.escrow.Length - 1; i++) * { * job.escrow[i].quantity -= recipe.ingredients[i].quantity; * } * * }*/ updates.crafting = nextStreamId; var returnResponse = new CraftingSlotResponse { result = job, updates = updates }; UtilityBlockUtils.UpdateUtilityBlocks(playerId, slot, job); Log.Debug($"[{playerId}]: Requested crafting slot {slot} status."); return(returnResponse); } catch (Exception e) { Log.Error($"[{playerId}]: Error while getting crafting job info! Crafting Slot: {slot}"); Log.Debug($"Exception: {e.StackTrace}"); return(null); } }
public static Updates ProgressChallenge(string playerId, ChallengeEventType challengeEvent, Guid eventId, int amount = 1) { var playerChallenges = ReadChallenges(playerId); var activeChallenges = playerChallenges.result.challenges.Where(pred => pred.Value.state == ChallengeState.Active).ToDictionary(pred => pred.Key, pred => pred.Value); // TODO: Implement challenge backend, since challenge requirements are not set in the response return(new Updates() { challenges = GenericUtils.GetNextStreamVersion() }); }
public static Updates RedeemRewards(string playerId, Rewards rewards) { Updates updates = new Updates(); uint nextStreamId = GenericUtils.GetNextStreamVersion(); foreach (var buildplate in rewards.Buildplates) { BuildplateUtils.AddToPlayer(playerId, buildplate.Id); updates.buildplates = nextStreamId; } foreach (var challenge in rewards.Challenges) { //ChallengeUtils.AddToPlayer(playerId, challenge.id); updates.challenges = nextStreamId; } foreach (var item in rewards.Inventory) { InventoryUtils.AddItemToInv(playerId, item.Id, item.Amount); updates.inventory = nextStreamId; updates.playerJournal = nextStreamId; } foreach (var utilityBlock in rewards.UtilityBlocks) { // TODO: This is most likely unused in the actual game, since crafting tables/furnaces dont have ids } foreach (var personaItem in rewards.PersonaItems) { // PersonaUtils.AddToPlayer(playerId, personaItem) If we can ever implement CC, this is already in place } if (rewards.ExperiencePoints != null) { ProfileUtils.AddExperienceToPlayer(playerId, rewards.ExperiencePoints.Value); updates.characterProfile = nextStreamId; } return(updates); }
public static CraftingUpdates UnlockCraftingSlot(string playerId, int slot) { var job = craftingJobs[playerId][slot]; RubyUtils.SetRubies(playerId, job.unlockPrice.cost - job.unlockPrice.discount, false); job.state = "Empty"; job.unlockPrice = null; var nextStreamId = GenericUtils.GetNextStreamVersion(); var returnUpdates = new CraftingUpdates { updates = new Updates() }; UtilityBlockUtils.UpdateUtilityBlocks(playerId, slot, job); Log.Debug($"[{playerId}]: Unlocked crafting slot {slot}."); returnUpdates.updates.crafting = nextStreamId; return(returnUpdates); }
public static CraftingUpdates ActivateBoost(string playerId, Guid boostId) { var updates = new CraftingUpdates { updates = new Updates() }; List <DateTime> expirationTimes = new List <DateTime>(); // This looks bad (and it totally is), but we can optimize it at a later date var currentTime = DateTime.UtcNow; var baseBoosts = ReadBoosts(playerId); var boostToApply = catalog.result.items.Find(match => match.id == boostId); var indexNum = 0; if (baseBoosts.result.scenarioBoosts.death != null) { indexNum = baseBoosts.result.scenarioBoosts.death.Count; // Only used if boost is scenario specific } var nextStreamId = GenericUtils.GetNextStreamVersion(); var locOfEffect = baseBoosts.result.activeEffects.Find(match => match.effect == boostToApply.item.boostMetadata.effects[0]); // null when not an active effect, e.g scenario boost ActiveBoost locOfBoost = null; if (baseBoosts.result.scenarioBoosts.death != null) { locOfBoost = baseBoosts.result.scenarioBoosts.death.Find(match => match.effects.Any(pred => pred == boostToApply.item.boostMetadata.effects[0])); } if (locOfEffect != null && boostToApply.item.boostMetadata.additive && boostToApply.item.boostMetadata.scenario == null) { locOfEffect.effect.duration += boostToApply.item.boostMetadata.activeDuration.Value.TimeOfDay; baseBoosts.result.potions.Find(match => match.itemId == boostId).expiration += boostToApply.item.boostMetadata.activeDuration.Value.TimeOfDay; } else if (locOfBoost != null && boostToApply.item.boostMetadata.additive && boostToApply.item.boostMetadata.scenario == "Death") { indexNum = baseBoosts.result.scenarioBoosts.death.IndexOf(locOfBoost); locOfBoost.expiration += boostToApply.item.boostMetadata.activeDuration.Value.TimeOfDay; baseBoosts.result.potions.Find(match => match.itemId == boostId).expiration += boostToApply.item.boostMetadata.activeDuration.Value.TimeOfDay; } else { Dictionary <Guid, string> uuidDict = new Dictionary <Guid, string>(); if (boostToApply.item.boostMetadata.scenario == null) { foreach (Item.Effect effect in boostToApply.item.boostMetadata.effects) { baseBoosts.result.activeEffects.Add(new ActiveEffect { effect = effect, expiration = currentTime.Add(effect.duration.Value) }); } } else { baseBoosts.result.scenarioBoosts.death ??= new List <ActiveBoost>(); baseBoosts.result.scenarioBoosts.death.Add(new ActiveBoost { effects = new List <Item.Effect>(), enabled = true, expiration = currentTime.Add(boostToApply.item.boostMetadata.activeDuration.Value.TimeOfDay), instanceId = Guid.NewGuid().ToString() }); foreach (Item.Effect effect in boostToApply.item.boostMetadata.effects) { baseBoosts.result.scenarioBoosts.death[indexNum].effects.Add(effect); } uuidDict.Add(boostId, baseBoosts.result.scenarioBoosts.death[indexNum].instanceId); } Potion potion = null; if (boostToApply.item.boostMetadata.activeDuration != null) { potion = new Potion { enabled = true, expiration = currentTime.Add(boostToApply.item.boostMetadata.activeDuration.Value.TimeOfDay), instanceId = Guid.NewGuid().ToString(), itemId = boostId }; } else if (boostToApply.item.boostMetadata.effects[0].duration != null) { potion = new Potion { enabled = true, expiration = currentTime.Add(boostToApply.item.boostMetadata.effects[0].duration.Value), instanceId = Guid.NewGuid().ToString(), itemId = boostId }; } if (uuidDict.ContainsKey(boostId) && potion != null) { potion.instanceId = uuidDict[boostId]; } var nullPotionIndex = baseBoosts.result.potions.FindIndex(match => match == null); if (nullPotionIndex != -1) { baseBoosts.result.potions[nullPotionIndex] = potion; } } if (boostToApply.item.boostMetadata.canBeRemoved) { InventoryUtils.RemoveItemFromInv(playerId, boostId); // UNCOMMENT/COMMENT THIS LINE TO REMOVE BOOSTS FROM INVENTORY WHEN USED updates.updates.inventory = nextStreamId; } foreach (ActiveEffect effect in baseBoosts.result.activeEffects) { expirationTimes.Add(effect.expiration.Value); } if (baseBoosts.result.scenarioBoosts.death != null) { foreach (ActiveBoost boost in baseBoosts.result.scenarioBoosts.death) { expirationTimes.Add(boost.expiration.Value); } } baseBoosts.result.expiration = expirationTimes.Min(); baseBoosts.result.statusEffects = CalculateStatusEffects(baseBoosts); WriteBoosts(playerId, baseBoosts); updates.updates.boosts = nextStreamId; return(updates); }
public static bool StartCraftingJob(string playerId, int slot, CraftingRequest request) // TODO: Check if slot not unlocked (not a big priority) { recipeList ??= Recipes.FromFile("./data/recipes"); var recipe = recipeList.result.crafting.Find(match => match.id == request.RecipeId); if (recipe != null) { var itemsToReturn = recipe.returnItems.ToList(); foreach (RecipeIngredients ingredient in recipe.ingredients) { if (itemsToReturn.Find(match => match.id == ingredient.items[0] && match.amount == ingredient.quantity) == null) { InventoryUtils.RemoveItemFromInv(playerId, ingredient.items[0], ingredient.quantity * request.Multiplier); } } var nextStreamId = GenericUtils.GetNextStreamVersion(); CraftingSlotInfo job = new CraftingSlotInfo { available = 0, boostState = null, completed = 0, escrow = request.Ingredients, nextCompletionUtc = null, output = recipe.output, recipeId = recipe.id, sessionId = request.SessionId, state = "Active", streamVersion = nextStreamId, total = request.Multiplier, totalCompletionUtc = DateTime.UtcNow.Add(recipe.duration.TimeOfDay * request.Multiplier), unlockPrice = null }; if (request.Multiplier != 1) { job.nextCompletionUtc = DateTime.UtcNow.Add(recipe.duration.TimeOfDay); } if (!craftingJobs.ContainsKey(playerId)) { craftingJobs.Add(playerId, new Dictionary <int, CraftingSlotInfo>()); craftingJobs[playerId].Add(1, new CraftingSlotInfo()); craftingJobs[playerId].Add(2, new CraftingSlotInfo()); craftingJobs[playerId].Add(3, new CraftingSlotInfo()); } craftingJobs[playerId][slot] = job; UtilityBlockUtils.UpdateUtilityBlocks(playerId, slot, job); Log.Debug($"[{playerId}]: Initiated crafting job in slot {slot}."); return(true); } return(false); }
public static CollectItemsResponse FinishCraftingJob(string playerId, int slot) { var job = craftingJobs[playerId][slot]; var recipe = recipeList.result.crafting.Find(match => match.id == job.recipeId & !match.deprecated); int craftedAmount = 0; var nextStreamId = GenericUtils.GetNextStreamVersion(); var returnResponse = new CollectItemsResponse { result = new CollectItemsInfo { rewards = new Rewards(), }, updates = new Updates() }; if (job.completed != job.total && job.nextCompletionUtc != null) { if (DateTime.UtcNow >= job.nextCompletionUtc) { craftedAmount++; while (DateTime.UtcNow >= job.nextCompletionUtc && job.nextCompletionUtc.Value.Add(recipe.duration.TimeOfDay) < job.totalCompletionUtc && craftedAmount < job.total - job.completed) { job.nextCompletionUtc = job.nextCompletionUtc.Value.Add(recipe.duration.TimeOfDay); craftedAmount++; } job.nextCompletionUtc = job.nextCompletionUtc.Value.Add(recipe.duration.TimeOfDay); job.completed += craftedAmount; //job.available -= craftedAmount; for (int i = 0; i < job.escrow.Length - 1; i++) { job.escrow[i].quantity -= recipe.ingredients[i].quantity * craftedAmount; } job.streamVersion = nextStreamId; InventoryUtils.AddItemToInv(playerId, job.output.itemId, job.output.quantity * craftedAmount); } } else { craftedAmount = job.available; InventoryUtils.AddItemToInv(playerId, job.output.itemId, job.output.quantity * craftedAmount); // TODO: Add to challenges, tokens, journal (when implemented) } if (!TokenUtils.GetTokenResponseForUserId(playerId).Result.tokens.Any(match => match.Value.clientProperties.ContainsKey("itemid") && match.Value.clientProperties["itemid"] == job.output.itemId.ToString())) { //TokenUtils.AddItemToken(playerId, job.output.itemId); -> List of item tokens not known. Could cause issues later, for now we just disable it. returnResponse.updates.tokens = nextStreamId; } returnResponse.result.rewards.Inventory = returnResponse.result.rewards.Inventory.Append(new RewardComponent { Amount = job.output.quantity * craftedAmount, Id = job.output.itemId }).ToArray(); returnResponse.updates.crafting = nextStreamId; returnResponse.updates.inventory = nextStreamId; returnResponse.updates.playerJournal = nextStreamId; if (job.completed == job.total || job.nextCompletionUtc == null) { job.nextCompletionUtc = null; job.available = 0; job.completed = 0; job.recipeId = null; job.sessionId = null; job.state = "Empty"; job.total = 0; job.boostState = null; job.totalCompletionUtc = null; job.unlockPrice = null; job.output = null; job.streamVersion = nextStreamId; } UtilityBlockUtils.UpdateUtilityBlocks(playerId, slot, job); Log.Debug($"[{playerId}]: Collected results of crafting slot {slot}."); return(returnResponse); }