base mod created

This commit is contained in:
Mohammad-Ali Minaie
2018-10-08 09:07:47 -04:00
parent 0a7700c356
commit b86dedad2f
7848 changed files with 584664 additions and 1 deletions

View File

@@ -0,0 +1,22 @@
package net.minecraft.client.util;
import java.util.List;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public interface ISearchTree<T>
{
/**
* Searches this search tree for the given text.
* <p>
* If the query does not contain a <code>:</code>, then only {@link #byName} is searched; if it does contain a
* colon, both {@link #byName} and {@link #byId} are searched and the results are merged using a {@link
* MergingIterator}.
* @return A list of all matching items in this search tree.
*
* @param searchText The text to search for. Must be normalized with <code>toLowerCase(Locale.ROOT)</code> before
* calling this method.
*/
List<T> search(String searchText);
}

View File

@@ -0,0 +1,29 @@
package net.minecraft.client.util;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public interface ITooltipFlag
{
boolean isAdvanced();
@SideOnly(Side.CLIENT)
public static enum TooltipFlags implements ITooltipFlag
{
NORMAL(false),
ADVANCED(true);
final boolean isAdvanced;
private TooltipFlags(boolean advanced)
{
this.isAdvanced = advanced;
}
public boolean isAdvanced()
{
return this.isAdvanced;
}
}
}

View File

@@ -0,0 +1,303 @@
package net.minecraft.client.util;
import com.google.gson.JsonObject;
import java.util.Locale;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.JsonUtils;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class JsonBlendingMode
{
private static JsonBlendingMode lastApplied;
private final int srcColorFactor;
private final int srcAlphaFactor;
private final int destColorFactor;
private final int destAlphaFactor;
private final int blendFunction;
private final boolean separateBlend;
private final boolean opaque;
private JsonBlendingMode(boolean separateBlendIn, boolean opaqueIn, int srcColorFactorIn, int destColorFactorIn, int srcAlphaFactorIn, int destAlphaFactorIn, int blendFunctionIn)
{
this.separateBlend = separateBlendIn;
this.srcColorFactor = srcColorFactorIn;
this.destColorFactor = destColorFactorIn;
this.srcAlphaFactor = srcAlphaFactorIn;
this.destAlphaFactor = destAlphaFactorIn;
this.opaque = opaqueIn;
this.blendFunction = blendFunctionIn;
}
public JsonBlendingMode()
{
this(false, true, 1, 0, 1, 0, 32774);
}
public JsonBlendingMode(int srcFactor, int dstFactor, int blendFunctionIn)
{
this(false, false, srcFactor, dstFactor, srcFactor, dstFactor, blendFunctionIn);
}
public JsonBlendingMode(int srcColorFactorIn, int destColorFactorIn, int srcAlphaFactorIn, int destAlphaFactorIn, int blendFunctionIn)
{
this(true, false, srcColorFactorIn, destColorFactorIn, srcAlphaFactorIn, destAlphaFactorIn, blendFunctionIn);
}
public void apply()
{
if (!this.equals(lastApplied))
{
if (lastApplied == null || this.opaque != lastApplied.isOpaque())
{
lastApplied = this;
if (this.opaque)
{
GlStateManager.disableBlend();
return;
}
GlStateManager.enableBlend();
}
GlStateManager.glBlendEquation(this.blendFunction);
if (this.separateBlend)
{
GlStateManager.tryBlendFuncSeparate(this.srcColorFactor, this.destColorFactor, this.srcAlphaFactor, this.destAlphaFactor);
}
else
{
GlStateManager.blendFunc(this.srcColorFactor, this.destColorFactor);
}
}
}
public boolean equals(Object p_equals_1_)
{
if (this == p_equals_1_)
{
return true;
}
else if (!(p_equals_1_ instanceof JsonBlendingMode))
{
return false;
}
else
{
JsonBlendingMode jsonblendingmode = (JsonBlendingMode)p_equals_1_;
if (this.blendFunction != jsonblendingmode.blendFunction)
{
return false;
}
else if (this.destAlphaFactor != jsonblendingmode.destAlphaFactor)
{
return false;
}
else if (this.destColorFactor != jsonblendingmode.destColorFactor)
{
return false;
}
else if (this.opaque != jsonblendingmode.opaque)
{
return false;
}
else if (this.separateBlend != jsonblendingmode.separateBlend)
{
return false;
}
else if (this.srcAlphaFactor != jsonblendingmode.srcAlphaFactor)
{
return false;
}
else
{
return this.srcColorFactor == jsonblendingmode.srcColorFactor;
}
}
}
public int hashCode()
{
int i = this.srcColorFactor;
i = 31 * i + this.srcAlphaFactor;
i = 31 * i + this.destColorFactor;
i = 31 * i + this.destAlphaFactor;
i = 31 * i + this.blendFunction;
i = 31 * i + (this.separateBlend ? 1 : 0);
i = 31 * i + (this.opaque ? 1 : 0);
return i;
}
public boolean isOpaque()
{
return this.opaque;
}
public static JsonBlendingMode parseBlendNode(JsonObject json)
{
if (json == null)
{
return new JsonBlendingMode();
}
else
{
int i = 32774;
int j = 1;
int k = 0;
int l = 1;
int i1 = 0;
boolean flag = true;
boolean flag1 = false;
if (JsonUtils.isString(json, "func"))
{
i = stringToBlendFunction(json.get("func").getAsString());
if (i != 32774)
{
flag = false;
}
}
if (JsonUtils.isString(json, "srcrgb"))
{
j = stringToBlendFactor(json.get("srcrgb").getAsString());
if (j != 1)
{
flag = false;
}
}
if (JsonUtils.isString(json, "dstrgb"))
{
k = stringToBlendFactor(json.get("dstrgb").getAsString());
if (k != 0)
{
flag = false;
}
}
if (JsonUtils.isString(json, "srcalpha"))
{
l = stringToBlendFactor(json.get("srcalpha").getAsString());
if (l != 1)
{
flag = false;
}
flag1 = true;
}
if (JsonUtils.isString(json, "dstalpha"))
{
i1 = stringToBlendFactor(json.get("dstalpha").getAsString());
if (i1 != 0)
{
flag = false;
}
flag1 = true;
}
if (flag)
{
return new JsonBlendingMode();
}
else
{
return flag1 ? new JsonBlendingMode(j, k, l, i1, i) : new JsonBlendingMode(j, k, i);
}
}
}
/**
* Converts a blend function name to an id, returning add (32774) if not recognized.
*/
private static int stringToBlendFunction(String funcName)
{
String s = funcName.trim().toLowerCase(Locale.ROOT);
if ("add".equals(s))
{
return 32774;
}
else if ("subtract".equals(s))
{
return 32778;
}
else if ("reversesubtract".equals(s))
{
return 32779;
}
else if ("reverse_subtract".equals(s))
{
return 32779;
}
else if ("min".equals(s))
{
return 32775;
}
else
{
return "max".equals(s) ? 32776 : 32774;
}
}
private static int stringToBlendFactor(String factorName)
{
String s = factorName.trim().toLowerCase(Locale.ROOT);
s = s.replaceAll("_", "");
s = s.replaceAll("one", "1");
s = s.replaceAll("zero", "0");
s = s.replaceAll("minus", "-");
if ("0".equals(s))
{
return 0;
}
else if ("1".equals(s))
{
return 1;
}
else if ("srccolor".equals(s))
{
return 768;
}
else if ("1-srccolor".equals(s))
{
return 769;
}
else if ("dstcolor".equals(s))
{
return 774;
}
else if ("1-dstcolor".equals(s))
{
return 775;
}
else if ("srcalpha".equals(s))
{
return 770;
}
else if ("1-srcalpha".equals(s))
{
return 771;
}
else if ("dstalpha".equals(s))
{
return 772;
}
else
{
return "1-dstalpha".equals(s) ? 773 : -1;
}
}
}

