Implemented new biome API.

This commit is contained in:
sk89q 2014-07-17 00:21:13 -07:00
parent d50e05480f
commit 42be110097
58 changed files with 1830 additions and 553 deletions

View File

@ -0,0 +1,79 @@
/*
* 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.bukkit;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import org.bukkit.block.Biome;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A biome registry for Bukkit.
*/
class BukkitBiomeRegistry implements BiomeRegistry {
BukkitBiomeRegistry() {
}
@Nullable
@Override
public BaseBiome createFromId(int id) {
return new BaseBiome(id);
}
@Override
public List<BaseBiome> getBiomes() {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
List<BaseBiome> biomes = new ArrayList<BaseBiome>();
for (Biome biome : Biome.values()) {
int biomeId = adapter.getBiomeId(biome);
biomes.add(new BaseBiome(biomeId));
}
return biomes;
} else {
return Collections.emptyList();
}
}
@Nullable
@Override
public BiomeData getData(BaseBiome biome) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
final Biome bukkitBiome = adapter.getBiome(biome.getId());
return new BiomeData() {
@Override
public String getName() {
return bukkitBiome.name();
}
};
} else {
return null;
}
}
}

View File

@ -1,106 +0,0 @@
/*
* 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.bukkit;
import java.util.Locale;
import org.bukkit.block.Biome;
import com.sk89q.worldedit.BiomeType;
public enum BukkitBiomeType implements BiomeType {
SWAMPLAND(Biome.SWAMPLAND),
FOREST(Biome.FOREST),
TAIGA(Biome.TAIGA),
DESERT(Biome.DESERT),
PLAINS(Biome.PLAINS),
HELL(Biome.HELL),
SKY(Biome.SKY),
RIVER(Biome.RIVER),
EXTREME_HILLS(Biome.EXTREME_HILLS),
OCEAN(Biome.OCEAN),
FROZEN_OCEAN(Biome.FROZEN_OCEAN),
FROZEN_RIVER(Biome.FROZEN_RIVER),
ICE_PLAINS(Biome.ICE_PLAINS),
ICE_MOUNTAINS(Biome.ICE_MOUNTAINS),
MUSHROOM_ISLAND(Biome.MUSHROOM_ISLAND),
MUSHROOM_SHORE(Biome.MUSHROOM_SHORE),
BEACH(Biome.BEACH),
DESERT_HILLS(Biome.DESERT_HILLS),
FOREST_HILLS(Biome.FOREST_HILLS),
TAIGA_HILLS(Biome.TAIGA_HILLS),
SMALL_MOUNTAINS(Biome.SMALL_MOUNTAINS),
JUNGLE(Biome.JUNGLE),
JUNGLE_HILLS(Biome.JUNGLE_HILLS),
JUNGLE_EDGE(Biome.JUNGLE_EDGE),
DEEP_OCEAN(Biome.DEEP_OCEAN),
STONE_BEACH(Biome.STONE_BEACH),
COLD_BEACH(Biome.COLD_BEACH),
BIRCH_FOREST(Biome.BIRCH_FOREST),
BIRCH_FOREST_HILLS(Biome.BIRCH_FOREST_HILLS),
ROOFED_FOREST(Biome.ROOFED_FOREST),
COLD_TAIGA(Biome.COLD_TAIGA),
COLD_TAIGA_HILLS(Biome.COLD_TAIGA_HILLS),
MEGA_TAIGA(Biome.MEGA_TAIGA),
MEGA_TAIGA_HILLS(Biome.MEGA_TAIGA_HILLS),
EXTREME_HILLS_PLUS(Biome.EXTREME_HILLS_PLUS),
SAVANNA(Biome.SAVANNA),
SAVANNA_PLATEAU(Biome.SAVANNA_PLATEAU),
MESA(Biome.MESA),
MESA_PLATEAU_FOREST(Biome.MESA_PLATEAU_FOREST),
MESA_PLATEAU(Biome.MESA_PLATEAU),
SUNFLOWER_PLAINS(Biome.SUNFLOWER_PLAINS),
DESERT_MOUNTAINS(Biome.DESERT_MOUNTAINS),
FLOWER_FOREST(Biome.FLOWER_FOREST),
TAIGA_MOUNTAINS(Biome.TAIGA_MOUNTAINS),
SWAMPLAND_MOUNTAINS(Biome.SWAMPLAND_MOUNTAINS),
ICE_PLAINS_SPIKES(Biome.ICE_PLAINS_SPIKES),
JUNGLE_MOUNTAINS(Biome.JUNGLE_MOUNTAINS),
JUNGLE_EDGE_MOUNTAINS(Biome.JUNGLE_EDGE_MOUNTAINS),
COLD_TAIGA_MOUNTAINS(Biome.COLD_TAIGA_MOUNTAINS),
SAVANNA_MOUNTAINS(Biome.SAVANNA_MOUNTAINS),
SAVANNA_PLATEAU_MOUNTAINS(Biome.SAVANNA_PLATEAU_MOUNTAINS),
MESA_BRYCE(Biome.MESA_BRYCE),
MESA_PLATEAU_FOREST_MOUNTAINS(Biome.MESA_PLATEAU_FOREST_MOUNTAINS),
MESA_PLATEAU_MOUNTAINS(Biome.MESA_PLATEAU_MOUNTAINS),
BIRCH_FOREST_MOUNTAINS(Biome.BIRCH_FOREST_MOUNTAINS),
BIRCH_FOREST_HILLS_MOUNTAINS(Biome.BIRCH_FOREST_HILLS_MOUNTAINS),
ROOFED_FOREST_MOUNTAINS(Biome.ROOFED_FOREST_MOUNTAINS),
MEGA_SPRUCE_TAIGA(Biome.MEGA_SPRUCE_TAIGA),
EXTREME_HILLS_MOUNTAINS(Biome.EXTREME_HILLS_MOUNTAINS),
EXTREME_HILLS_PLUS_MOUNTAINS(Biome.EXTREME_HILLS_PLUS_MOUNTAINS),
MEGA_SPRUCE_TAIGA_HILLS(Biome.MEGA_SPRUCE_TAIGA_HILLS);
private Biome bukkitBiome;
private BukkitBiomeType(Biome biome) {
this.bukkitBiome = biome;
}
@Override
public String getName() {
return name().toLowerCase(Locale.ENGLISH);
}
public Biome getBukkitBiome() {
return bukkitBiome;
}
}

View File

@ -1,59 +0,0 @@
/*
* 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.bukkit;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.UnknownBiomeTypeException;
public class BukkitBiomeTypes implements BiomeTypes {
public BukkitBiomeTypes() {
}
@Override
public boolean has(String name) {
try {
BukkitBiomeType.valueOf(name.toUpperCase(Locale.ENGLISH));
return true;
} catch (IllegalArgumentException exc) {
return false;
}
}
@Override
public BiomeType get(String name) throws UnknownBiomeTypeException {
try {
return BukkitBiomeType.valueOf(name.toUpperCase(Locale.ENGLISH));
} catch (IllegalArgumentException exc) {
throw new UnknownBiomeTypeException(name);
}
}
@Override
public List<BiomeType> all() {
return Arrays.<BiomeType>asList(BukkitBiomeType.values());
}
}

View File

@ -21,7 +21,6 @@ package com.sk89q.worldedit.bukkit;
import com.sk89q.bukkit.util.CommandInfo; import com.sk89q.bukkit.util.CommandInfo;
import com.sk89q.bukkit.util.CommandRegistration; import com.sk89q.bukkit.util.CommandRegistration;
import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.LocalWorld;
import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.ServerInterface;
@ -50,13 +49,13 @@ public class BukkitServerInterface extends ServerInterface implements MultiUserP
public Server server; public Server server;
public WorldEditPlugin plugin; public WorldEditPlugin plugin;
private CommandRegistration dynamicCommands; private CommandRegistration dynamicCommands;
private BukkitBiomeTypes biomes; private BukkitBiomeRegistry biomes;
private boolean hookingEvents; private boolean hookingEvents;
public BukkitServerInterface(WorldEditPlugin plugin, Server server) { public BukkitServerInterface(WorldEditPlugin plugin, Server server) {
this.plugin = plugin; this.plugin = plugin;
this.server = server; this.server = server;
this.biomes = new BukkitBiomeTypes(); this.biomes = new BukkitBiomeRegistry();
dynamicCommands = new CommandRegistration(plugin); dynamicCommands = new CommandRegistration(plugin);
} }
@ -81,11 +80,6 @@ public class BukkitServerInterface extends ServerInterface implements MultiUserP
plugin.loadConfiguration(); plugin.loadConfiguration();
} }
@Override
public BiomeTypes getBiomes() {
return biomes;
}
@Override @Override
public int schedule(long delay, long period, Runnable task) { public int schedule(long delay, long period, Runnable task) {
return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period); return Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, task, delay, period);

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit; package com.sk89q.worldedit.bukkit;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.LocalWorld;
@ -34,7 +33,7 @@ import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.util.TreeGenerator;
import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.WorldData; import com.sk89q.worldedit.world.registry.WorldData;
import org.bukkit.Effect; import org.bukkit.Effect;
import org.bukkit.Material; import org.bukkit.Material;
@ -161,25 +160,6 @@ public class BukkitWorld extends LocalWorld {
return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel(); return getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getLightLevel();
} }
@Override
public BiomeType getBiome(Vector2D pt) {
Biome bukkitBiome = getWorld().getBiome(pt.getBlockX(), pt.getBlockZ());
try {
return BukkitBiomeType.valueOf(bukkitBiome.name());
} catch (IllegalArgumentException exc) {
return BiomeType.UNKNOWN;
}
}
@Override
public void setBiome(Vector2D pt, BiomeType biome) {
if (biome instanceof BukkitBiomeType) {
Biome bukkitBiome;
bukkitBiome = ((BukkitBiomeType) biome).getBukkitBiome();
getWorld().setBiome(pt.getBlockX(), pt.getBlockZ(), bukkitBiome);
}
}
@Override @Override
public boolean regenerate(Region region, EditSession editSession) { public boolean regenerate(Region region, EditSession editSession) {
BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)]; BaseBlock[] history = new BaseBlock[16 * 16 * (getMaxY() + 1)];
@ -413,7 +393,7 @@ public class BukkitWorld extends LocalWorld {
@Override @Override
public WorldData getWorldData() { public WorldData getWorldData() {
return LegacyWorldData.getInstance(); return BukkitWorldData.getInstance();
} }
@Override @Override
@ -451,6 +431,29 @@ public class BukkitWorld extends LocalWorld {
return new LazyBlock(bukkitBlock.getTypeId(), bukkitBlock.getData(), this, position); return new LazyBlock(bukkitBlock.getTypeId(), bukkitBlock.getData(), this, position);
} }
@Override
public BaseBiome getBiome(Vector2D position) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
int id = adapter.getBiomeId(getWorld().getBiome(position.getBlockX(), position.getBlockZ()));
return new BaseBiome(id);
} else {
return new BaseBiome(0);
}
}
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
if (adapter != null) {
Biome bukkitBiome = adapter.getBiome(biome.getId());
getWorld().setBiome(position.getBlockX(), position.getBlockZ(), bukkitBiome);
return true;
} else {
return false;
}
}
/** /**
* @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)} * @deprecated Use {@link #setBlock(Vector, BaseBlock, boolean)}
*/ */
@ -458,5 +461,4 @@ public class BukkitWorld extends LocalWorld {
public boolean setBlock(Vector pt, com.sk89q.worldedit.foundation.Block block, boolean notifyAdjacent) throws WorldEditException { public boolean setBlock(Vector pt, com.sk89q.worldedit.foundation.Block block, boolean notifyAdjacent) throws WorldEditException {
return setBlock(pt, (BaseBlock) block, notifyAdjacent); return setBlock(pt, (BaseBlock) block, notifyAdjacent);
} }
} }

