初始化
This commit is contained in:
1 parent
dffebce01d
commit
ff618906d3
2501 files changed
+1181005
-21
No files matched your search
@@ -1,5 +1,6 @@
|
||||
# coding=utf-8
|
||||
import copy
|
||||
from ToolsConfig import *
|
||||
|
||||
MOD_NAME = 'rtdd'
|
||||
MOD_VERSION = '0.0.1'
|
||||
|
||||
+31
-19
@@ -1,4 +1,6 @@
|
||||
# coding=utf-8
|
||||
import copy
|
||||
|
||||
from ..ToolsConfig import *
|
||||
from BlueFoxSystem import BlueFoxServerSystem
|
||||
from ..OtherTools import Mount
|
||||
@@ -28,23 +30,27 @@ def GetLoadedBlockBlock():
|
||||
class BlockBlock(object):
|
||||
"""
|
||||
方块块,用于解决模型体积过大导致的模型消失的问题
|
||||
blockList = {
|
||||
(0, 0, 0): {'name': 'rtdd:carrotandbeef', 'aux': 0}
|
||||
(相对坐标位置): {'name': 方块ID, 'aux': 方块AUX}
|
||||
}
|
||||
"""
|
||||
blueFoxSystem = BlueFoxServerSystem if 0 else None
|
||||
blockList = {}
|
||||
|
||||
@classmethod
|
||||
def Load(cls, posDim):
|
||||
# type:(Tuple[int,int,int,int]) -> None
|
||||
"""
|
||||
通过维度坐标加载储存的块数据
|
||||
"""
|
||||
def getInstance(cls, posDim):
|
||||
instance = blockBlocks.get(posDim)
|
||||
if instance: return instance
|
||||
data = blockEntityDataComp.GetBlockEntityData(posDim[3], posDim[:3])
|
||||
if data and data['isCenter']:
|
||||
posDims = [tuple(_) for _ in data['posDims']]
|
||||
return cls(tuple(data['centerPosDim']), data['aux'], posDims)
|
||||
blockData = serverCompFactory.CreateBlockInfo(LevelId).GetBlockNew(posDim[:3], posDim[3])
|
||||
return cls(posDim, blockData['aux'])
|
||||
|
||||
def __init__(self, posDim, aux, posDims=None):
|
||||
# type:(Tuple[int,int,int,int],int,List[Tuple]) -> None
|
||||
# type:(Tuple,int,List[Tuple]) -> None
|
||||
self.blockPosDims = posDims # 方块块控制坐标
|
||||
self.centerPosDim = posDim # 控制中心
|
||||
self.aux = aux
|
||||
@@ -59,7 +65,7 @@ class BlockBlock(object):
|
||||
for posDim in self.blockPosDims:
|
||||
blockBlocks[posDim] = self
|
||||
|
||||
def ReplaceBlocks(self, newBlockList, otherData):
|
||||
def ReplaceBlocks(self, newBlockList, otherData=None, drop=0):
|
||||
"""
|
||||
替换方块,新方块依然具有方块实体的要求
|
||||
"""
|
||||
@@ -67,14 +73,10 @@ class BlockBlock(object):
|
||||
'posDims': self.blockPosDims,
|
||||
'aux': self.aux
|
||||
}
|
||||
if otherData is None: otherData = {}
|
||||
oldData.update(otherData)
|
||||
self.DestroyBlocks()
|
||||
self.DestroyBlocks(drop)
|
||||
self.CreateBlocks(newBlockList)
|
||||
self.ResetBlockData(oldData)
|
||||
|
||||
def ResetBlockData(self, data):
|
||||
for K_V in data.items():
|
||||
self.dataComp[K_V[0]] = K_V[1]
|
||||
|
||||
def DestroyFunction(self):
|
||||
"""
|
||||
@@ -83,20 +85,29 @@ class BlockBlock(object):
|
||||
for posDim in self.blockPosDims:
|
||||
del blockBlocks[posDim]
|
||||
|
||||
def Destroy(self):
|
||||
def Destroy(self, drop=0):
|
||||
"""
|
||||
销毁方块块
|
||||
:param drop:是否掉落核心方块
|
||||
"""
|
||||
self.DestroyFunction()
|
||||
self.DestroyBlocks()
|
||||
self.DestroyBlocks(drop)
|
||||
|
||||
def DestroyBlocks(self):
|
||||
def DestroyBlocks(self, drop=0):
|
||||
"""
|
||||
销毁方块块所控制的方块
|
||||
"""
|
||||
blockComp = serverCompFactory.CreateBlockInfo(LevelId)
|
||||
for posDim in self.blockPosDims:
|
||||
blockComp.SetBlockNew(posDim[:3], blockDict={'name': 'minecraft:air'}, dimensionId=posDim[3])
|
||||
posDim = copy.copy(self.blockPosDims)
|
||||
posDim.remove(self.centerPosDim)
|
||||
for posDim in posDim:
|
||||
blockComp.SetBlockNew(
|
||||
posDim[:3], blockDict={'name': 'minecraft:air'}, dimensionId=posDim[3]
|
||||
)
|
||||
blockComp.SetBlockNew(
|
||||
self.centerPosDim[:3], blockDict={'name': 'minecraft:air'}, dimensionId=self.centerPosDim[3],
|
||||
oldBlockHandling=1 if drop else 0
|
||||
)
|
||||
|
||||
def CreateBlocks(self, blockList=None):
|
||||
"""
|
||||
@@ -107,7 +118,6 @@ class BlockBlock(object):
|
||||
blockComp = serverCompFactory.CreateBlockInfo(LevelId)
|
||||
for pos in self.blockList:
|
||||
blockInfo = blockList[pos]
|
||||
blockInfo['aux'] = self.aux
|
||||
posDim = self.CalculatePosDimFromOffset(pos, self.centerPosDim, self.aux)
|
||||
blockComp.SetBlockNew(posDim[:3], blockDict=blockInfo, dimensionId=posDim[3])
|
||||
dataComp = blockEntityDataComp.GetBlockEntityData(posDim[3], posDim[:3])
|
||||
@@ -128,6 +138,7 @@ class BlockBlock(object):
|
||||
|
||||
@classmethod
|
||||
def CreatePosDims(cls, posDim, aux):
|
||||
# type:(Tuple,int) -> List[Tuple]
|
||||
"""
|
||||
创建方块块控制坐标
|
||||
"""
|
||||
@@ -135,6 +146,7 @@ class BlockBlock(object):
|
||||
|
||||
@classmethod
|
||||
def CalculatePosDimFromOffset(cls, offset, posDim, aux):
|
||||
"""计算偏移坐标维度"""
|
||||
originCoord = OriginCoord(posDim)
|
||||
_, __, ___ = FixPosition(originCoord.AbsPos(
|
||||
RotCoord(BlockFaceRot[aux], RotAxes.Y).CalculatePos(offset)
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
# coding=utf-8
|
||||
import time
|
||||
|
||||
from BlueFoxTools.SpecialFunciton.BlockBlock import BlockBlock
|
||||
from BlueFoxTools.ToolsConfig import *
|
||||
from BlueFoxTools.SystemTools import SystemTools
|
||||
from BlueFoxTools.ItemTools import CreateItemDict
|
||||
import ModUtil as util
|
||||
|
||||
|
||||
class CookingStateEnum(object):
|
||||
Default = -1
|
||||
Boil = 0
|
||||
|
||||
|
||||
class BaseBlock(BlockBlock):
|
||||
instances = {}
|
||||
dropItems = []
|
||||
|
||||
def __init__(self, posDim, aux, posDims=None):
|
||||
super(BaseBlock, self).__init__(posDim, aux, posDims)
|
||||
self.__stirFryProperty = self.dataComp['stirFry']
|
||||
self.__boilProperty = self.dataComp['boil']
|
||||
BaseBlock.instances[self.centerPosDim] = self
|
||||
self.cookingState = CookingStateEnum.Default
|
||||
self.isFinish = False
|
||||
self.serverSystem = SystemTools.GetSystemByClsName('MainServer')
|
||||
|
||||
@classmethod
|
||||
def Instances(cls):
|
||||
return cls.instances.values()
|
||||
|
||||
def Tick(self):
|
||||
pass
|
||||
|
||||
def BlockUse(self, playerId, itemDict):
|
||||
"""玩家尝试使用方块"""
|
||||
|
||||
@property
|
||||
def stirFryProperty(self):
|
||||
# type:()->int
|
||||
"""
|
||||
翻炒属性,用于记录翻炒了多久
|
||||
"""
|
||||
return self.__stirFryProperty if self.__stirFryProperty is not None else 0
|
||||
|
||||
@stirFryProperty.setter
|
||||
def stirFryProperty(self, value):
|
||||
self.__stirFryProperty = value
|
||||
|
||||
@property
|
||||
def boilProperty(self):
|
||||
# type:()->float
|
||||
"""
|
||||
煮了多久
|
||||
:return:
|
||||
"""
|
||||
return self.__boilProperty if self.__boilProperty is not None else 0.0
|
||||
|
||||
@boilProperty.setter
|
||||
def boilProperty(self, value):
|
||||
self.__boilProperty = value
|
||||
|
||||
def SaveData(self):
|
||||
self.dataComp['stirFry'] = self.__stirFryProperty
|
||||
self.dataComp['boil'] = self.__boilProperty
|
||||
|
||||
def Destroy(self, drop=0):
|
||||
del BaseBlock.instances[self.centerPosDim]
|
||||
super(BaseBlock, self).Destroy(0)
|
||||
if drop:
|
||||
for dropItem in self.dropItems:
|
||||
self.serverSystem.CreateEngineItemEntity(dropItem, self.centerPosDim[3], self.centerPosDim[:3])
|
||||
|
||||
def Translater(self, newBlock):
|
||||
"""转换方块为新的方块"""
|
||||
cls = blockIndex.get(newBlock)
|
||||
if cls:
|
||||
self.Destroy()
|
||||
cls.getInstance(self.centerPosDim)
|
||||
|
||||
|
||||
class WoK(BaseBlock):
|
||||
blockList = {(0, 0, 0): {'name': 'rtdd:wok', 'aux': 0}}
|
||||
|
||||
def __init__(self, *args):
|
||||
super(WoK, self).__init__(*args)
|
||||
|
||||
def BlockUse(self, playerId, itemDict):
|
||||
if util.Normal.GetItemOil(itemDict) and util.Normal.IsBlockBelow(
|
||||
self.centerPosDim, 'minecraft:campfire'
|
||||
):
|
||||
self.Translater('rtdd:cookinggarlic') # 转化为带油的煎锅
|
||||
util.Normal.SetItemOil(itemDict, False)
|
||||
serverCompFactory.CreateItem(LevelId).SpawnItemToPlayerCarried(itemDict, playerId)
|
||||
util.ServerUtil.PlaySoundToAllClient(
|
||||
self.centerPosDim, 'random.fizz', 2.4
|
||||
)
|
||||
|
||||
|
||||
OID_CAN_MAX_SIZE = 16 # 油瓶最大油量
|
||||
|
||||
|
||||
class OilCan(BaseBlock):
|
||||
blockList = {(0, 0, 0): {'name': 'rtdd:oilcan', 'aux': 0}}
|
||||
|
||||
def __init__(self, *args):
|
||||
super(OilCan, self).__init__(*args)
|
||||
self.__oil = self.dataComp['oil']
|
||||
self.SetFill()
|
||||
|
||||
def SetFill(self):
|
||||
self.oil = OID_CAN_MAX_SIZE
|
||||
|
||||
def BlockUse(self, playerId, itemDict):
|
||||
if util.Normal.GetItemOil(itemDict):
|
||||
if self.oil < OID_CAN_MAX_SIZE:
|
||||
self.oil += 1
|
||||
util.Normal.SetItemOil(itemDict, False)
|
||||
serverCompFactory.CreateItem(playerId).SpawnItemToPlayerCarried(itemDict, playerId)
|
||||
elif self.oil > 0:
|
||||
util.Normal.SetItemOil(itemDict, True)
|
||||
serverCompFactory.CreateItem(playerId).SpawnItemToPlayerCarried(itemDict, playerId)
|
||||
self.oil -= 1
|
||||
|
||||
serverCompFactory.CreateGame(LevelId).SetOneTipMessage(
|
||||
playerId, '剩余油量{}/{}'.format(self.oil, OID_CAN_MAX_SIZE)
|
||||
)
|
||||
|
||||
@property
|
||||
def oil(self):
|
||||
return 0 if self.__oil is None else self.__oil
|
||||
|
||||
@oil.setter
|
||||
def oil(self, value):
|
||||
self.__oil = value
|
||||
|
||||
def SaveData(self):
|
||||
super(OilCan, self).SaveData()
|
||||
self.dataComp['oil'] = self.__oil
|
||||
|
||||
|
||||
class CookingWok(BaseBlock):
|
||||
blockList = {(0, 0, 0): {'name': 'rtdd:cookinggarlic', 'aux': 0}}
|
||||
dropItems = [CreateItemDict('rtdd:wok')]
|
||||
|
||||
def __init__(self, *args):
|
||||
super(CookingWok, self).__init__(*args)
|
||||
|
||||
def BlockUse(self, playerId, itemDict):
|
||||
if itemDict and itemDict.get('newItemName') == 'minecraft:beef':
|
||||
self.Translater('rtdd:carrotandbeef')
|
||||
util.ServerUtil.PlaySoundToAllClient(
|
||||
self.centerPosDim, 'random.fizz', 0.8
|
||||
)
|
||||
|
||||
|
||||
class CarrotAndBeef(BaseBlock):
|
||||
blockList = {(0, 0, 0): {'name': 'rtdd:carrotandbeef', 'aux': 0}}
|
||||
dropItems = [CreateItemDict('rtdd:wok'), CreateItemDict('minecraft:beef')]
|
||||
|
||||
def __init__(self, *args):
|
||||
super(CarrotAndBeef, self).__init__(*args)
|
||||
self.stirTime = time.time()
|
||||
|
||||
def BlockUse(self, playerId, itemDict):
|
||||
stirTime = time.time()
|
||||
if stirTime - self.stirTime > 1.2:
|
||||
if itemDict and itemDict.get('newItemName') == 'minecraft:wooden_sword':
|
||||
self.stirFryProperty += 1
|
||||
util.ServerUtil.PlaySoundToAllClient(
|
||||
self.centerPosDim, 'random.fizz', 2.1
|
||||
)
|
||||
util.ServerUtil.PlayAttackToClient(playerId)
|
||||
self.ReplaceBlocks({(0, 0, 0): {'name': 'rtdd:carrotandbeef', 'aux': self.stirFryProperty % 4}})
|
||||
if self.stirFryProperty > 5:
|
||||
self.Translater('rtdd:carrotandbeef_1')
|
||||
self.stirTime = stirTime
|
||||
else:
|
||||
serverCompFactory.CreateGame(LevelId).SetOneTipMessage(playerId, '这时候翻动会不好熟的!')
|
||||
|
||||
|
||||
class CarrotAndBeef1(BaseBlock):
|
||||
blockList = {(0, 0, 0): {'name': 'rtdd:carrotandbeef_1', 'aux': 0}}
|
||||
dropItems = [CreateItemDict('rtdd:wok'), CreateItemDict('minecraft:beef')]
|
||||
|
||||
def __init__(self, *args):
|
||||
super(CarrotAndBeef1, self).__init__(*args)
|
||||
self.stirTime = time.time()
|
||||
|
||||
def BlockUse(self, playerId, itemDict):
|
||||
stirTime = time.time()
|
||||
if stirTime - self.stirTime > 0.8:
|
||||
if itemDict and itemDict.get('newItemName') == 'minecraft:wooden_sword' and not self.isFinish:
|
||||
self.stirFryProperty += 1
|
||||
util.ServerUtil.PlaySoundToAllClient(
|
||||
self.centerPosDim, 'random.fizz', 2.1
|
||||
)
|
||||
util.ServerUtil.PlayAttackToClient(playerId)
|
||||
self.ReplaceBlocks({(0, 0, 0): {'name': 'rtdd:carrotandbeef_1', 'aux': self.stirFryProperty % 4}})
|
||||
self.isFinish = self.stirFryProperty > 3
|
||||
elif itemDict and itemDict.get('newItemName') == 'minecraft:wooden_sword' and self.isFinish:
|
||||
serverCompFactory.CreateGame(LevelId).SetOneTipMessage(playerId, '出锅啦!拿盘子盛出来')
|
||||
else:
|
||||
serverCompFactory.CreateGame(LevelId).SetOneTipMessage(playerId, '这时候翻动会不好熟的!')
|
||||
|
||||
def Destroy(self, drop=0):
|
||||
if self.isFinish: self.dropItems = [CreateItemDict('minecraft:cooked_beef'), CreateItemDict('rtdd:wok')]
|
||||
super(CarrotAndBeef1, self).Destroy(drop)
|
||||
|
||||
|
||||
blockIndex = {
|
||||
'rtdd:wok': WoK,
|
||||
'rtdd:cookinggarlic': CookingWok,
|
||||
'rtdd:carrotandbeef': CarrotAndBeef,
|
||||
'rtdd:carrotandbeef_1': CarrotAndBeef1,
|
||||
'rtdd:oilcan': OilCan
|
||||
}
|
||||
|
||||
|
||||
def GetBaseBlock(posDim):
|
||||
# type:(Tuple)->BaseBlock
|
||||
return BaseBlock.instances.get(posDim)
|
||||
@@ -0,0 +1,20 @@
|
||||
# coding=utf-8
|
||||
from ..BlueFoxTools.ItemTools import GetItemUserData
|
||||
from ..BlueFoxTools.OtherTools import NbtTranslator
|
||||
from ..BlueFoxTools.ToolsConfig import *
|
||||
|
||||
|
||||
def IsBlockBelow(posDim, blockName):
|
||||
"""检查指定位置下方是否为指定方块"""
|
||||
x, y, z, d = posDim
|
||||
return serverCompFactory.CreateBlockInfo(LevelId).GetBlockNew((x, y - 1, z), d)['name'] == blockName
|
||||
|
||||
|
||||
def SetItemOil(itemDict, oiled):
|
||||
"""设置物品含油"""
|
||||
GetItemUserData(itemDict, 'rtdd')['oil'] = oiled
|
||||
|
||||
|
||||
def GetItemOil(itemDict):
|
||||
"""获取物品是否含油"""
|
||||
return NbtTranslator(GetItemUserData(itemDict, 'rtdd')).get('oil', False)
|
||||
@@ -0,0 +1,14 @@
|
||||
# coding=utf-8
|
||||
from ..BlueFoxTools.SystemTools import SystemTools
|
||||
|
||||
|
||||
def PlaySoundToAllClient(posDim, soundName, pitch=1):
|
||||
"""向所有玩家播放指定声音"""
|
||||
SystemTools.GetSystemByClsName('BlueFoxServerSystem').BroadcastToAllClient('PlaySound', {
|
||||
'posDim': posDim, 'soundName': soundName, 'pitch': pitch
|
||||
})
|
||||
|
||||
|
||||
def PlayAttackToClient(playerId):
|
||||
"""向所有玩家播放指定声音"""
|
||||
SystemTools.GetSystemByClsName('BlueFoxServerSystem').NotifyToClient(playerId, 'PlayAttackAnim', {})
|
||||
@@ -0,0 +1,2 @@
|
||||
import Normal
|
||||
import ServerUtil
|
||||
@@ -0,0 +1,40 @@
|
||||
# coding=utf-8
|
||||
from ...BlueFoxTools.SystemTools import SystemTools
|
||||
from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxClientSystem
|
||||
from ...BlueFoxTools.ToolsConfig import *
|
||||
from ...BlueFoxTools.EventFilter import BlueFoxFilterEnum as ef
|
||||
from ...Function import blockIndex
|
||||
|
||||
|
||||
class MainClient(BlueFoxClientSystem):
|
||||
systemTools = SystemTools.GetTools('MainClient')
|
||||
mcListener = systemTools.ListenForEvent()
|
||||
blueFox = systemTools.GetBlueFoxServerListener()
|
||||
mainServer = systemTools.ListenForEvent(
|
||||
namespace=MOD_NAME, systemName='MainServer'
|
||||
)
|
||||
blockUse = systemTools.FilterListener('ClientBlockUseEvent')
|
||||
|
||||
def __init__(self, *args):
|
||||
super(MainClient, self).__init__(*args)
|
||||
self.systemTools.Binding(self)
|
||||
|
||||
@blueFox
|
||||
def PlaySound(self, args):
|
||||
posDim = args['posDim']
|
||||
pitch = args['pitch']
|
||||
if posDim[3] == clientCompFactory.CreateGame(LevelId).GetCurrentDimension():
|
||||
clientCompFactory.CreateCustomAudio(LevelId).PlayCustomMusic(
|
||||
args['soundName'], posDim[:3], pitch=pitch
|
||||
)
|
||||
|
||||
# @blockUse(ef.ClientEvent.NormalEvent.NotInCd('rtdd:blockUse', 0.2))
|
||||
# def BlockUseNotIn02(self, args):
|
||||
# print args
|
||||
# blockName = args['blockName']
|
||||
# if blockName in blockName:
|
||||
# args['cancel'] = True
|
||||
|
||||
@blueFox
|
||||
def PlayAttackAnim(self, args):
|
||||
clientCompFactory.CreatePlayer(LevelId).Swing()
|
||||
Whitespace-only changes.
@@ -0,0 +1,59 @@
|
||||
from ...BlueFoxTools.SystemTools import SystemTools
|
||||
from ...BlueFoxTools.ModConfig import *
|
||||
from ...BlueFoxTools.SpecialFunciton.BlueFoxSystem import BlueFoxServerSystem
|
||||
from ...BlueFoxTools.EventFilter import BlueFoxFilterEnum as eF
|
||||
from ...Function import *
|
||||
from ...BlueFoxTools.SpecialFunciton.BlockBlock import GetLoadedBlockBlock, GetLoadedBlockBlockByPosDim
|
||||
from ...Function import GetBaseBlock
|
||||
|
||||
|
||||
class MainServer(BlueFoxServerSystem):
|
||||
systemTools = SystemTools.GetTools('MainServer')
|
||||
mcListener = systemTools.ListenForEvent()
|
||||
blockUse = systemTools.FilterListener('ServerBlockUseEvent')
|
||||
|
||||
def __init__(self, *args):
|
||||
super(MainServer, self).__init__(*args)
|
||||
self.systemTools.Binding(self)
|
||||
|
||||
@mcListener
|
||||
def ServerEntityTryPlaceBlockEvent(self, args):
|
||||
blockName = args['fullName']
|
||||
cls = blockIndex.get(blockName)
|
||||
if cls:
|
||||
posDim = (args['x'], args['y'], args['z'], args['dimensionId'])
|
||||
args['cancel'] = not cls.Able(posDim, args['auxData'])
|
||||
|
||||
@mcListener
|
||||
def EntityPlaceBlockAfterServerEvent(self, args):
|
||||
print args
|
||||
blockName = args['fullName']
|
||||
cls = blockIndex.get(blockName)
|
||||
if cls:
|
||||
posDim = (args['x'], args['y'], args['z'], args['dimensionId'])
|
||||
cls.getInstance(posDim)
|
||||
|
||||
@blockUse(eF.ServerEvent.NormalEvent.NotInCd('main.blockUse', 0.2))
|
||||
def BlockUseEventNotIn02(self, args):
|
||||
posDim = (args['x'], args['y'], args['z'], args['dimensionId'])
|
||||
instance = GetBaseBlock(posDim)
|
||||
if instance:
|
||||
playerId = args['playerId']
|
||||
carriedItem = serverCompFactory.CreateItem(playerId).GetPlayerItem(
|
||||
serverApi.GetMinecraftEnum().ItemPosType.CARRIED, getUserData=True
|
||||
)
|
||||
if carriedItem is None: carriedItem = {}
|
||||
instance.BlockUse(playerId, carriedItem)
|
||||
|
||||
@mcListener
|
||||
def ServerPlayerTryDestroyBlockEvent(self, args):
|
||||
posDim = (args['x'], args['y'], args['z'], args['dimensionId'])
|
||||
fullName = args['fullName']
|
||||
instance = GetBaseBlock(posDim)
|
||||
if instance: instance.Destroy(1)
|
||||
|
||||
@mcListener
|
||||
def ChunkLoadedServerEvent(self, args):
|
||||
blockEntities = args['blockEntities']
|
||||
for blockEntity in blockEntities:
|
||||
pass
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,7 @@
|
||||
from BlueFoxTools.ModLoader import *
|
||||
|
||||
from System.Server.MainServer import MainServer
|
||||
|
||||
if not serverApi.IsInServer():
|
||||
from System.Client.MainClient import MainClient
|
||||
LoadMod()
|
||||
Reference in new issue
Block a user