Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarItemDatabase.hpp
blob: 8268acef51096a5111c1551e7971a57526a2a980 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#pragma once

#include "StarThread.hpp"
#include "StarItemRecipe.hpp"
#include "StarItem.hpp"
#include "StarCasting.hpp"
#include "StarLuaRoot.hpp"
#include "StarTtlCache.hpp"

namespace Star {

STAR_CLASS(RecipeDatabase);
STAR_CLASS(AugmentItem);

STAR_CLASS(ItemDatabase);

STAR_EXCEPTION(ItemDatabaseException, ItemException);

enum class ItemType {
  Generic,
  LiquidItem,
  MaterialItem,
  ObjectItem,
  CurrencyItem,
  MiningTool,
  Flashlight,
  WireTool,
  BeamMiningTool,
  HarvestingTool,
  TillingTool,
  PaintingBeamTool,
  HeadArmor,
  ChestArmor,
  LegsArmor,
  BackArmor,
  Consumable,
  Blueprint,
  Codex,
  InspectionTool,
  InstrumentItem,
  GrapplingHook,
  ThrownItem,
  UnlockItem,
  ActiveItem,
  AugmentItem
};
extern EnumMap<ItemType> ItemTypeNames;

class ItemDatabase {
public:
  // During item loading, the ItemDatabase takes the ItemDescriptor and
  // produces a set of things from it:
  struct ItemConfig {
    // The relative path in assets to the base config
    String directory;

    // A possibly modified / generated config from the base config that is
    // re-constructed each time an ItemDescriptor is loaded.  Become's the
    // Item's base config.
    Json config;

    // The parameters from the ItemDescriptor, also possibly modified during
    // loading.  Since this become's the Item's parameters, it will be
    // subsequently stored with the Item as the new ItemDescriptor.
    Json parameters;
  };

  static uint64_t getCountOfItem(List<ItemPtr> const& bag, ItemDescriptor const& item, bool exactMatch = false);
  static uint64_t getCountOfItem(HashMap<ItemDescriptor, uint64_t> const& bag, ItemDescriptor const& item, bool exactMatch = false);
  static HashMap<ItemDescriptor, uint64_t> normalizeBag(List<ItemPtr> const& bag);
  static bool canMakeRecipe(ItemRecipe const& recipe, HashMap<ItemDescriptor, uint64_t> const& availableIngredients, StringMap<uint64_t> const& availableCurrencies);
  static HashSet<ItemRecipe> recipesFromSubset(HashMap<ItemDescriptor, uint64_t> const& normalizedBag, StringMap<uint64_t> const& availableCurrencies, HashSet<ItemRecipe> const& subset);
  static HashSet<ItemRecipe> recipesFromSubset(HashMap<ItemDescriptor, uint64_t> const& normalizedBag, StringMap<uint64_t> const& availableCurrencies, HashSet<ItemRecipe> const& subset, StringSet const& allowedTypes);
  static String guiFilterString(ItemPtr const& item);

  ItemDatabase();

  void cleanup();

  // Load an item based on item descriptor.  If loadItem is called with a
  // live ptr, and the ptr matches the descriptor read, then no new item is
  // constructed.  If ItemT is some other type than Item, then loadItem will
  // clear the item if the new item is not castable to it.  Returns whether
  // itemPtr was changed.  No exception will be thrown if there is an error
  // spawning the new item, it will be logged and the itemPtr will be set to a
  // default item.
  template <typename ItemT>
  bool loadItem(ItemDescriptor const& descriptor, shared_ptr<ItemT>& itemPtr) const;

  // Protects against re-instantiating an item in the same was as loadItem
  template <typename ItemT>
  bool diskLoad(Json const& diskStore, shared_ptr<ItemT>& itemPtr) const;

  ItemPtr diskLoad(Json const& diskStore) const;
  ItemPtr fromJson(Json const& spec) const;

  Json diskStore(ItemConstPtr const& itemPtr) const;

  Json toJson(ItemConstPtr const& itemPtr) const;

  bool hasItem(String const& itemName) const;
  ItemType itemType(String const& itemName) const;
  // Friendly name here can be different than the final friendly name, as it
  // can be modified by custom config or builder scripts.
  String itemFriendlyName(String const& itemName) const;
  StringSet itemTags(String const& itemName) const;

  // Generate an item config for the given itemName, parameters, level and seed.
  // Level and seed are used by generation in some item types, and may be stored as part
  // of the unique item data or may be ignored.
  ItemConfig itemConfig(String const& itemName, Json parameters, Maybe<float> level = {}, Maybe<uint64_t> seed = {}) const;

  // Returns the path to the item's json file in the assets.
  Maybe<String> itemFile(String const& itemName) const;

