EntryStack.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /*
  2. * This file is licensed under the MIT License, part of Roughly Enough Items.
  3. * Copyright (c) 2018, 2019, 2020 shedaniel
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. * SOFTWARE.
  22. */
  23. package me.shedaniel.rei.api;
  24. import com.google.gson.JsonElement;
  25. import com.google.gson.JsonObject;
  26. import me.shedaniel.math.Point;
  27. import me.shedaniel.math.Rectangle;
  28. import me.shedaniel.rei.api.fluid.FluidSupportProvider;
  29. import me.shedaniel.rei.api.widgets.Tooltip;
  30. import me.shedaniel.rei.impl.EmptyEntryStack;
  31. import me.shedaniel.rei.impl.FluidEntryStack;
  32. import me.shedaniel.rei.impl.ItemEntryStack;
  33. import net.fabricmc.api.EnvType;
  34. import net.fabricmc.api.Environment;
  35. import net.minecraft.client.resource.language.I18n;
  36. import net.minecraft.client.util.math.MatrixStack;
  37. import net.minecraft.fluid.Fluid;
  38. import net.minecraft.item.Item;
  39. import net.minecraft.item.ItemConvertible;
  40. import net.minecraft.item.ItemStack;
  41. import net.minecraft.nbt.CompoundTag;
  42. import net.minecraft.nbt.StringNbtReader;
  43. import net.minecraft.recipe.Ingredient;
  44. import net.minecraft.text.Text;
  45. import net.minecraft.util.Identifier;
  46. import net.minecraft.util.math.MathHelper;
  47. import net.minecraft.util.registry.Registry;
  48. import org.jetbrains.annotations.ApiStatus;
  49. import org.jetbrains.annotations.Nullable;
  50. import java.util.ArrayList;
  51. import java.util.Collection;
  52. import java.util.Collections;
  53. import java.util.List;
  54. import java.util.Optional;
  55. import java.util.function.Function;
  56. import java.util.function.Supplier;
  57. @Environment(EnvType.CLIENT)
  58. @SuppressWarnings("deprecation")
  59. public interface EntryStack extends TextRepresentable {
  60. static EntryStack empty() {
  61. return EmptyEntryStack.EMPTY;
  62. }
  63. static EntryStack create(Fluid fluid) {
  64. return new FluidEntryStack(fluid);
  65. }
  66. static EntryStack create(Fluid fluid, int amount) {
  67. return new FluidEntryStack(fluid, amount);
  68. }
  69. static EntryStack create(Fluid fluid, double amount) {
  70. return new FluidEntryStack(fluid, amount);
  71. }
  72. static EntryStack create(ItemStack stack) {
  73. return new ItemEntryStack(stack);
  74. }
  75. static EntryStack create(ItemConvertible item) {
  76. return create(new ItemStack(item));
  77. }
  78. static List<EntryStack> create(Collection<ItemStack> stacks) {
  79. List<EntryStack> result = new ArrayList<>(stacks.size());
  80. for (ItemStack stack : stacks) {
  81. result.add(create(stack));
  82. }
  83. return result;
  84. }
  85. static List<EntryStack> create(Ingredient ingredient) {
  86. ItemStack[] matchingStacks = ingredient.getMatchingStacksClient();
  87. List<EntryStack> result = new ArrayList<>(matchingStacks.length);
  88. for (ItemStack matchingStack : matchingStacks) {
  89. result.add(create(matchingStack));
  90. }
  91. return result;
  92. }
  93. static List<List<EntryStack>> create(List<Ingredient> ingredients) {
  94. List<List<EntryStack>> result = new ArrayList<>(ingredients.size());
  95. for (Ingredient ingredient : ingredients) {
  96. result.add(create(ingredient));
  97. }
  98. return result;
  99. }
  100. @ApiStatus.Internal
  101. static EntryStack readFromJson(JsonElement jsonElement) {
  102. try {
  103. JsonObject obj = jsonElement.getAsJsonObject();
  104. switch (obj.getAsJsonPrimitive("type").getAsString()) {
  105. case "stack":
  106. return EntryStack.create(ItemStack.fromTag(StringNbtReader.parse(obj.get("nbt").getAsString())));
  107. case "fluid":
  108. return EntryStack.create(Registry.FLUID.get(Identifier.tryParse(obj.get("id").getAsString())));
  109. case "empty":
  110. return EntryStack.empty();
  111. default:
  112. throw new IllegalArgumentException("Invalid Entry Type!");
  113. }
  114. } catch (Exception e) {
  115. e.printStackTrace();
  116. return EntryStack.empty();
  117. }
  118. }
  119. @ApiStatus.Internal
  120. @Nullable
  121. default JsonElement toJson() {
  122. try {
  123. switch (getType()) {
  124. case ITEM:
  125. JsonObject obj1 = new JsonObject();
  126. obj1.addProperty("type", "stack");
  127. obj1.addProperty("nbt", getItemStack().toTag(new CompoundTag()).toString());
  128. return obj1;
  129. case FLUID:
  130. Optional<Identifier> optionalIdentifier = getIdentifier();
  131. if (!optionalIdentifier.isPresent())
  132. throw new NullPointerException("Invalid Fluid: " + toString());
  133. JsonObject obj2 = new JsonObject();
  134. obj2.addProperty("type", "fluid");
  135. obj2.addProperty("id", optionalIdentifier.get().toString());
  136. return obj2;
  137. case EMPTY:
  138. JsonObject obj3 = new JsonObject();
  139. obj3.addProperty("type", "empty");
  140. return obj3;
  141. default:
  142. throw new IllegalArgumentException("Invalid Entry Type!");
  143. }
  144. } catch (Exception e) {
  145. e.printStackTrace();
  146. return null;
  147. }
  148. }
  149. @Deprecated
  150. @ApiStatus.ScheduledForRemoval
  151. static EntryStack copyFluidToBucket(EntryStack stack) {
  152. return copyFluidToItem(stack);
  153. }
  154. @Deprecated
  155. @ApiStatus.ScheduledForRemoval
  156. static EntryStack copyFluidToItem(EntryStack stack) {
  157. Item bucketItem = stack.getFluid().getBucketItem();
  158. if (bucketItem != null) {
  159. return EntryStack.create(bucketItem);
  160. }
  161. return EntryStack.empty();
  162. }
  163. @Deprecated
  164. @ApiStatus.ScheduledForRemoval
  165. static EntryStack copyBucketToFluid(EntryStack stack) {
  166. return copyItemToFluid(stack);
  167. }
  168. static EntryStack copyItemToFluid(EntryStack stack) {
  169. return FluidSupportProvider.INSTANCE.itemToFluid(stack);
  170. }
  171. Optional<Identifier> getIdentifier();
  172. EntryStack.Type getType();
  173. default int getAmount() {
  174. return MathHelper.floor(getFloatingAmount());
  175. }
  176. double getFloatingAmount();
  177. default void setAmount(int amount) {
  178. setFloatingAmount(amount);
  179. }
  180. void setFloatingAmount(double amount);
  181. boolean isEmpty();
  182. EntryStack copy();
  183. Object getObject();
  184. boolean equals(EntryStack stack, boolean ignoreTags, boolean ignoreAmount);
  185. boolean equalsIgnoreTagsAndAmount(EntryStack stack);
  186. boolean equalsIgnoreTags(EntryStack stack);
  187. boolean equalsIgnoreAmount(EntryStack stack);
  188. boolean equalsAll(EntryStack stack);
  189. /**
  190. * {@link #hashCode()} for {@link #equalsAll(EntryStack)}.
  191. */
  192. default int hashOfAll() {
  193. return hashCode();
  194. }
  195. /**
  196. * {@link #hashCode()} for {@link #equalsIgnoreAmount(EntryStack)}
  197. */
  198. default int hashIgnoreAmount() {
  199. return hashCode();
  200. }
  201. /**
  202. * {@link #hashCode()} for {@link #equalsIgnoreTags(EntryStack)}
  203. */
  204. default int hashIgnoreTags() {
  205. return hashCode();
  206. }
  207. /**
  208. * {@link #hashCode()} for {@link #equalsIgnoreTagsAndAmount(EntryStack)}
  209. */
  210. default int hashIgnoreAmountAndTags() {
  211. return hashCode();
  212. }
  213. int getZ();
  214. void setZ(int z);
  215. default ItemStack getItemStack() {
  216. if (getType() == Type.ITEM)
  217. return (ItemStack) getObject();
  218. return null;
  219. }
  220. default Item getItem() {
  221. if (getType() == Type.ITEM)
  222. return ((ItemStack) getObject()).getItem();
  223. return null;
  224. }
  225. default Fluid getFluid() {
  226. if (getType() == Type.FLUID)
  227. return (Fluid) getObject();
  228. return null;
  229. }
  230. <T> EntryStack setting(Settings<T> settings, T value);
  231. <T> EntryStack removeSetting(Settings<T> settings);
  232. EntryStack clearSettings();
  233. default <T> EntryStack addSetting(Settings<T> settings, T value) {
  234. return setting(settings, value);
  235. }
  236. <T> T get(Settings<T> settings);
  237. @Nullable
  238. default Tooltip getTooltip(Point mouse) {
  239. return null;
  240. }
  241. void render(MatrixStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta);
  242. enum Type {
  243. ITEM,
  244. FLUID,
  245. EMPTY,
  246. RENDER
  247. }
  248. class Settings<T> {
  249. public static final Supplier<Boolean> TRUE = () -> true;
  250. public static final Supplier<Boolean> FALSE = () -> false;
  251. public static final Settings<Supplier<Boolean>> RENDER = new Settings<>(TRUE);
  252. public static final Settings<Supplier<Boolean>> CHECK_TAGS = new Settings<>(FALSE);
  253. public static final Settings<Supplier<Boolean>> CHECK_AMOUNT = new Settings<>(FALSE);
  254. public static final Settings<Supplier<Boolean>> TOOLTIP_ENABLED = new Settings<>(TRUE);
  255. public static final Settings<Supplier<Boolean>> TOOLTIP_APPEND_MOD = new Settings<>(TRUE);
  256. public static final Settings<Supplier<Boolean>> RENDER_COUNTS = new Settings<>(TRUE);
  257. public static final Settings<Function<EntryStack, List<Text>>> TOOLTIP_APPEND_EXTRA = new Settings<>(stack -> Collections.emptyList());
  258. public static final Settings<Function<EntryStack, String>> COUNTS = new Settings<>(stack -> null);
  259. private T defaultValue;
  260. public Settings(T defaultValue) {
  261. this.defaultValue = defaultValue;
  262. }
  263. public T getDefaultValue() {
  264. return defaultValue;
  265. }
  266. public static class Item {
  267. public static final Settings<Supplier<Boolean>> RENDER_ENCHANTMENT_GLINT = new Settings<>(TRUE);
  268. private Item() {
  269. }
  270. }
  271. public static class Fluid {
  272. // Return null to disable
  273. public static final Settings<Function<EntryStack, String>> AMOUNT_TOOLTIP = new Settings<>(stack -> I18n.translate("tooltip.rei.fluid_amount", stack.getAmount()));
  274. private Fluid() {
  275. }
  276. }
  277. }
  278. }