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.world; 019 020import com.google.common.collect.Lists; 021import net.tridentsdk.base.Block; 022import net.tridentsdk.base.Position; 023import net.tridentsdk.base.Substance; 024import net.tridentsdk.docs.InternalUseOnly; 025import net.tridentsdk.meta.block.AbstractBlockMetaOwner; 026import net.tridentsdk.meta.block.BlockMeta; 027import net.tridentsdk.meta.component.MetaCollection; 028import net.tridentsdk.meta.component.MetaFactory; 029import net.tridentsdk.server.packets.play.out.PacketPlayOutBlockChange; 030import net.tridentsdk.server.player.TridentPlayer; 031import net.tridentsdk.util.Vector; 032 033import java.util.Collections; 034import java.util.List; 035 036public class TridentBlock extends AbstractBlockMetaOwner<Block> implements Block { 037 private final Position location; 038 /** 039 * The type for this block 040 */ 041 protected volatile Substance material; 042 /** 043 * The block metadata 044 */ 045 protected byte data; 046 047 /** 048 * Constructs the wrapper representing the block 049 * 050 * @param location Location of the Block 051 */ 052 @InternalUseOnly 053 public TridentBlock(Position location) { 054 this.location = location; 055 056 // Note: Avoid recursion by not creating a new instance from World#blockAt(Location) 057 Block worldBlock = location.world().blockAt(location); 058 this.material = worldBlock.substance(); 059 } 060 061 public TridentBlock(Position location, Substance substance, byte meta) { 062 this.location = location; 063 this.material = substance; 064 this.data = meta; 065 } 066 067 @Override 068 public Substance substance() { 069 return this.material; 070 } 071 072 @Override 073 public void setSubstance(Substance substance) { 074 setSubstanceAndMeta(substance, (byte) 0); 075 } 076 077 @Override 078 public Position position() { 079 return this.location; 080 } 081 082 @Override 083 public byte meta() { 084 return this.data; 085 } 086 087 @Override 088 public void setMeta(byte data) { 089 setSubstanceAndMeta(this.material, data); 090 } 091 092 @Override 093 public Block relativeBlock(Vector vector) { 094 return new TridentBlock(this.location.relative(vector)); 095 } 096 097 @Override 098 public void setSubstanceAndMeta(Substance substance, byte data) { 099 this.material = substance; 100 this.data = data; 101 102 TridentPlayer.sendAll(new PacketPlayOutBlockChange() 103 .set("blockId", substance().id() << 4 | data) 104 .set("location", location)); 105 106 ((TridentChunk) position().chunk()).setAt(location, substance, data, (byte) 255, (byte) 0); 107 } 108 109 @Override 110 protected MetaCollection<Block> collect() { 111 return MetaFactory.newCollection(); 112 } 113 114 @Override 115 public void clearMeta() { 116 super.clearMeta(); 117 this.data = 0; 118 } 119 120 @Override 121 public <M extends BlockMeta<Block>> boolean applyMeta(boolean replace, M... meta) { 122 TridentChunk chunk = ((TridentChunk) location.chunk()); 123 Vector key = new Vector((int) location.x() & 15, location.y(), (int) location.z() & 15); 124 List<BlockMeta> tiles = chunk.tilesInternal().computeIfAbsent(key, k -> Lists.newCopyOnWriteArrayList()); 125 Collections.addAll(tiles, meta); 126 chunk.tilesInternal().put(key, tiles); 127 128 return super.applyMeta(replace, meta); 129 } 130}