001/* 002 * Trident - A Multithreaded Server Alternative 003 * Copyright 2014 The TridentSDK Team 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package net.tridentsdk.server.packets.play.in; 019 020import io.netty.buffer.ByteBuf; 021import net.tridentsdk.base.Block; 022import net.tridentsdk.base.Position; 023import net.tridentsdk.base.Substance; 024import net.tridentsdk.effect.sound.SoundEffect; 025import net.tridentsdk.effect.sound.SoundEffectType; 026import net.tridentsdk.meta.block.ChestMeta; 027import net.tridentsdk.meta.block.FurnaceMeta; 028import net.tridentsdk.meta.component.MetaFactory; 029import net.tridentsdk.server.data.block.FurnaceMetaImpl; 030import net.tridentsdk.server.inventory.TridentInventory; 031import net.tridentsdk.server.netty.ClientConnection; 032import net.tridentsdk.server.netty.packet.InPacket; 033import net.tridentsdk.server.netty.packet.Packet; 034import net.tridentsdk.server.player.PlayerConnection; 035import net.tridentsdk.server.player.TridentPlayer; 036import net.tridentsdk.server.util.OwnedTridentBlock; 037import net.tridentsdk.util.Value; 038import net.tridentsdk.util.Vector; 039 040import static net.tridentsdk.meta.block.ByteArray.writeFirst; 041import static net.tridentsdk.meta.block.ByteArray.writeSecond; 042 043public class PacketPlayInBlockPlace extends InPacket { 044 /** 045 * Location of the block being placed 046 */ 047 protected Position location; 048 protected byte direction; 049 /** 050 * PositionWritable of the cursor, incorrect use of a Vector 051 */ 052 protected Vector cursorPosition; 053 054 @Override 055 public int id() { 056 return 0x1C; 057 } 058 059 @Override 060 public Packet decode(ByteBuf buf) { 061 long encodedLocation = buf.readLong(); 062 063 this.location = Position.create(null, (double) (encodedLocation >> 38), 064 (double) ((encodedLocation >> 26) & 0xFFF), (double) (encodedLocation << 38 >> 38)); 065 this.direction = buf.readByte(); 066 067 // ignore held item 068 for (int i = 0; i < buf.readableBytes() - 3; i++) { 069 buf.readByte(); 070 } 071 072 double x = (double) buf.readByte(); 073 double y = (double) buf.readByte(); 074 double z = (double) buf.readByte(); 075 076 this.cursorPosition = new Vector(x, y, z); 077 return this; 078 } 079 080 public Position location() { 081 return this.location; 082 } 083 084 public byte blockDirection() { 085 return this.direction; 086 } 087 088 public Vector cursorPosition() { 089 return this.cursorPosition; 090 } 091 092 @Override 093 public void handleReceived(ClientConnection connection) { 094 TridentPlayer player = ((PlayerConnection) connection).player(); 095 location.setWorld(player.world()); 096 097 if(player.heldItem() == null) { 098 //TODO: add a check where this is called from so it will not be null while a player interacts with the item slots containing air while placing blocks. 099 return; 100 } 101 102 Substance substance = player.heldItem().type(); 103 Vector vector = determineOffset(); 104 if (!substance.isBlock()) { 105 // TODO eat food or pull bow or release/obtain water in a bucket, etc 106 return; 107 } 108 109 if (location.y() + vector.y() > 255 || location.y() + vector.y() < 0) { 110 // Illegal block position 111 return; 112 } 113 114 Position position = location.block().substance().canBeReplaced() ? location : location.relative(vector); 115 Block block = new OwnedTridentBlock(player, position.block()); 116 117 if (location.y() < 255 && location.block() != null && block.substance().isFunctional() && !player.isCrouching()) { 118 switch (block.substance()) { 119 case FURNACE: 120 case BURNING_FURNACE: 121 ((FurnaceMetaImpl) block.obtainMeta(FurnaceMeta.class)).furnaceInventory().sendTo(player); 122 break; 123 case CHEST: 124 ((TridentInventory) block.obtainMeta(ChestMeta.class).inventory()).sendTo(player); 125 break; 126 } 127 // TODO Add all functional blocks (workbench, furnace, anvil, etc) 128 } else if (player.heldItem() != null && player.heldItem().type() != Substance.AIR) { 129 short yaw = (short) (player.position().yaw() * 10); 130 short meta = player.heldItem().damageValue(); 131 Value<Byte> result = Value.of((byte) 0); 132 Value<Substance> substanceValue = Value.of(substance); 133 134 boolean allow = MetaFactory.decode(block, substanceValue, new byte[]{ 135 writeFirst(yaw), writeSecond(yaw), direction, 136 ((byte) cursorPosition.x()), ((byte) cursorPosition.y()), ((byte) cursorPosition.z()), 137 writeFirst(meta), writeSecond(meta) 138 }, result); 139 140 if (allow) { 141 block.setSubstanceAndMeta(substanceValue.get(), result.get()); 142 143 SoundEffectType soundEffectType = substanceValue.get().placeSound(); 144 if (soundEffectType != null) { 145 SoundEffect sound = location.world().playSound(soundEffectType); 146 sound.setPosition(location); 147 sound.apply(); 148 } 149 } 150 } 151 } 152 153 private Vector determineOffset() { 154 int x = 0; 155 int y = 0; 156 int z = 0; 157 158 switch (blockDirection()) { 159 case 0: 160 y--; 161 break; 162 case 1: 163 y++; 164 break; 165 case 2: 166 z--; 167 break; 168 case 3: 169 z++; 170 break; 171 case 4: 172 x--; 173 break; 174 case 5: 175 x++; 176 break; 177 default: 178 return new Vector(0, 0, 0); 179 } 180 181 return new Vector(x, y, z); 182 } 183}