View File

@@ -0,0 +1,98 @@
package net.minecraft.client.util;
import com.google.common.collect.Lists;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.commons.lang3.StringUtils;
@SideOnly(Side.CLIENT)
public class JsonException extends IOException
{
private final List<JsonException.Entry> entries = Lists.<JsonException.Entry>newArrayList();
private final String message;
public JsonException(String messageIn)
{
this.entries.add(new JsonException.Entry());
this.message = messageIn;
}
public JsonException(String messageIn, Throwable cause)
{
super(cause);
this.entries.add(new JsonException.Entry());
this.message = messageIn;
}
public void prependJsonKey(String key)
{
((JsonException.Entry)this.entries.get(0)).addJsonKey(key);
}
public void setFilenameAndFlush(String filenameIn)
{
(this.entries.get(0)).filename = filenameIn;
this.entries.add(0, new JsonException.Entry());
}
public String getMessage()
{
return "Invalid " + this.entries.get(this.entries.size() - 1) + ": " + this.message;
}
public static JsonException forException(Exception exception)
{
if (exception instanceof JsonException)
{
return (JsonException)exception;
}
else
{
String s = exception.getMessage();
if (exception instanceof FileNotFoundException)
{
s = "File not found";
}
return new JsonException(s, exception);
}
}
@SideOnly(Side.CLIENT)
public static class Entry
{
private String filename;
private final List<String> jsonKeys;
private Entry()
{
this.jsonKeys = Lists.<String>newArrayList();
}
private void addJsonKey(String key)
{
this.jsonKeys.add(0, key);
}
public String getJsonKeys()
{
return StringUtils.join((Iterable)this.jsonKeys, "->");
}
public String toString()
{
if (this.filename != null)
{
return this.jsonKeys.isEmpty() ? this.filename : this.filename + " " + this.getJsonKeys();
}
else
{
return this.jsonKeys.isEmpty() ? "(Unknown file)" : "(Unknown file) " + this.getJsonKeys();
}
}
}
}

