Skip to content

Commit

Permalink
Merge pull request #429 from sk89q/bugfix/config-no-plat-dependency
Browse files Browse the repository at this point in the history
Make block states lazy, fix forge for new block API
  • Loading branch information
me4502 committed Oct 7, 2018
2 parents 79a4121 + ff877ec commit 88f22f2
Show file tree
Hide file tree
Showing 10 changed files with 412 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ public void setName(final String name) {
this.name = name;
}

@Override
public String toString() {
return getClass().getSimpleName() + "{name=" + name + "}";
}

@Override
public int hashCode() {
return name.hashCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

package com.sk89q.worldedit.world.block;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.sk89q.worldedit.WorldEdit;
Expand All @@ -34,19 +36,22 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;

import javax.annotation.Nullable;

public class BlockType {

public static final NamespacedRegistry<BlockType> REGISTRY = new NamespacedRegistry<>("block type");

private String id;
private BlockState defaultState;
private Map<String, ? extends Property> properties;
private BlockMaterial blockMaterial;
private Map<Map<Property<?>, Object>, BlockState> blockStatesMap;
private final String id;
private final Function<BlockState, BlockState> values;
private final AtomicReference<BlockState> defaultState = new AtomicReference<>();
private final AtomicReference<Map<String, ? extends Property>> properties = new AtomicReference<>();
private final AtomicReference<BlockMaterial> blockMaterial = new AtomicReference<>();
private final AtomicReference<Map<Map<Property<?>, Object>, BlockState>> blockStatesMap = new AtomicReference<>();

public BlockType(String id) {
this(id, null);
Expand All @@ -58,11 +63,27 @@ public BlockType(String id, Function<BlockState, BlockState> values) {
id = "minecraft:" + id;
}
this.id = id;
this.blockStatesMap = BlockState.generateStateMap(this);
this.defaultState = new ArrayList<>(this.blockStatesMap.values()).get(0);
if (values != null) {
this.defaultState = values.apply(this.defaultState);
this.values = values;
}

private <T> T updateField(AtomicReference<T> field, Supplier<T> value) {
T result = field.get();
if (result == null) {
// swap in new value, if someone doesn't beat us
T update = value.get();
if (field.compareAndSet(null, update)) {
// use ours
result = update;
} else {
// update to real value
result = field.get();
}
}
return result;
}

private Map<Map<Property<?>, Object>, BlockState> getBlockStatesMap() {
return updateField(blockStatesMap, () -> BlockState.generateStateMap(this));
}

/**
Expand Down Expand Up @@ -94,11 +115,8 @@ public String getName() {
* @return The properties map
*/
public Map<String, ? extends Property> getPropertyMap() {
if (properties == null) {
properties = ImmutableMap.copyOf(WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(this));
}
return this.properties;
return updateField(properties, () -> ImmutableMap.copyOf(WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getProperties(this)));
}

/**
Expand All @@ -117,7 +135,9 @@ public List<? extends Property> getProperties() {
* @return The property
*/
public <V> Property<V> getProperty(String name) {
return getPropertyMap().get(name);
Property<V> property = getPropertyMap().get(name);
checkArgument(property != null, "%s has no property named %s", this, name);
return property;
}

/**
Expand All @@ -126,7 +146,13 @@ public <V> Property<V> getProperty(String name) {
* @return The default state
*/
public BlockState getDefaultState() {
return this.defaultState;
return updateField(defaultState, () -> {
BlockState defaultState = new ArrayList<>(getBlockStatesMap().values()).get(0);
if (values != null) {
defaultState = values.apply(defaultState);
}
return defaultState;
});
}

/**
Expand All @@ -135,7 +161,18 @@ public BlockState getDefaultState() {
* @return All possible states
*/
public List<BlockState> getAllStates() {
return ImmutableList.copyOf(this.blockStatesMap.values());
return ImmutableList.copyOf(getBlockStatesMap().values());
}

/**
* Gets a state of this BlockType with the given properties.
*
* @return The state, if it exists
*/
public BlockState getState(Map<Property<?>, Object> key) {
BlockState state = getBlockStatesMap().get(key);
checkArgument(state != null, "%s has no state for %s", this, key);
return state;
}

/**
Expand Down Expand Up @@ -163,10 +200,8 @@ public ItemType getItemType() {
* @return The material
*/
public BlockMaterial getMaterial() {
if (this.blockMaterial == null) {
this.blockMaterial = WorldEdit.getInstance().getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(this);
}
return this.blockMaterial;
return updateField(blockMaterial, () -> WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.GAME_HOOKS).getRegistries().getBlockRegistry().getMaterial(this));
}

/**
Expand Down
5 changes: 5 additions & 0 deletions worldedit-forge/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ buildscript {

apply plugin: 'net.minecraftforge.gradle.forge'

configurations.all {
resolutionStrategy {
force 'org.ow2.asm:asm:5.2'
}
}

dependencies {
compile project(':worldedit-core')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,27 @@

package com.sk89q.worldedit.forge;

import com.google.common.collect.ImmutableList;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.registry.state.BooleanProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.world.World;

import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.properties.PropertyDirection;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;

import java.util.stream.Collectors;

final class ForgeAdapter {

private ForgeAdapter() {
Expand Down Expand Up @@ -60,8 +74,41 @@ public static EnumFacing adapt(Direction face) {
}
}

public static Direction adaptEnumFacing(EnumFacing face) {
switch (face) {
case NORTH: return Direction.NORTH;
case SOUTH: return Direction.SOUTH;
case WEST: return Direction.WEST;
case EAST: return Direction.EAST;
case DOWN: return Direction.DOWN;
case UP:
default:
return Direction.UP;
}
}

public static BlockPos toBlockPos(Vector vector) {
return new BlockPos(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ());
}

public static Property<?> adaptProperty(IProperty<?> property) {
if (property instanceof PropertyBool) {
return new BooleanProperty(property.getName(), ImmutableList.copyOf(((PropertyBool) property).getAllowedValues()));
}
if (property instanceof PropertyInteger) {
return new IntegerProperty(property.getName(), ImmutableList.copyOf(((PropertyInteger) property).getAllowedValues()));
}
if (property instanceof PropertyDirection) {
return new DirectionalProperty(property.getName(), ((PropertyDirection) property).getAllowedValues().stream()
.map(ForgeAdapter::adaptEnumFacing)
.collect(Collectors.toList()));
}
if (property instanceof PropertyEnum) {
return new EnumProperty(property.getName(), ((PropertyEnum<?>) property).getAllowedValues().stream()
.map(e -> e.getName())
.collect(Collectors.toList()));
}
return new IPropertyAdapter<>(property);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.worldedit.forge;

import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial;

import net.minecraft.block.material.EnumPushReaction;
import net.minecraft.block.material.Material;

import javax.annotation.Nullable;

/**
* Forge block material that pulls as much info as possible from the Minecraft
* Material, and passes the rest to another implementation, typically the
* bundled block info.
*/
public class ForgeBlockMaterial extends PassthroughBlockMaterial {

private final Material delegate;

public ForgeBlockMaterial(Material delegate, @Nullable BlockMaterial secondary) {
super(secondary);
this.delegate = delegate;
}

@Override
public boolean isAir() {
return delegate == Material.AIR || super.isAir();
}

@Override
public boolean isOpaque() {
return delegate.isOpaque();
}

@Override
public boolean isLiquid() {
return delegate.isLiquid();
}

@Override
public boolean isSolid() {
return delegate.isSolid();
}

@Override
public boolean isFragileWhenPushed() {
return delegate.getMobilityFlag() == EnumPushReaction.DESTROY;
}

@Override
public boolean isUnpushable() {
return delegate.getMobilityFlag() == EnumPushReaction.BLOCK;
}

@Override
public boolean isMovementBlocker() {
return delegate.blocksMovement();
}

@Override
public boolean isBurnable() {
return delegate.getCanBurn();
}

@Override
public boolean isToolRequired() {
return !delegate.isToolNotRequired();
}

@Override
public boolean isReplacedDuringPlacement() {
return delegate.isReplaceable();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.sk89q.worldedit.forge;

import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import com.sk89q.worldedit.world.registry.BundledBlockRegistry;

import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class ForgeBlockRegistry extends BundledBlockRegistry {

private Map<Material, ForgeBlockMaterial> materialMap = new HashMap<>();

@Override
public BlockMaterial getMaterial(BlockType blockType) {
return materialMap.computeIfAbsent(Block.getBlockFromName(blockType.getId()).getDefaultState().getMaterial(),
m -> new ForgeBlockMaterial(m, super.getMaterial(blockType)));
}

@Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
Map<String, Property<?>> map = new TreeMap<>();
Collection<IProperty<?>> propertyKeys = Block.getBlockFromName(blockType.getId())
.getDefaultState()
.getPropertyKeys();
for (IProperty<?> key : propertyKeys) {
map.put(key.getName(), ForgeAdapter.adaptProperty(key));
}
return map;
}

}
Loading

0 comments on commit 88f22f2

Please sign in to comment.