Fixed part of the colors problems
This commit is contained in:
@@ -42,11 +42,11 @@ import com.seibel.lod.wrappers.Chunk.ChunkPosWrapper;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
|
||||
import com.seibel.lod.wrappers.World.BiomeColorWrapper;
|
||||
import com.seibel.lod.wrappers.World.BiomeWrapper;
|
||||
import com.seibel.lod.wrappers.World.WorldWrapper;
|
||||
|
||||
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.world.DimensionType;
|
||||
import net.minecraft.world.IWorld;
|
||||
|
||||
@@ -215,7 +215,6 @@ public class LodBuilder
|
||||
int size = 1 << detail.detailLevel;
|
||||
|
||||
long[] dataToMerge = ThreadMapUtil.getBuilderVerticalArray(detail.detailLevel);
|
||||
|
||||
int verticalData = DataPointUtil.worldHeight / 2 + 1;
|
||||
|
||||
ChunkPosWrapper chunkPos = chunk.getPos();
|
||||
@@ -322,7 +321,6 @@ public class LodBuilder
|
||||
{
|
||||
for (int y = yAbs; y >= 0; y--)
|
||||
{
|
||||
blockPos.set(xAbs, y, zAbs);
|
||||
blockPos.set(xAbs, y, zAbs);
|
||||
if (isLayerValidLodPoint(chunk, blockPos))
|
||||
{
|
||||
@@ -368,9 +366,9 @@ public class LodBuilder
|
||||
aboveColorInt = getColorForBlock(chunk, blockPos);
|
||||
}
|
||||
|
||||
if (colorInt == 0 && yAbs > 0)
|
||||
//if (colorInt == 0 && yAbs > 0)
|
||||
// if this block is invisible, check the block below it
|
||||
colorInt = generateLodColor(chunk, config, xRel, yAbs - 1, zRel, blockPos);
|
||||
// colorInt = generateLodColor(chunk, config, xRel, yAbs - 1, zRel, blockPos);
|
||||
|
||||
// override this block's color if there was a block above this
|
||||
// and we were avoiding non-full/non-solid blocks
|
||||
@@ -472,48 +470,51 @@ public class LodBuilder
|
||||
int y = blockPos.getY();
|
||||
int z = blockPos.getZ();
|
||||
|
||||
//Biome biome = chunk.getBiomes().getNoiseBiome(xRel >> 2, y >> 2, zRel >> 2);
|
||||
BlockColorWrapper blockColorWrapper;
|
||||
BlockShapeWrapper blockShapeWrapper;
|
||||
|
||||
if (chunk.isWaterLogged(blockPos))
|
||||
{
|
||||
blockColorWrapper = BlockColorWrapper.WATER_COLOR;
|
||||
blockShapeWrapper = BlockShapeWrapper.WATER_SHAPE;
|
||||
BiomeWrapper biome = chunk.getBiome(xRel, y, zRel);
|
||||
return biome.getWaterTint();
|
||||
//blockColorWrapper = BlockColorWrapper.WATER_COLOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockColorWrapper = chunk.getBlockColorWrapper(blockPos);
|
||||
blockShapeWrapper = chunk.getBlockShapeWrapper(blockPos);
|
||||
}
|
||||
|
||||
/*
|
||||
if (blockShapeWrapper.isToAvoid())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*/
|
||||
colorOfBlock = blockColorWrapper.getColor();
|
||||
|
||||
|
||||
if (blockColorWrapper.hasTint())
|
||||
{
|
||||
BiomeWrapper biome = chunk.getBiome(xRel, y, zRel);
|
||||
|
||||
WorldWrapper world = MinecraftWrapper.INSTANCE.getWrappedServerWorld();
|
||||
|
||||
if (world.isEmpty())
|
||||
{
|
||||
world = MinecraftWrapper.INSTANCE.getWrappedClientWorld();
|
||||
}
|
||||
|
||||
int tintValue;
|
||||
if (blockColorWrapper.hasGrassTint())
|
||||
{
|
||||
// grass and green plants
|
||||
tintValue = biome.getGrassTint(x, z);
|
||||
tintValue = BiomeColorWrapper.getGrassColor(world,blockPos);
|
||||
}
|
||||
else if (blockColorWrapper.hasFolliageTint())
|
||||
{
|
||||
tintValue = biome.getFolliageTint();
|
||||
tintValue = BiomeColorWrapper.getFoliageColor(world,blockPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we can reintroduce this with the wrappers
|
||||
//tintValue = BiomeColors.getAverageFoliageColor(serverWorld, blockPos);
|
||||
tintValue = biome.getWaterTint();
|
||||
tintValue = BiomeColorWrapper.getWaterColor(world,blockPos);
|
||||
}
|
||||
colorInt = ColorUtil.multiplyRGBcolors(tintValue | 0xFF000000, colorOfBlock);
|
||||
}
|
||||
@@ -535,8 +536,7 @@ public class LodBuilder
|
||||
boolean noCollisionAvoidance = LodConfig.CLIENT.worldGenerator.blockToAvoid.get().noCollision;
|
||||
|
||||
BlockShapeWrapper block = chunk.getBlockShapeWrapper(blockPos);
|
||||
return block != null
|
||||
&& !block.isToAvoid()
|
||||
return !block.isToAvoid()
|
||||
&& !(nonFullAvoidance && block.isNonFull())
|
||||
&& !(noCollisionAvoidance && block.hasNoCollision());
|
||||
|
||||
|
||||
@@ -125,11 +125,11 @@ public class ThreadMapUtil
|
||||
if (!threadBuilderVerticalArrayMap.containsKey(Thread.currentThread().getName()) || (threadBuilderVerticalArrayMap.get(Thread.currentThread().getName()) == null))
|
||||
{
|
||||
long[][] array = new long[5][];
|
||||
int size = 1;
|
||||
int size;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
size = 1 << i;
|
||||
array[i] = new long[size * size * DataPointUtil.worldHeight / 2 + 1];
|
||||
size = size << 1;
|
||||
}
|
||||
threadBuilderVerticalArrayMap.put(Thread.currentThread().getName(), array);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
package com.seibel.lod.wrappers.Block;
|
||||
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.wrappers.Chunk.ChunkWrapper;
|
||||
import com.seibel.lod.wrappers.MinecraftWrapper;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.client.renderer.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.shapes.VoxelShape;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
import net.minecraftforge.client.model.data.ModelDataMap;
|
||||
|
||||
import java.util.List;
|
||||
@@ -26,8 +22,10 @@ public class BlockColorWrapper
|
||||
//set of block which require tint
|
||||
public static final ConcurrentMap<Block, BlockColorWrapper> blockColorWrapperMap = new ConcurrentHashMap<>();
|
||||
public static final ModelDataMap dataMap = new ModelDataMap.Builder().build();
|
||||
public static final BlockPos blockPos = new BlockPos(0,0,0);
|
||||
public static Random random = new Random(0);
|
||||
public static BlockColorWrapper WATER_COLOR = getBlockColorWrapper(Blocks.WATER);
|
||||
//public static BlockColourWrapper WATER_COLOR = getBlockColorWrapper(Blocks.WATER);
|
||||
public static final Direction[] directions = new Direction[] { Direction.UP, Direction.EAST, Direction.SOUTH, Direction.WEST, Direction.NORTH, Direction.DOWN };
|
||||
|
||||
private Block block;
|
||||
private int color;
|
||||
@@ -39,29 +37,33 @@ public class BlockColorWrapper
|
||||
|
||||
|
||||
/**Constructor only require for the block instance we are wrapping**/
|
||||
public BlockColorWrapper(Block block)
|
||||
public BlockColorWrapper(BlockState blockState, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
this.block = blockState.getBlock();
|
||||
this.color = 0;
|
||||
this.isColored = true;
|
||||
this.toTint = false;
|
||||
this.block = block;
|
||||
setupColorAndTint();
|
||||
this.folliageTint = false;
|
||||
this.grassTint = false;
|
||||
this.waterTint = false;
|
||||
setupColorAndTint(blockState,blockPosWrapper);
|
||||
System.out.println(block + " color " + Integer.toHexString(color) + " to tint " + toTint + " folliageTint " + folliageTint + " grassTint " + grassTint + " waterTint " + waterTint);
|
||||
}
|
||||
|
||||
/**
|
||||
* this return a wrapper of the block in input
|
||||
* @param block Block object to wrap
|
||||
* @param blockState of the block to wrap
|
||||
*/
|
||||
static public BlockColorWrapper getBlockColorWrapper(Block block)
|
||||
static public BlockColorWrapper getBlockColorWrapper(BlockState blockState, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
//first we check if the block has already been wrapped
|
||||
if (blockColorWrapperMap.containsKey(block) && blockColorWrapperMap.get(block) != null)
|
||||
return blockColorWrapperMap.get(block);
|
||||
if (blockColorWrapperMap.containsKey(blockState.getBlock()) && blockColorWrapperMap.get(blockState.getBlock()) != null)
|
||||
return blockColorWrapperMap.get(blockState.getBlock());
|
||||
|
||||
|
||||
//if it hasn't been created yet, we create it and save it in the map
|
||||
BlockColorWrapper blockWrapper = new BlockColorWrapper(block);
|
||||
blockColorWrapperMap.put(block, blockWrapper);
|
||||
BlockColorWrapper blockWrapper = new BlockColorWrapper(blockState, blockPosWrapper);
|
||||
blockColorWrapperMap.put(blockState.getBlock(), blockWrapper);
|
||||
|
||||
//we return the newly created wrapper
|
||||
return blockWrapper;
|
||||
@@ -71,7 +73,7 @@ public class BlockColorWrapper
|
||||
* Generate the color of the given block from its texture
|
||||
* and store it for later use.
|
||||
*/
|
||||
private void setupColorAndTint()
|
||||
private void setupColorAndTint(BlockState blockState, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
MinecraftWrapper mc = MinecraftWrapper.INSTANCE;
|
||||
TextureAtlasSprite texture;
|
||||
@@ -81,9 +83,9 @@ public class BlockColorWrapper
|
||||
int listSize = 0;
|
||||
|
||||
// first step is to check if this block has a tinted face
|
||||
for (Direction direction : Direction.values())
|
||||
for (Direction direction : directions)
|
||||
{
|
||||
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(block.defaultBlockState(), direction, random, dataMap);
|
||||
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, dataMap);
|
||||
listSize = Math.max(listSize, quads.size());
|
||||
for (BakedQuad bakedQuad : quads)
|
||||
{
|
||||
@@ -96,19 +98,24 @@ public class BlockColorWrapper
|
||||
this.toTint = true;
|
||||
|
||||
//now we get the first non empty face
|
||||
for (Direction direction : Direction.values())
|
||||
for (Direction direction : directions)
|
||||
{
|
||||
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(block.defaultBlockState(), direction, random, dataMap);
|
||||
quads = mc.getModelManager().getBlockModelShaper().getBlockModel(block.defaultBlockState()).getQuads(blockState, direction, random, dataMap);
|
||||
if (!quads.isEmpty())
|
||||
break;
|
||||
}
|
||||
|
||||
//the quads list is not empty we extract the first one
|
||||
if (!quads.isEmpty())
|
||||
{
|
||||
isColored = true;
|
||||
texture = quads.get(0).getSprite();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
isColored = false;
|
||||
texture = mc.getModelManager().getBlockModelShaper().getTexture(block.defaultBlockState(), mc.getClientWorld(), blockPosWrapper.getBlockPos());
|
||||
//return;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
@@ -128,11 +135,12 @@ public class BlockColorWrapper
|
||||
{
|
||||
for (int v = 0; v < texture.getWidth(); v++)
|
||||
{
|
||||
if (texture.isTransparent(frameIndex, u, v))
|
||||
continue;
|
||||
|
||||
tempColor = texture.getPixelRGBA(frameIndex, u, v);
|
||||
|
||||
if (ColorUtil.getAlpha(texture.getPixelRGBA(frameIndex, u, v)) == 0)
|
||||
continue;
|
||||
|
||||
// determine if this pixel is gray
|
||||
int colorMax = Math.max(Math.max(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
|
||||
int colorMin = 4 + Math.min(Math.min(ColorUtil.getBlue(tempColor), ColorUtil.getGreen(tempColor)), ColorUtil.getRed(tempColor));
|
||||
@@ -177,14 +185,11 @@ public class BlockColorWrapper
|
||||
this.toTint = true;
|
||||
|
||||
// we check which kind of tint we need to apply
|
||||
if (grassInstance())
|
||||
this.grassTint = true;
|
||||
this.grassTint = grassInstance() && toTint;
|
||||
|
||||
if (leavesInstance())
|
||||
this.folliageTint = true;
|
||||
this.folliageTint = leavesInstance() && toTint;
|
||||
|
||||
if (waterIstance())
|
||||
this.waterTint = true;
|
||||
this.waterTint = waterIstance() && toTint;
|
||||
|
||||
color = tempColor;
|
||||
}
|
||||
@@ -225,7 +230,7 @@ public class BlockColorWrapper
|
||||
|
||||
public int getColor()
|
||||
{
|
||||
if(hasColor())
|
||||
if (hasColor())
|
||||
return color;
|
||||
else
|
||||
return block.defaultMaterialColor().col;
|
||||
|
||||
@@ -37,8 +37,9 @@ public class BlockShapeWrapper
|
||||
this.block = block;
|
||||
this.nonFull = false;
|
||||
this.noCollision = false;
|
||||
this.toAvoid = false;
|
||||
this.toAvoid = ofBlockToAvoid();
|
||||
setupShapes(chunkWrapper, blockPosWrapper);
|
||||
System.out.println(block + " non full " + nonFull + " no collision " + noCollision + " to avoid " + toAvoid);
|
||||
}
|
||||
|
||||
private BlockShapeWrapper()
|
||||
@@ -91,10 +92,7 @@ public class BlockShapeWrapper
|
||||
double xWidth = (bbox.maxX - bbox.minX);
|
||||
double yWidth = (bbox.maxY - bbox.minY);
|
||||
double zWidth = (bbox.maxZ - bbox.minZ);
|
||||
if (xWidth < 1 && zWidth < 1 && yWidth < 1)
|
||||
nonFull = true;
|
||||
else
|
||||
nonFull = false;
|
||||
nonFull = xWidth < 1 && zWidth < 1 && yWidth < 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -107,15 +105,13 @@ public class BlockShapeWrapper
|
||||
VoxelShape collisionShape = block.defaultBlockState().getCollisionShape(chunk, blockPos);
|
||||
noCollision = collisionShape.isEmpty();
|
||||
}
|
||||
|
||||
toAvoid = ofBlockToAvoid(block);
|
||||
}
|
||||
|
||||
private boolean ofBlockToAvoid(Block block)
|
||||
public boolean ofBlockToAvoid()
|
||||
{
|
||||
return block == Blocks.AIR
|
||||
|| block != Blocks.CAVE_AIR
|
||||
|| block != Blocks.BARRIER;
|
||||
return block.equals(Blocks.AIR)
|
||||
|| block.equals(Blocks.CAVE_AIR)
|
||||
|| block.equals(Blocks.BARRIER);
|
||||
}
|
||||
//-----------------//
|
||||
//Avoidance getters//
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ChunkWrapper
|
||||
|
||||
public BlockColorWrapper getBlockColorWrapper(BlockPosWrapper blockPos)
|
||||
{
|
||||
return BlockColorWrapper.getBlockColorWrapper(chunk.getBlockState(blockPos.getBlockPos()).getBlock());
|
||||
return BlockColorWrapper.getBlockColorWrapper(chunk.getBlockState(blockPos.getBlockPos()),blockPos);
|
||||
}
|
||||
|
||||
public BlockShapeWrapper getBlockShapeWrapper(BlockPosWrapper blockPos)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.seibel.lod.wrappers.World;
|
||||
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.material.MaterialColor;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeColors;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
|
||||
public class BiomeColorWrapper
|
||||
{
|
||||
|
||||
public static int getGrassColor(WorldWrapper worldWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
return BiomeColors.getAverageGrassColor(worldWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
}
|
||||
public static int getWaterColor(WorldWrapper worldWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
|
||||
return BiomeColors.getAverageWaterColor(worldWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
}
|
||||
public static int getFoliageColor(WorldWrapper worldWrapper, BlockPosWrapper blockPosWrapper)
|
||||
{
|
||||
|
||||
return BiomeColors.getAverageFoliageColor(worldWrapper.getWorld(), blockPosWrapper.getBlockPos());
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
package com.seibel.lod.wrappers.World;
|
||||
|
||||
import com.seibel.lod.util.ColorUtil;
|
||||
import com.seibel.lod.util.LodUtil;
|
||||
import com.seibel.lod.wrappers.Block.BlockColorWrapper;
|
||||
import com.seibel.lod.wrappers.Block.BlockPosWrapper;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.material.MaterialColor;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.biome.Biome;
|
||||
import net.minecraft.world.biome.BiomeColors;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@@ -42,72 +48,55 @@ public class BiomeWrapper
|
||||
public int getColorForBiome(int x, int z)
|
||||
{
|
||||
int colorInt;
|
||||
int color;
|
||||
int tint;
|
||||
|
||||
switch (biome.getBiomeCategory())
|
||||
{
|
||||
|
||||
case NETHER:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.NETHERRACK).getColor();
|
||||
colorInt = Blocks.NETHERRACK.defaultBlockState().materialColor.col;
|
||||
break;
|
||||
|
||||
case THEEND:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.END_STONE).getColor();
|
||||
colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col;
|
||||
break;
|
||||
|
||||
case BEACH:
|
||||
case DESERT:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.SAND).getColor();
|
||||
colorInt = Blocks.SAND.defaultBlockState().materialColor.col;
|
||||
break;
|
||||
|
||||
case EXTREME_HILLS:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.STONE).getColor();
|
||||
colorInt = Blocks.STONE.defaultMaterialColor().col;
|
||||
break;
|
||||
|
||||
case MUSHROOM:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.MYCELIUM).getColor();
|
||||
colorInt = MaterialColor.COLOR_LIGHT_GRAY.col;
|
||||
break;
|
||||
|
||||
case ICY:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.SNOW).getColor();
|
||||
colorInt = Blocks.SNOW.defaultMaterialColor().col;
|
||||
break;
|
||||
|
||||
case MESA:
|
||||
colorInt = BlockColorWrapper.getBlockColorWrapper(Blocks.RED_SAND).getColor();
|
||||
colorInt = Blocks.RED_SAND.defaultMaterialColor().col;
|
||||
break;
|
||||
|
||||
case OCEAN:
|
||||
case RIVER:
|
||||
colorInt = biome.getWaterColor();
|
||||
break;
|
||||
|
||||
case SWAMP:
|
||||
case FOREST:
|
||||
color = BlockColorWrapper.getBlockColorWrapper(Blocks.OAK_LEAVES).getColor();
|
||||
tint = biome.getFoliageColor();
|
||||
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
|
||||
break;
|
||||
|
||||
case TAIGA:
|
||||
color = BlockColorWrapper.getBlockColorWrapper(Blocks.SPRUCE_LEAVES).getColor();
|
||||
tint = biome.getFoliageColor();
|
||||
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
|
||||
break;
|
||||
|
||||
case JUNGLE:
|
||||
color = BlockColorWrapper.getBlockColorWrapper(Blocks.JUNGLE_LEAVES).getColor();
|
||||
tint = biome.getFoliageColor();
|
||||
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
case NONE:
|
||||
case FOREST:
|
||||
case TAIGA:
|
||||
case JUNGLE:
|
||||
case PLAINS:
|
||||
case SAVANNA:
|
||||
color = BlockColorWrapper.getBlockColorWrapper(Blocks.GRASS_BLOCK).getColor();
|
||||
tint = biome.getGrassColor(x,z);
|
||||
colorInt = ColorUtil.multiplyRGBcolors(color, tint);
|
||||
case SWAMP:
|
||||
default:
|
||||
Color tmp = LodUtil.intToColor(biome.getGrassColor(x, z));
|
||||
tmp = tmp.darker();
|
||||
colorInt = LodUtil.colorToInt(tmp);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@@ -57,6 +57,11 @@ public class WorldWrapper
|
||||
return BiomeWrapper.getBiomeWrapper(world.getBiome(blockPos.getBlockPos()));
|
||||
}
|
||||
|
||||
public IWorld getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
|
||||
public boolean hasCeiling()
|
||||
{
|
||||
return world.dimensionType().hasCeiling();
|
||||
|
||||
Reference in New Issue
Block a user