View File

@@ -0,0 +1,94 @@
package net.minecraft.client.util;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.client.gui.recipebook.RecipeList;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.CraftingManager;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.stats.RecipeBook;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class RecipeBookClient extends RecipeBook
{
public static final Map<CreativeTabs, List<RecipeList>> RECIPES_BY_TAB = Maps.<CreativeTabs, List<RecipeList>>newHashMap();
public static final List<RecipeList> ALL_RECIPES = Lists.<RecipeList>newArrayList();
private static RecipeList newRecipeList(CreativeTabs p_194082_0_)
{
RecipeList recipelist = new RecipeList();
ALL_RECIPES.add(recipelist);
(RECIPES_BY_TAB.computeIfAbsent(p_194082_0_, (p_194085_0_) ->
{
return new ArrayList();
})).add(recipelist);
(RECIPES_BY_TAB.computeIfAbsent(CreativeTabs.SEARCH, (p_194083_0_) ->
{
return new ArrayList();
})).add(recipelist);
return recipelist;
}
private static CreativeTabs getItemStackTab(ItemStack p_194084_0_)
{
CreativeTabs creativetabs = p_194084_0_.getItem().getCreativeTab();
if (creativetabs != CreativeTabs.BUILDING_BLOCKS && creativetabs != CreativeTabs.TOOLS && creativetabs != CreativeTabs.REDSTONE)
{
return creativetabs == CreativeTabs.COMBAT ? CreativeTabs.TOOLS : CreativeTabs.MISC;
}
else
{
return creativetabs;
}
}
static
{
rebuildTable();
}
public static void rebuildTable()
{
RECIPES_BY_TAB.clear();
ALL_RECIPES.clear();
Table<CreativeTabs, String, RecipeList> table = HashBasedTable.<CreativeTabs, String, RecipeList>create();
for (IRecipe irecipe : CraftingManager.REGISTRY)
{
if (!irecipe.isDynamic())
{
CreativeTabs creativetabs = getItemStackTab(irecipe.getRecipeOutput());
String s = irecipe.getGroup();
RecipeList recipelist1;
if (s.isEmpty())
{
recipelist1 = newRecipeList(creativetabs);
}
else
{
recipelist1 = table.get(creativetabs, s);
if (recipelist1 == null)
{
recipelist1 = newRecipeList(creativetabs);
table.put(creativetabs, s, recipelist1);
}
}
recipelist1.add(irecipe);
}
}
}
}

View File

