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 */ 017package net.tridentsdk.server.data; 018 019import net.tridentsdk.base.Block; 020import net.tridentsdk.base.Substance; 021import net.tridentsdk.meta.block.BlockMeta; 022import net.tridentsdk.meta.component.*; 023import net.tridentsdk.server.data.block.*; 024import net.tridentsdk.util.Value; 025 026import java.util.Collection; 027import java.util.Map; 028import java.util.Set; 029import java.util.concurrent.ConcurrentHashMap; 030import java.util.concurrent.ConcurrentSkipListSet; 031import java.util.stream.Collectors; 032 033/** 034 * Provides metadata implementations to the API 035 * 036 * @author The TridentSDK Team 037 */ 038public class MetaProviderFactory implements MetaProvider { 039 private final MetaCollection collection = MetaFactory.newCollection(); 040 private final Map<Substance, MetaCompiler> metaMap = new ConcurrentHashMap<>(); 041 042 public MetaProviderFactory() { 043 register(new ColorMetaImpl()); 044 register(new SignMetaImpl()); 045 register(new FurnaceMetaImpl()); 046 register(new ChestMetaImpl()); 047 register(new DirectionMetaImpl()); 048 register(new CauldronMetaImpl()); 049 } 050 051 public boolean hasData(Substance substance) { 052 return metaMap.containsKey(substance); 053 } 054 055 @Override 056 public boolean decode(Block block, Value<Substance> substance, byte[] data, Value<Byte> result) { 057 MetaCompiler compiler = metaMap.get(substance.get()); 058 if (compiler != null) { 059 byte metaByte = 0; 060 for (Meta<?> meta : compiler.compileBlock(block, data)) { 061 if (meta instanceof IllegalMeta) { 062 block.clearMeta(); 063 return false; 064 } 065 066 block.applyMeta((BlockMeta) meta); 067 metaByte |= meta.encodeMeta()[0]; 068 } 069 070 result.set(metaByte); 071 substance.set(block.substance()); 072 } else { 073 // If no data was found for an item, the item is not placeable 074 if (!substance.get().isBlock()) { 075 return false; 076 } 077 } 078 079 return true; 080 } 081 082 @Override 083 public <S, T extends Meta<S>> T provide(Class<T> cls) { 084 return (T) collection.get(cls).make(); 085 } 086 087 @Override 088 public void register(Meta meta) { 089 Substance[] substances = meta.applyTo(collection); 090 for (Substance substance : substances) { 091 MetaCompiler metaCompiler = metaMap.get(substance); 092 if (metaCompiler == null) { 093 metaCompiler = new MetaCompiler(); 094 } 095 096 metaCompiler.add(meta); 097 metaMap.put(substance, metaCompiler); 098 } 099 } 100 101 private class MetaCompiler { 102 private final Set<Meta> metas = new ConcurrentSkipListSet<>((m1, m2) -> { 103 if (m1 instanceof BlockMeta && m2 instanceof BlockMeta) { 104 BlockMeta<?> b1 = ((BlockMeta) m1); 105 BlockMeta<?> b2 = ((BlockMeta) m2); 106 107 for (Class c : b1.dependencies()) { 108 if (c.isInstance(b2)) { 109 return 1; 110 } 111 } 112 113 for (Class c : b2.dependencies()) { 114 if (c.isInstance(b1)) { 115 return -1; 116 } 117 } 118 } 119 120 return 0; 121 }); 122 123 public void add(Meta meta) { 124 metas.add(meta); 125 } 126 127 public Collection<Meta> compileBlock(Block block, byte[] data) { 128 return metas.stream() 129 .map((meta) -> meta.decodeMeta(block, data)) 130 .collect(Collectors.toList()); 131 } 132 } 133}