001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.plot.flag.types; 020 021import com.google.common.base.Objects; 022import com.google.common.base.Preconditions; 023import com.plotsquared.core.configuration.Settings; 024import com.sk89q.worldedit.world.block.BlockCategory; 025import com.sk89q.worldedit.world.block.BlockStateHolder; 026import com.sk89q.worldedit.world.block.BlockType; 027import org.apache.logging.log4j.LogManager; 028import org.apache.logging.log4j.Logger; 029import org.checkerframework.checker.nullness.qual.NonNull; 030import org.checkerframework.checker.nullness.qual.Nullable; 031 032import java.util.HashMap; 033import java.util.Map; 034 035/** 036 * Container that class either contains a {@link BlockType} 037 * or a {@link BlockCategory} 038 */ 039public class BlockTypeWrapper { 040 041 private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + BlockTypeWrapper.class.getSimpleName()); 042 043 private static final Map<BlockType, BlockTypeWrapper> blockTypes = new HashMap<>(); 044 private static final Map<String, BlockTypeWrapper> blockCategories = new HashMap<>(); 045 private static final String minecraftNamespace = "minecraft"; 046 @Nullable 047 private final BlockType blockType; 048 @Nullable 049 private final String blockCategoryId; 050 @Nullable 051 private BlockCategory blockCategory; 052 053 private BlockTypeWrapper(final @NonNull BlockType blockType) { 054 this.blockType = Preconditions.checkNotNull(blockType); 055 this.blockCategory = null; 056 this.blockCategoryId = null; 057 } 058 059 private BlockTypeWrapper(final @NonNull BlockCategory blockCategory) { 060 this.blockType = null; 061 this.blockCategory = Preconditions.checkNotNull(blockCategory); 062 this.blockCategoryId = blockCategory.getId(); // used in toString()/equals()/hashCode() 063 } 064 065 private BlockTypeWrapper(final @NonNull String blockCategoryId) { 066 this.blockType = null; 067 this.blockCategory = null; 068 this.blockCategoryId = Preconditions.checkNotNull(blockCategoryId); 069 } 070 071 public static BlockTypeWrapper get(final BlockType blockType) { 072 return blockTypes.computeIfAbsent(blockType, BlockTypeWrapper::new); 073 } 074 075 public static BlockTypeWrapper get(final BlockCategory blockCategory) { 076 return blockCategories 077 .computeIfAbsent(blockCategory.getId(), id -> new BlockTypeWrapper(blockCategory)); 078 } 079 080 public static BlockTypeWrapper get(final String blockCategoryId) { 081 // use minecraft as default namespace 082 String id; 083 if (blockCategoryId.indexOf(':') == -1) { 084 id = minecraftNamespace + ":" + blockCategoryId; 085 } else { 086 id = blockCategoryId; 087 } 088 return blockCategories.computeIfAbsent(id, BlockTypeWrapper::new); 089 } 090 091 @Override 092 public String toString() { 093 if (this.blockType != null) { 094 final String key = this.blockType.toString(); 095 if (key.startsWith("minecraft:")) { 096 return key.substring(10); 097 } else { 098 return key; 099 } 100 } else if (this.blockCategoryId != null) { 101 final String key = this.blockCategoryId; 102 if (key.startsWith("minecraft:")) { 103 return '#' + key.substring(10); 104 } else { 105 return '#' + key; 106 } 107 } else { 108 return null; 109 } 110 } 111 112 public boolean accepts(final BlockType blockType) { 113 if (this.getBlockType() != null) { 114 return this.getBlockType().equals(blockType); 115 } else if (this.getBlockCategory() != null) { 116 return this.getBlockCategory().contains(blockType); 117 } else { 118 return false; 119 } 120 } 121 122 /** 123 * Returns the block category associated with this wrapper. 124 * <br> 125 * Invocation will try to lazily initialize the block category if it's not 126 * set yet but the category id is present. If {@link BlockCategory#REGISTRY} is already populated 127 * but does not contain a category with the given name, a BlockCategory containing no items 128 * is returned. 129 * If this wrapper does not wrap a BlockCategory, null is returned. 130 * <br> 131 * <b>If {@link BlockCategory#REGISTRY} isn't populated yet, null is returned.</b> 132 * 133 * @return the block category represented by this wrapper. 134 */ 135 public @Nullable BlockCategory getBlockCategory() { 136 if (this.blockCategory == null 137 && this.blockCategoryId != null) { // only if name is available 138 this.blockCategory = BlockCategory.REGISTRY.get(this.blockCategoryId); 139 if (this.blockCategory == null && !BlockCategory.REGISTRY.values().isEmpty()) { 140 if (Settings.DEBUG) { 141 LOGGER.info("- Block category #{} does not exist", this.blockCategoryId); 142 } 143 this.blockCategory = new NullBlockCategory(this.blockCategoryId); 144 } 145 } 146 return this.blockCategory; 147 } 148 149 @Override 150 public boolean equals(final Object o) { 151 if (this == o) { 152 return true; 153 } 154 if (o == null || getClass() != o.getClass()) { 155 return false; 156 } 157 BlockTypeWrapper that = (BlockTypeWrapper) o; 158 return Objects.equal(this.blockType, that.blockType) && Objects 159 .equal(this.blockCategoryId, that.blockCategoryId); 160 } 161 162 @Override 163 public int hashCode() { 164 return Objects.hashCode(this.blockType, this.blockCategoryId); 165 } 166 167 public @Nullable BlockType getBlockType() { 168 return this.blockType; 169 } 170 171 172 /** 173 * Prevents exceptions when loading/saving block categories 174 */ 175 private static class NullBlockCategory extends BlockCategory { 176 177 public NullBlockCategory(String id) { 178 super(id); 179 } 180 181 @Override 182 public <B extends BlockStateHolder<B>> boolean contains(B blockStateHolder) { 183 return false; 184 } 185 186 } 187 188}