/// <summary> Handles manually-placed/deleted blocks. /// Returns true if player's action should result in a kick. </summary> public bool PlaceBlock(short x, short y, short h, bool buildMode, Block type) { LastUsedBlockType = type; // check if player is frozen or too far away to legitimately place a block if (Info.IsFrozen || Math.Abs(x * 32 - Position.X) > MaxRange || Math.Abs(y * 32 - Position.Y) > MaxRange || Math.Abs(h * 32 - Position.H) > MaxRange) { RevertBlockNow(x, y, h); return(false); } if (World.IsLocked) { RevertBlockNow(x, y, h); Message("This map is currently locked (read-only)."); return(false); } if (CheckBlockSpam()) { return(true); } // bindings bool requiresUpdate = (type != bindings[(byte)type] || IsPainting); if (!buildMode && !IsPainting) { type = Block.Air; } type = bindings[(byte)type]; // selection handling if (SelectionMarksExpected > 0) { RevertBlockNow(x, y, h); AddSelectionMark(new Position(x, y, h), true); return(false); } CanPlaceResult canPlaceResult; if (type == Block.Stair && h > 0 && World.Map.GetBlock(x, y, h - 1) == Block.Stair) { // stair stacking canPlaceResult = CanPlace(x, y, h - 1, Block.DoubleStair, true); } else { // normal placement canPlaceResult = CanPlace(x, y, h, type, true); } // if all is well, try placing it switch (canPlaceResult) { case CanPlaceResult.Allowed: BlockUpdate blockUpdate; if (type == Block.Stair && h > 0 && World.Map.GetBlock(x, y, h - 1) == Block.Stair) { // handle stair stacking blockUpdate = new BlockUpdate(this, x, y, h - 1, Block.DoubleStair); if (!World.FireChangedBlockEvent(ref blockUpdate)) { RevertBlockNow(x, y, h); return(false); } Info.ProcessBlockPlaced((byte)Block.DoubleStair); World.Map.QueueUpdate(blockUpdate); Server.RaisePlayerPlacedBlockEvent(this, x, y, (short)(h - 1), Block.Stair, Block.DoubleStair, true); Session.SendNow(PacketWriter.MakeSetBlock(x, y, h - 1, Block.DoubleStair)); RevertBlockNow(x, y, h); break; } else { // handle normal blocks blockUpdate = new BlockUpdate(this, x, y, h, type); if (!World.FireChangedBlockEvent(ref blockUpdate)) { RevertBlockNow(x, y, h); return(false); } Info.ProcessBlockPlaced((byte)type); Block old = World.Map.GetBlock(x, y, h); World.Map.QueueUpdate(blockUpdate); Server.RaisePlayerPlacedBlockEvent(this, x, y, h, old, type, true); if (requiresUpdate || RelayAllUpdates) { Session.SendNow(PacketWriter.MakeSetBlock(x, y, h, type)); } } break; case CanPlaceResult.BlocktypeDenied: Message("&WYou are not permitted to affect this block type."); RevertBlockNow(x, y, h); break; case CanPlaceResult.RankDenied: Message("&WYour rank is not allowed to build."); RevertBlockNow(x, y, h); break; case CanPlaceResult.WorldDenied: switch (World.BuildSecurity.CheckDetailed(Info)) { case SecurityCheckResult.RankTooLow: case SecurityCheckResult.RankTooHigh: Message("&WYour rank is not allowed to build in this world."); break; case SecurityCheckResult.BlackListed: Message("&WYou are not allowed to build in this world."); break; } RevertBlockNow(x, y, h); break; case CanPlaceResult.ZoneDenied: Zone deniedZone = World.Map.FindDeniedZone(x, y, h, this); if (deniedZone != null) { Message("&WYou are not allowed to build in zone \"{0}\".", deniedZone.Name); } else { Message("&WYou are not allowed to build here."); } RevertBlockNow(x, y, h); break; case CanPlaceResult.PluginDenied: RevertBlockNow(x, y, h); break; //case CanPlaceResult.PluginDeniedNoUpdate: // break; } return(false); }