@@ -0,0 +1,384 @@
package net.minecraft.client.util;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntCollection;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntListIterator;
import java.util.BitSet;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
public class RecipeItemHelper
{
/** Map from {@link #pack} packed ids to counts */
public final Int2IntMap itemToCount = new Int2IntOpenHashMap();
public void accountStack(ItemStack stack)
{
this.accountStack(stack, -1);
}
public void accountStack(ItemStack stack, int forceCount)
{
if (!stack.isEmpty() && !stack.isItemDamaged() && !stack.isItemEnchanted() && !stack.hasDisplayName())
{
int i = pack(stack);
int j = forceCount == -1 ? stack.getCount() : forceCount;
this.increment(i, j);
}
}
public static int pack(ItemStack stack)
{
Item item = stack.getItem();
int i = item.getHasSubtypes() ? stack.getMetadata() : 0;
return Item.REGISTRY.getIDForObject(item) << 16 | i & 65535;
}
public boolean containsItem(int p_194120_1_)
{
return this.itemToCount.get(p_194120_1_) > 0;
}
public int tryTake(int p_194122_1_, int maximum)
{
int i = this.itemToCount.get(p_194122_1_);
if (i >= maximum)
{
this.itemToCount.put(p_194122_1_, i - maximum);
return p_194122_1_;
}
else
{
return 0;
}
}
private void increment(int p_194117_1_, int amount)
{
this.itemToCount.put(p_194117_1_, this.itemToCount.get(p_194117_1_) + amount);
}
public boolean canCraft(IRecipe recipe, @Nullable IntList p_194116_2_)
{
return this.canCraft(recipe, p_194116_2_, 1);
}
public boolean canCraft(IRecipe recipe, @Nullable IntList p_194118_2_, int p_194118_3_)
{
return (new RecipeItemHelper.RecipePicker(recipe)).tryPick(p_194118_3_, p_194118_2_);
}
public int getBiggestCraftableStack(IRecipe recipe, @Nullable IntList p_194114_2_)
{
return this.getBiggestCraftableStack(recipe, Integer.MAX_VALUE, p_194114_2_);
}
public int getBiggestCraftableStack(IRecipe recipe, int p_194121_2_, @Nullable IntList p_194121_3_)
{
return (new RecipeItemHelper.RecipePicker(recipe)).tryPickAll(p_194121_2_, p_194121_3_);
}
public static ItemStack unpack(int p_194115_0_)
{
return p_194115_0_ == 0 ? ItemStack.EMPTY : new ItemStack(Item.getItemById(p_194115_0_ >> 16 & 65535), 1, p_194115_0_ & 65535);
}
public void clear()
{
this.itemToCount.clear();
}
class RecipePicker
{
private final IRecipe recipe;
private final List<Ingredient> ingredients = Lists.<Ingredient>newArrayList();
private final int ingredientCount;
private final int[] possessedIngredientStacks;
private final int possessedIngredientStackCount;
private final BitSet data;
private IntList path = new IntArrayList();
public RecipePicker(IRecipe p_i47608_2_)
{
this.recipe = p_i47608_2_;
this.ingredients.addAll(p_i47608_2_.getIngredients());
this.ingredients.removeIf((p_194103_0_) ->
{
return p_194103_0_ == Ingredient.EMPTY;
});
this.ingredientCount = this.ingredients.size();
this.possessedIngredientStacks = this.getUniqueAvailIngredientItems();
this.possessedIngredientStackCount = this.possessedIngredientStacks.length;
this.data = new BitSet(this.ingredientCount + this.possessedIngredientStackCount + this.ingredientCount + this.ingredientCount * this.possessedIngredientStackCount);
for (int i = 0; i < this.ingredients.size(); ++i)
{
IntList intlist = ((Ingredient)this.ingredients.get(i)).getValidItemStacksPacked();
for (int j = 0; j < this.possessedIngredientStackCount; ++j)
{
if (intlist.contains(this.possessedIngredientStacks[j]))
{
this.data.set(this.getIndex(true, j, i));
}
}
}
}
public boolean tryPick(int p_194092_1_, @Nullable IntList listIn)
{
if (p_194092_1_ <= 0)
{
return true;
}
else
{
int k;
for (k = 0; this.dfs(p_194092_1_); ++k)
{
RecipeItemHelper.this.tryTake(this.possessedIngredientStacks[this.path.getInt(0)], p_194092_1_);
int l = this.path.size() - 1;
this.setSatisfied(this.path.getInt(l));
for (int i1 = 0; i1 < l; ++i1)
{
this.toggleResidual((i1 & 1) == 0, ((Integer)this.path.get(i1)).intValue(), ((Integer)this.path.get(i1 + 1)).intValue());
}
this.path.clear();
this.data.clear(0, this.ingredientCount + this.possessedIngredientStackCount);
}
boolean flag = k == this.ingredientCount;
boolean flag1 = flag && listIn != null;
if (flag1)
{
listIn.clear();
}
this.data.clear(0, this.ingredientCount + this.possessedIngredientStackCount + this.ingredientCount);
int j1 = 0;
List<Ingredient> list = this.recipe.getIngredients();
for (int k1 = 0; k1 < list.size(); ++k1)
{
if (flag1 && list.get(k1) == Ingredient.EMPTY)
{
listIn.add(0);
}
else
{
for (int l1 = 0; l1 < this.possessedIngredientStackCount; ++l1)
{
if (this.hasResidual(false, j1, l1))
{
this.toggleResidual(true, l1, j1);
RecipeItemHelper.this.increment(this.possessedIngredientStacks[l1], p_194092_1_);
if (flag1)
{
listIn.add(this.possessedIngredientStacks[l1]);
}
}
}
++j1;
}
}
return flag;
}
}
private int[] getUniqueAvailIngredientItems()
{
IntCollection intcollection = new IntAVLTreeSet();
for (Ingredient ingredient : this.ingredients)
{
intcollection.addAll(ingredient.getValidItemStacksPacked());
}
IntIterator intiterator = intcollection.iterator();
while (intiterator.hasNext())
{
if (!RecipeItemHelper.this.containsItem(intiterator.nextInt()))
{
intiterator.remove();
}
}
return intcollection.toIntArray();
}
private boolean dfs(int p_194098_1_)
{
int k = this.possessedIngredientStackCount;
for (int l = 0; l < k; ++l)
{
if (RecipeItemHelper.this.itemToCount.get(this.possessedIngredientStacks[l]) >= p_194098_1_)
{
this.visit(false, l);
while (!this.path.isEmpty())
{
int i1 = this.path.size();
boolean flag = (i1 & 1) == 1;
int j1 = this.path.getInt(i1 - 1);
if (!flag && !this.isSatisfied(j1))
{
break;
}
int k1 = flag ? this.ingredientCount : k;
for (int l1 = 0; l1 < k1; ++l1)
{
if (!this.hasVisited(flag, l1) && this.hasConnection(flag, j1, l1) && this.hasResidual(flag, j1, l1))
{
this.visit(flag, l1);
break;
}
}
int i2 = this.path.size();
if (i2 == i1)
{
this.path.removeInt(i2 - 1);
}
}
if (!this.path.isEmpty())
{
return true;
}
}
}
return false;
}
private boolean isSatisfied(int p_194091_1_)
{
return this.data.get(this.getSatisfiedIndex(p_194091_1_));
}
private void setSatisfied(int p_194096_1_)
{
this.data.set(this.getSatisfiedIndex(p_194096_1_));
}
private int getSatisfiedIndex(int p_194094_1_)
{
return this.ingredientCount + this.possessedIngredientStackCount + p_194094_1_;
}
private boolean hasConnection(boolean p_194093_1_, int p_194093_2_, int p_194093_3_)
{
return this.data.get(this.getIndex(p_194093_1_, p_194093_2_, p_194093_3_));
}
private boolean hasResidual(boolean p_194100_1_, int p_194100_2_, int p_194100_3_)
{
return p_194100_1_ != this.data.get(1 + this.getIndex(p_194100_1_, p_194100_2_, p_194100_3_));
}
private void toggleResidual(boolean p_194089_1_, int p_194089_2_, int p_194089_3_)
{
this.data.flip(1 + this.getIndex(p_194089_1_, p_194089_2_, p_194089_3_));
}
private int getIndex(boolean p_194095_1_, int p_194095_2_, int p_194095_3_)
{
int k = p_194095_1_ ? p_194095_2_ * this.ingredientCount + p_194095_3_ : p_194095_3_ * this.ingredientCount + p_194095_2_;
return this.ingredientCount + this.possessedIngredientStackCount + this.ingredientCount + 2 * k;
}
private void visit(boolean p_194088_1_, int p_194088_2_)
{
this.data.set(this.getVisitedIndex(p_194088_1_, p_194088_2_));
this.path.add(p_194088_2_);
}
private boolean hasVisited(boolean p_194101_1_, int p_194101_2_)
{
return this.data.get(this.getVisitedIndex(p_194101_1_, p_194101_2_));
}
private int getVisitedIndex(boolean p_194099_1_, int p_194099_2_)
{
return (p_194099_1_ ? 0 : this.ingredientCount) + p_194099_2_;
}
public int tryPickAll(int p_194102_1_, @Nullable IntList list)
{
int k = 0;
int l = Math.min(p_194102_1_, this.getMinIngredientCount()) + 1;
while (true)
{
int i1 = (k + l) / 2;
if (this.tryPick(i1, (IntList)null))
{
if (l - k <= 1)
{
if (i1 > 0)
{
this.tryPick(i1, list);
}
return i1;
}
k = i1;
}
else
{
l = i1;
}
}
}
private int getMinIngredientCount()
{
int k = Integer.MAX_VALUE;
for (Ingredient ingredient : this.ingredients)
{
int l = 0;
int i1;
for (IntListIterator intlistiterator = ingredient.getValidItemStacksPacked().iterator(); intlistiterator.hasNext(); l = Math.max(l, RecipeItemHelper.this.itemToCount.get(i1)))
{
i1 = ((Integer)intlistiterator.next()).intValue();
}
if (k > 0)
{
k = Math.min(k, l);
}
}
return k;
}
}
}

