|
| 1 | +package org.cloudburstmc.server.block; |
| 2 | + |
| 3 | +import com.fasterxml.jackson.core.type.TypeReference; |
| 4 | +import com.fasterxml.jackson.databind.ObjectMapper; |
| 5 | +import lombok.extern.log4j.Log4j2; |
| 6 | +import org.checkerframework.checker.nullness.qual.Nullable; |
| 7 | +import org.cloudburstmc.api.block.BlockState; |
| 8 | +import org.cloudburstmc.api.util.AxisAlignedBB; |
| 9 | +import org.cloudburstmc.api.util.Identifier; |
| 10 | +import org.cloudburstmc.api.util.SimpleAxisAlignedBB; |
| 11 | +import org.cloudburstmc.server.Bootstrap; |
| 12 | + |
| 13 | +import java.io.IOException; |
| 14 | +import java.io.InputStream; |
| 15 | +import java.util.HashMap; |
| 16 | +import java.util.List; |
| 17 | +import java.util.Map; |
| 18 | +import java.util.function.Function; |
| 19 | + |
| 20 | +@Log4j2 |
| 21 | +public class BlockPropertyCache { |
| 22 | + |
| 23 | + private final BlockPalette palette; |
| 24 | + private final Map<String, AxisAlignedBB> blockNameToCollisionShape = new HashMap<>(); |
| 25 | + private final Map<String, Map<String, Float>> floatProperties = new HashMap<>(); |
| 26 | + private final Map<String, Map<String, Integer>> intProperties = new HashMap<>(); |
| 27 | + private final Map<String, Map<String, Boolean>> booleanProperties = new HashMap<>(); |
| 28 | + private final Map<String, Map<String, String>> stringProperties = new HashMap<>(); |
| 29 | + |
| 30 | + public BlockPropertyCache(BlockPalette palette) { |
| 31 | + this.palette = palette; |
| 32 | + } |
| 33 | + |
| 34 | + public void loadProperties() { |
| 35 | + InputStream stream = Bootstrap.class.getClassLoader().getResourceAsStream("data/block_properties.json"); |
| 36 | + |
| 37 | + try (stream) { |
| 38 | + try { |
| 39 | + if (stream == null) { |
| 40 | + log.warn("Unable to load block_properties.json - blocks will use default properties"); |
| 41 | + return; |
| 42 | + } |
| 43 | + |
| 44 | + ObjectMapper mapper = new ObjectMapper(); |
| 45 | + List<BlockStateData> blockStates = mapper.readValue(stream, new TypeReference<>() { |
| 46 | + }); |
| 47 | + for (BlockStateData data : blockStates) { |
| 48 | + String blockName = data.getName(); |
| 49 | + |
| 50 | + if (blockName == null) { |
| 51 | + continue; |
| 52 | + } |
| 53 | + |
| 54 | + if (data.getCollisionShape() != null) { |
| 55 | + AxisAlignedBB boundingBox; |
| 56 | + if (data.getCollisionShape().isEmpty()) { |
| 57 | + boundingBox = new SimpleAxisAlignedBB(0, 0, 0, 0, 0, 0); |
| 58 | + } else { |
| 59 | + List<Double> shape = data.getCollisionShape().get(0); |
| 60 | + if (shape.size() >= 6) { |
| 61 | + boundingBox = new SimpleAxisAlignedBB( |
| 62 | + shape.get(0).floatValue(), shape.get(1).floatValue(), shape.get(2).floatValue(), |
| 63 | + shape.get(3).floatValue(), shape.get(4).floatValue(), shape.get(5).floatValue() |
| 64 | + ); |
| 65 | + } else { |
| 66 | + continue; |
| 67 | + } |
| 68 | + } |
| 69 | + |
| 70 | + blockNameToCollisionShape.put(blockName, boundingBox); |
| 71 | + } |
| 72 | + |
| 73 | + storeFloatProperty(BlockPropertyNames.HARDNESS, blockName, (float) data.getHardness()); |
| 74 | + storeFloatProperty(BlockPropertyNames.EXPLOSION_RESISTANCE, blockName, (float) data.getExplosionResistance()); |
| 75 | + storeFloatProperty(BlockPropertyNames.FRICTION, blockName, (float) data.getFriction()); |
| 76 | + storeFloatProperty(BlockPropertyNames.THICKNESS, blockName, (float) data.getThickness()); |
| 77 | + storeFloatProperty(BlockPropertyNames.TRANSLUCENCY, blockName, (float) data.getTranslucency()); |
| 78 | + |
| 79 | + storeIntProperty(BlockPropertyNames.LIGHT_EMISSION, blockName, data.getLightEmission()); |
| 80 | + storeIntProperty(BlockPropertyNames.LIGHT_DAMPENING, blockName, data.getLightDampening()); |
| 81 | + storeIntProperty(BlockPropertyNames.BURN_ODDS, blockName, data.getBurnOdds()); |
| 82 | + storeIntProperty(BlockPropertyNames.FLAME_ODDS, blockName, data.getFlameOdds()); |
| 83 | + |
| 84 | + storeBooleanProperty(BlockPropertyNames.IS_SOLID, blockName, data.isSolid()); |
| 85 | + storeBooleanProperty(BlockPropertyNames.REQUIRES_CORRECT_TOOL_FOR_DROPS, blockName, data.isRequiresCorrectToolForDrops()); |
| 86 | + storeBooleanProperty(BlockPropertyNames.CAN_CONTAIN_LIQUID_SOURCE, blockName, data.isCanContainLiquidSource()); |
| 87 | + |
| 88 | + storeStringProperty(BlockPropertyNames.MAP_COLOR, blockName, data.getMapColor()); |
| 89 | + storeStringProperty(BlockPropertyNames.TINT_METHOD, blockName, data.getTintMethod()); |
| 90 | + storeStringProperty(BlockPropertyNames.LIQUID_REACTION_ON_TOUCH, blockName, data.getLiquidReactionOnTouch()); |
| 91 | + } |
| 92 | + } catch (IOException e) { |
| 93 | + log.error("Failed to load block_properties.json", e); |
| 94 | + } |
| 95 | + } catch (IOException e) { |
| 96 | + log.error("Failed to close block_properties.json stream", e); |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + private void storeFloatProperty(String propertyName, String blockName, float value) { |
| 101 | + floatProperties.computeIfAbsent(propertyName, k -> new HashMap<>()).put(blockName, value); |
| 102 | + } |
| 103 | + |
| 104 | + private void storeIntProperty(String propertyName, String blockName, int value) { |
| 105 | + intProperties.computeIfAbsent(propertyName, k -> new HashMap<>()).put(blockName, value); |
| 106 | + } |
| 107 | + |
| 108 | + private void storeBooleanProperty(String propertyName, String blockName, boolean value) { |
| 109 | + booleanProperties.computeIfAbsent(propertyName, k -> new HashMap<>()).put(blockName, value); |
| 110 | + } |
| 111 | + |
| 112 | + private void storeStringProperty(String propertyName, String blockName, String value) { |
| 113 | + if (value != null) { |
| 114 | + stringProperties.computeIfAbsent(propertyName, k -> new HashMap<>()).put(blockName, value); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + @Nullable |
| 119 | + public AxisAlignedBB getCollisionShape(String identifier) { |
| 120 | + return blockNameToCollisionShape.get(identifier); |
| 121 | + } |
| 122 | + |
| 123 | + @Nullable |
| 124 | + public AxisAlignedBB getCollisionShape(BlockState blockState) { |
| 125 | + return getProperty(blockState, blockNameToCollisionShape::get); |
| 126 | + } |
| 127 | + |
| 128 | + @Nullable |
| 129 | + public Float getFloatProperty(String propertyName, String identifier) { |
| 130 | + Map<String, Float> propertyMap = floatProperties.get(propertyName); |
| 131 | + return propertyMap != null ? propertyMap.get(identifier) : null; |
| 132 | + } |
| 133 | + |
| 134 | + @Nullable |
| 135 | + public Float getFloatProperty(String propertyName, BlockState blockState) { |
| 136 | + return getProperty(blockState, id -> getFloatProperty(propertyName, id)); |
| 137 | + } |
| 138 | + |
| 139 | + @Nullable |
| 140 | + public Integer getIntProperty(String propertyName, String identifier) { |
| 141 | + Map<String, Integer> propertyMap = intProperties.get(propertyName); |
| 142 | + return propertyMap != null ? propertyMap.get(identifier) : null; |
| 143 | + } |
| 144 | + |
| 145 | + @Nullable |
| 146 | + public Integer getIntProperty(String propertyName, BlockState blockState) { |
| 147 | + return getProperty(blockState, id -> getIntProperty(propertyName, id)); |
| 148 | + } |
| 149 | + |
| 150 | + @Nullable |
| 151 | + public Boolean getBooleanProperty(String propertyName, String identifier) { |
| 152 | + Map<String, Boolean> propertyMap = booleanProperties.get(propertyName); |
| 153 | + return propertyMap != null ? propertyMap.get(identifier) : null; |
| 154 | + } |
| 155 | + |
| 156 | + @Nullable |
| 157 | + public Boolean getBooleanProperty(String propertyName, BlockState blockState) { |
| 158 | + return getProperty(blockState, id -> getBooleanProperty(propertyName, id)); |
| 159 | + } |
| 160 | + |
| 161 | + @Nullable |
| 162 | + public String getStringProperty(String propertyName, String identifier) { |
| 163 | + Map<String, String> propertyMap = stringProperties.get(propertyName); |
| 164 | + return propertyMap != null ? propertyMap.get(identifier) : null; |
| 165 | + } |
| 166 | + |
| 167 | + @Nullable |
| 168 | + public String getStringProperty(String propertyName, BlockState blockState) { |
| 169 | + return getProperty(blockState, id -> getStringProperty(propertyName, id)); |
| 170 | + } |
| 171 | + |
| 172 | + @Nullable |
| 173 | + private <T> T getProperty(BlockState blockState, Function<String, T> propertyGetter) { |
| 174 | + if (blockState == null) { |
| 175 | + return null; |
| 176 | + } |
| 177 | + |
| 178 | + Identifier id = palette.getIdentifier(blockState); |
| 179 | + if (id != null) { |
| 180 | + T value = propertyGetter.apply(id.toString()); |
| 181 | + if (value != null) { |
| 182 | + return value; |
| 183 | + } |
| 184 | + } |
| 185 | + |
| 186 | + Identifier typeId = blockState.getType().getId(); |
| 187 | + if (typeId != null) { |
| 188 | + return propertyGetter.apply(typeId.toString()); |
| 189 | + } |
| 190 | + |
| 191 | + return null; |
| 192 | + } |
| 193 | +} |
0 commit comments