private void CycleCold() { if (this.coldCount > this.coldCapacity) { Interlocked.Decrement(ref this.coldCount); if (this.coldQueue.TryDequeue(out LongTickCountLruItem <TKey, TValue> item)) { ItemDestination where = this.policy.RouteCold(item); if (where == ItemDestination.Warm && this.warmCount <= this.warmCapacity) { this.Move(item, where); } else { this.Move(item, ItemDestination.Remove); } } else { Interlocked.Increment(ref this.coldCount); } } }
private void CycleWarm() { if (this.warmCount > this.warmCapacity) { Interlocked.Decrement(ref this.warmCount); if (this.warmQueue.TryDequeue(out LongTickCountLruItem <TKey, TValue> item)) { ItemDestination where = this.policy.RouteWarm(item); // When the warm queue is full, we allow an overflow of 1 item before redirecting warm items to cold. // This only happens when hit rate is high, in which case we can consider all items relatively equal in // terms of which was least recently used. if (where == ItemDestination.Warm && this.warmCount <= this.warmCapacity) { this.Move(item, where); } else { this.Move(item, ItemDestination.Cold); } } else { Interlocked.Increment(ref this.warmCount); } } }
private void CycleHot() { if (this.hotCount > this.hotCapacity) { Interlocked.Decrement(ref this.hotCount); if (this.hotQueue.TryDequeue(out LongTickCountLruItem <TKey, TValue> item)) { ItemDestination where = this.policy.RouteHot(item); this.Move(item, where); } else { Interlocked.Increment(ref this.hotCount); } } }
private static Item FinalizeItem(int requestIndex, IConfigItem config, ItemDestination type, Item item) { if (type == ItemDestination.PlayerDropped) { if (!ItemInfo.IsSaneItemForDrop(item)) { throw new Exception($"Unsupported item: (index {requestIndex})."); } if (config.WrapAllItems && item.ShouldWrapItem()) { item.SetWrapping(ItemWrapping.WrappingPaper, config.WrappingPaper, true); } } item.IsDropped = type == ItemDestination.FieldItemDropped; return(item); }
private void Move(LongTickCountLruItem <TKey, TValue> item, ItemDestination where) { item.WasAccessed = false; switch (where) { case ItemDestination.Warm: this.warmQueue.Enqueue(item); Interlocked.Increment(ref this.warmCount); break; case ItemDestination.Cold: this.coldQueue.Enqueue(item); Interlocked.Increment(ref this.coldCount); break; case ItemDestination.Remove: if (!item.WasRemoved) { // Avoid race where 2 threads could remove the same key - see TryRemove for details. lock (item) { if (item.WasRemoved) { break; } if (this.dictionary.TryRemove(item.Key, out LongTickCountLruItem <TKey, TValue> removedItem)) { item.WasRemoved = true; if (removedItem.Value is IDisposable d) { d.Dispose(); } } } } break; } }
public void RouteCold(bool wasAccessed, ItemDestination expectedDestination) { var item = CreateItem(wasAccessed); this.policy.RouteCold(item).Should().Be(expectedDestination); }
/// <summary> /// Gets a list of items from the requested hex string(s). /// </summary> /// <remarks> /// If the first input is a language code (2 characters), the logic will try to parse item names for that language instead of item IDs. /// </remarks> /// <param name="requestHex">8 byte hex item values (u64 format)</param> /// <param name="cfg">Options for packaging items</param> /// <param name="type">End destination of the item</param> public static IReadOnlyCollection <Item> GetItemsFromUserInput(string requestHex, IConfigItem cfg, ItemDestination type = ItemDestination.PlayerDropped) { try { // having a language 2char code will cause an exception in parsing; this is fine and is handled by our catch statement. var split = requestHex.Split(SplittersHex, StringSplitOptions.RemoveEmptyEntries); return(GetItemsHexCode(split, cfg, type)); } #pragma warning disable CA1031 // Do not catch general exception types catch #pragma warning restore CA1031 // Do not catch general exception types { var split = requestHex.Split(SplittersName, StringSplitOptions.RemoveEmptyEntries); return(GetItemsLanguage(split, cfg, type, GameLanguage.DefaultLanguage)); } }
private static Item CreateItem(byte[] convert, int requestIndex, IConfigItem config, ItemDestination type) { Item item; try { if (convert.Length != Item.SIZE) { throw new Exception(); } item = convert.ToClass <Item>(); } catch (Exception ex) { throw new Exception($"Failed to convert item (index {requestIndex}: {ex.Message})."); } return(FinalizeItem(requestIndex, config, type, item)); }
private static Item CreateItem(string name, int requestIndex, IConfigItem config, ItemDestination type, string lang = "en") { var item = GetItem(name, lang); if (item.IsNone) { throw new Exception($"Failed to convert item (index {requestIndex}: {name}) for Language {lang}."); } return(FinalizeItem(requestIndex, config, type, item)); }
/// <summary> /// Gets a list of items from the requested list of item hex code strings. /// </summary> /// <remarks> /// If a hex code parse fails or a recipe ID does not exist, exceptions will be thrown. /// </remarks> /// <param name="split">List of recipe IDs as u16 hex</param> /// <param name="config">Item packaging options</param> /// <param name="type">Destination where the item will end up at</param> public static IReadOnlyCollection <Item> GetItemsHexCode(IReadOnlyList <string> split, IConfigItem config, ItemDestination type = ItemDestination.PlayerDropped) { var strings = GameInfo.Strings.itemlistdisplay; var result = new Item[split.Count]; for (int i = 0; i < result.Length; i++) { var text = split[i].Trim(); var convert = GetBytesFromString(text); var item = CreateItem(convert, i, config, type); if (item.ItemId >= strings.Length) { throw new Exception($"Item requested is out of expected range ({item.ItemId:X4} > {strings.Length:X4})."); } if (string.IsNullOrWhiteSpace(strings[item.ItemId])) { throw new Exception($"Item requested does not have a valid name ({item.ItemId:X4})."); } result[i] = item; } return(result); }
/// <summary> /// Gets a list of items from the requested list of item name strings. /// </summary> /// <remarks> /// If a item name parse fails or the item ID does not exist as a known item, exceptions will be thrown. /// </remarks> /// <param name="split">List of item names</param> /// <param name="config">Item packaging options</param> /// <param name="type">Destination where the item will end up at</param> /// <param name="lang">Language code to parse with. If the first entry in <see cref="split"/> is a language code, it will be used instead of <see cref="lang"/>.</param> public static IReadOnlyCollection <Item> GetItemsLanguage(IReadOnlyList <string> split, IConfigItem config, ItemDestination type = ItemDestination.PlayerDropped, string lang = GameLanguage.DefaultLanguage) { if (split.Count > 1 && split[0].Length < 3) { var langIndex = GameLanguage.GetLanguageIndex(split[0]); lang = GameLanguage.Language2Char(langIndex); split = split.Skip(1).ToArray(); } var strings = GameInfo.Strings.itemlistdisplay; var result = new Item[split.Count]; for (int i = 0; i < result.Length; i++) { var text = split[i].Trim(); var item = CreateItem(text, i, config, type, lang); if (item.ItemId >= strings.Length) { throw new Exception($"Item requested is out of expected range ({item.ItemId:X4} > {strings.Length:X4})."); } if (string.IsNullOrWhiteSpace(strings[item.ItemId])) { throw new Exception($"Item requested does not have a valid name ({item.ItemId:X4})."); } result[i] = item; } return(result); }
// Methods public ItemAction(byte[] data) : base(data) { this.superiorType = SuperiorItemType.NotApplicable; this.charClass = CharacterClass.NotApplicable; this.level = -1; this.usedSockets = -1; this.use = -1; this.graphic = -1; this.color = -1; this.stats = new List<StatBase>(); this.unknown1 = -1; this.runewordID = -1; this.runewordParam = -1; BitReader br = new BitReader(data, 1); this.action = (ItemActionType) br.ReadByte(); br.SkipBytes(1); this.category = (ItemCategory) br.ReadByte(); this.uid = br.ReadUInt32(); if (data[0] == 0x9d) { br.SkipBytes(5); } this.flags = (ItemFlags) br.ReadUInt32(); this.version = (ItemVersion) br.ReadByte(); this.unknown1 = br.ReadByte(2); this.destination = (ItemDestination) br.ReadByte(3); if (this.destination == ItemDestination.Ground) { this.x = br.ReadUInt16(); this.y = br.ReadUInt16(); } else { this.location = (EquipmentLocation) br.ReadByte(4); this.x = br.ReadByte(4); this.y = br.ReadByte(3); this.container = (ItemContainer) br.ReadByte(4); } if ((this.action == ItemActionType.AddToShop) || (this.action == ItemActionType.RemoveFromShop)) { int num = ((int) this.container) | 0x80; if ((num & 1) == 1) { num--; this.y += 8; } this.container = (ItemContainer) num; } else if (this.container == ItemContainer.Unspecified) { if (this.location == EquipmentLocation.NotApplicable) { if ((this.Flags & ItemFlags.InSocket) == ItemFlags.InSocket) { this.container = ItemContainer.Item; this.y = -1; } else if ((this.action == ItemActionType.PutInBelt) || (this.action == ItemActionType.RemoveFromBelt)) { this.container = ItemContainer.Belt; this.y = this.x / 4; this.x = this.x % 4; } } else { this.x = -1; this.y = -1; } } if ((this.flags & ItemFlags.Ear) == ItemFlags.Ear) { this.charClass = (CharacterClass) br.ReadByte(3); this.level = br.ReadByte(7); this.name = br.ReadString(7, '\0', 0x10); this.baseItem = BaseItem.Get(ItemType.Ear); } else { this.baseItem = BaseItem.GetByID(this.category, br.ReadUInt32()); if (this.baseItem.Type == ItemType.Gold) { this.stats.Add(new SignedStat(BaseStat.Get(StatType.Quantity), br.ReadInt32(br.ReadBoolean(1) ? 0x20 : 12))); } else { this.usedSockets = br.ReadByte(3); if ((this.flags & (ItemFlags.Compact | ItemFlags.Gamble)) == ItemFlags.None) { BaseStat stat; int num2; this.level = br.ReadByte(7); this.quality = (ItemQuality) br.ReadByte(4); if (br.ReadBoolean(1)) { this.graphic = br.ReadByte(3); } if (br.ReadBoolean(1)) { this.color = br.ReadInt32(11); } if ((this.flags & ItemFlags.Identified) == ItemFlags.Identified) { switch (this.quality) { case ItemQuality.Inferior: this.prefix = new ItemAffix(ItemAffixType.InferiorPrefix, br.ReadByte(3)); break; case ItemQuality.Superior: this.prefix = new ItemAffix(ItemAffixType.SuperiorPrefix, 0); this.superiorType = (SuperiorItemType) br.ReadByte(3); break; case ItemQuality.Magic: this.prefix = new ItemAffix(ItemAffixType.MagicPrefix, br.ReadUInt16(11)); this.suffix = new ItemAffix(ItemAffixType.MagicSuffix, br.ReadUInt16(11)); break; case ItemQuality.Set: this.setItem = BaseSetItem.Get(br.ReadUInt16(12)); break; case ItemQuality.Rare: case ItemQuality.Crafted: this.prefix = new ItemAffix(ItemAffixType.RarePrefix, br.ReadByte(8)); this.suffix = new ItemAffix(ItemAffixType.RareSuffix, br.ReadByte(8)); break; case ItemQuality.Unique: if (this.baseItem.Code != "std") { try { this.uniqueItem = BaseUniqueItem.Get(br.ReadUInt16(12)); } catch{} } break; } } if ((this.quality == ItemQuality.Rare) || (this.quality == ItemQuality.Crafted)) { this.magicPrefixes = new List<MagicPrefixType>(); this.magicSuffixes = new List<MagicSuffixType>(); for (int i = 0; i < 3; i++) { if (br.ReadBoolean(1)) { this.magicPrefixes.Add((MagicPrefixType) br.ReadUInt16(11)); } if (br.ReadBoolean(1)) { this.magicSuffixes.Add((MagicSuffixType) br.ReadUInt16(11)); } } } if ((this.Flags & ItemFlags.Runeword) == ItemFlags.Runeword) { this.runewordID = br.ReadUInt16(12); this.runewordParam = br.ReadUInt16(4); num2 = -1; if (this.runewordParam == 5) { num2 = this.runewordID - (this.runewordParam * 5); if (num2 < 100) { num2--; } } else if (this.runewordParam == 2) { num2 = ((this.runewordID & 0x3ff) >> 5) + 2; } br.ByteOffset -= 2; this.runewordParam = br.ReadUInt16(); this.runewordID = num2; if (num2 == -1) { throw new Exception("Unknown Runeword: " + this.runewordParam); } this.runeword = BaseRuneword.Get(num2); } if ((this.Flags & ItemFlags.Personalized) == ItemFlags.Personalized) { this.name = br.ReadString(7, '\0', 0x10); } if (this.baseItem is BaseArmor) { stat = BaseStat.Get(StatType.ArmorClass); this.stats.Add(new SignedStat(stat, br.ReadInt32(stat.SaveBits) - stat.SaveAdd)); } if ((this.baseItem is BaseArmor) || (this.baseItem is BaseWeapon)) { stat = BaseStat.Get(StatType.MaxDurability); num2 = br.ReadInt32(stat.SaveBits); this.stats.Add(new SignedStat(stat, num2)); if (num2 > 0) { stat = BaseStat.Get(StatType.Durability); this.stats.Add(new SignedStat(stat, br.ReadInt32(stat.SaveBits))); } } if ((this.Flags & (ItemFlags.None | ItemFlags.Socketed)) == (ItemFlags.None | ItemFlags.Socketed)) { stat = BaseStat.Get(StatType.Sockets); this.stats.Add(new SignedStat(stat, br.ReadInt32(stat.SaveBits))); } if (this.baseItem.Stackable) { if (this.baseItem.Useable) { this.use = br.ReadByte(5); } this.stats.Add(new SignedStat(BaseStat.Get(StatType.Quantity), br.ReadInt32(9))); } if ((this.Flags & ItemFlags.Identified) == ItemFlags.Identified) { StatBase base2; int num4 = (this.Quality == ItemQuality.Set) ? br.ReadByte(5) : -1; this.mods = new List<StatBase>(); while ((base2 = ReadStat(br)) != null) { this.mods.Add(base2); } if ((this.flags & ItemFlags.Runeword) == ItemFlags.Runeword) { while ((base2 = ReadStat(br)) != null) { this.mods.Add(base2); } } if (num4 > 0) { this.setBonuses = new List<StatBase>[5]; for (int j = 0; j < 5; j++) { if ((num4 & (((int) 1) << j)) != 0) { this.setBonuses[j] = new List<StatBase>(); while ((base2 = ReadStat(br)) != null) { this.setBonuses[j].Add(base2); } } } } } } } } }