mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-13 17:28:52 -04:00
minor refactoring moving power related stuff to its own package; made receiver trait use provider trait instead of internal distributor implementation; made some minor things more scala-ish
This commit is contained in:
parent
efe25b35e8
commit
efb8f297db
@ -1,30 +0,0 @@
|
|||||||
package li.cil.oc.api.network
|
|
||||||
|
|
||||||
trait Producer extends Receiver {
|
|
||||||
demand = 0
|
|
||||||
|
|
||||||
def powerDemand:Double= {
|
|
||||||
if (main != null) {
|
|
||||||
main.getDemand
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def maxEnergy:Double= {
|
|
||||||
if (main != null) {
|
|
||||||
main.MAXENERGY
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
0.0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def addEnergy(amount: Double) {
|
|
||||||
if (main != null) {
|
|
||||||
main.addEnergy(amount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
package li.cil.oc.api.network
|
|
||||||
|
|
||||||
import li.cil.oc.common.tileentity.PowerDistributor
|
|
||||||
import scala.collection.mutable
|
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
|
||||||
|
|
||||||
|
|
||||||
trait Receiver extends Node {
|
|
||||||
var powerDistributors = mutable.Set[PowerDistributor]()
|
|
||||||
|
|
||||||
private var _demand = 2.0
|
|
||||||
|
|
||||||
def demand = _demand
|
|
||||||
|
|
||||||
def demand_=(value: Double) = {
|
|
||||||
|
|
||||||
powerDistributors.foreach(e => e.updateDemand(this, value))
|
|
||||||
_demand = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override def receive(message: Message): Option[Array[Any]] = {
|
|
||||||
message.name match {
|
|
||||||
case "system.connect" => {
|
|
||||||
message.source match {
|
|
||||||
case distributor: PowerDistributor => {
|
|
||||||
println("connect")
|
|
||||||
if (!powerDistributors.contains(distributor)) {
|
|
||||||
powerDistributors += distributor
|
|
||||||
distributor.connectNode(this, _demand)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "system.disconnect" => {
|
|
||||||
message.source match {
|
|
||||||
case distributor: PowerDistributor => {
|
|
||||||
println("connect")
|
|
||||||
if (powerDistributors.contains(distributor)) {
|
|
||||||
powerDistributors -= distributor
|
|
||||||
distributor.disconnectNode(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case _ =>
|
|
||||||
}
|
|
||||||
super.receive(message)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override protected def onDisconnect() {
|
|
||||||
super.onDisconnect()
|
|
||||||
powerDistributors.foreach(e => {
|
|
||||||
e.disconnectNode(this)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main: PowerDistributor = {
|
|
||||||
powerDistributors.find(p => p.isActive) match {
|
|
||||||
case Some(p: PowerDistributor) => p
|
|
||||||
case _ => null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
override def load(nbt: NBTTagCompound) = {
|
|
||||||
super.load(nbt)
|
|
||||||
buffer = nbt.getDouble("buffer")
|
|
||||||
}
|
|
||||||
|
|
||||||
override def save(nbt: NBTTagCompound) = {
|
|
||||||
super.save(nbt)
|
|
||||||
nbt.setDouble("buffer",buffer)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var buffer = 0.0
|
|
||||||
private val maxBuffer = 100.0
|
|
||||||
private var hasEnergy = false
|
|
||||||
private var isConnected = false
|
|
||||||
|
|
||||||
override def update() {
|
|
||||||
super.update()
|
|
||||||
//if has enough energy to operate
|
|
||||||
if (isConnected) {
|
|
||||||
//increase buffer
|
|
||||||
if (maxBuffer > buffer + 1)
|
|
||||||
buffer += 1
|
|
||||||
//notify if energy wasn't available before
|
|
||||||
if (!hasEnergy) {
|
|
||||||
hasEnergy = true
|
|
||||||
onPowerAvailable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//continue running until we are out of energy
|
|
||||||
if (buffer - demand < 0) {
|
|
||||||
if (hasEnergy) {
|
|
||||||
hasEnergy = false
|
|
||||||
onPowerLoss()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
buffer -= demand
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* called from the producer when he has enough energy to operate
|
|
||||||
*/
|
|
||||||
final def connect() {
|
|
||||||
isConnected = true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called from the producer when there is not enough energy to operate
|
|
||||||
*/
|
|
||||||
final def unConnect() {
|
|
||||||
isConnected = false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the receiver has enough power to operate.
|
|
||||||
*/
|
|
||||||
def onPowerAvailable() {
|
|
||||||
println("received energy")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the receiver has no power to operate. This can happen at a later time
|
|
||||||
* then unConnect was called, because of the internal capacity
|
|
||||||
*/
|
|
||||||
def onPowerLoss() {
|
|
||||||
println("no more energy")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
20
li/cil/oc/api/power/Producer.scala
Normal file
20
li/cil/oc/api/power/Producer.scala
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package li.cil.oc.api.power
|
||||||
|
|
||||||
|
trait Producer extends Receiver {
|
||||||
|
demand = 0
|
||||||
|
|
||||||
|
def powerDemand: Double = provider match {
|
||||||
|
case Some(p) => p.getDemand
|
||||||
|
case _ => 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def maxEnergy: Double = provider match {
|
||||||
|
case Some(p) => p.MAXENERGY
|
||||||
|
case _ => 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def addEnergy(amount: Double) = provider match {
|
||||||
|
case Some(p) => p.addEnergy(amount)
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +1,20 @@
|
|||||||
package li.cil.oc.api.network
|
package li.cil.oc.api.power
|
||||||
|
|
||||||
import scala.collection.mutable
|
import li.cil.oc.api.network.{Message, Node}
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
trait Provider extends Node {
|
||||||
trait Provider extends Node{
|
|
||||||
|
|
||||||
var isActive = false
|
var isActive = false
|
||||||
var updateNodes = false
|
var updateNodes = false
|
||||||
var energyDemand =0.0
|
var energyDemand = 0.0
|
||||||
var storedEnergy =0.0
|
var storedEnergy = 0.0
|
||||||
var MAXENERGY :Double =2000.0
|
var MAXENERGY: Double = 2000.0
|
||||||
|
|
||||||
|
|
||||||
var energyStorageList = mutable.Set[EnergyStorage]()
|
var energyStorageList = mutable.Set[EnergyStorage]()
|
||||||
|
|
||||||
override def load(nbt: NBTTagCompound) = {
|
override def receive(message: Message): Option[Array[Any]] = super.receive(message) orElse {
|
||||||
super.load(nbt)
|
|
||||||
storedEnergy = nbt.getDouble("storedEnergy")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override def save(nbt: NBTTagCompound) = {
|
|
||||||
super.save(nbt)
|
|
||||||
nbt.setDouble("storedEnergy",storedEnergy)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override def receive(message: Message): Option[Array[Any]] = {
|
|
||||||
if (message.source != this) {
|
if (message.source != this) {
|
||||||
message.name match {
|
message.name match {
|
||||||
case "system.connect" => {
|
case "system.connect" => {
|
||||||
@ -61,13 +47,27 @@ trait Provider extends Node{
|
|||||||
}
|
}
|
||||||
case _ =>
|
case _ =>
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
case _ => // Ignore.
|
case _ => // Ignore.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.receive(message)
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected def onConnect() {
|
||||||
|
//check if other distributors already are in the network
|
||||||
|
searchMain()
|
||||||
|
super.onConnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override def load(nbt: NBTTagCompound) = {
|
||||||
|
super.load(nbt)
|
||||||
|
storedEnergy = nbt.getDouble("storedEnergy")
|
||||||
|
}
|
||||||
|
|
||||||
|
override def save(nbt: NBTTagCompound) = {
|
||||||
|
super.save(nbt)
|
||||||
|
nbt.setDouble("storedEnergy", storedEnergy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,7 +76,7 @@ trait Provider extends Node{
|
|||||||
* @param amount
|
* @param amount
|
||||||
*/
|
*/
|
||||||
def connectNode(receiver: Receiver, amount: Double) {
|
def connectNode(receiver: Receiver, amount: Double) {
|
||||||
if (energyStorageList.filter(x => x.node == receiver).isEmpty) {
|
if (!energyStorageList.exists(_.node == receiver)) {
|
||||||
energyStorageList += new EnergyStorage(receiver, amount)
|
energyStorageList += new EnergyStorage(receiver, amount)
|
||||||
energyDemand += amount
|
energyDemand += amount
|
||||||
updateNodes = true
|
updateNodes = true
|
||||||
@ -110,9 +110,8 @@ trait Provider extends Node{
|
|||||||
else if (e.node == receiver) {
|
else if (e.node == receiver) {
|
||||||
energyStorageList -= e
|
energyStorageList -= e
|
||||||
energyDemand -= e.amount
|
energyDemand -= e.amount
|
||||||
if(isActive)
|
if (isActive) {
|
||||||
{
|
receiver.isReceivingPower = false
|
||||||
receiver.unConnect()
|
|
||||||
updateNodes = true
|
updateNodes = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,36 +121,31 @@ trait Provider extends Node{
|
|||||||
println("demand now (disc) " + energyDemand)
|
println("demand now (disc) " + energyDemand)
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected def onConnect() {
|
private var hasEnergy = false
|
||||||
//check if other distributors already are in the network
|
|
||||||
searchMain()
|
|
||||||
super.onConnect()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var hasEnergy = false
|
override def update() {
|
||||||
override def update() {
|
|
||||||
super.update()
|
super.update()
|
||||||
//check if is main
|
//check if is main
|
||||||
if (isActive) {
|
if (isActive) {
|
||||||
//if enough energy is available to supply all recievers
|
//if enough energy is available to supply all receivers
|
||||||
if(storedEnergy>energyDemand){
|
if (storedEnergy > energyDemand) {
|
||||||
storedEnergy-=energyDemand
|
storedEnergy -= energyDemand
|
||||||
if(!hasEnergy)
|
if (!hasEnergy)
|
||||||
updateNodes = true
|
updateNodes = true
|
||||||
hasEnergy = true
|
hasEnergy = true
|
||||||
println("energy level now "+storedEnergy)
|
println("energy level now " + storedEnergy)
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
if(hasEnergy)
|
if (hasEnergy)
|
||||||
updateNodes = true
|
updateNodes = true
|
||||||
hasEnergy = false
|
hasEnergy = false
|
||||||
}
|
}
|
||||||
//if nodes must be updated send message to them
|
//if nodes must be updated send message to them
|
||||||
if(updateNodes){
|
if (updateNodes) {
|
||||||
if(hasEnergy)
|
if (hasEnergy)
|
||||||
energyStorageList.foreach(storage=>storage.node.connect())
|
energyStorageList.foreach(storage => storage.node.isReceivingPower = true)
|
||||||
else
|
else
|
||||||
energyStorageList.foreach(storage=>storage.node.unConnect())
|
energyStorageList.foreach(storage => storage.node.isReceivingPower = false)
|
||||||
updateNodes = false
|
updateNodes = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,8 +157,6 @@ trait Provider extends Node{
|
|||||||
|
|
||||||
def addEnergy(amount: Double) {
|
def addEnergy(amount: Double) {
|
||||||
storedEnergy += amount
|
storedEnergy += amount
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def searchMain() {
|
def searchMain() {
|
||||||
@ -182,7 +174,6 @@ trait Provider extends Node{
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
class EnergyStorage(var node: Receiver, var amount: Double) {
|
class EnergyStorage(var node: Receiver, var amount: Double)
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
114
li/cil/oc/api/power/Receiver.scala
Normal file
114
li/cil/oc/api/power/Receiver.scala
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package li.cil.oc.api.power
|
||||||
|
|
||||||
|
import li.cil.oc.api.network.{Message, Node}
|
||||||
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
trait Receiver extends Node {
|
||||||
|
def demand = _demand
|
||||||
|
|
||||||
|
def demand_=(value: Double) = if (value != _demand) {
|
||||||
|
providers.foreach(_.updateDemand(this, value))
|
||||||
|
_demand = value
|
||||||
|
}
|
||||||
|
|
||||||
|
def provider: Option[Provider] = providers.find(_.isActive)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the receiver has enough power to operate.
|
||||||
|
*/
|
||||||
|
def onPowerAvailable() {
|
||||||
|
println("received energy")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the receiver has no power to operate. This can happen at a later time
|
||||||
|
* then unConnect was called, because of the internal capacity
|
||||||
|
*/
|
||||||
|
def onPowerUnavailable() {
|
||||||
|
println("no more energy")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
override def receive(message: Message) = super.receive(message) orElse {
|
||||||
|
message.name match {
|
||||||
|
case "system.connect" => {
|
||||||
|
message.source match {
|
||||||
|
case p: Provider => {
|
||||||
|
if (providers.add(p)) {
|
||||||
|
p.connectNode(this, _demand)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "system.disconnect" => {
|
||||||
|
message.source match {
|
||||||
|
case p: Provider => {
|
||||||
|
if (providers.remove(p)) {
|
||||||
|
p.disconnectNode(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
override protected def onDisconnect() {
|
||||||
|
super.onDisconnect()
|
||||||
|
providers.foreach(_.disconnectNode(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
override def load(nbt: NBTTagCompound) {
|
||||||
|
super.load(nbt)
|
||||||
|
buffer = nbt.getDouble("buffer")
|
||||||
|
}
|
||||||
|
|
||||||
|
override def save(nbt: NBTTagCompound) {
|
||||||
|
super.save(nbt)
|
||||||
|
nbt.setDouble("buffer", buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
private var _demand = 2.0
|
||||||
|
private val providers = mutable.Set.empty[Provider]
|
||||||
|
private var buffer = 0.0
|
||||||
|
private val maxBuffer = 100.0
|
||||||
|
private var isPowerAvailable = false
|
||||||
|
|
||||||
|
/** Set from the provider whenever its power state changes. */
|
||||||
|
private[power] var isReceivingPower = false
|
||||||
|
|
||||||
|
override def update() {
|
||||||
|
super.update()
|
||||||
|
//if has enough energy to operate
|
||||||
|
if (isReceivingPower) {
|
||||||
|
//increase buffer
|
||||||
|
// TODO maybe make the speed of the "cooldown" dependent on the demand?
|
||||||
|
// TODO another possibility: increase the demand dynamically while charging?
|
||||||
|
if (maxBuffer > buffer + 1)
|
||||||
|
buffer += 1
|
||||||
|
//notify if energy wasn't available before
|
||||||
|
if (!isPowerAvailable) {
|
||||||
|
isPowerAvailable = true
|
||||||
|
onPowerAvailable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//continue running until we are out of energy
|
||||||
|
else if (buffer >= demand) {
|
||||||
|
buffer -= demand
|
||||||
|
}
|
||||||
|
else if (isPowerAvailable) {
|
||||||
|
isPowerAvailable = false
|
||||||
|
onPowerUnavailable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,7 +31,7 @@ class Screen(val tileEntity: tileentity.Screen) extends MCGuiScreen {
|
|||||||
private val pressedKeys = mutable.Map.empty[Int, Char]
|
private val pressedKeys = mutable.Map.empty[Int, Char]
|
||||||
|
|
||||||
/** Must be called when the size of the underlying screen changes */
|
/** Must be called when the size of the underlying screen changes */
|
||||||
def setSize(w: Double, h: Double) = {
|
def changeSize(w: Double, h: Double) = {
|
||||||
// Re-compute sizes and positions.
|
// Re-compute sizes and positions.
|
||||||
val totalMargin = Screen.margin + Screen.innerMargin
|
val totalMargin = Screen.margin + Screen.innerMargin
|
||||||
val bufferWidth = w * MonospaceFontRenderer.fontWidth
|
val bufferWidth = w * MonospaceFontRenderer.fontWidth
|
||||||
@ -83,7 +83,7 @@ class Screen(val tileEntity: tileentity.Screen) extends MCGuiScreen {
|
|||||||
MonospaceFontRenderer.init(mc.renderEngine)
|
MonospaceFontRenderer.init(mc.renderEngine)
|
||||||
Screen.init(mc.renderEngine)
|
Screen.init(mc.renderEngine)
|
||||||
val (w, h) = tileEntity.screen.resolution
|
val (w, h) = tileEntity.screen.resolution
|
||||||
setSize(w, h)
|
changeSize(w, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
override def onGuiClosed() = {
|
override def onGuiClosed() = {
|
||||||
|
@ -2,7 +2,7 @@ package li.cil.oc.common.tileentity
|
|||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import li.cil.oc.api.driver.Slot
|
import li.cil.oc.api.driver.Slot
|
||||||
import li.cil.oc.api.network.Receiver
|
import li.cil.oc.api.power.Receiver
|
||||||
import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
||||||
import li.cil.oc.server.component
|
import li.cil.oc.server.component
|
||||||
import li.cil.oc.server.component.Redstone
|
import li.cil.oc.server.component.Redstone
|
||||||
|
@ -3,6 +3,7 @@ package li.cil.oc.common.tileentity
|
|||||||
import li.cil.oc.api.network._
|
import li.cil.oc.api.network._
|
||||||
import scala.collection.mutable
|
import scala.collection.mutable
|
||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
|
import li.cil.oc.api.power.Provider
|
||||||
|
|
||||||
class PowerDistributor extends Rotatable with Provider {
|
class PowerDistributor extends Rotatable with Provider {
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import net.minecraft.world.World
|
|||||||
import net.minecraft.nbt.NBTTagCompound
|
import net.minecraft.nbt.NBTTagCompound
|
||||||
import universalelectricity.core.block.IElectrical
|
import universalelectricity.core.block.IElectrical
|
||||||
import universalelectricity.core.electricity.ElectricityPack
|
import universalelectricity.core.electricity.ElectricityPack
|
||||||
|
import li.cil.oc.api.power.Producer
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created with IntelliJ IDEA.
|
* Created with IntelliJ IDEA.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package li.cil.oc.common.tileentity
|
package li.cil.oc.common.tileentity
|
||||||
|
|
||||||
import li.cil.oc.api.network.Receiver
|
import li.cil.oc.api.power.Receiver
|
||||||
import li.cil.oc.client.gui
|
import li.cil.oc.client.gui
|
||||||
import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
import li.cil.oc.client.{PacketSender => ClientPacketSender}
|
||||||
import li.cil.oc.common.component
|
import li.cil.oc.common.component
|
||||||
@ -44,7 +44,7 @@ class Screen extends Rotatable with component.Screen.Environment with Receiver {
|
|||||||
override def onScreenResolutionChange(w: Int, h: Int) = {
|
override def onScreenResolutionChange(w: Int, h: Int) = {
|
||||||
super.onScreenResolutionChange(w, h)
|
super.onScreenResolutionChange(w, h)
|
||||||
if (worldObj.isRemote) {
|
if (worldObj.isRemote) {
|
||||||
guiScreen.foreach(_.setSize(w, h))
|
guiScreen.foreach(_.changeSize(w, h))
|
||||||
hasChanged = true
|
hasChanged = true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user