View File

@@ -0,0 +1,194 @@
package net.minecraft.client.util;
import com.google.common.collect.AbstractIterator;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.function.Consumer;
import java.util.function.Function;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class SearchTree<T> implements ISearchTree<T>
{
/** A {@link SuffixArray} that contains values keyed by the ID (as produced by {@link #idFunc}). */
protected SuffixArray<T> byId = new SuffixArray<T>();
/** A {@link SuffixArray} that contains values keyed by the name (as produced by {@link #nameFunc}). */
protected SuffixArray<T> byName = new SuffixArray<T>();
/**
* A function that takes a <code>T</code> and returns a list of Strings describing it normally.
* <p>
* For both items and recipes, this is implemented via {@link net.minecraft.item.ItemStack#getTooltip()
* ItemStack.getTooltip} (with NORMAL tooltip flags), with formatting codes stripped, text trimmed, and empty lines
* removed.
*
* The result does not need to be corrected for
*/
private final Function<T, Iterable<String>> nameFunc;
/**
* A function that takes a <code>T</code> and returns a list of {@link ResourceLocation}s describing it.
* <p>
* For both items and recipes, this is implemented via <code>Item.REGISTRY.getNameForObject</code>. (In the case of
* registries, it is applied to all results)
*/
private final Function<T, Iterable<ResourceLocation>> idFunc;
/** All entries in the search tree. */
private final List<T> contents = Lists.<T>newArrayList();
/** Maps each entry in the search tree to a locally unique, increasing number (staring at 0). */
private Object2IntMap<T> numericContents = new Object2IntOpenHashMap<T>();
public SearchTree(Function<T, Iterable<String>> nameFuncIn, Function<T, Iterable<ResourceLocation>> idFuncIn)
{
this.nameFunc = nameFuncIn;
this.idFunc = idFuncIn;
}
/**
* Recalculates the contents of this search tree, reapplying {@link #nameFunc} and {@link #idFunc}. Should be called
* whenever resources are reloaded (e.g. language changes).
*/
public void recalculate()
{
this.byId = new SuffixArray<T>();
this.byName = new SuffixArray<T>();
for (T t : this.contents)
{
this.index(t);
}
this.byId.generate();
this.byName.generate();
}
/**
* Adds the given item to the search tree.
*
* @param element The element to add
*/
public void add(T element)
{
this.numericContents.put(element, this.contents.size());
this.contents.add(element);
this.index(element);
}
/**
* Directly puts the given item into {@link #byId} and {@link #byName}, applying {@link #nameFunc} and {@link
* idFunc}.
*
* @param element The element to add
*/
private void index(T element)
{
(this.idFunc.apply(element)).forEach((p_194039_2_) ->
{
this.byName.add(element, p_194039_2_.toString().toLowerCase(Locale.ROOT));
});
(this.nameFunc.apply(element)).forEach((p_194041_2_) ->
{
this.byId.add(element, p_194041_2_.toLowerCase(Locale.ROOT));
});
}
/**
* Searches this search tree for the given text.
* <p>
* If the query does not contain a <code>:</code>, then only {@link #byName} is searched; if it does contain a
* colon, both {@link #byName} and {@link #byId} are searched and the results are merged using a {@link
* MergingIterator}.
* @return A list of all matching items in this search tree.
*
* @param searchText The text to search for. Must be normalized with <code>toLowerCase(Locale.ROOT)</code> before
* calling this method.
*/
public List<T> search(String searchText)
{
List<T> list = this.byId.search(searchText);
if (searchText.indexOf(58) < 0)
{
return list;
}
else
{
List<T> list1 = this.byName.search(searchText);
return (List<T>)(list1.isEmpty() ? list : Lists.newArrayList(new SearchTree.MergingIterator(list.iterator(), list1.iterator(), this.numericContents)));
}
}
@SideOnly(Side.CLIENT)
static class MergingIterator<T> extends AbstractIterator<T>
{
private final Iterator<T> leftItr;
private final Iterator<T> rightItr;
/**
* A mapping of objects to unique numeric IDs, used to sort the list.
* <p>
* Since there's no good place to document how this class works, it basically just interleaves two iterators
* together, choosing the entry that has the lower numeric ID in this map.
*/
private final Object2IntMap<T> numbers;
/** Current element from {@link #leftItr} */
private T left;
/** Current element from {@link #rightItr} */
private T right;
public MergingIterator(Iterator<T> leftIn, Iterator<T> rightIn, Object2IntMap<T> numbersIn)
{
this.leftItr = leftIn;
this.rightItr = rightIn;
this.numbers = numbersIn;
this.left = (T)(leftIn.hasNext() ? leftIn.next() : null);
this.right = (T)(rightIn.hasNext() ? rightIn.next() : null);
}
protected T computeNext()
{
if (this.left == null && this.right == null)
{
return (T)this.endOfData();
}
else
{
int i;
if (this.left == this.right)
{
i = 0;
}
else if (this.left == null)
{
i = 1;
}
else if (this.right == null)
{
i = -1;
}
else
{
i = Integer.compare(this.numbers.getInt(this.left), this.numbers.getInt(this.right));
}
T t = (T)(i <= 0 ? this.left : this.right);
if (i <= 0)
{
this.left = (T)(this.leftItr.hasNext() ? this.leftItr.next() : null);
}
if (i >= 0)
{
this.right = (T)(this.rightItr.hasNext() ? this.rightItr.next() : null);
}
return t;
}
}
}
}