View File

@ -0,0 +1,53 @@
/*
* 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.bukkit;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import com.sk89q.worldedit.world.registry.LegacyWorldData;
/**
* World data for the Bukkit platform.
*/
class BukkitWorldData extends LegacyWorldData {
private static final BukkitWorldData INSTANCE = new BukkitWorldData();
private final BiomeRegistry biomeRegistry = new BukkitBiomeRegistry();
/**
* Create a new instance.
*/
BukkitWorldData() {
}
@Override
public BiomeRegistry getBiomeRegistry() {
return biomeRegistry;
}
/**
* Get a static instance.
*
* @return an instance
*/
public static BukkitWorldData getInstance() {
return INSTANCE;
}
}

View File

@ -22,6 +22,8 @@ package com.sk89q.worldedit.bukkit.adapter;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -31,6 +33,46 @@ import javax.annotation.Nullable;
*/ */
public interface BukkitImplAdapter { public interface BukkitImplAdapter {
/**
* Get the block ID for the given material.
*
* <p>Returns 0 if it is not known or it doesn't exist.</p>
*
* @param material the material
* @return the block ID
*/
int getBlockId(Material material);
/**
* Get the material for the given block ID.
*
* <p>Returns {@link Material#AIR} if it is not known or it doesn't exist.</p>
*
* @param id the block ID
* @return the material
*/
Material getMaterial(int id);
/**
* Get the biome ID for the given biome.
*
* <p>Returns 0 if it is not known or it doesn't exist.</p>
*
* @param biome biome
* @return the biome ID
*/
int getBiomeId(Biome biome);
/**
* Get the biome ID for the given biome ID..
*
* <p>Returns {@link Biome#OCEAN} if it is not known or it doesn't exist.</p>
*
* @param id the biome ID
* @return the biome
*/
Biome getBiome(int id);
/** /**
* Get the block at the given location. * Get the block at the given location.
* *

View File

@ -0,0 +1,107 @@
/*
* 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.google.common.collect.HashBiMap;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import net.minecraft.world.biome.BiomeGenBase;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Provides access to biome data in Forge.
*/
class ForgeBiomeRegistry implements BiomeRegistry {
private static Map<Integer, BiomeGenBase> biomes = Collections.emptyMap();
private static Map<Integer, BiomeData> biomeData = Collections.emptyMap();
@Nullable
@Override
public BaseBiome createFromId(int id) {
return new BaseBiome(id);
}
@Override
public List<BaseBiome> getBiomes() {
List<BaseBiome> list = new ArrayList<BaseBiome>();
for (int biome : biomes.keySet()) {
list.add(new BaseBiome(biome));
}
return list;
}
@Nullable
@Override
public BiomeData getData(BaseBiome biome) {
return biomeData.get(biome.getId());
}
/**
* Populate the internal static list of biomes.
*
* <p>If called repeatedly, the last call will overwrite all previous
* calls.</p>
*/
static void populate() {
Map<Integer, BiomeGenBase> biomes = HashBiMap.create();
Map<Integer, BiomeData> biomeData = new HashMap<Integer, BiomeData>();
for (BiomeGenBase biome : BiomeGenBase.biomeList) {
if ((biome == null) || (biomes.containsValue(biome))) {
continue;
}
biomes.put(biome.biomeID, biome);
biomeData.put(biome.biomeID, new ForgeBiomeData(biome));
}
ForgeBiomeRegistry.biomes = biomes;
ForgeBiomeRegistry.biomeData = biomeData;
}
/**
* Cached biome data information.
*/
private static class ForgeBiomeData implements BiomeData {
private final BiomeGenBase biome;
/**
* Create a new instance.
*
* @param biome the base biome
*/
private ForgeBiomeData(BiomeGenBase biome) {
this.biome = biome;
}
@Override
public String getName() {
return biome.biomeName;
}
}
}

View File

@ -1,87 +0,0 @@
/*
* 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import net.minecraft.world.biome.BiomeGenBase;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.UnknownBiomeTypeException;
public class ForgeBiomeTypes implements BiomeTypes {
private static BiMap<BiomeType, BiomeGenBase> biomes = HashBiMap.create();
public ForgeBiomeTypes() {
all();
}
public boolean has(String name) {
for (BiomeGenBase biome : BiomeGenBase.biomeList) {
if ((biome != null) && (biome.biomeName.equalsIgnoreCase(name))) {
return true;
}
}
return false;
}
public BiomeType get(String name) throws UnknownBiomeTypeException {
if (biomes == null) {
all();
}
Iterator<BiomeType> it = biomes.keySet().iterator();
while (it.hasNext()) {
BiomeType test = (BiomeType) it.next();
if (test.getName().equalsIgnoreCase(name)) {
return test;
}
}
throw new UnknownBiomeTypeException(name);
}
public List<BiomeType> all() {
if (biomes.isEmpty()) {
biomes = HashBiMap.create(new HashMap<BiomeType, BiomeGenBase>());
for (BiomeGenBase biome : BiomeGenBase.biomeList) {
if ((biome == null) || (biomes.containsValue(biome))) {
continue;
}
biomes.put(new ForgeBiomeType(biome), biome);
}
}
List<BiomeType> retBiomes = new ArrayList<BiomeType>();
retBiomes.addAll(biomes.keySet());
return retBiomes;
}
public static BiomeType getFromBaseBiome(BiomeGenBase biome) {
return biomes.containsValue(biome) ? (BiomeType) biomes.inverse().get(biome) : BiomeType.UNKNOWN;
}
public static BiomeGenBase getFromBiomeType(BiomeType biome) {
return (BiomeGenBase) biomes.get(biome);
}
}

View File

@ -19,7 +19,7 @@
package com.sk89q.worldedit.forge; package com.sk89q.worldedit.forge;
import com.sk89q.worldedit.BiomeTypes; import com.sk89q.worldedit.world.registry.BiomeRegistry;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.ServerInterface;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
@ -56,13 +56,13 @@ class ForgePlatform extends ServerInterface implements MultiUserPlatform {
private final ForgeWorldEdit mod; private final ForgeWorldEdit mod;
private final MinecraftServer server; private final MinecraftServer server;
private final ForgeBiomeTypes biomes; private final ForgeBiomeRegistry biomes;
private boolean hookingEvents = false; private boolean hookingEvents = false;
ForgePlatform(ForgeWorldEdit mod) { ForgePlatform(ForgeWorldEdit mod) {
this.mod = mod; this.mod = mod;
this.server = FMLCommonHandler.instance().getMinecraftServerInstance(); this.server = FMLCommonHandler.instance().getMinecraftServerInstance();
this.biomes = new ForgeBiomeTypes(); this.biomes = new ForgeBiomeRegistry();
} }
boolean isHookingEvents() { boolean isHookingEvents() {
@ -95,11 +95,6 @@ class ForgePlatform extends ServerInterface implements MultiUserPlatform {
public void reload() { public void reload() {
} }
@Override
public BiomeTypes getBiomes() {
return this.biomes;
}
@Override @Override
public int schedule(long delay, long period, Runnable task) { public int schedule(long delay, long period, Runnable task) {
return -1; return -1;

View File

@ -20,7 +20,6 @@
package com.sk89q.worldedit.forge; package com.sk89q.worldedit.forge;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
@ -36,7 +35,7 @@ import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.AbstractWorld; import com.sk89q.worldedit.world.AbstractWorld;
import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.WorldData; import com.sk89q.worldedit.world.registry.WorldData;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityList;
@ -181,22 +180,23 @@ public class ForgeWorld extends AbstractWorld {
} }
@Override @Override
public BiomeType getBiome(Vector2D position) { public BaseBiome getBiome(Vector2D position) {
checkNotNull(position); checkNotNull(position);
return ForgeBiomeTypes.getFromBaseBiome(getWorld().getBiomeGenForCoords(position.getBlockX(), position.getBlockZ())); return new BaseBiome(getWorld().getBiomeGenForCoords(position.getBlockX(), position.getBlockZ()).biomeID);
} }
@Override @Override
public void setBiome(Vector2D position, BiomeType biome) { public boolean setBiome(Vector2D position, BaseBiome biome) {
checkNotNull(position); checkNotNull(position);
checkNotNull(biome); checkNotNull(biome);
if (getWorld().getChunkProvider().chunkExists(position.getBlockX(), position.getBlockZ())) {
Chunk chunk = getWorld().getChunkFromBlockCoords(position.getBlockX(), position.getBlockZ()); Chunk chunk = getWorld().getChunkFromBlockCoords(position.getBlockX(), position.getBlockZ());
if ((chunk != null) && (chunk.isChunkLoaded)) { if ((chunk != null) && (chunk.isChunkLoaded)) {
chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = (byte) ForgeBiomeTypes.getFromBiomeType(biome).biomeID; chunk.getBiomeArray()[((position.getBlockZ() & 0xF) << 4 | position.getBlockX() & 0xF)] = (byte) biome.getId();
} return true;
} }
return false;
} }
@Override @Override
@ -317,7 +317,7 @@ public class ForgeWorld extends AbstractWorld {
@Override @Override
public WorldData getWorldData() { public WorldData getWorldData() {
return LegacyWorldData.getInstance(); return ForgeWorldData.getInstance();
} }
@Override @Override

View File

@ -19,18 +19,35 @@
package com.sk89q.worldedit.forge; package com.sk89q.worldedit.forge;
import net.minecraft.world.biome.BiomeGenBase; import com.sk89q.worldedit.world.registry.BiomeRegistry;
import com.sk89q.worldedit.world.registry.LegacyWorldData;
import com.sk89q.worldedit.BiomeType; /**
* World data for the Forge platform.
*/
class ForgeWorldData extends LegacyWorldData {
public class ForgeBiomeType implements BiomeType { private static final ForgeWorldData INSTANCE = new ForgeWorldData();
private BiomeGenBase biome; private final BiomeRegistry biomeRegistry = new ForgeBiomeRegistry();
public ForgeBiomeType(BiomeGenBase biome) { /**
this.biome = biome; * Create a new instance.
*/
ForgeWorldData() {
} }
public String getName() { @Override
return this.biome.biomeName; public BiomeRegistry getBiomeRegistry() {
return biomeRegistry;
} }
/**
* Get a static instance.
*
* @return an instance
*/
public static ForgeWorldData getInstance() {
return INSTANCE;
}
} }

View File

@ -103,6 +103,8 @@ public class ForgeWorldEdit {
WorldEdit.getInstance().getPlatformManager().unregister(platform); WorldEdit.getInstance().getPlatformManager().unregister(platform);
} }
ForgeBiomeRegistry.populate();
this.platform = new ForgePlatform(this); this.platform = new ForgePlatform(this);
WorldEdit.getInstance().getPlatformManager().register(platform); WorldEdit.getInstance().getPlatformManager().register(platform);

View File

@ -76,6 +76,7 @@ import com.sk89q.worldedit.util.collection.DoubleArrayList;
import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.eventbus.EventBus;
import com.sk89q.worldedit.world.NullWorld; import com.sk89q.worldedit.world.NullWorld;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.*; import java.util.*;
@ -377,6 +378,16 @@ public class EditSession implements Extent {
return changeSet.size(); return changeSet.size();
} }
@Override
public BaseBiome getBiome(Vector2D position) {
return bypassNone.getBiome(position);
}
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
return bypassNone.setBiome(position, biome);
}
@Override @Override
public BaseBlock getLazyBlock(Vector position) { public BaseBlock getLazyBlock(Vector position) {
return world.getLazyBlock(position); return world.getLazyBlock(position);
@ -2248,7 +2259,7 @@ public class EditSession implements Extent {
} // while } // while
} }
public int makeBiomeShape(final Region region, final Vector zero, final Vector unit, final BiomeType biomeType, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException { public int makeBiomeShape(final Region region, final Vector zero, final Vector unit, final BaseBiome biomeType, final String expressionString, final boolean hollow) throws ExpressionException, MaxChangedBlocksException {
final Vector2D zero2D = zero.toVector2D(); final Vector2D zero2D = zero.toVector2D();
final Vector2D unit2D = unit.toVector2D(); final Vector2D unit2D = unit.toVector2D();
@ -2261,7 +2272,7 @@ public class EditSession implements Extent {
final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) { final ArbitraryBiomeShape shape = new ArbitraryBiomeShape(region) {
@Override @Override
protected BiomeType getBiome(int x, int z, BiomeType defaultBiomeType) { protected BaseBiome getBiome(int x, int z, BaseBiome defaultBiomeType) {
final Vector2D current = new Vector2D(x, z); final Vector2D current = new Vector2D(x, z);
environment.setCurrentBlock(current.toVector(0)); environment.setCurrentBlock(current.toVector(0));
final Vector2D scaled = current.subtract(zero2D).divide(unit2D); final Vector2D scaled = current.subtract(zero2D).divide(unit2D);

View File

@ -23,15 +23,29 @@ import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.function.FlatRegionFunction;
import com.sk89q.worldedit.function.FlatRegionMaskingFilter;
import com.sk89q.worldedit.function.biome.BiomeReplace;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.masks.BiomeTypeMask; import com.sk89q.worldedit.function.mask.Mask2D;
import com.sk89q.worldedit.masks.InvertedMask; import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.function.visitor.FlatRegionVisitor;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.Regions;
import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.BiomeData;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -64,7 +78,7 @@ public class BiomeCommands {
max = 1 max = 1
) )
@CommandPermissions("worldedit.biome.list") @CommandPermissions("worldedit.biome.list")
public void biomeList(Actor actor, CommandContext args) throws WorldEditException { public void biomeList(Player player, CommandContext args) throws WorldEditException {
int page; int page;
int offset; int offset;
int count = 0; int count = 0;
@ -76,17 +90,23 @@ public class BiomeCommands {
offset = (page - 1) * 19; offset = (page - 1) * 19;
} }
List<BiomeType> biomes = worldEdit.getServer().getBiomes().all(); BiomeRegistry biomeRegistry = player.getWorld().getWorldData().getBiomeRegistry();
List<BaseBiome> biomes = biomeRegistry.getBiomes();
int totalPages = biomes.size() / 19 + 1; int totalPages = biomes.size() / 19 + 1;
actor.print("Available Biomes (page " + page + "/" + totalPages + ") :"); player.print("Available Biomes (page " + page + "/" + totalPages + ") :");
for (BiomeType biome : biomes) { for (BaseBiome biome : biomes) {
if (offset > 0) { if (offset > 0) {
offset--; offset--;
} else { } else {
actor.print(" " + biome.getName()); BiomeData data = biomeRegistry.getData(biome);
if (data != null) {
player.print(" " + data.getName());
if (++count == 19) { if (++count == 19) {
break; break;
} }
} else {
player.print(" <unknown #" + biome.getId() + ">");
}
} }
} }
} }
@ -103,7 +123,11 @@ public class BiomeCommands {
max = 0 max = 0
) )
@CommandPermissions("worldedit.biome.info") @CommandPermissions("worldedit.biome.info")
public void biomeInfo(CommandContext args, Player player, LocalSession session) throws WorldEditException { public void biomeInfo(Player player, LocalSession session, CommandContext args) throws WorldEditException {
BiomeRegistry biomeRegistry = player.getWorld().getWorldData().getBiomeRegistry();
Set<BaseBiome> biomes = new HashSet<BaseBiome>();
String qualifier;
if (args.hasFlag('t')) { if (args.hasFlag('t')) {
Vector blockPosition = player.getBlockTrace(300); Vector blockPosition = player.getBlockTrace(300);
if (blockPosition == null) { if (blockPosition == null) {
@ -111,15 +135,18 @@ public class BiomeCommands {
return; return;
} }
BiomeType biome = player.getWorld().getBiome(blockPosition.toVector2D()); BaseBiome biome = player.getWorld().getBiome(blockPosition.toVector2D());
player.print("Biome: " + biome.getName()); biomes.add(biome);
qualifier = "at line of sight point";
} else if (args.hasFlag('p')) { } else if (args.hasFlag('p')) {
BiomeType biome = player.getWorld().getBiome(player.getPosition().toVector2D()); BaseBiome biome = player.getWorld().getBiome(player.getPosition().toVector2D());
player.print("Biome: " + biome.getName()); biomes.add(biome);
qualifier = "at your position";
} else { } else {
World world = player.getWorld(); World world = player.getWorld();
Region region = session.getSelection(world); Region region = session.getSelection(world);
Set<BiomeType> biomes = new HashSet<BiomeType>();
if (region instanceof FlatRegion) { if (region instanceof FlatRegion) {
for (Vector2D pt : ((FlatRegion) region).asFlatRegion()) { for (Vector2D pt : ((FlatRegion) region).asFlatRegion()) {
@ -131,9 +158,16 @@ public class BiomeCommands {
} }
} }
player.print("Biomes:"); qualifier = "in your selection";
for (BiomeType biome : biomes) { }
player.print(" " + biome.getName());
player.print(biomes.size() != 1 ? "Biomes " + qualifier + ":" : "Biome " + qualifier + ":");
for (BaseBiome biome : biomes) {
BiomeData data = biomeRegistry.getData(biome);
if (data != null) {
player.print(" " + data.getName());
} else {
player.print(" <unknown #" + biome.getId() + ">");
} }
} }
} }
@ -146,64 +180,30 @@ public class BiomeCommands {
help = help =
"Set the biome of the region.\n" + "Set the biome of the region.\n" +
"By default use all the blocks contained in your selection.\n" + "By default use all the blocks contained in your selection.\n" +
"-p use the block you are currently in", "-p use the block you are currently in"
min = 1,
max = 1
) )
@Logging(REGION) @Logging(REGION)
@CommandPermissions("worldedit.biome.set") @CommandPermissions("worldedit.biome.set")
public void setBiome(CommandContext args, Player player, LocalSession session, EditSession editSession) throws WorldEditException { public void setBiome(Player player, LocalSession session, EditSession editSession, BaseBiome target, @Switch('p') boolean atPosition) throws WorldEditException {
final BiomeType target = worldEdit.getServer().getBiomes().get(args.getString(0));
if (target == null) {
player.printError("Biome '" + args.getString(0) + "' does not exist!");
return;
}
Mask mask = editSession.getMask();
BiomeTypeMask biomeMask = null;
boolean inverted = false;
if (mask instanceof BiomeTypeMask) {
biomeMask = (BiomeTypeMask) mask;
} else if (mask instanceof InvertedMask && ((InvertedMask) mask).getInvertedMask() instanceof BiomeTypeMask) {
inverted = true;
biomeMask = (BiomeTypeMask) ((InvertedMask) mask).getInvertedMask();
}
if (args.hasFlag('p')) {
Vector2D pos = player.getPosition().toVector2D();
if (biomeMask == null || (biomeMask.matches2D(editSession, pos) ^ inverted)) {
player.getWorld().setBiome(pos, target);
player.print("Biome changed to " + target.getName() + " at your current location.");
} else {
player.print("Your global mask doesn't match this biome. Type //gmask to disable it.");
}
} else {
int affected = 0;
World world = player.getWorld(); World world = player.getWorld();
Region region = session.getSelection(world); Region region;
Mask mask = editSession.getMask();
Mask2D mask2d = mask != null ? mask.toMask2D() : null;
if (region instanceof FlatRegion) { if (atPosition) {
for (Vector2D pt : ((FlatRegion) region).asFlatRegion()) { region = new CuboidRegion(player.getPosition(), player.getPosition());
if (biomeMask == null || (biomeMask.matches2D(editSession, pt) ^ inverted)) {
world.setBiome(pt, target);
++affected;
}
}
} else { } else {
HashSet<Long> alreadyVisited = new HashSet<Long>(); region = session.getSelection(world);
for (Vector pt : region) {
if (!alreadyVisited.contains((long)pt.getBlockX() << 32 | pt.getBlockZ())) {
alreadyVisited.add(((long)pt.getBlockX() << 32 | pt.getBlockZ()));
if (biomeMask == null || (biomeMask.matches(editSession, pt) ^ inverted)) {
world.setBiome(pt.toVector2D(), target);
++affected;
}
}
}
} }
player.print("Biome changed to " + target.getName() + ". " + affected + " columns affected."); FlatRegionFunction replace = new BiomeReplace(editSession, target);
if (mask2d != null) {
replace = new FlatRegionMaskingFilter(mask2d, replace);
} }
FlatRegionVisitor visitor = new FlatRegionVisitor(Regions.asFlatRegion(region), replace);
Operations.completeLegacy(visitor);
player.print("Biomes were changed in " + visitor.getAffected() + " columns. You may have to rejoin your game (or close and reopen your world) to see a change.");
} }
} }

View File

@ -22,7 +22,11 @@ package com.sk89q.worldedit.command;
import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandPermissions; import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.Logging; import com.sk89q.minecraft.util.commands.Logging;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.function.pattern.Patterns; import com.sk89q.worldedit.function.pattern.Patterns;
@ -35,6 +39,7 @@ import com.sk89q.worldedit.util.command.binding.Range;
import com.sk89q.worldedit.util.command.binding.Switch; import com.sk89q.worldedit.util.command.binding.Switch;
import com.sk89q.worldedit.util.command.binding.Text; import com.sk89q.worldedit.util.command.binding.Text;
import com.sk89q.worldedit.util.command.parametric.Optional; import com.sk89q.worldedit.util.command.parametric.Optional;
import com.sk89q.worldedit.world.biome.BaseBiome;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.sk89q.minecraft.util.commands.Logging.LogMode.*; import static com.sk89q.minecraft.util.commands.Logging.LogMode.*;
@ -332,7 +337,7 @@ public class GenerationCommands {
@Logging(ALL) @Logging(ALL)
public void generateBiome(Player player, LocalSession session, EditSession editSession, public void generateBiome(Player player, LocalSession session, EditSession editSession,
@Selection Region region, @Selection Region region,
BiomeType target, BaseBiome target,
@Text String expression, @Text String expression,
@Switch('h') boolean hollow, @Switch('h') boolean hollow,
@Switch('r') boolean useRawCoords, @Switch('r') boolean useRawCoords,
@ -368,7 +373,7 @@ public class GenerationCommands {
try { try {
final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow); final int affected = editSession.makeBiomeShape(region, zero, unit, target, expression, hollow);
player.findFreePosition(); player.findFreePosition();
player.print("Biome changed to " + target.getName() + ". " + affected + " columns affected."); player.print("" + affected + " columns affected.");
} catch (ExpressionException e) { } catch (ExpressionException e) {
player.printError(e.getMessage()); player.printError(e.getMessage());
} }

View File

@ -19,17 +19,30 @@
package com.sk89q.worldedit.extension.factory; package com.sk89q.worldedit.extension.factory;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.NoMatchException; import com.sk89q.worldedit.extension.input.NoMatchException;
import com.sk89q.worldedit.extension.input.ParserContext; import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.*; import com.sk89q.worldedit.function.mask.BiomeMask2D;
import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.function.mask.ExistingBlockMask;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.MaskIntersection;
import com.sk89q.worldedit.function.mask.Masks;
import com.sk89q.worldedit.function.mask.NoiseFilter;
import com.sk89q.worldedit.function.mask.OffsetMask;
import com.sk89q.worldedit.function.mask.RegionMask;
import com.sk89q.worldedit.function.mask.SolidBlockMask;
import com.sk89q.worldedit.internal.registry.InputParser; import com.sk89q.worldedit.internal.registry.InputParser;
import com.sk89q.worldedit.masks.BiomeTypeMask;
import com.sk89q.worldedit.math.noise.RandomNoise; import com.sk89q.worldedit.math.noise.RandomNoise;
import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.Request;
import com.sk89q.worldedit.session.request.RequestSelection; import com.sk89q.worldedit.session.request.RequestSelection;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
@ -109,18 +122,19 @@ class DefaultMaskParser extends InputParser<Mask> {
return new MaskIntersection(offsetMask, Masks.negate(submask)); return new MaskIntersection(offsetMask, Masks.negate(submask));
case '$': case '$':
Set<BiomeType> biomes = new HashSet<BiomeType>(); Set<BaseBiome> biomes = new HashSet<BaseBiome>();
String[] biomesList = component.substring(1).split(","); String[] biomesList = component.substring(1).split(",");
BiomeRegistry biomeRegistry = context.requireWorld().getWorldData().getBiomeRegistry();
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
for (String biomeName : biomesList) { for (String biomeName : biomesList) {
try { BaseBiome biome = Biomes.findBiomeByName(knownBiomes, biomeName, biomeRegistry);
BiomeType biome = worldEdit.getServer().getBiomes().get(biomeName); if (biome == null) {
biomes.add(biome);
} catch (UnknownBiomeTypeException e) {
throw new InputParseException("Unknown biome '" + biomeName + "'"); throw new InputParseException("Unknown biome '" + biomeName + "'");
} }
biomes.add(biome);
} }
return Masks.wrap(new BiomeTypeMask(biomes)); return Masks.asMask(new BiomeMask2D(context.requireExtent(), biomes));
case '%': case '%':
int i = Integer.parseInt(component.substring(1)); int i = Integer.parseInt(component.substring(1));

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.extension.platform; package com.sk89q.worldedit.extension.platform;
import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.util.command.Dispatcher; import com.sk89q.worldedit.util.command.Dispatcher;
@ -58,13 +57,6 @@ public interface Platform {
*/ */
void reload(); void reload();
/**
* Returns all available biomes.
*
* @return an object containing all the biomes
*/
BiomeTypes getBiomes();
/** /**
* Schedules the given <code>task</code> to be invoked once every <code>period</code> ticks * Schedules the given <code>task</code> to be invoked once every <code>period</code> ticks
* after an initial delay of <code>delay</code> ticks. * after an initial delay of <code>delay</code> ticks.

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.extent; package com.sk89q.worldedit.extent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
@ -28,6 +29,7 @@ import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.function.operation.OperationQueue; import com.sk89q.worldedit.function.operation.OperationQueue;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -92,6 +94,16 @@ public abstract class AbstractDelegateExtent implements Extent {
return extent.getEntities(region); return extent.getEntities(region);
} }
@Override
public BaseBiome getBiome(Vector2D position) {
return extent.getBiome(position);
}
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
return extent.setBiome(position, biome);
}
@Override @Override
public Vector getMinimumPoint() { public Vector getMinimumPoint() {
return extent.getMinimumPoint(); return extent.getMinimumPoint();

View File

@ -20,9 +20,10 @@
package com.sk89q.worldedit.extent; package com.sk89q.worldedit.extent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.world.biome.BaseBiome;
/** /**
* Provides the current state of blocks, entities, and so on. * Provides the current state of blocks, entities, and so on.
@ -74,4 +75,15 @@ public interface InputExtent {
*/ */
BaseBlock getLazyBlock(Vector position); BaseBlock getLazyBlock(Vector position);
/**
* Get the biome at the given location.
*
* <p>If there is no biome available, then the ocean biome should be
* returned.</p>
*
* @param position the (x, z) location to check the biome at
* @return the biome at the location
*/
BaseBiome getBiome(Vector2D position);
} }

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.extent; package com.sk89q.worldedit.extent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
@ -27,6 +28,7 @@ import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections; import java.util.Collections;
@ -76,11 +78,22 @@ public class NullExtent implements Extent {
return new BaseBlock(0); return new BaseBlock(0);
} }
@Nullable
@Override
public BaseBiome getBiome(Vector2D position) {
return null;
}
@Override @Override
public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException { public boolean setBlock(Vector position, BaseBlock block) throws WorldEditException {
return false; return false;
} }
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
return false;
}
@Nullable @Nullable
@Override @Override
public Operation commit() { public Operation commit() {

View File

@ -20,9 +20,11 @@
package com.sk89q.worldedit.extent; package com.sk89q.worldedit.extent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -49,6 +51,15 @@ public interface OutputExtent {
*/ */
boolean setBlock(Vector position, BaseBlock block) throws WorldEditException; boolean setBlock(Vector position, BaseBlock block) throws WorldEditException;
/**
* Set the biome.
*
* @param position the (x, z) location to set the biome at
* @param biome the biome to set to
* @return true if the biome was successfully set (return value may not be accurate)
*/
boolean setBiome(Vector2D position, BaseBiome biome);
/** /**
* Return an {@link Operation} that should be called to tie up loose ends * Return an {@link Operation} that should be called to tie up loose ends
* (such as to commit changes in a buffer). * (such as to commit changes in a buffer).

View File

@ -20,6 +20,7 @@
package com.sk89q.worldedit.extent.clipboard; package com.sk89q.worldedit.extent.clipboard;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockID;
@ -28,6 +29,7 @@ import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.world.biome.BaseBiome;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@ -146,6 +148,16 @@ public class BlockArrayClipboard implements Clipboard {
} }
} }
@Override
public BaseBiome getBiome(Vector2D position) {
return new BaseBiome(0);
}
@Override
public boolean setBiome(Vector2D position, BaseBiome biome) {
return false;
}
@Nullable @Nullable
@Override @Override
public Operation commit() { public Operation commit() {

View File

@ -0,0 +1,56 @@
/*
* 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.function.biome;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.FlatRegionFunction;
import com.sk89q.worldedit.world.biome.BaseBiome;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Replaces the biome at the locations that this function is applied to.
*/
public class BiomeReplace implements FlatRegionFunction {
private final Extent extent;
private BaseBiome biome;
/**
* Create a new instance.
*
* @param extent an extent
* @param biome a biome
*/
public BiomeReplace(Extent extent, BaseBiome biome) {
checkNotNull(extent);
checkNotNull(biome);
this.extent = extent;
this.biome = biome;
}
@Override
public boolean apply(Vector2D position) throws WorldEditException {
return extent.setBiome(position, biome);
}
}

View File

@ -0,0 +1,98 @@
/*
* 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.function.mask;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.biome.BaseBiome;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Tests true if the biome at applied points is the same as the one given.
*/
public class BiomeMask2D extends AbstractMask2D {
private final Extent extent;
private final Set<BaseBiome> biomes = new HashSet<BaseBiome>();
/**
* Create a new biome mask.
*
* @param extent the extent
* @param biomes a list of biomes to match
*/
public BiomeMask2D(Extent extent, Collection<BaseBiome> biomes) {
checkNotNull(extent);
checkNotNull(biomes);
this.extent = extent;
this.biomes.addAll(biomes);
}
/**
* Create a new biome mask.
*
* @param extent the extent
* @param biome an array of biomes to match
*/
public BiomeMask2D(Extent extent, BaseBiome... biome) {
this(extent, Arrays.asList(checkNotNull(biome)));
}
/**
* Add the given biomes to the list of criteria.
*
* @param biomes a list of biomes
*/
public void add(Collection<BaseBiome> biomes) {
checkNotNull(biomes);
this.biomes.addAll(biomes);
}
/**
* Add the given biomes to the list of criteria.
*
* @param biome an array of biomes
*/
public void add(BaseBiome... biome) {
add(Arrays.asList(checkNotNull(biome)));
}
/**
* Get the list of biomes that are tested with.
*
* @return a list of biomes
*/
public Collection<BaseBiome> getBiomes() {
return biomes;
}
@Override
public boolean test(Vector2D vector) {
BaseBiome biome = extent.getBiome(vector);
return biomes.contains(biome);
}
}

View File

@ -23,6 +23,7 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import javax.annotation.Nullable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
@ -96,4 +97,11 @@ public class BlockMask extends AbstractExtentMask {
BaseBlock block = getExtent().getBlock(vector); BaseBlock block = getExtent().getBlock(vector);
return blocks.contains(block) || blocks.contains(new BaseBlock(block.getType(), -1)); return blocks.contains(block) || blocks.contains(new BaseBlock(block.getType(), -1));
} }
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
} }

View File

@ -21,6 +21,8 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
/** /**
@ -49,4 +51,10 @@ public class BoundedHeightMask extends AbstractMask {
return vector.getY() >= minY && vector.getY() <= maxY; return vector.getY() >= minY && vector.getY() <= maxY;
} }
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
} }

View File

@ -23,6 +23,8 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockID;
import javax.annotation.Nullable;
/** /**
* A mask that returns true whenever the block at the location is not * A mask that returns true whenever the block at the location is not
* an air block (it contains some other block). * an air block (it contains some other block).
@ -43,4 +45,10 @@ public class ExistingBlockMask extends AbstractExtentMask {
return getExtent().getLazyBlock(vector).getType() != BlockID.AIR; return getExtent().getLazyBlock(vector).getType() != BlockID.AIR;
} }
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
} }

View File

@ -21,6 +21,8 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import javax.annotation.Nullable;
/** /**
* Tests whether a given vector meets a criteria. * Tests whether a given vector meets a criteria.
*/ */
@ -34,4 +36,12 @@ public interface Mask {
*/ */
boolean test(Vector vector); boolean test(Vector vector);
/**
* Get the 2D version of this mask if one exists.
*
* @return a 2D mask version or {@code null} if this mask can't be 2D
*/
@Nullable
Mask2D toMask2D();
} }

View File

@ -21,9 +21,12 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -86,7 +89,7 @@ public class MaskIntersection extends AbstractMask {
@Override @Override
public boolean test(Vector vector) { public boolean test(Vector vector) {
if (masks.size() == 0) { if (masks.isEmpty()) {
return false; return false;
} }
@ -99,4 +102,19 @@ public class MaskIntersection extends AbstractMask {
return true; return true;
} }
@Nullable
@Override
public Mask2D toMask2D() {
List<Mask2D> mask2dList = new ArrayList<Mask2D>();
for (Mask mask : masks) {
Mask2D mask2d = mask.toMask2D();
if (mask2d != null) {
mask2dList.add(mask2d);
} else {
return null;
}
}
return new MaskIntersection2D(mask2dList);
}
} }

View File

@ -0,0 +1,100 @@
/*
* 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.function.mask;
import com.sk89q.worldedit.Vector2D;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Tests true if all contained masks test true.
*/
public class MaskIntersection2D implements Mask2D {
private final Set<Mask2D> masks = new HashSet<Mask2D>();
/**
* Create a new intersection.
*
* @param masks a list of masks
*/
public MaskIntersection2D(Collection<Mask2D> masks) {
checkNotNull(masks);
this.masks.addAll(masks);
}
/**
* Create a new intersection.
*
* @param mask a list of masks
*/
public MaskIntersection2D(Mask2D... mask) {
this(Arrays.asList(checkNotNull(mask)));
}
/**
* Add some masks to the list.
*
* @param masks the masks
*/
public void add(Collection<Mask2D> masks) {
checkNotNull(masks);
this.masks.addAll(masks);
}
/**
* Add some masks to the list.
*
* @param mask the masks
*/
public void add(Mask2D... mask) {
add(Arrays.asList(checkNotNull(mask)));
}
/**
* Get the masks that are tested with.
*
* @return the masks
*/
public Collection<Mask2D> getMasks() {
return masks;
}
@Override
public boolean test(Vector2D vector) {
if (masks.isEmpty()) {
return false;
}
for (Mask2D mask : masks) {
if (!mask.test(vector)) {
return false;
}
}
return true;
}
}

View File

@ -21,7 +21,10 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
/** /**
* Combines several masks and requires that one or more masks return true * Combines several masks and requires that one or more masks return true
@ -61,4 +64,18 @@ public class MaskUnion extends MaskIntersection {
return false; return false;
} }
@Nullable
@Override
public Mask2D toMask2D() {
List<Mask2D> mask2dList = new ArrayList<Mask2D>();
for (Mask mask : getMasks()) {
Mask2D mask2d = mask.toMask2D();
if (mask2d != null) {
mask2dList.add(mask2d);
} else {
return null;
}
}
return new MaskUnion2D(mask2dList);
}
} }

View File

@ -17,34 +17,46 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit.masks; package com.sk89q.worldedit.function.mask;
import java.util.HashSet;
import java.util.Set;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.Vector2D;
public class BiomeTypeMask extends AbstractMask { import java.util.Collection;
private final Set<BiomeType> biomes;
public BiomeTypeMask() { /**
this(new HashSet<BiomeType>()); * Tests true if any contained mask is true, even if it just one.
*/
public class MaskUnion2D extends MaskIntersection2D {
/**
* Create a new union.
*
* @param masks a list of masks
*/
public MaskUnion2D(Collection<Mask2D> masks) {
super(masks);
} }
public BiomeTypeMask(Set<BiomeType> biomes) { /**
this.biomes = biomes; * Create a new union.
} *
* @param mask a list of masks
public boolean matches2D(EditSession editSession, Vector2D pos) { */
BiomeType biome = editSession.getWorld().getBiome(pos); public MaskUnion2D(Mask2D... mask) {
return biomes.contains(biome); super(mask);
} }
@Override @Override
public boolean matches(EditSession editSession, Vector pos) { public boolean test(Vector2D vector) {
return matches2D(editSession, pos.toVector2D()); Collection<Mask2D> masks = getMasks();
for (Mask2D mask : masks) {
if (mask.test(vector)) {
return true;
} }
} }
return false;
}
}

View File

@ -22,6 +22,8 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.*;
import com.sk89q.worldedit.session.request.Request; import com.sk89q.worldedit.session.request.Request;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
/** /**
@ -29,6 +31,9 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/ */
public final class Masks { public final class Masks {
private static final AlwaysTrue ALWAYS_TRUE = new AlwaysTrue();
private static final AlwaysFalse ALWAYS_FALSE = new AlwaysFalse();
private Masks() { private Masks() {
} }
@ -38,12 +43,7 @@ public final class Masks {
* @return a mask * @return a mask
*/ */
public static Mask alwaysTrue() { public static Mask alwaysTrue() {
return new AbstractMask() { return ALWAYS_TRUE;
@Override
public boolean test(Vector vector) {
return true;
}
};
} }
/** /**
@ -52,12 +52,7 @@ public final class Masks {
* @return a mask * @return a mask
*/ */
public static Mask2D alwaysTrue2D() { public static Mask2D alwaysTrue2D() {
return new AbstractMask2D() { return ALWAYS_TRUE;
@Override
public boolean test(Vector2D vector) {
return true;
}
};
} }
/** /**
@ -67,12 +62,29 @@ public final class Masks {
* @return a new mask * @return a new mask
*/ */
public static Mask negate(final Mask mask) { public static Mask negate(final Mask mask) {
if (mask instanceof AlwaysTrue) {
return ALWAYS_FALSE;
} else if (mask instanceof AlwaysFalse) {
return ALWAYS_TRUE;
}
checkNotNull(mask); checkNotNull(mask);
return new AbstractMask() { return new AbstractMask() {
@Override @Override
public boolean test(Vector vector) { public boolean test(Vector vector) {
return !mask.test(vector); return !mask.test(vector);
} }
@Nullable
@Override
public Mask2D toMask2D() {
Mask2D mask2d = mask.toMask2D();
if (mask2d != null) {
return negate(mask2d);
} else {
return null;
}
}
}; };
} }
@ -83,6 +95,12 @@ public final class Masks {
* @return a new mask * @return a new mask
*/ */
public static Mask2D negate(final Mask2D mask) { public static Mask2D negate(final Mask2D mask) {
if (mask instanceof AlwaysTrue) {
return ALWAYS_FALSE;
} else if (mask instanceof AlwaysFalse) {
return ALWAYS_TRUE;
}
checkNotNull(mask); checkNotNull(mask);
return new AbstractMask2D() { return new AbstractMask2D() {
@Override @Override
@ -92,6 +110,27 @@ public final class Masks {
}; };
} }
/**
* Return a 3-dimensional version of a 2D mask.
*
* @param mask the mask to make 3D
* @return a 3D mask
*/
public static Mask asMask(final Mask2D mask) {
return new AbstractMask() {
@Override
public boolean test(Vector vector) {
return mask.test(vector.toVector2D());
}
@Nullable
@Override
public Mask2D toMask2D() {
return mask;
}
};
}
/** /**
* Wrap an old-style mask and convert it to a new mask. * Wrap an old-style mask and convert it to a new mask.
* </p> * </p>
@ -113,6 +152,12 @@ public final class Masks {
public boolean test(Vector vector) { public boolean test(Vector vector) {
return mask.matches(editSession, vector); return mask.matches(editSession, vector);
} }
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
}; };
} }
@ -135,6 +180,12 @@ public final class Masks {
EditSession editSession = Request.request().getEditSession(); EditSession editSession = Request.request().getEditSession();
return editSession != null && mask.matches(editSession, vector); return editSession != null && mask.matches(editSession, vector);
} }
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
}; };
} }
@ -156,4 +207,40 @@ public final class Masks {
}; };
} }
private static class AlwaysTrue implements Mask, Mask2D {
@Override
public boolean test(Vector vector) {
return true;
}
@Override
public boolean test(Vector2D vector) {
return true;
}
@Nullable
@Override
public Mask2D toMask2D() {
return this;
}
}
private static class AlwaysFalse implements Mask, Mask2D {
@Override
public boolean test(Vector vector) {
return false;
}
@Override
public boolean test(Vector2D vector) {
return false;
}
@Nullable
@Override
public Mask2D toMask2D() {
return this;
}
}
} }

View File

@ -22,6 +22,8 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.math.noise.NoiseGenerator; import com.sk89q.worldedit.math.noise.NoiseGenerator;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -89,4 +91,10 @@ public class NoiseFilter extends AbstractMask {
return noiseGenerator.noise(vector) <= density; return noiseGenerator.noise(vector) <= density;
} }
@Nullable
@Override
public Mask2D toMask2D() {
return new NoiseFilter2D(getNoiseGenerator(), getDensity());
}
} }

View File

@ -21,10 +21,13 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
/** /**
* Checks whether the provided mask tests true for an offset position. * Checks whether another mask tests true for a position that is offset
* a given vector.
*/ */
public class OffsetMask extends AbstractMask { public class OffsetMask extends AbstractMask {
@ -87,4 +90,15 @@ public class OffsetMask extends AbstractMask {
return getMask().test(vector.add(offset)); return getMask().test(vector.add(offset));
} }
@Nullable
@Override
public Mask2D toMask2D() {
Mask2D childMask = getMask().toMask2D();
if (childMask != null) {
return new OffsetMask2D(childMask, getOffset().toVector2D());
} else {
return null;
}
}
} }

View File

@ -0,0 +1,91 @@
/*
* 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.function.mask;
import com.sk89q.worldedit.Vector2D;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Checks whether another mask tests true for a position that is offset
* a given vector.
*/
public class OffsetMask2D extends AbstractMask2D {
private Mask2D mask;
private Vector2D offset;
/**
* Create a new instance.
*
* @param mask the mask
* @param offset the offset
*/
public OffsetMask2D(Mask2D mask, Vector2D offset) {
checkNotNull(mask);
checkNotNull(offset);
this.mask = mask;
this.offset = offset;
}
/**
* Get the mask.
*
* @return the mask
*/
public Mask2D getMask() {
return mask;
}
/**
* Set the mask.
*
* @param mask the mask
*/
public void setMask(Mask2D mask) {
checkNotNull(mask);
this.mask = mask;
}
/**
* Get the offset.
*
* @return the offset
*/
public Vector2D getOffset() {
return offset;
}
/**
* Set the offset.
*
* @param offset the offset
*/
public void setOffset(Vector2D offset) {
checkNotNull(offset);
this.offset = offset;
}
@Override
public boolean test(Vector2D vector) {
return getMask().test(vector.add(offset));
}
}

View File

@ -22,6 +22,8 @@ package com.sk89q.worldedit.function.mask;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
/** /**
@ -64,4 +66,10 @@ public class RegionMask extends AbstractMask {
return region.contains(vector); return region.contains(vector);
} }
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
} }

View File

@ -24,6 +24,8 @@ import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BlockType; import com.sk89q.worldedit.blocks.BlockType;
import javax.annotation.Nullable;
public class SolidBlockMask extends AbstractExtentMask { public class SolidBlockMask extends AbstractExtentMask {
public SolidBlockMask(Extent extent) { public SolidBlockMask(Extent extent) {
@ -37,4 +39,10 @@ public class SolidBlockMask extends AbstractExtentMask {
return !BlockType.canPassThrough(lazyBlock.getType(), lazyBlock.getData()); return !BlockType.canPassThrough(lazyBlock.getType(), lazyBlock.getData());
} }
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
} }

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.internal; package com.sk89q.worldedit.internal;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.LocalWorld; import com.sk89q.worldedit.LocalWorld;
@ -37,6 +36,7 @@ import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.WorldData; import com.sk89q.worldedit.world.registry.WorldData;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -109,13 +109,13 @@ public class LocalWorldAdapter extends LocalWorld {
} }
@Override @Override
public BiomeType getBiome(Vector2D position) { public BaseBiome getBiome(Vector2D position) {
return world.getBiome(position); return world.getBiome(position);
} }
@Override @Override
public void setBiome(Vector2D position, BiomeType biome) { public boolean setBiome(Vector2D position, BaseBiome biome) {
world.setBiome(position, biome); return world.setBiome(position, biome);
} }
@Override @Override

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.internal; package com.sk89q.worldedit.internal;
import com.sk89q.worldedit.BiomeTypes;
import com.sk89q.worldedit.LocalConfiguration; import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.ServerInterface; import com.sk89q.worldedit.ServerInterface;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
@ -67,11 +66,6 @@ public class ServerInterfaceAdapter extends ServerInterface {
platform.reload(); platform.reload();
} }
@Override
public BiomeTypes getBiomes() {
return platform.getBiomes();
}
@Override @Override
public int schedule(long delay, long period, Runnable task) { public int schedule(long delay, long period, Runnable task) {
return platform.schedule(delay, period, task); return platform.schedule(delay, period, task);

View File

@ -19,7 +19,6 @@
package com.sk89q.worldedit.internal.command; package com.sk89q.worldedit.internal.command;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
@ -47,8 +46,12 @@ import com.sk89q.worldedit.util.command.parametric.BindingHelper;
import com.sk89q.worldedit.util.command.parametric.BindingMatch; import com.sk89q.worldedit.util.command.parametric.BindingMatch;
import com.sk89q.worldedit.util.command.parametric.ParameterException; import com.sk89q.worldedit.util.command.parametric.ParameterException;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.Biomes;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
/** /**
* Binds standard WorldEdit classes such as {@link Player} and {@link LocalSession}. * Binds standard WorldEdit classes such as {@link Player} and {@link LocalSession}.
@ -288,25 +291,40 @@ public class WorldEditBinding extends BindingHelper {
} }
/** /**
* Gets an {@link BiomeType} from a {@link ArgumentStack}. * Gets an {@link BaseBiome} from a {@link ArgumentStack}.
* *
* @param context the context * @param context the context
* @return a pattern * @return a pattern
* @throws ParameterException on error * @throws ParameterException on error
* @throws WorldEditException on error * @throws WorldEditException on error
*/ */
@BindingMatch(type = BiomeType.class, @BindingMatch(type = BaseBiome.class,
behavior = BindingBehavior.CONSUMES, behavior = BindingBehavior.CONSUMES,
consumedCount = 1) consumedCount = 1)
public BiomeType getBiomeType(ArgumentStack context) throws ParameterException, WorldEditException { public BaseBiome getBiomeType(ArgumentStack context) throws ParameterException, WorldEditException {
String input = context.next(); String input = context.next();
if (input != null) { if (input != null) {
BiomeType type = worldEdit.getServer().getBiomes().get(input); Actor actor = context.getContext().getLocals().get(Actor.class);
if (type != null) { World world;
return type; if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) {
world = (World) extent;
} else {
throw new ParameterException("A world is required.");
}
} else {
throw new ParameterException("An entity is required.");
}
BiomeRegistry biomeRegistry = world.getWorldData().getBiomeRegistry();
List<BaseBiome> knownBiomes = biomeRegistry.getBiomes();
BaseBiome biome = Biomes.findBiomeByName(knownBiomes, input, biomeRegistry);
if (biome != null) {
return biome;
} else { } else {
throw new ParameterException( throw new ParameterException(
String.format("Can't recognize biome type '%s' -- use //biomelist to list available types", input)); String.format("Can't recognize biome type '%s' -- use /biomelist to list available types", input));
} }
} else { } else {
throw new ParameterException( throw new ParameterException(

View File

@ -19,12 +19,12 @@
package com.sk89q.worldedit.regions.shape; package com.sk89q.worldedit.regions.shape;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector2D; import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.FlatRegion; import com.sk89q.worldedit.regions.FlatRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.biome.BaseBiome;
/** /**
* Generates solid and hollow shapes according to materials returned by the * Generates solid and hollow shapes according to materials returned by the
@ -58,7 +58,7 @@ public abstract class ArbitraryBiomeShape {
cacheSizeX = (int) (max.getX() - cacheOffsetX + 2); cacheSizeX = (int) (max.getX() - cacheOffsetX + 2);
cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2); cacheSizeZ = (int) (max.getZ() - cacheOffsetZ + 2);
cache = new BiomeType[cacheSizeX * cacheSizeZ]; cache = new BaseBiome[cacheSizeX * cacheSizeZ];
} }
protected Iterable<Vector2D> getExtent() { protected Iterable<Vector2D> getExtent() {
@ -72,24 +72,24 @@ public abstract class ArbitraryBiomeShape {
* OUTSIDE = outside * OUTSIDE = outside
* else = inside * else = inside
*/ */
private final BiomeType[] cache; private final BaseBiome[] cache;
/** /**
* Override this function to specify the shape to generate. * Override this function to specify the shape to generate.
* *
* @param x X coordinate to be queried * @param x X coordinate to be queried
* @param z Z coordinate to be queried * @param z Z coordinate to be queried
* @param defaultBiomeType The default biome for the current column. * @param defaultBaseBiome The default biome for the current column.
* @return material to place or null to not place anything. * @return material to place or null to not place anything.
*/ */
protected abstract BiomeType getBiome(int x, int z, BiomeType defaultBiomeType); protected abstract BaseBiome getBiome(int x, int z, BaseBiome defaultBaseBiome);
private BiomeType getBiomeCached(int x, int z, BiomeType biomeType) { private BaseBiome getBiomeCached(int x, int z, BaseBiome BaseBiome) {
final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ;
final BiomeType cacheEntry = cache[index]; final BaseBiome cacheEntry = cache[index];
if (cacheEntry == null) {// unknown, fetch material if (cacheEntry == null) {// unknown, fetch material
final BiomeType material = getBiome(x, z, biomeType); final BaseBiome material = getBiome(x, z, BaseBiome);
if (material == null) { if (material == null) {
// outside // outside
cache[index] = OUTSIDE; cache[index] = OUTSIDE;
@ -108,13 +108,13 @@ public abstract class ArbitraryBiomeShape {
return cacheEntry; return cacheEntry;
} }
private boolean isInsideCached(int x, int z, BiomeType biomeType) { private boolean isInsideCached(int x, int z, BaseBiome BaseBiome) {
final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ; final int index = (z - cacheOffsetZ) + (x - cacheOffsetX) * cacheSizeZ;
final BiomeType cacheEntry = cache[index]; final BaseBiome cacheEntry = cache[index];
if (cacheEntry == null) { if (cacheEntry == null) {
// unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape // unknown block, meaning they must be outside the extent at this stage, but might still be inside the shape
return getBiomeCached(x, z, biomeType) != null; return getBiomeCached(x, z, BaseBiome) != null;
} }
return cacheEntry != OUTSIDE; return cacheEntry != OUTSIDE;
@ -124,11 +124,11 @@ public abstract class ArbitraryBiomeShape {
* Generates the shape. * Generates the shape.
* *
* @param editSession The EditSession to use. * @param editSession The EditSession to use.
* @param biomeType The default biome type. * @param BaseBiome The default biome type.
* @param hollow Specifies whether to generate a hollow shape. * @param hollow Specifies whether to generate a hollow shape.
* @return number of affected blocks. * @return number of affected blocks.
*/ */
public int generate(EditSession editSession, BiomeType biomeType, boolean hollow) { public int generate(EditSession editSession, BaseBiome BaseBiome, boolean hollow) {
int affected = 0; int affected = 0;
for (Vector2D position : getExtent()) { for (Vector2D position : getExtent()) {
@ -136,7 +136,7 @@ public abstract class ArbitraryBiomeShape {
int z = position.getBlockZ(); int z = position.getBlockZ();
if (!hollow) { if (!hollow) {
final BiomeType material = getBiome(x, z, biomeType); final BaseBiome material = getBiome(x, z, BaseBiome);
if (material != OUTSIDE) { if (material != OUTSIDE) {
editSession.getWorld().setBiome(position, material); editSession.getWorld().setBiome(position, material);
++affected; ++affected;
@ -145,26 +145,26 @@ public abstract class ArbitraryBiomeShape {
continue; continue;
} }
final BiomeType material = getBiomeCached(x, z, biomeType); final BaseBiome material = getBiomeCached(x, z, BaseBiome);
if (material == null) { if (material == null) {
continue; continue;
} }
boolean draw = false; boolean draw = false;
do { do {
if (!isInsideCached(x + 1, z, biomeType)) { if (!isInsideCached(x + 1, z, BaseBiome)) {
draw = true; draw = true;
break; break;
} }
if (!isInsideCached(x - 1, z, biomeType)) { if (!isInsideCached(x - 1, z, BaseBiome)) {
draw = true; draw = true;
break; break;
} }
if (!isInsideCached(x, z + 1, biomeType)) { if (!isInsideCached(x, z + 1, BaseBiome)) {
draw = true; draw = true;
break; break;
} }
if (!isInsideCached(x, z - 1, biomeType)) { if (!isInsideCached(x, z - 1, BaseBiome)) {
draw = true; draw = true;
break; break;
} }
@ -181,9 +181,15 @@ public abstract class ArbitraryBiomeShape {
return affected; return affected;
} }
private static final BiomeType OUTSIDE = new BiomeType() { private static final BaseBiome OUTSIDE = new BaseBiome(0) {
public String getName() { @Override
throw new UnsupportedOperationException(); public int hashCode() {
return 0;
}
@Override
public boolean equals(Object o) {
return this == o;
} }
}; };
} }

View File

@ -0,0 +1,118 @@
/*
* 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.util;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Returns the best choice given a weighting function and a target weight.
*
* <p>A function must be supplied that returns a numeric score for each
* choice. The function can return null to mean that the choice should
* not be considered.</p>
*
* @param <T> the type of choice
*/
public class WeightedChoice<T> {
private final Function<T, ? extends Number> function;
private double target;
private double best;
private T current;
/**
* Create a new instance.
*
* @param function a function that assigns a score for each choice
* @param target the target score that the best choice should be closest to
*/
public WeightedChoice(Function<T, ? extends Number> function, double target) {
checkNotNull(function);
this.function = function;
this.target = target;
}
/**
* Consider the given object.
*
* @param object the choice
*/
public void consider(T object) {
checkNotNull(object);
Number value = checkNotNull(function.apply(object));
if (value != null) {
double distance = Math.abs(target - value.doubleValue());
if (current == null || distance <= best) {
best = distance;
current = object;
}
}
}
/**
* Get the best choice.
*
* @return the best choice
*/
public Optional<Choice<T>> getChoice() {
if (current != null) {
return Optional.of(new Choice<T>(current, best));
} else {
return Optional.absent();
}
}
/**
* A tuple of choice and score.
*
* @param <T> the choice type
*/
public static class Choice<T> {
private final T object;
private final double value;
private Choice(T object, double value) {
this.object = object;
this.value = value;
}
/**
* Get the chosen value.
*
* @return the value
*/
public T getValue() {
return object;
}
/**
* Get the score.
*
* @return the score
*/
public double getScore() {
return value;
}
}
}

View File

@ -0,0 +1,192 @@
/*
* 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.util.function;
import com.google.common.base.Function;
import javax.annotation.Nullable;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Provides a Levenshtein distance between a given string and each string
* that this function is applied to.
*/
public class LevenshteinDistance implements Function<String, Integer> {
public final static Pattern STANDARD_CHARS = Pattern.compile("[ _\\-]");
private final String baseString;
private final boolean caseSensitive;
private final Pattern replacePattern;
/**
* Create a new instance.
*
* @param baseString the string to compare to
* @param caseSensitive true to make case sensitive comparisons
*/
public LevenshteinDistance(String baseString, boolean caseSensitive) {
this(baseString, caseSensitive, null);
}
/**
* Create a new instance.
*
* @param baseString the string to compare to
* @param caseSensitive true to make case sensitive comparisons
* @param replacePattern pattern to match characters to be removed in both the input and test strings (may be null)
*/
public LevenshteinDistance(String baseString, boolean caseSensitive, @Nullable Pattern replacePattern) {
checkNotNull(baseString);
this.caseSensitive = caseSensitive;
this.replacePattern = replacePattern;
baseString = caseSensitive ? baseString : baseString.toLowerCase();
baseString = replacePattern != null ? replacePattern.matcher(baseString).replaceAll("") : baseString;
this.baseString = baseString;
}
@Nullable
@Override
public Integer apply(String input) {
if (input == null) {
return null;
}
if (replacePattern != null) {
input = replacePattern.matcher(input).replaceAll("");
}
if (caseSensitive) {
return distance(baseString, input);
} else {
return distance(baseString, input.toLowerCase());
}
}
/**
* <p>Find the Levenshtein distance between two Strings.</p>
*
* <p>This is the number of changes needed to change one String into
* another, where each change is a single character modification (deletion,
* insertion or substitution).</p>
*
* <p>The previous implementation of the Levenshtein distance algorithm
* was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
*
* <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
* which can occur when my Java implementation is used with very large strings.<br>
* This implementation of the Levenshtein distance algorithm
* is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
*
* <pre>
* distance(null, *) = IllegalArgumentException
* distance(*, null) = IllegalArgumentException
* distance("","") = 0
* distance("","a") = 1
* distance("aaapppp", "") = 7
* distance("frog", "fog") = 1
* distance("fly", "ant") = 3
* distance("elephant", "hippo") = 7
* distance("hippo", "elephant") = 7
* distance("hippo", "zzzzzzzz") = 8
* distance("hello", "hallo") = 1
* </pre>
*
* @param s the first String, must not be null
* @param t the second String, must not be null
* @return result distance
* @throws IllegalArgumentException if either String input <code>null</code>
*/
public static int distance(String s, String t) {
if (s == null || t == null) {
throw new IllegalArgumentException("Strings must not be null");
}
/*
* The difference between this impl. and the previous is that, rather
* than creating and retaining a matrix of size s.length()+1 by
* t.length()+1, we maintain two single-dimensional arrays of length
* s.length()+1. The first, d, is the 'current working' distance array
* that maintains the newest distance cost counts as we iterate through
* the characters of String s. Each time we increment the index of
* String t we are comparing, d is copied to p, the second int[]. Doing
* so allows us to retain the previous cost counts as required by the
* algorithm (taking the minimum of the cost count to the left, up one,
* and diagonally up and to the left of the current cost count being
* calculated). (Note that the arrays aren't really copied anymore, just
* switched...this is clearly much better than cloning an array or doing
* a System.arraycopy() each time through the outer loop.)
*
* Effectively, the difference between the two implementations is this
* one does not cause an out of memory condition when calculating the LD
* over two very large strings.
*/
int n = s.length(); // length of s
int m = t.length(); // length of t
if (n == 0) {
return m;
} else if (m == 0) {
return n;
}
int p[] = new int[n + 1]; // 'previous' cost array, horizontally
int d[] = new int[n + 1]; // cost array, horizontally
int _d[]; // placeholder to assist in swapping p and d
// indexes into strings s and t
int i; // iterates through s
int j; // iterates through t
char tj; // jth character of t
int cost; // cost
for (i = 0; i <= n; ++i) {
p[i] = i;
}
for (j = 1; j <= m; ++j) {
tj = t.charAt(j - 1);
d[0] = j;
for (i = 1; i <= n; ++i) {
cost = s.charAt(i - 1) == tj ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left
// and up +cost
d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1]
+ cost);
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
// our last action in the above loop was to switch d and p, so p now
// actually has the most recent cost counts
return p[n];
}
}

View File

@ -19,7 +19,11 @@
package com.sk89q.worldedit.world; package com.sk89q.worldedit.world;
import com.sk89q.worldedit.*; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.blocks.BlockID; import com.sk89q.worldedit.blocks.BlockID;
@ -28,6 +32,7 @@ import com.sk89q.worldedit.entity.Entity;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.Location;
import com.sk89q.worldedit.util.TreeGenerator.TreeType; import com.sk89q.worldedit.util.TreeGenerator.TreeType;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.registry.LegacyWorldData; import com.sk89q.worldedit.world.registry.LegacyWorldData;
import com.sk89q.worldedit.world.registry.WorldData; import com.sk89q.worldedit.world.registry.WorldData;
@ -62,12 +67,13 @@ public class NullWorld extends AbstractWorld {
} }
@Override @Override
public BiomeType getBiome(Vector2D position) { public BaseBiome getBiome(Vector2D position) {
return null; return null;
} }
@Override @Override
public void setBiome(Vector2D position, BiomeType biome) { public boolean setBiome(Vector2D position, BaseBiome biome) {
return false;
} }
@Override @Override

View File

@ -19,12 +19,10 @@
package com.sk89q.worldedit.world; package com.sk89q.worldedit.world;
import com.sk89q.worldedit.BiomeType;
import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.BlockVector2D;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.Vector2D;
import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.blocks.BaseItemStack;
@ -147,22 +145,6 @@ public interface World extends Extent {
*/ */
boolean clearContainerBlockContents(Vector position); boolean clearContainerBlockContents(Vector position);
/**
* Get the biome type.
*
* @param position the (x, z) location to check the biome at
* @return the biome type at the location
*/
BiomeType getBiome(Vector2D position);
/**
* Set the biome type.
*
* @param position the (x, z) location to set the biome at
* @param biome the biome type to set to
*/
void setBiome(Vector2D position, BiomeType biome);
/** /**
* Drop an item at the given position. * Drop an item at the given position.
* *

View File

@ -0,0 +1,82 @@
/*
* 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.world.biome;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Basic storage object to represent a given biome.
*/
public class BaseBiome {
private int id;
/**
* Create a new biome with the given biome ID.
*
* @param id the biome ID
*/
public BaseBiome(int id) {
this.id = id;
}
/**
* Create a clone of the given biome.
*
* @param biome the biome to clone
*/
public BaseBiome(BaseBiome biome) {
checkNotNull(biome);
this.id = biome.getId();
}
/**
* Get the biome ID.
*
* @return the biome ID
*/
public int getId() {
return id;
}
/**
* Set the biome id.
*
* @param id the biome ID
*/
public void setId(int id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseBiome baseBiome = (BaseBiome) o;
return id == baseBiome.id;
}
@Override
public int hashCode() {
return id;
}
}

View File

@ -17,20 +17,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit; package com.sk89q.worldedit.world.biome;
public interface BiomeType {
public static final BiomeType UNKNOWN = new BiomeType() {
public String getName() {
return "Unknown";
}
};
/** /**
* Get the name of this biome type. * Provides information about a biome.
*
* @return String
*/ */
public String getName(); public interface BiomeData {
/**
* Get the name of the biome, which does not have to follow any
* particular convention.
*
* @return the biome's name
*/
String getName();
} }

View File

@ -0,0 +1,57 @@
/*
* 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.world.biome;
import com.google.common.base.Function;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Returns the name of a biome using a given {@code BiomeRegistry}.
*/
class BiomeName implements Function<BaseBiome, String> {
private final BiomeRegistry registry;
/**
* Create a new instance.
*
* @param registry the biome registry
*/
BiomeName(BiomeRegistry registry) {
checkNotNull(registry);
this.registry = registry;
}
@Nullable
@Override
public String apply(BaseBiome input) {
BiomeData data = registry.getData(input);
if (data != null) {
return data.getName();
} else {
return null;
}
}
}

View File

@ -0,0 +1,70 @@
/*
* 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.world.biome;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Optional;
import com.sk89q.worldedit.util.WeightedChoice;
import com.sk89q.worldedit.util.WeightedChoice.Choice;
import com.sk89q.worldedit.util.function.LevenshteinDistance;
import com.sk89q.worldedit.world.registry.BiomeRegistry;
import javax.annotation.Nullable;
import java.util.Collection;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Utility methods related to biomes.
*/
public final class Biomes {
private Biomes() {
}
/**
* Find a biome that matches the given input name.
*
* @param biomes a list of biomes
* @param name the name to test
* @param registry a biome registry
* @return a biome or null
*/
@Nullable
public static BaseBiome findBiomeByName(Collection<BaseBiome> biomes, String name, BiomeRegistry registry) {
checkNotNull(biomes);
checkNotNull(name);
checkNotNull(registry);
Function<String, ? extends Number> compare = new LevenshteinDistance(name, false, LevenshteinDistance.STANDARD_CHARS);
WeightedChoice<BaseBiome> chooser = new WeightedChoice<BaseBiome>(Functions.compose(compare, new BiomeName(registry)), 0);
for (BaseBiome biome : biomes) {
chooser.consider(biome);
}
Optional<Choice<BaseBiome>> choice = chooser.getChoice();
if (choice.isPresent() && choice.get().getScore() <= 1) {
return choice.get().getValue();
} else {
return null;
}
}
}

View File

@ -17,31 +17,42 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.sk89q.worldedit; package com.sk89q.worldedit.world.registry;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.BiomeData;
import javax.annotation.Nullable;
import java.util.List; import java.util.List;
public interface BiomeTypes { /**
* Provides information on biomes.
*/
public interface BiomeRegistry {
/** /**
* Returns if a biome with the given name is available. * Create a new biome given its biome ID.
* *
* @param name * @param id its biome ID
* @return * @return a new biome or null if it can't be created
*/ */
boolean has(String name); @Nullable
BaseBiome createFromId(int id);
/** /**
* Returns the biome type for the given name * Get a list of available biomes.
* *
* @return * @return a list of biomes
*/ */
BiomeType get(String name) throws UnknownBiomeTypeException; List<BaseBiome> getBiomes();
/** /**
* Returns a list of all available biome types. * Get data about a biome.
* *
* @return * @param biome the biome
* @return a data object or null if information is not known
*/ */
List<BiomeType> all(); @Nullable
BiomeData getData(BaseBiome biome);
} }

View File

@ -23,16 +23,17 @@ package com.sk89q.worldedit.world.registry;
* An implementation of {@link WorldData} that uses legacy numeric IDs and * An implementation of {@link WorldData} that uses legacy numeric IDs and
* a built-in block database. * a built-in block database.
*/ */
public final class LegacyWorldData implements WorldData { public class LegacyWorldData implements WorldData {
private static final LegacyWorldData INSTANCE = new LegacyWorldData(); private static final LegacyWorldData INSTANCE = new LegacyWorldData();
private final LegacyBlockRegistry blockRegistry = new LegacyBlockRegistry(); private final LegacyBlockRegistry blockRegistry = new LegacyBlockRegistry();
private final NullEntityRegistry entityRegistry = new NullEntityRegistry(); private final NullEntityRegistry entityRegistry = new NullEntityRegistry();
private final NullBiomeRegistry biomeRegistry = new NullBiomeRegistry();
/** /**
* Create a new instance. * Create a new instance.
*/ */
private LegacyWorldData() { protected LegacyWorldData() {
} }
@Override @Override
@ -45,6 +46,11 @@ public final class LegacyWorldData implements WorldData {
return entityRegistry; return entityRegistry;
} }
@Override
public BiomeRegistry getBiomeRegistry() {
return biomeRegistry;
}
/** /**
* Get a singleton instance. * Get a singleton instance.
* *

View File

@ -0,0 +1,57 @@
/*
* 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.world.registry;
import com.sk89q.worldedit.world.biome.BaseBiome;
import com.sk89q.worldedit.world.biome.BiomeData;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
/**
* A biome registry that knows nothing.
*/
public class NullBiomeRegistry implements BiomeRegistry {
/**
* Create a new instance.
*/
public NullBiomeRegistry() {
}
@Nullable
@Override
public BaseBiome createFromId(int id) {
return null;
}
@Override
public List<BaseBiome> getBiomes() {
return Collections.emptyList();
}
@Nullable
@Override
public BiomeData getData(BaseBiome biome) {
return null;
}
}

View File

@ -39,4 +39,11 @@ public interface WorldData {
*/ */
EntityRegistry getEntityRegistry(); EntityRegistry getEntityRegistry();
/**
* Get the biome registry.
*
* @return the biome registry
*/
BiomeRegistry getBiomeRegistry();
} }