  // Generates the config for the given item descriptor and then loads the item
  // from the appropriate factory.  If there is a problem instantiating the
  // item, will return a default item instead.  If item is passed a null
  // ItemDescriptor, it will return a null pointer.
  // The returned item pointer will be shared. Either call ->clone() or use item() instead for a copy.
  ItemPtr itemShared(ItemDescriptor descriptor, Maybe<float> level = {}, Maybe<uint64_t> seed = {}) const;
  // Same as itemShared, but makes a copy instead. Does not cache.
  ItemPtr item(ItemDescriptor descriptor, Maybe<float> level = {}, Maybe<uint64_t> seed = {}, bool ignoreInvalid = false) const;


  bool hasRecipeToMake(ItemDescriptor const& item) const;
  bool hasRecipeToMake(ItemDescriptor const& item, StringSet const& allowedTypes) const;

  HashSet<ItemRecipe> recipesForOutputItem(String itemName) const;

  HashSet<ItemRecipe> recipesFromBagContents(List<ItemPtr> const& bag, StringMap<uint64_t> const& availableCurrencies) const;
  HashSet<ItemRecipe> recipesFromBagContents(HashMap<ItemDescriptor, uint64_t> const& bag, StringMap<uint64_t> const& availableCurrencies) const;

  HashSet<ItemRecipe> recipesFromBagContents(List<ItemPtr> const& bag, StringMap<uint64_t> const& availableCurrencies, StringSet const& allowedTypes) const;
  HashSet<ItemRecipe> recipesFromBagContents(HashMap<ItemDescriptor, uint64_t> const& bag, StringMap<uint64_t> const& availableCurrencies, StringSet const& allowedTypes) const;

  uint64_t maxCraftableInBag(List<ItemPtr> const& bag, StringMap<uint64_t> const& availableCurrencies, ItemRecipe const& recipe) const;
  uint64_t maxCraftableInBag(HashMap<ItemDescriptor, uint64_t> const& bag, StringMap<uint64_t> const& availableCurrencies, ItemRecipe const& recipe) const;

  ItemRecipe getPreciseRecipeForMaterials(String const& group, List<ItemPtr> const& bag, StringMap<uint64_t> const& availableCurrencies) const;

  ItemRecipe parseRecipe(Json const& config) const;

  HashSet<ItemRecipe> const& allRecipes() const;
  HashSet<ItemRecipe> allRecipes(StringSet const& types) const;

  ItemPtr applyAugment(ItemPtr const item, AugmentItem* augment) const;
  bool ageItem(ItemPtr& item, double aging) const;

  List<String> allItems() const;

private:
  struct ItemData {
    ItemType type;
    String name;
    String friendlyName;
    StringSet itemTags;
    StringList agingScripts;
    Maybe<String> assetsConfig;
    JsonObject customConfig;
    String directory;
    String filename;
  };

  static ItemPtr createItem(ItemType type, ItemConfig const& config);
  ItemPtr tryCreateItem(ItemDescriptor const& descriptor, Maybe<float> level = {}, Maybe<uint64_t> seed = {}, bool ignoreInvalid = false) const;

  ItemData const& itemData(String const& name) const;
  ItemRecipe makeRecipe(List<ItemDescriptor> inputs, ItemDescriptor output, float duration, StringSet groups) const;

  void addItemSet(ItemType type, String const& extension);
  void addObjectDropItem(String const& objectPath, Json const& objectConfig);

  void scanItems();
  void addObjectItems();
  void scanRecipes();
  void addBlueprints();
  void addCodexes();

  StringMap<ItemData> m_items;
  HashSet<ItemRecipe> m_recipes;

  mutable RecursiveMutex m_luaMutex;
  LuaRootPtr m_luaRoot;

  typedef tuple<ItemDescriptor, Maybe<float>, Maybe<uint64_t>> ItemCacheEntry;

  mutable Mutex m_cacheMutex;
  mutable HashTtlCache<ItemCacheEntry, ItemPtr> m_itemCache;
};

template <typename ItemT>
bool ItemDatabase::loadItem(ItemDescriptor const& descriptor, shared_ptr<ItemT>& itemPtr) const {
  if (descriptor.isNull()) {
    if (itemPtr) {
      itemPtr.reset();
      return true;
    }
  } else {
    if (!itemPtr || !itemPtr->matches(descriptor, true)) {
      itemPtr = as<ItemT>(item(descriptor));
      return true;
    } else if (itemPtr->count() != descriptor.count()) {
      itemPtr->setCount(descriptor.count());
      return true;
    }
  }
  return false;
}

template <typename ItemT>
bool ItemDatabase::diskLoad(Json const& diskStore, shared_ptr<ItemT>& itemPtr) const {
  try {
    return loadItem(ItemDescriptor::loadStore(diskStore), itemPtr);
  } catch (StarException const&) {
    return false;
  }
}
}