View File

@@ -0,0 +1,46 @@
package net.minecraft.client.util;
import com.google.common.collect.Maps;
import java.util.Map;
import net.minecraft.client.gui.recipebook.RecipeList;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
public class SearchTreeManager implements IResourceManagerReloadListener
{
/** The item search tree, used for the creative inventory's search tab */
public static final SearchTreeManager.Key<ItemStack> ITEMS = new SearchTreeManager.Key<ItemStack>();
/** The recipe search tree, used for the recipe book */
public static final SearchTreeManager.Key<RecipeList> RECIPES = new SearchTreeManager.Key<RecipeList>();
private final Map < SearchTreeManager.Key<?>, SearchTree<? >> trees = Maps. < SearchTreeManager.Key<?>, SearchTree<? >> newHashMap();
public void onResourceManagerReload(IResourceManager resourceManager)
{
for (SearchTree<?> searchtree : this.trees.values())
{
searchtree.recalculate();
}
}
public <T> void register(SearchTreeManager.Key<T> key, SearchTree<T> searchTreeIn)
{
this.trees.put(key, searchTreeIn);
}
/**
* Gets the {@link ISearchTree} for the given search tree key, returning null if no such tree exists.
*/
public <T> ISearchTree<T> get(SearchTreeManager.Key<T> key)
{
return (ISearchTree)this.trees.get(key);
}
@SideOnly(Side.CLIENT)
public static class Key<T>
{
}
}

