Re-add oredict mode with "exact mode" off/on (by default ON)
This commit is contained in:
@@ -32,9 +32,9 @@ public interface ICraftingPattern {
|
|||||||
boolean isProcessing();
|
boolean isProcessing();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the crafting pattern is oredicted, false otherwise
|
* @return true if the crafting pattern is in exact mode, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean isOredict();
|
boolean isExact();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the inputs per slot
|
* @return the inputs per slot
|
||||||
|
|||||||
@@ -9,10 +9,12 @@ import com.raoulvdberge.refinedstorage.item.PatternItem;
|
|||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.inventory.CraftingInventory;
|
import net.minecraft.inventory.CraftingInventory;
|
||||||
import net.minecraft.inventory.container.Container;
|
import net.minecraft.inventory.container.Container;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.crafting.ICraftingRecipe;
|
import net.minecraft.item.crafting.ICraftingRecipe;
|
||||||
import net.minecraft.item.crafting.IRecipeType;
|
import net.minecraft.item.crafting.IRecipeType;
|
||||||
import net.minecraft.item.crafting.Ingredient;
|
import net.minecraft.item.crafting.Ingredient;
|
||||||
|
import net.minecraft.tags.ItemTags;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
@@ -26,7 +28,7 @@ public class CraftingPattern implements ICraftingPattern {
|
|||||||
private ICraftingPatternContainer container;
|
private ICraftingPatternContainer container;
|
||||||
private ItemStack stack;
|
private ItemStack stack;
|
||||||
private boolean processing;
|
private boolean processing;
|
||||||
private boolean oredict;
|
private boolean exact;
|
||||||
private boolean valid;
|
private boolean valid;
|
||||||
private ICraftingRecipe recipe;
|
private ICraftingRecipe recipe;
|
||||||
private List<NonNullList<ItemStack>> inputs = new ArrayList<>();
|
private List<NonNullList<ItemStack>> inputs = new ArrayList<>();
|
||||||
@@ -39,7 +41,7 @@ public class CraftingPattern implements ICraftingPattern {
|
|||||||
this.container = container;
|
this.container = container;
|
||||||
this.stack = stack;
|
this.stack = stack;
|
||||||
this.processing = PatternItem.isProcessing(stack);
|
this.processing = PatternItem.isProcessing(stack);
|
||||||
this.oredict = PatternItem.isOredict(stack);
|
this.exact = PatternItem.isExact(stack);
|
||||||
|
|
||||||
if (processing) {
|
if (processing) {
|
||||||
for (int i = 0; i < 9; ++i) {
|
for (int i = 0; i < 9; ++i) {
|
||||||
@@ -47,30 +49,18 @@ public class CraftingPattern implements ICraftingPattern {
|
|||||||
|
|
||||||
if (input.isEmpty()) {
|
if (input.isEmpty()) {
|
||||||
inputs.add(NonNullList.create());
|
inputs.add(NonNullList.create());
|
||||||
} else if (oredict) {
|
} else if (exact) {
|
||||||
NonNullList<ItemStack> ores = NonNullList.create();
|
NonNullList<ItemStack> possibilities = NonNullList.create();
|
||||||
|
|
||||||
ores.add(input.copy());
|
possibilities.add(input.copy());
|
||||||
|
|
||||||
// TODO: OREDICT
|
for (ResourceLocation owningTag : ItemTags.getCollection().getOwningTags(input.getItem())) {
|
||||||
/*for (int id : OreDictionary.getOreIDs(input)) {
|
for (Item element : ItemTags.getCollection().get(owningTag).getAllElements()) {
|
||||||
String name = OreDictionary.getOreName(id);
|
possibilities.add(new ItemStack(element, input.getCount()));
|
||||||
|
|
||||||
for (ItemStack ore : OreDictionary.getOres(name)) {
|
|
||||||
if (ore.getMetadata() == OreDictionary.WILDCARD_VALUE) {
|
|
||||||
ore.getItem().getSubItems(CreativeTabs.SEARCH, ores);
|
|
||||||
} else {
|
|
||||||
ores.add(ore.copy());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}*/
|
|
||||||
|
|
||||||
// Fix item count
|
|
||||||
for (ItemStack ore : ores) {
|
|
||||||
ore.setCount(input.getCount());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs.add(ores);
|
inputs.add(possibilities);
|
||||||
} else {
|
} else {
|
||||||
inputs.add(NonNullList.from(ItemStack.EMPTY, input));
|
inputs.add(NonNullList.from(ItemStack.EMPTY, input));
|
||||||
}
|
}
|
||||||
@@ -120,7 +110,7 @@ public class CraftingPattern implements ICraftingPattern {
|
|||||||
|
|
||||||
outputs.add(output);
|
outputs.add(output);
|
||||||
|
|
||||||
if (oredict) {
|
if (exact) {
|
||||||
if (recipe.getIngredients().size() > 0) {
|
if (recipe.getIngredients().size() > 0) {
|
||||||
inputs.clear();
|
inputs.clear();
|
||||||
|
|
||||||
@@ -157,8 +147,8 @@ public class CraftingPattern implements ICraftingPattern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOredict() {
|
public boolean isExact() {
|
||||||
return oredict;
|
return exact;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -248,7 +238,7 @@ public class CraftingPattern implements ICraftingPattern {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canBeInChainWith(ICraftingPattern other) {
|
public boolean canBeInChainWith(ICraftingPattern other) {
|
||||||
if (other.isProcessing() != processing || other.isOredict() != oredict) {
|
if (other.isProcessing() != processing || other.isExact() != exact) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +302,7 @@ public class CraftingPattern implements ICraftingPattern {
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
result = 31 * result + (processing ? 1 : 0);
|
result = 31 * result + (processing ? 1 : 0);
|
||||||
result = 31 * result + (oredict ? 1 : 0);
|
result = 31 * result + (exact ? 1 : 0);
|
||||||
|
|
||||||
for (List<ItemStack> inputs : this.inputs) {
|
for (List<ItemStack> inputs : this.inputs) {
|
||||||
for (ItemStack input : inputs) {
|
for (ItemStack input : inputs) {
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public class CraftingTask implements ICraftingTask {
|
|||||||
|
|
||||||
private static final int DEFAULT_EXTRACT_FLAGS = IComparer.COMPARE_NBT;
|
private static final int DEFAULT_EXTRACT_FLAGS = IComparer.COMPARE_NBT;
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManager.getLogger();
|
private static final Logger LOGGER = LogManager.getLogger(CraftingTask.class);
|
||||||
|
|
||||||
private INetwork network;
|
private INetwork network;
|
||||||
private ICraftingRequestInfo requested;
|
private ICraftingRequestInfo requested;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, I
|
|||||||
public static final String NBT_SORTING_DIRECTION = "SortingDirection";
|
public static final String NBT_SORTING_DIRECTION = "SortingDirection";
|
||||||
public static final String NBT_SORTING_TYPE = "SortingType";
|
public static final String NBT_SORTING_TYPE = "SortingType";
|
||||||
public static final String NBT_SEARCH_BOX_MODE = "SearchBoxMode";
|
public static final String NBT_SEARCH_BOX_MODE = "SearchBoxMode";
|
||||||
private static final String NBT_OREDICT_PATTERN = "OredictPattern";
|
private static final String NBT_EXACT_MODE = "Exact";
|
||||||
public static final String NBT_TAB_SELECTED = "TabSelected";
|
public static final String NBT_TAB_SELECTED = "TabSelected";
|
||||||
public static final String NBT_TAB_PAGE = "TabPage";
|
public static final String NBT_TAB_PAGE = "TabPage";
|
||||||
public static final String NBT_SIZE = "Size";
|
public static final String NBT_SIZE = "Size";
|
||||||
@@ -159,7 +159,7 @@ public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, I
|
|||||||
private int tabSelected = -1;
|
private int tabSelected = -1;
|
||||||
private int tabPage = 0;
|
private int tabPage = 0;
|
||||||
|
|
||||||
private boolean oredictPattern = false;
|
private boolean exactPattern = true;
|
||||||
private boolean processingPattern = false;
|
private boolean processingPattern = false;
|
||||||
private int processingType = IType.ITEMS;
|
private int processingType = IType.ITEMS;
|
||||||
|
|
||||||
@@ -213,12 +213,12 @@ public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, I
|
|||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOredictPattern() {
|
public boolean isExactPattern() {
|
||||||
return oredictPattern;
|
return exactPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOredictPattern(boolean oredictPattern) {
|
public void setExactPattern(boolean exactPattern) {
|
||||||
this.oredictPattern = oredictPattern;
|
this.exactPattern = exactPattern;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isProcessingPattern() {
|
public boolean isProcessingPattern() {
|
||||||
@@ -402,7 +402,7 @@ public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, I
|
|||||||
ItemStack pattern = new ItemStack(RSItems.PATTERN);
|
ItemStack pattern = new ItemStack(RSItems.PATTERN);
|
||||||
|
|
||||||
PatternItem.setToCurrentVersion(pattern);
|
PatternItem.setToCurrentVersion(pattern);
|
||||||
PatternItem.setOredict(pattern, oredictPattern);
|
PatternItem.setExact(pattern, exactPattern);
|
||||||
PatternItem.setProcessing(pattern, processingPattern);
|
PatternItem.setProcessing(pattern, processingPattern);
|
||||||
|
|
||||||
if (processingPattern) {
|
if (processingPattern) {
|
||||||
@@ -633,7 +633,7 @@ public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, I
|
|||||||
tag.putInt(NBT_SEARCH_BOX_MODE, searchBoxMode);
|
tag.putInt(NBT_SEARCH_BOX_MODE, searchBoxMode);
|
||||||
tag.putInt(NBT_SIZE, size);
|
tag.putInt(NBT_SIZE, size);
|
||||||
|
|
||||||
tag.putBoolean(NBT_OREDICT_PATTERN, oredictPattern);
|
tag.putBoolean(NBT_EXACT_MODE, exactPattern);
|
||||||
tag.putBoolean(NBT_PROCESSING_PATTERN, processingPattern);
|
tag.putBoolean(NBT_PROCESSING_PATTERN, processingPattern);
|
||||||
tag.putInt(NBT_PROCESSING_TYPE, processingType);
|
tag.putInt(NBT_PROCESSING_TYPE, processingType);
|
||||||
|
|
||||||
@@ -664,8 +664,8 @@ public class GridNetworkNode extends NetworkNode implements INetworkAwareGrid, I
|
|||||||
size = tag.getInt(NBT_SIZE);
|
size = tag.getInt(NBT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag.contains(NBT_OREDICT_PATTERN)) {
|
if (tag.contains(NBT_EXACT_MODE)) {
|
||||||
oredictPattern = tag.getBoolean(NBT_OREDICT_PATTERN);
|
exactPattern = tag.getBoolean(NBT_EXACT_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag.contains(NBT_PROCESSING_PATTERN)) {
|
if (tag.contains(NBT_PROCESSING_PATTERN)) {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class PatternItem extends Item implements ICraftingPatternProvider {
|
|||||||
private static final String NBT_OUTPUT_SLOT = "Output_%d";
|
private static final String NBT_OUTPUT_SLOT = "Output_%d";
|
||||||
private static final String NBT_FLUID_INPUT_SLOT = "FluidInput_%d";
|
private static final String NBT_FLUID_INPUT_SLOT = "FluidInput_%d";
|
||||||
private static final String NBT_FLUID_OUTPUT_SLOT = "FluidOutput_%d";
|
private static final String NBT_FLUID_OUTPUT_SLOT = "FluidOutput_%d";
|
||||||
private static final String NBT_OREDICT = "Oredict"; // TODO - Rename since oredict is gone
|
private static final String NBT_EXACT = "Exact";
|
||||||
private static final String NBT_PROCESSING = "Processing";
|
private static final String NBT_PROCESSING = "Processing";
|
||||||
|
|
||||||
private static final int VERSION = 1;
|
private static final int VERSION = 1;
|
||||||
@@ -85,8 +85,8 @@ public class PatternItem extends Item implements ICraftingPatternProvider {
|
|||||||
RenderUtils.addCombinedItemsToTooltip(tooltip, true, pattern.getOutputs());
|
RenderUtils.addCombinedItemsToTooltip(tooltip, true, pattern.getOutputs());
|
||||||
RenderUtils.addCombinedFluidsToTooltip(tooltip, true, pattern.getFluidOutputs());
|
RenderUtils.addCombinedFluidsToTooltip(tooltip, true, pattern.getFluidOutputs());
|
||||||
|
|
||||||
if (isOredict(stack)) {
|
if (isExact(stack)) {
|
||||||
tooltip.add(new TranslationTextComponent("misc.refinedstorage.pattern.oredict").setStyle(blue));
|
tooltip.add(new TranslationTextComponent("misc.refinedstorage.pattern.exact").setStyle(blue));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isProcessing(stack)) {
|
if (isProcessing(stack)) {
|
||||||
@@ -198,16 +198,20 @@ public class PatternItem extends Item implements ICraftingPatternProvider {
|
|||||||
pattern.getTag().putBoolean(NBT_PROCESSING, processing);
|
pattern.getTag().putBoolean(NBT_PROCESSING, processing);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isOredict(ItemStack pattern) {
|
public static boolean isExact(ItemStack pattern) {
|
||||||
return pattern.hasTag() && pattern.getTag().contains(NBT_OREDICT) && pattern.getTag().getBoolean(NBT_OREDICT);
|
if (!pattern.hasTag() || !pattern.getTag().contains(NBT_EXACT)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pattern.getTag().getBoolean(NBT_EXACT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setOredict(ItemStack pattern, boolean oredict) {
|
public static void setExact(ItemStack pattern, boolean exact) {
|
||||||
if (!pattern.hasTag()) {
|
if (!pattern.hasTag()) {
|
||||||
pattern.setTag(new CompoundNBT());
|
pattern.setTag(new CompoundNBT());
|
||||||
}
|
}
|
||||||
|
|
||||||
pattern.getTag().putBoolean(NBT_OREDICT, oredict);
|
pattern.getTag().putBoolean(NBT_EXACT, exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setToCurrentVersion(ItemStack pattern) {
|
public static void setToCurrentVersion(ItemStack pattern) {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public class GridScreen extends BaseScreen<GridContainer> implements IScreenInfo
|
|||||||
private IGridView view;
|
private IGridView view;
|
||||||
|
|
||||||
private SearchWidget searchField;
|
private SearchWidget searchField;
|
||||||
private GuiCheckBox oredictPattern;
|
private GuiCheckBox exactPattern;
|
||||||
private GuiCheckBox processingPattern;
|
private GuiCheckBox processingPattern;
|
||||||
|
|
||||||
private ScrollbarWidget scrollbar;
|
private ScrollbarWidget scrollbar;
|
||||||
@@ -135,14 +135,14 @@ public class GridScreen extends BaseScreen<GridContainer> implements IScreenInfo
|
|||||||
TileDataManager.setParameter(GridTile.PROCESSING_PATTERN, processingPattern.isChecked());
|
TileDataManager.setParameter(GridTile.PROCESSING_PATTERN, processingPattern.isChecked());
|
||||||
});
|
});
|
||||||
|
|
||||||
boolean showOredict = true;
|
boolean showExactPatternOption = true;
|
||||||
if (((GridNetworkNode) grid).isProcessingPattern() && ((GridNetworkNode) grid).getType() == IType.FLUIDS) {
|
if (((GridNetworkNode) grid).isProcessingPattern() && ((GridNetworkNode) grid).getType() == IType.FLUIDS) {
|
||||||
showOredict = false;
|
showExactPatternOption = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showOredict) {
|
if (showExactPatternOption) {
|
||||||
oredictPattern = addCheckBox(processingPattern.x + processingPattern.getWidth() + 5, y + getTopHeight() + (getVisibleRows() * 18) + 60, I18n.format("misc.refinedstorage:oredict"), GridTile.OREDICT_PATTERN.getValue(), btn -> {
|
exactPattern = addCheckBox(processingPattern.x + processingPattern.getWidth() + 5, y + getTopHeight() + (getVisibleRows() * 18) + 60, I18n.format("misc.refinedstorage.exact"), GridTile.EXACT_PATTERN.getValue(), btn -> {
|
||||||
TileDataManager.setParameter(GridTile.OREDICT_PATTERN, oredictPattern.isChecked());
|
TileDataManager.setParameter(GridTile.EXACT_PATTERN, exactPattern.isChecked());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,9 +540,9 @@ public class GridScreen extends BaseScreen<GridContainer> implements IScreenInfo
|
|||||||
return searchField;
|
return searchField;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateOredictPattern(boolean checked) {
|
public void updateExactPattern(boolean checked) {
|
||||||
if (oredictPattern != null) {
|
if (exactPattern != null) {
|
||||||
oredictPattern.setIsChecked(checked);
|
exactPattern.setIsChecked(checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,10 +62,10 @@ public class GridTile extends NetworkNodeTile<GridNetworkNode> {
|
|||||||
t.getNode().markDirty();
|
t.getNode().markDirty();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
public static final TileDataParameter<Boolean, GridTile> OREDICT_PATTERN = new TileDataParameter<>(DataSerializers.BOOLEAN, false, t -> t.getNode().isOredictPattern(), (t, v) -> {
|
public static final TileDataParameter<Boolean, GridTile> EXACT_PATTERN = new TileDataParameter<>(DataSerializers.BOOLEAN, true, t -> t.getNode().isExactPattern(), (t, v) -> {
|
||||||
t.getNode().setOredictPattern(v);
|
t.getNode().setExactPattern(v);
|
||||||
t.getNode().markDirty();
|
t.getNode().markDirty();
|
||||||
}, (initial, p) -> BaseScreen.executeLater(GridScreen.class, grid -> grid.updateOredictPattern(p)));
|
}, (initial, p) -> BaseScreen.executeLater(GridScreen.class, grid -> grid.updateExactPattern(p)));
|
||||||
public static final TileDataParameter<Boolean, GridTile> PROCESSING_PATTERN = new TileDataParameter<>(DataSerializers.BOOLEAN, false, t -> t.getNode().isProcessingPattern(), (t, v) -> {
|
public static final TileDataParameter<Boolean, GridTile> PROCESSING_PATTERN = new TileDataParameter<>(DataSerializers.BOOLEAN, false, t -> t.getNode().isProcessingPattern(), (t, v) -> {
|
||||||
t.getNode().setProcessingPattern(v);
|
t.getNode().setProcessingPattern(v);
|
||||||
t.getNode().clearMatrix();
|
t.getNode().clearMatrix();
|
||||||
@@ -95,7 +95,7 @@ public class GridTile extends NetworkNodeTile<GridNetworkNode> {
|
|||||||
dataManager.addWatchedParameter(SIZE);
|
dataManager.addWatchedParameter(SIZE);
|
||||||
dataManager.addWatchedParameter(TAB_SELECTED);
|
dataManager.addWatchedParameter(TAB_SELECTED);
|
||||||
dataManager.addWatchedParameter(TAB_PAGE);
|
dataManager.addWatchedParameter(TAB_PAGE);
|
||||||
dataManager.addWatchedParameter(OREDICT_PATTERN);
|
dataManager.addWatchedParameter(EXACT_PATTERN);
|
||||||
dataManager.addWatchedParameter(PROCESSING_PATTERN);
|
dataManager.addWatchedParameter(PROCESSING_PATTERN);
|
||||||
dataManager.addWatchedParameter(PROCESSING_TYPE);
|
dataManager.addWatchedParameter(PROCESSING_TYPE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,14 +102,14 @@
|
|||||||
"misc.refinedstorage.pattern.inputs": "Inputs",
|
"misc.refinedstorage.pattern.inputs": "Inputs",
|
||||||
"misc.refinedstorage.pattern.outputs": "Outputs",
|
"misc.refinedstorage.pattern.outputs": "Outputs",
|
||||||
"misc.refinedstorage.pattern.invalid": "Invalid pattern",
|
"misc.refinedstorage.pattern.invalid": "Invalid pattern",
|
||||||
"misc.refinedstorage.pattern.oredict": "Uses ore dictionary",
|
"misc.refinedstorage.pattern.exact": "Uses exact mode",
|
||||||
"misc.refinedstorage.security.no_permission": "You have no permission to perform that action.",
|
"misc.refinedstorage.security.no_permission": "You have no permission to perform that action.",
|
||||||
"misc.refinedstorage.start": "Start",
|
"misc.refinedstorage.start": "Start",
|
||||||
"misc.refinedstorage.clear": "Clear",
|
"misc.refinedstorage.clear": "Clear",
|
||||||
"misc.refinedstorage.set": "Set",
|
"misc.refinedstorage.set": "Set",
|
||||||
"misc.refinedstorage:cancel_all": "Cancel All",
|
"misc.refinedstorage:cancel_all": "Cancel All",
|
||||||
"misc.refinedstorage.priority": "Priority",
|
"misc.refinedstorage.priority": "Priority",
|
||||||
"misc.refinedstorage:oredict": "Oredict",
|
"misc.refinedstorage.exact": "Exact",
|
||||||
"misc.refinedstorage.processing": "Processing",
|
"misc.refinedstorage.processing": "Processing",
|
||||||
"misc.refinedstorage.total": "%s total",
|
"misc.refinedstorage.total": "%s total",
|
||||||
"misc.refinedstorage.last_modified.just_now": "Last modified just now by %s",
|
"misc.refinedstorage.last_modified.just_now": "Last modified just now by %s",
|
||||||
|
|||||||
Reference in New Issue
Block a user