View File

@@ -0,0 +1,288 @@
package net.minecraft.client.util;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.Arrays;
import it.unimi.dsi.fastutil.Swapper;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntComparator;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@SideOnly(Side.CLIENT)
public class SuffixArray<T>
{
/**
* A debug property (<code>SuffixArray.printComparisons</code>) that can be specified in the JVM arguments, that
* causes debug printing of comparisons as they happen.
*/
private static final boolean DEBUG_PRINT_COMPARISONS = Boolean.parseBoolean(System.getProperty("SuffixArray.printComparisons", "false"));
/**
* A debug property (<code>SuffixArray.printArray</code>) that can be specified in the JVM arguments, that causes
* the full array to be printed ({@link #printArray()}) after calling {@link #generate()}
*/
private static final boolean DEBUG_PRINT_ARRAY = Boolean.parseBoolean(System.getProperty("SuffixArray.printArray", "false"));
private static final Logger LOGGER = LogManager.getLogger();
protected final List<T> list = Lists.<T>newArrayList();
private final IntList chars = new IntArrayList();
private final IntList wordStarts = new IntArrayList();
private IntList suffixToT = new IntArrayList();
private IntList offsets = new IntArrayList();
private int maxStringLength;
public void add(T p_194057_1_, String p_194057_2_)
{
this.maxStringLength = Math.max(this.maxStringLength, p_194057_2_.length());
int i = this.list.size();
this.list.add(p_194057_1_);
this.wordStarts.add(this.chars.size());
for (int j = 0; j < p_194057_2_.length(); ++j)
{
this.suffixToT.add(i);
this.offsets.add(j);
this.chars.add(p_194057_2_.charAt(j));
}
this.suffixToT.add(i);
this.offsets.add(p_194057_2_.length());
this.chars.add(-1);
}
public void generate()
{
int i = this.chars.size();
int[] aint = new int[i];
final int[] aint1 = new int[i];
final int[] aint2 = new int[i];
int[] aint3 = new int[i];
IntComparator intcomparator = new IntComparator()
{
public int compare(int p_compare_1_, int p_compare_2_)
{
return aint1[p_compare_1_] == aint1[p_compare_2_] ? Integer.compare(aint2[p_compare_1_], aint2[p_compare_2_]) : Integer.compare(aint1[p_compare_1_], aint1[p_compare_2_]);
}
public int compare(Integer p_compare_1_, Integer p_compare_2_)
{
return this.compare(p_compare_1_.intValue(), p_compare_2_.intValue());
}
};
Swapper swapper = (p_194054_3_, p_194054_4_) ->
{
if (p_194054_3_ != p_194054_4_)
{
int i2 = aint1[p_194054_3_];
aint1[p_194054_3_] = aint1[p_194054_4_];
aint1[p_194054_4_] = i2;
i2 = aint2[p_194054_3_];
aint2[p_194054_3_] = aint2[p_194054_4_];
aint2[p_194054_4_] = i2;
i2 = aint3[p_194054_3_];
aint3[p_194054_3_] = aint3[p_194054_4_];
aint3[p_194054_4_] = i2;
}
};
for (int j = 0; j < i; ++j)
{
aint[j] = this.chars.getInt(j);
}
int k1 = 1;
for (int k = Math.min(i, this.maxStringLength); k1 * 2 < k; k1 *= 2)
{
for (int l = 0; l < i; aint3[l] = l++)
{
aint1[l] = aint[l];
aint2[l] = l + k1 < i ? aint[l + k1] : -2;
}
Arrays.quickSort(0, i, intcomparator, swapper);
for (int l1 = 0; l1 < i; ++l1)
{
if (l1 > 0 && aint1[l1] == aint1[l1 - 1] && aint2[l1] == aint2[l1 - 1])
{
aint[aint3[l1]] = aint[aint3[l1 - 1]];
}
else
{
aint[aint3[l1]] = l1;
}
}
}
IntList intlist1 = this.suffixToT;
IntList intlist = this.offsets;
this.suffixToT = new IntArrayList(intlist1.size());
this.offsets = new IntArrayList(intlist.size());
for (int i1 = 0; i1 < i; ++i1)
{
int j1 = aint3[i1];
this.suffixToT.add(intlist1.getInt(j1));
this.offsets.add(intlist.getInt(j1));
}
if (DEBUG_PRINT_ARRAY)
{
this.printArray();
}
}
/**
* Prints the entire array to the logger, on debug level
*/
private void printArray()
{
for (int i2 = 0; i2 < this.suffixToT.size(); ++i2)
{
LOGGER.debug("{} {}", Integer.valueOf(i2), this.getString(i2));
}
LOGGER.debug("");
}
private String getString(int p_194059_1_)
{
int i2 = this.offsets.getInt(p_194059_1_);
int j2 = this.wordStarts.getInt(this.suffixToT.getInt(p_194059_1_));
StringBuilder stringbuilder = new StringBuilder();
for (int k2 = 0; j2 + k2 < this.chars.size(); ++k2)
{
if (k2 == i2)
{
stringbuilder.append('^');
}
int l2 = ((Integer)this.chars.get(j2 + k2)).intValue();
if (l2 == -1)
{
break;
}
stringbuilder.append((char)l2);
}
return stringbuilder.toString();
}
private int compare(String p_194056_1_, int p_194056_2_)
{
int i2 = this.wordStarts.getInt(this.suffixToT.getInt(p_194056_2_));
int j2 = this.offsets.getInt(p_194056_2_);
for (int k2 = 0; k2 < p_194056_1_.length(); ++k2)
{
int l2 = this.chars.getInt(i2 + j2 + k2);
if (l2 == -1)
{
return 1;
}
char c0 = p_194056_1_.charAt(k2);
char c1 = (char)l2;
if (c0 < c1)
{
return -1;
}
if (c0 > c1)
{
return 1;
}
}
return 0;
}
public List<T> search(String p_194055_1_)
{
int i2 = this.suffixToT.size();
int j2 = 0;
int k2 = i2;
while (j2 < k2)
{
int l2 = j2 + (k2 - j2) / 2;
int i3 = this.compare(p_194055_1_, l2);
if (DEBUG_PRINT_COMPARISONS)
{
LOGGER.debug("comparing lower \"{}\" with {} \"{}\": {}", p_194055_1_, Integer.valueOf(l2), this.getString(l2), Integer.valueOf(i3));
}
if (i3 > 0)
{
j2 = l2 + 1;
}
else
{
k2 = l2;
}
}
if (j2 >= 0 && j2 < i2)
{
int i4 = j2;
k2 = i2;
while (j2 < k2)
{
int j4 = j2 + (k2 - j2) / 2;
int j3 = this.compare(p_194055_1_, j4);
if (DEBUG_PRINT_COMPARISONS)
{
LOGGER.debug("comparing upper \"{}\" with {} \"{}\": {}", p_194055_1_, Integer.valueOf(j4), this.getString(j4), Integer.valueOf(j3));
}
if (j3 >= 0)
{
j2 = j4 + 1;
}
else
{
k2 = j4;
}
}
int k4 = j2;
IntSet intset = new IntOpenHashSet();
for (int k3 = i4; k3 < k4; ++k3)
{
intset.add(this.suffixToT.getInt(k3));
}
int[] aint4 = intset.toIntArray();
java.util.Arrays.sort(aint4);
Set<T> set = Sets.<T>newLinkedHashSet();
for (int l3 : aint4)
{
set.add(this.list.get(l3));
}
return Lists.newArrayList(set);
}
else
{
return Collections.<T>emptyList();
}
}
}

View File

@@ -0,0 +1,7 @@
// Auto generated package-info by MCP
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
package net.minecraft.client.util;
import mcp.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;