More work on compile errors, New system for ToolClasses, using a ToolType class instead to de-stringify things.

This commit is contained in:
LexManos 2018-09-20 23:50:50 -07:00
parent 0cd21ebe7e
commit cdfa7caaeb
33 changed files with 1668 additions and 519 deletions

View File

@ -10,6 +10,9 @@ buildscript {
}
}
plugins {
id 'net.minecrell.licenser' version '0.4'
}
apply plugin: 'eclipse'
group = 'net.minecraftforge'
@ -52,6 +55,7 @@ project(':forge') {
apply plugin: 'java-library'
apply plugin: 'eclipse'
apply plugin: 'net.minecraftforge.gradle.forgedev.patcher'
apply plugin: 'net.minecrell.licenser'
sourceSets {
main {
java {
@ -161,6 +165,26 @@ project(':forge') {
environment target:'fmldevserver'
workingDir 'runserver'
}
license {
header = file("$rootDir/LICENSE-header.txt")
include 'net/minecraftforge/'
exclude 'net/minecraftforge/server/terminalconsole/'
exclude 'net/minecraftforge/fml/common/versioning/ComparableVersion.java'
exclude 'net/minecraftforge/fml/common/versioning/InvalidVersionSpecificationException.java'
exclude 'net/minecraftforge/fml/common/versioning/Restriction.java'
exclude 'net/minecraftforge/fml/common/versioning/VersionRange.java'
tasks {
main {
files = files("$rootDir/src/main/java")
}
test {
files = files("$rootDir/src/test/java")
}
}
}
}
//evaluationDependsOnChildren()

View File

@ -9,66 +9,79 @@
protected static final Logger field_196273_d = LogManager.getLogger();
private static final ResourceLocation AIR_ID = new ResourceLocation("air");
public static final RegistryNamespacedDefaultedByKey<ResourceLocation, Block> REGISTRY = new RegistryNamespacedDefaultedByKey<ResourceLocation, Block>(AIR_ID);
@@ -1604,4 +1604,62 @@
@@ -502,8 +502,8 @@
if (f == -1.0F) {
return 0.0F;
} else {
- int i = player.canHarvestBlock(state) ? 30 : 100;
- return player.getDigSpeed(state) / f / (float)i;
+ int i = net.minecraftforge.common.ForgeHooks.canHarvestBlock(state, player, worldIn, pos) ? 30 : 100;
+ return player.getDigSpeed(state, pos) / f / (float)i;
}
}
@@ -625,6 +625,7 @@
}
+ @Deprecated //Use state sensitive version
protected boolean canSilkHarvest() {
return this.getDefaultState().isFullCube() && !this.hasTileEntity();
}
@@ -1604,4 +1605,56 @@
return Objects.hash(this.field_212164_a, this.field_212165_b, this.field_212166_c);
}
}
+ /* ======================================== FORGE START =====================================*/
+
+ private ThreadLocal<IBlockState> silkCheck = new ThreadLocal<>();
+ private String[] harvestTool = new String[16];
+ private int[] harvestLevel = new int[]{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
+ private net.minecraftforge.common.ToolType harvestTool;
+ private int harvestLevel;
+ protected static ThreadLocal<Boolean> captureDrops = ThreadLocal.withInitial(() -> false);
+ protected static ThreadLocal<NonNullList<ItemStack>> capturedDrops = ThreadLocal.withInitial(NonNullList::create);
+ protected NonNullList<ItemStack> captureDrops(boolean start)
+ {
+ if (start)
+ {
+ if (start) {
+ captureDrops.set(true);
+ capturedDrops.get().clear();
+ return NonNullList.create();
+ }
+ else
+ {
+ } else {
+ captureDrops.set(false);
+ return capturedDrops.get();
+ }
+ }
+
+ @Override
+ public float getSlipperiness(IBlockState state, IWorldReader world, BlockPos pos, @Nullable Entity entity)
+ {
+ public float getSlipperiness(IBlockState state, IWorldReader world, BlockPos pos, @Nullable Entity entity) {
+ return this.slipperiness;
+ }
+
+ @Override
+ public boolean canSilkHarvest(IWorldReader world, BlockPos pos, IBlockState state, EntityPlayer player)
+ {
+ silkCheck.set(state);
+ boolean ret = this.canSilkHarvest();
+ return ret;
+ public boolean canSilkHarvest(IBlockState state, IWorldReader world, BlockPos pos, EntityPlayer player) {
+ return this.canSilkHarvest() && !state.hasTileEntity();
+ }
+
+ @Override
+ public void onBlockExploded(World world, BlockPos pos, Explosion explosion)
+ {
+ public void onBlockExploded(IBlockState state, World world, BlockPos pos, Explosion explosion) {
+ world.setBlockToAir(pos);
+ onExplosionDestroy(world, pos, explosion);
+ }
+
+ @Nullable
+ @Override
+ public String getHarvestTool(IBlockState state)
+ {
+ return harvestTool[0]; //TODO: RE-Evaluate
+ public net.minecraftforge.common.ToolType getHarvestTool(IBlockState state) {
+ return harvestTool; //TODO: RE-Evaluate
+ }
+
+ @Override
+ public int getHarvestLevel(IBlockState state)
+ {
+
+ return harvestLevel[0]; //TODO: RE-Evaluate
+ public int getHarvestLevel(IBlockState state) {
+ return harvestLevel; //TODO: RE-Evaluate
+ }
+
+ static {
+ net.minecraftforge.common.ForgeHooks.setBlockToolSetter((block, tool, level) -> {
+ block.harvestTool = tool;
+ block.harvestLevel = level;
+ });
+ }
+ /* ========================================= FORGE END ======================================*/
}

View File

@ -0,0 +1,11 @@
--- a/net/minecraft/block/state/IBlockState.java
+++ b/net/minecraft/block/state/IBlockState.java
@@ -30,7 +30,7 @@
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
-public interface IBlockState extends IStateHolder<IBlockState> {
+public interface IBlockState extends IStateHolder<IBlockState>, net.minecraftforge.common.extensions.IForgeBlockState {
ThreadLocal<Object2ByteMap<IBlockState>> field_208776_a = ThreadLocal.<Object2ByteMap<IBlockState>>withInitial(() -> {
Object2ByteOpenHashMap<IBlockState> object2byteopenhashmap = new Object2ByteOpenHashMap<IBlockState>();
object2byteopenhashmap.defaultReturnValue((byte)127);

View File

@ -0,0 +1,21 @@
--- a/net/minecraft/client/gui/GuiBossOverlay.java
+++ b/net/minecraft/client/gui/GuiBossOverlay.java
@@ -28,12 +28,17 @@
for(BossInfoClient bossinfoclient : this.mapBossInfos.values()) {
int k = i / 2 - 91;
+ net.minecraftforge.client.event.RenderGameOverlayEvent.BossInfo event =
+ net.minecraftforge.client.ForgeHooksClient.bossBarRenderPre(this.client.field_195558_d, bossinfoclient, k, j, 10 + this.client.fontRenderer.FONT_HEIGHT);
+ if (!event.isCanceled()) {
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
this.client.getTextureManager().bindTexture(GUI_BARS_TEXTURES);
this.render(k, j, bossinfoclient);
String s = bossinfoclient.getName().getFormattedText();
this.client.fontRenderer.drawStringWithShadow(s, (float)(i / 2 - this.client.fontRenderer.getStringWidth(s) / 2), (float)(j - 9), 16777215);
- j += 10 + this.client.fontRenderer.FONT_HEIGHT;
+ }
+ j += event.getIncrement();
+ net.minecraftforge.client.ForgeHooksClient.bossBarRenderPost(this.client.field_195558_d);
if (j >= this.client.field_195558_d.func_198087_p() / 3) {
break;
}

View File

@ -9,3 +9,24 @@
private static final DataParameter<Float> ABSORPTION = EntityDataManager.<Float>createKey(EntityPlayer.class, DataSerializers.FLOAT);
private static final DataParameter<Integer> PLAYER_SCORE = EntityDataManager.<Integer>createKey(EntityPlayer.class, DataSerializers.VARINT);
protected static final DataParameter<Byte> PLAYER_MODEL_FLAG = EntityDataManager.<Byte>createKey(EntityPlayer.class, DataSerializers.BYTE);
@@ -663,7 +665,12 @@
return p_184816_1_.getItem();
}
+ @Deprecated //Use location sensitive version below
public float getDigSpeed(IBlockState state) {
+ return getDigSpeed(state, null);
+ }
+
+ public float getDigSpeed(IBlockState state, @Nullable BlockPos pos) {
float f = this.inventory.getDestroySpeed(state);
if (f > 1.0F) {
int i = EnchantmentHelper.getEfficiencyModifier(this);
@@ -705,6 +712,7 @@
f /= 5.0F;
}
+ f = net.minecraftforge.event.ForgeEventFactory.getBreakSpeed(this, state, f, pos);
return f;
}

View File

@ -73,7 +73,7 @@
ItemGroup itemgroup = this.getCreativeTab();
return itemgroup != null && (targetTab == ItemGroup.SEARCH || targetTab == itemgroup);
}
@@ -310,10 +318,49 @@
@@ -310,10 +318,48 @@
return false;
}
@ -87,7 +87,7 @@
+ @Nullable
+ private final java.util.function.Supplier<net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer> teisr;
+
+ private final java.util.Map<String, Integer> toolClasses = new java.util.HashMap<String, Integer>();
+ private final java.util.Map<net.minecraftforge.common.ToolType, Integer> toolClasses = Maps.newHashMap();
+
+ protected final boolean canRepair;
+
@ -98,16 +98,15 @@
+ }
+
+ @Override
+ public java.util.Set<String> getToolClasses(ItemStack stack)
+ public java.util.Set<net.minecraftforge.common.ToolType> getToolTypes(ItemStack stack)
+ {
+ return toolClasses.keySet();
+ }
+
+ @Override
+ public int getHarvestLevel(ItemStack stack, String toolClass, @Nullable EntityPlayer player, @Nullable IBlockState blockState)
+ public int getHarvestLevel(ItemStack stack, net.minecraftforge.common.ToolType tool, @Nullable EntityPlayer player, @Nullable IBlockState blockState)
+ {
+ Integer ret = toolClasses.get(toolClass);
+ return ret == null ? -1 : ret;
+ return toolClasses.getOrDefault(tool, -1);
+ }
+
+ @OnlyIn(Dist.CLIENT)
@ -123,24 +122,34 @@
public static void registerItems() {
registerItemBlock(Blocks.AIR, new ItemAir(Blocks.AIR, new Item.Builder()));
func_200879_a(Blocks.STONE, ItemGroup.BUILDING_BLOCKS);
@@ -1147,6 +1194,9 @@
@@ -1147,6 +1193,9 @@
private Item field_200922_c;
private ItemGroup field_200923_d;
private EnumRarity field_208104_e = EnumRarity.COMMON;
+ private boolean canRepair = true;
+ private java.util.Map<String, Integer> toolClasses = new java.util.HashMap<String, Integer>();
+ private java.util.Map<net.minecraftforge.common.ToolType, Integer> toolClasses = Maps.newHashMap();
+ private java.util.function.Supplier<java.util.concurrent.Callable<net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer>> teisr;
public Item.Builder func_200917_a(int p_200917_1_) {
if (this.field_200921_b > 0) {
@@ -1181,5 +1231,10 @@
@@ -1181,5 +1230,20 @@
this.field_208104_e = p_208103_1_;
return this;
}
+
+ public Item.Builder setNoRepair() {
+ canRepair = false;
+ return this;
+ canRepair = false;
+ return this;
+ }
+
+ public Item.Builder addToolType(net.minecraftforge.common.ToolType type, int level) {
+ toolClasses.put(type, level);
+ return this;
+ }
+
+ public Item.Builder setTEISR(java.util.function.Supplier<java.util.concurrent.Callable<net.minecraft.client.renderer.tileentity.TileEntityItemStackRenderer>> teisr) {
+ this.teisr = teisr;
+ return this;
+ }
}
}

View File

@ -0,0 +1,25 @@
--- a/net/minecraft/item/ItemPickaxe.java
+++ b/net/minecraft/item/ItemPickaxe.java
@@ -17,18 +17,11 @@
public boolean canHarvestBlock(IBlockState blockIn) {
Block block = blockIn.getBlock();
int i = this.func_200891_e().func_200925_d();
- if (block == Blocks.OBSIDIAN) {
- return i == 3;
- } else if (block != Blocks.DIAMOND_BLOCK && block != Blocks.DIAMOND_ORE && block != Blocks.EMERALD_ORE && block != Blocks.EMERALD_BLOCK && block != Blocks.GOLD_BLOCK && block != Blocks.GOLD_ORE && block != Blocks.REDSTONE_ORE) {
- if (block != Blocks.IRON_BLOCK && block != Blocks.IRON_ORE && block != Blocks.LAPIS_BLOCK && block != Blocks.LAPIS_ORE) {
- Material material = blockIn.getMaterial();
- return material == Material.ROCK || material == Material.IRON || material == Material.ANVIL;
- } else {
- return i >= 1;
- }
- } else {
- return i >= 2;
+ if (blockIn.getHarvestTool() == net.minecraftforge.common.ToolType.PICKAXE) {
+ return i >= blockIn.getHarvestLevel();
}
+ Material material = blockIn.getMaterial();
+ return material == Material.ROCK || material == Material.IRON || material == Material.ANVIL;
}
public float getDestroySpeed(ItemStack stack, IBlockState state) {

View File

@ -5,7 +5,7 @@
import org.apache.logging.log4j.Logger;
-public final class ItemStack {
+public final class ItemStack extends net.minecraftforge.common.capabilities.CapabilityProvider implements net.minecraftforge.common.capabilities.ICapabilitySerializable<NBTTagCompound>, net.minecraftforge.common.extensions.IForgeItemStack {
+public final class ItemStack extends net.minecraftforge.common.capabilities.CapabilityProvider implements net.minecraftforge.common.extensions.IForgeItemStack {
private static final Logger field_199558_c = LogManager.getLogger();
public static final ItemStack EMPTY = new ItemStack((Item)null);
public static final DecimalFormat DECIMALFORMAT = func_208306_D();
@ -68,7 +68,7 @@
}
public EnumActionResult func_196084_a(ItemUseContext p_196084_1_) {
+ if (!p_196084_1_.field_196006_g.isRemote) return net.minecraftforge.common.ForgeHooks.onPlaceItemIntoWorld(p_196084_1_);
+ //if (!p_196084_1_.field_196006_g.isRemote) return net.minecraftforge.common.ForgeHooks.onPlaceItemIntoWorld(p_196084_1_);
EntityPlayer entityplayer = p_196084_1_.func_195999_j();
BlockPos blockpos = p_196084_1_.func_195995_a();
BlockWorldState blockworldstate = new BlockWorldState(p_196084_1_.func_195991_k(), blockpos, false);
@ -153,7 +153,7 @@
public boolean canHarvestBlock(IBlockState blockIn) {
- return this.getItem().canHarvestBlock(blockIn);
+ return this.getItem().canHarvestBlock(blockIn, this);
+ return this.getItem().canHarvestBlock(this, blockIn);
}
public boolean interactWithEntity(EntityPlayer playerIn, EntityLivingBase entityIn, EnumHand hand) {

View File

@ -9,6 +9,17 @@
public class BannerDuplicateRecipe extends IRecipeHidden {
public BannerDuplicateRecipe(ResourceLocation p_i48171_1_) {
@@ -77,8 +75,8 @@
for(int i = 0; i < nonnulllist.size(); ++i) {
ItemStack itemstack = inv.getStackInSlot(i);
if (!itemstack.isEmpty()) {
- if (itemstack.getItem().hasContainerItem()) {
- nonnulllist.set(i, new ItemStack(itemstack.getItem().getContainerItem()));
+ if (itemstack.hasContainerItem()) {
+ nonnulllist.set(i, itemstack.getContainerItem());
} else if (itemstack.hasTagCompound() && TileEntityBanner.getPatterns(itemstack) > 0) {
ItemStack itemstack1 = itemstack.copy();
itemstack1.setCount(1);
@@ -94,7 +92,6 @@
return RecipeSerializers.field_199586_l;
}

View File

@ -0,0 +1,70 @@
--- a/net/minecraft/network/ServerStatusResponse.java
+++ b/net/minecraft/network/ServerStatusResponse.java
@@ -26,6 +26,7 @@
public void setServerDescription(ITextComponent descriptionIn) {
this.description = descriptionIn;
+ invalidateJson();
}
public ServerStatusResponse.Players getPlayers() {
@@ -34,6 +35,7 @@
public void setPlayers(ServerStatusResponse.Players playersIn) {
this.players = playersIn;
+ invalidateJson();
}
public ServerStatusResponse.Version getVersion() {
@@ -42,16 +44,51 @@
public void setVersion(ServerStatusResponse.Version versionIn) {
this.version = versionIn;
+ invalidateJson();
}
public void setFavicon(String faviconBlob) {
this.favicon = faviconBlob;
+ invalidateJson();
}
public String getFavicon() {
return this.favicon;
}
+ private java.util.concurrent.Semaphore mutex = new java.util.concurrent.Semaphore(1);
+ private String json = null;
+ /**
+ * Returns this object as a Json string.
+ * Converting to JSON if a cached version is not available.
+ *
+ * Also to prevent potentially large memory allocations on the server
+ * this is moved from the SPacketServerInfo writePacket function
+ *
+ * As this method is called from the network threads so thread safety is important!
+ */
+ public String getJson() {
+ String ret = this.json;
+ if (ret == null) {
+ mutex.acquireUninterruptibly();
+ ret = this.json;
+ if (ret == null) {
+ ret = net.minecraft.network.status.server.SPacketServerInfo.GSON.toJson(this);
+ this.json = ret;
+ }
+ mutex.release();
+ }
+ return ret;
+ }
+
+ /**
+ * Invalidates the cached json, causing the next call to getJson to rebuild it.
+ * This is needed externally because PlayerCountData.setPlayer's is public.
+ */
+ public void invalidateJson() {
+ this.json = null;
+ }
+
public static class Players {
private final int maxPlayers;
private final int onlinePlayerCount;

View File

@ -0,0 +1,11 @@
--- a/net/minecraft/network/status/server/SPacketServerInfo.java
+++ b/net/minecraft/network/status/server/SPacketServerInfo.java
@@ -30,7 +30,7 @@
}
public void writePacketData(PacketBuffer buf) throws IOException {
- buf.writeString(GSON.toJson(this.response));
+ buf.writeString(this.response.getJson()); //Forge: Let the response cache the JSON
}
public void processPacket(INetHandlerStatusClient handler) {

View File

@ -1,34 +1,67 @@
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -130,7 +130,7 @@
private final DataFixer dataFixer;
private String hostname;
private int serverPort = -1;
- public WorldServer[] worlds;
+ public WorldServer[] worlds = new WorldServer[0];
private PlayerList playerList;
private boolean serverRunning = true;
private boolean serverStopped;
@@ -148,7 +148,8 @@
@@ -148,7 +148,6 @@
private int buildLimit;
private int maxPlayerIdleMinutes;
public final long[] tickTimeArray = new long[100];
- public long[][] timeOfLastDimensionTick;
+ //public long[][] timeOfLastDimensionTick;
+ public java.util.Hashtable<Integer, long[]> worldTickTimes = new java.util.Hashtable<Integer, long[]>();
private KeyPair serverKeyPair;
private String serverOwner;
private String folderName;
@@ -287,8 +288,6 @@
@@ -287,8 +286,7 @@
public void loadAllWorlds(String saveName, String worldNameIn, long seed, WorldType type, JsonElement generatorOptions) {
this.convertMapIfNeeded(saveName);
this.func_200245_b(new TextComponentTranslation("menu.loadingLevel", new Object[0]));
- this.worlds = new WorldServer[3];
- this.timeOfLastDimensionTick = new long[this.worlds.length][100];
+ this.worlds = new WorldServer[1]; //Forge only initialize overworld, we will do the rest.
ISaveHandler isavehandler = this.anvilConverterForAnvilFile.func_197715_a(saveName, this);
this.setResourcePackFromWorld(this.getFolderName(), isavehandler);
WorldInfo worldinfo = isavehandler.loadWorldInfo();
@@ -523,6 +522,7 @@
@@ -340,6 +338,18 @@
}
}
+ for (int dim : net.minecraftforge.common.DimensionManager.getStaticDimensionIDs()) {
+ WorldServer world = this.worlds[0];
+ if (dim != 0) {
+ world = (WorldServer)(new WorldServerMulti(this, isavehandler, dim, this.worlds[0], this.profiler).init());
+ world.addEventListener(new ServerWorldEventHandler(this, world));
+ if (!this.isSinglePlayer()) {
+ world.getWorldInfo().setGameType(getGameType());
+ }
+ }
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Load(world));
+ }
+
this.playerList.setPlayerManager(this.worlds);
if (worldinfo.func_201357_P() != null) {
this.func_201300_aS().func_201381_a(worldinfo.func_201357_P());
@@ -378,7 +388,7 @@
this.func_200245_b(new TextComponentTranslation("menu.generatingTerrain", new Object[0]));
int j1 = 0;
LOGGER.info("Preparing start region for level 0");
- WorldServer worldserver = this.worlds[0];
+ WorldServer worldserver = getWorld(0);
BlockPos blockpos = worldserver.getSpawnPoint();
List<ChunkPos> list = Lists.<ChunkPos>newArrayList();
Set<ChunkPos> set = Sets.<ChunkPos>newConcurrentHashSet();
@@ -493,9 +503,14 @@
for(WorldServer worldserver1 : this.worlds) {
if (worldserver1 != null) {
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Unload(worldserver1));
worldserver1.close();
}
}
+
+ WorldServer[] tmp = this.worlds;
+ for (WorldServer world : tmp)
+ net.minecraftforge.common.DimensionManager.setWorld(world.provider.getId(), null, this);
}
if (this.usageSnooper.isSnooperRunning()) {
@@ -523,6 +538,7 @@
public void run() {
try {
if (this.init()) {
@ -36,7 +69,7 @@
this.field_211151_aa = Util.func_211177_b();
this.statusResponse.setServerDescription(new TextComponentString(this.motd));
this.statusResponse.setVersion(new ServerStatusResponse.Version("1.13", 393));
@@ -546,7 +546,10 @@
@@ -546,7 +562,10 @@
this.serverIsRunning = true;
}
@ -47,7 +80,7 @@
this.finalTick((CrashReport)null);
}
} catch (Throwable throwable1) {
@@ -565,6 +568,7 @@
@@ -565,6 +584,7 @@
LOGGER.error("We were unable to save this crash report to disk.");
}
@ -55,7 +88,7 @@
this.finalTick(crashreport);
} finally {
try {
@@ -573,6 +577,7 @@
@@ -573,6 +593,7 @@
} catch (Throwable throwable) {
LOGGER.error("Exception stopping the server", throwable);
} finally {
@ -63,7 +96,15 @@
this.systemExitNow();
}
@@ -686,10 +691,12 @@
@@ -648,6 +669,7 @@
Collections.shuffle(Arrays.asList(agameprofile));
this.statusResponse.getPlayers().setPlayers(agameprofile);
+ this.statusResponse.invalidateJson();
}
if (this.tickCounter % 900 == 0) {
@@ -686,16 +708,18 @@
this.getFunctionManager().update();
this.profiler.endStartSection("levels");
@ -74,17 +115,74 @@
long j = Util.func_211178_c();
- if (i == 0 || this.getAllowNether()) {
- WorldServer worldserver = this.worlds[i];
+ WorldServer worldserver = getWorld(id);
+ if (id == 0 || this.getAllowNether()) {
+ WorldServer worldserver = net.minecraftforge.common.DimensionManager.getWorld(id);
this.profiler.func_194340_a(() -> {
return worldserver.getWorldInfo().getWorldName();
});
@@ -724,7 +731,7 @@
if (this.tickCounter % 20 == 0) {
this.profiler.startSection("timeSync");
- this.playerList.sendPacketToAllPlayersInDimension(new SPacketTimeUpdate(worldserver.getTotalWorldTime(), worldserver.getWorldTime(), worldserver.getGameRules().getBoolean("doDaylightCycle")), worldserver.provider.getDimensionType().getId());
+ this.playerList.sendPacketToAllPlayersInDimension(new SPacketTimeUpdate(worldserver.getTotalWorldTime(), worldserver.getWorldTime(), worldserver.getGameRules().getBoolean("doDaylightCycle")), worldserver.provider.getId());
this.profiler.endSection();
}
@@ -724,9 +748,11 @@
this.profiler.endSection();
}
- this.timeOfLastDimensionTick[i][this.tickCounter % 100] = Util.func_211178_c() - j;
+ worldTickTimes.get(id)[this.tickCounter % 100] = Util.func_211178_c() - j;
+ worldserver.setTickTime(this.tickCounter, Util.func_211178_c() - j);
}
+ this.profiler.endStartSection("dim_unloading");
+ net.minecraftforge.common.DimensionManager.unloadWorlds();
this.profiler.endStartSection("connection");
this.getNetworkSystem().networkTick();
this.profiler.endStartSection("players");
@@ -749,6 +775,14 @@
}
public static void main(String[] p_main_0_) {
+ //Forge: Copied from DedicatedServer.init as to run as early as possible, Old code left in place intentionally.
+ //Done in good faith with permission: https://github.com/MinecraftForge/MinecraftForge/issues/3659#issuecomment-390467028
+ ServerEula eula = new ServerEula(new File("eula.txt"));
+ if (!eula.hasAcceptedEULA()) {
+ LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
+ eula.createEULAFile();
+ return;
+ }
Bootstrap.register();
try {
@@ -851,7 +885,7 @@
}
public void startServerThread() {
- this.serverThread = new Thread(this, "Server thread");
+ this.serverThread = new Thread(net.minecraftforge.fml.common.thread.SidedThreadGroups.SERVER, this, "Server thread");
this.serverThread.setUncaughtExceptionHandler((p_195574_0_, p_195574_1_) -> {
LOGGER.error(p_195574_1_);
});
@@ -871,11 +905,7 @@
}
public WorldServer getWorld(int dimension) {
- if (dimension == -1) {
- return this.worlds[1];
- } else {
- return dimension == 1 ? this.worlds[2] : this.worlds[0];
- }
+ return net.minecraftforge.common.DimensionManager.getWorld(dimension, true, true);
}
public WorldServer func_200667_a(DimensionType p_200667_1_) {
@@ -918,7 +948,7 @@
}
public String getServerModName() {
- return "vanilla";
+ return net.minecraftforge.common.ForgeHooks.getServerModName();
}
public CrashReport addServerInfoToCrashReport(CrashReport report) {

View File

@ -1,6 +1,35 @@
--- a/net/minecraft/server/integrated/IntegratedServer.java
+++ b/net/minecraft/server/integrated/IntegratedServer.java
@@ -121,9 +121,10 @@
@@ -62,8 +62,7 @@
public void loadAllWorlds(String saveName, String worldNameIn, long seed, WorldType type, JsonElement generatorOptions) {
this.convertMapIfNeeded(saveName);
- this.worlds = new WorldServer[3];
- this.timeOfLastDimensionTick = new long[this.worlds.length][100];
+ this.worlds = new WorldServer[1]; //Forge only initialize overworld, we will do the rest.
ISaveHandler isavehandler = this.getActiveAnvilConverter().func_197715_a(saveName, this);
this.setResourcePackFromWorld(this.getFolderName(), isavehandler);
WorldInfo worldinfo = isavehandler.loadWorldInfo();
@@ -100,6 +99,18 @@
this.worlds[i].addEventListener(new ServerWorldEventHandler(this, this.worlds[i]));
}
+ for (int dim : net.minecraftforge.common.DimensionManager.getStaticDimensionIDs()) {
+ WorldServer world = this.worlds[0];
+ if (dim != 0) {
+ world = (WorldServer)(new WorldServerMulti(this, isavehandler, dim, this.worlds[0], this.profiler).init());
+ world.addEventListener(new ServerWorldEventHandler(this, world));
+ if (!this.isSinglePlayer()) {
+ world.getWorldInfo().setGameType(getGameType());
+ }
+ }
+ net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.world.WorldEvent.Load(world));
+ }
+
this.getPlayerList().setPlayerManager(this.worlds);
if (worldinfo.func_201357_P() != null) {
this.func_201300_aS().func_201381_a(worldinfo.func_201357_P());
@@ -121,9 +132,10 @@
this.setAllowFlight(true);
LOGGER.info("Generating keypair");
this.setKeyPair(CryptManager.generateKeyPair());
@ -12,3 +41,19 @@
}
public void tick() {
@@ -176,6 +188,7 @@
}
public EnumDifficulty getDifficulty() {
+ if (this.mc.world == null) return this.mc.gameSettings.difficulty; // Fix NPE just in case.
return this.mc.world.getWorldInfo().getDifficulty();
}
@@ -275,6 +288,7 @@
}
public void initiateShutdown() {
+ if (isServerRunning())
Futures.getUnchecked(this.addScheduledTask(() -> {
for(EntityPlayerMP entityplayermp : Lists.newArrayList(this.getPlayerList().getPlayers())) {
if (!entityplayermp.getUniqueID().equals(this.field_211528_n)) {

View File

@ -0,0 +1,105 @@
--- a/net/minecraft/tileentity/TileEntityFurnace.java
+++ b/net/minecraft/tileentity/TileEntityFurnace.java
@@ -185,9 +185,9 @@
super.readFromNBT(compound);
this.furnaceItemStacks = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
ItemStackHelper.loadAllItems(compound, this.furnaceItemStacks);
- this.furnaceBurnTime = compound.getShort("BurnTime");
- this.cookTime = compound.getShort("CookTime");
- this.totalCookTime = compound.getShort("CookTimeTotal");
+ this.furnaceBurnTime = compound.getInteger("BurnTime");
+ this.cookTime = compound.getInteger("CookTime");
+ this.totalCookTime = compound.getInteger("CookTimeTotal");
this.currentItemBurnTime = getItemBurnTime(this.furnaceItemStacks.get(1));
int i = compound.getShort("RecipesUsedSize");
@@ -205,9 +205,9 @@
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
- compound.setShort("BurnTime", (short)this.furnaceBurnTime);
- compound.setShort("CookTime", (short)this.cookTime);
- compound.setShort("CookTimeTotal", (short)this.totalCookTime);
+ compound.setInteger("BurnTime", this.furnaceBurnTime);
+ compound.setInteger("CookTime", this.cookTime);
+ compound.setInteger("CookTimeTotal", this.totalCookTime);
ItemStackHelper.saveAllItems(compound, this.furnaceItemStacks);
compound.setShort("RecipesUsedSize", (short)this.field_203901_m.size());
int i = 0;
@@ -254,6 +254,10 @@
this.currentItemBurnTime = this.furnaceBurnTime;
if (this.isBurning()) {
flag1 = true;
+ if (itemstack.hasContainerItem()) {
+ this.furnaceItemStacks.set(1, itemstack.getContainerItem());
+ }
+ else
if (!itemstack.isEmpty()) {
Item item = itemstack.getItem();
itemstack.shrink(1);
@@ -308,10 +312,10 @@
return true;
} else if (!itemstack1.isItemEqual(itemstack)) {
return false;
- } else if (itemstack1.getCount() < this.getInventoryStackLimit() && itemstack1.getCount() < itemstack1.getMaxStackSize()) {
+ } else if (itemstack1.getCount() + itemstack.getCount() <= this.getInventoryStackLimit() && itemstack1.getCount() < itemstack1.getMaxStackSize()) { // Forge fix: make furnace respect stack sizes in furnace recipes
return true;
} else {
- return itemstack1.getCount() < itemstack.getMaxStackSize();
+ return itemstack1.getCount() + itemstack.getCount() <= itemstack.getMaxStackSize(); // Forge fix: make furnace respect stack sizes in furnace recipes
}
}
} else {
@@ -327,7 +331,7 @@
if (itemstack2.isEmpty()) {
this.furnaceItemStacks.set(2, itemstack1.copy());
} else if (itemstack2.getItem() == itemstack1.getItem()) {
- itemstack2.grow(1);
+ itemstack2.grow(itemstack1.getCount());
}
if (!this.world.isRemote) {
@@ -347,12 +351,13 @@
return 0;
} else {
Item item = stack.getItem();
- return func_201564_p().getOrDefault(item, 0);
+ int ret = stack.getBurnTime();
+ return net.minecraftforge.event.ForgeEventFactory.getItemBurnTime(stack, ret == -1 ? func_201564_p().getOrDefault(item, 0) : ret);
}
}
public static boolean isItemFuel(ItemStack stack) {
- return func_201564_p().containsKey(stack.getItem());
+ return getItemBurnTime(stack) > 0;
}
public boolean isUsableByPlayer(EntityPlayer player) {
@@ -501,4 +506,27 @@
this.field_203901_m.clear();
}
+
+ net.minecraftforge.common.capabilities.OptionalCapabilityInstance<? extends net.minecraftforge.items.IItemHandler>[] handlers =
+ net.minecraftforge.items.wrapper.SidedInvWrapper.create(this, EnumFacing.UP, EnumFacing.DOWN, EnumFacing.NORTH);
+
+ @Override
+ public <T> net.minecraftforge.common.capabilities.OptionalCapabilityInstance<T> getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, @Nullable EnumFacing facing) {
+ if (facing != null && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
+ if (facing == EnumFacing.UP)
+ return handlers[0].cast();
+ else if (facing == EnumFacing.UP)
+ return handlers[1].cast();
+ else
+ return handlers[2].cast();
+ }
+ return super.getCapability(capability, facing);
+ }
+
+ @Override
+ public void invalidate() {
+ super.invalidate();
+ for (int x = 0; x < handlers.length; x++)
+ handlers[x].invalidate();
+ }
}

View File

@ -17,3 +17,16 @@
return this;
}
@@ -957,4 +958,12 @@
public NetworkTagManager func_205772_D() {
return this.server.func_199731_aO();
}
+
+ private long[] tickTime = new long[100];
+ public void setTickTime(int tick, long time) {
+ this.tickTime[tick % 100] = time;
+ }
+ public long[] getTickTimes() {
+ return this.tickTime;
+ }
}

View File

@ -40,9 +40,9 @@ import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.GameSettings;
import net.minecraft.client.MainWindow;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.SoundHandler;
@ -138,14 +138,13 @@ import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import com.google.common.collect.Maps;
public class ForgeHooksClient
{
private static final Logger LOGGER = LogManager.getLogger();
//private static final ResourceLocation ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png");
public static String getArmorTexture(Entity entity, ItemStack armor, String _default, EntityEquipmentSlot slot, String type)
@ -154,19 +153,6 @@ public class ForgeHooksClient
return result != null ? result : _default;
}
//Optifine Helper Functions u.u, these are here specifically for Optifine
//Note: When using Optifine, these methods are invoked using reflection, which
//incurs a major performance penalty.
public static void orientBedCamera(IWorldReader world, BlockPos pos, IBlockState state, Entity entity)
{
Block block = state.getBlock();
if (block != null && block.isBed(state, world, pos, entity))
{
glRotatef((float)(block.getBedDirection(state, world, pos).getHorizontalIndex() * 90), 0.0F, 1.0F, 0.0F);
}
}
public static boolean onDrawBlockHighlight(RenderGlobal context, EntityPlayer player, RayTraceResult target, int subID, float partialTicks)
{
return MinecraftForge.EVENT_BUS.post(new DrawBlockHighlightEvent(context, player, target, subID, partialTicks));
@ -729,7 +715,7 @@ public class ForgeHooksClient
return new BlockFaceUV(new float[]{ uMin, vMin, uMax, vMax }, angle);
}
public static RenderGameOverlayEvent.BossInfo bossBarRenderPre(ScaledResolution res, BossInfoClient bossInfo, int x, int y, int increment)
public static RenderGameOverlayEvent.BossInfo bossBarRenderPre(MainWindow res, BossInfoClient bossInfo, int x, int y, int increment)
{
RenderGameOverlayEvent.BossInfo evt = new RenderGameOverlayEvent.BossInfo(new RenderGameOverlayEvent(Animation.getPartialTickTime(), res),
BOSSINFO, bossInfo, x, y, increment);
@ -737,7 +723,7 @@ public class ForgeHooksClient
return evt;
}
public static void bossBarRenderPost(ScaledResolution res)
public static void bossBarRenderPost(MainWindow res)
{
MinecraftForge.EVENT_BUS.post(new RenderGameOverlayEvent.Post(new RenderGameOverlayEvent(Animation.getPartialTickTime(), res), BOSSINFO));
}

View File

@ -22,6 +22,7 @@ package net.minecraftforge.client.model.pipeline;
import java.util.List;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.BufferBuilder;
@ -113,7 +114,7 @@ public class ForgeBlockModelRenderer extends BlockModelRenderer
quads = model.func_200117_a(state, side, rand);
if(!quads.isEmpty())
{
if(!checkSides || state.shouldSideBeRendered(world, pos, side))
if(!checkSides || Block.shouldSideBeRendered(state, world, pos, side))
{
if(empty) lighter.updateBlockInfo();
empty = false;

View File

@ -219,13 +219,11 @@ public class DimensionManager
{
worlds.put(id, world);
weakWorldMap.put(world, world);
server.worldTickTimes.put(id, new long[100]);
LOGGER.info(DIMMGR,"Loading dimension {} ({}) ({})", id, world.getWorldInfo().getWorldName(), world.getMinecraftServer());
}
else
{
worlds.remove(id);
server.worldTickTimes.remove(id);
LOGGER.info(DIMMGR,"Unloading dimension {}", id);
}
@ -287,12 +285,23 @@ public class DimensionManager
}
public static WorldServer getWorld(int id, boolean resetUnloadDelay)
{
return getWorld(id, resetUnloadDelay, false);
}
public static WorldServer getWorld(int id, boolean resetUnloadDelay, boolean forceLoad)
{
if (resetUnloadDelay && unloadQueue.contains(id))
{
dimensions.get(id).ticksWaited = 0;
}
return worlds.get(id);
WorldServer ret = worlds.get(id);
if (ret != null && forceLoad)
{
initDimension(id);
ret = worlds.get(id);
}
return ret;
}
public static WorldServer[] getWorlds()
@ -379,7 +388,7 @@ public class DimensionManager
/*
* To be called by the server at the appropriate time, do not call from mod code.
*/
public static void unloadWorlds(Hashtable<Integer, long[]> worldTickTimes)
public static void unloadWorlds()
{
IntIterator queueIterator = unloadQueue.iterator();
while (queueIterator.hasNext())

View File

@ -21,8 +21,10 @@ package net.minecraftforge.common;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@ -38,6 +40,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;
import com.google.common.collect.Sets;
@ -49,7 +52,6 @@ import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementManager;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFarmland;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
@ -64,7 +66,9 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.entity.projectile.EntityThrowable;
import net.minecraft.fluid.IFluidState;
import net.minecraft.init.Blocks;
import net.minecraft.init.Fluids;
import net.minecraft.init.Items;
import net.minecraft.inventory.ContainerRepair;
import net.minecraft.inventory.IInventory;
@ -73,7 +77,6 @@ import net.minecraft.item.Item;
import net.minecraft.item.ItemAxe;
import net.minecraft.item.ItemBucket;
import net.minecraft.item.ItemEnchantedBook;
import net.minecraft.item.ItemMonsterPlacer;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemPotion;
import net.minecraft.item.ItemSpade;
@ -91,11 +94,12 @@ import net.minecraft.network.play.server.SPacketRecipeBook;
import net.minecraft.network.play.server.SPacketRecipeBook.State;
import net.minecraft.potion.PotionType;
import net.minecraft.potion.PotionUtils;
import net.minecraft.resources.IResource;
import net.minecraft.resources.IResourceManager;
import net.minecraft.stats.StatList;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.Tag;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityNote;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumFacing;
@ -117,6 +121,7 @@ import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.GameType;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.storage.loot.LootEntry;
import net.minecraft.world.storage.loot.LootTable;
import net.minecraft.world.storage.loot.LootTableManager;
@ -149,17 +154,12 @@ import net.minecraftforge.event.entity.player.AdvancementEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.NoteBlockEvent;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.LoaderState;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher;
import net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.ConnectionType;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.network.ConnectionType;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
import net.minecraftforge.fml.network.NetworkHooks;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.RegistryManager;
@ -168,10 +168,12 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
import org.apache.logging.log4j.util.TriConsumer;
public class ForgeHooks
{
@ -210,20 +212,16 @@ public class ForgeHooks
return entry.getStack(rand, fortune);
}
private static boolean toolInit = false;
//static HashSet<List> toolEffectiveness = new HashSet<List>();
public static boolean canHarvestBlock(@Nonnull Block block, @Nonnull EntityPlayer player, @Nonnull IWorldReader world, @Nonnull BlockPos pos)
public static boolean canHarvestBlock(@Nonnull IBlockState state, @Nonnull EntityPlayer player, @Nonnull IBlockReader world, @Nonnull BlockPos pos)
{
IBlockState state = world.getBlockState(pos);
state = state.getBlock().getActualState(state, world, pos);
//state = state.getActualState(world, pos);
if (state.getMaterial().isToolNotRequired())
{
return true;
}
ItemStack stack = player.getHeldItemMainhand();
String tool = block.getHarvestTool(state);
ToolType tool = state.getHarvestTool();
if (stack.isEmpty() || tool == null)
{
return player.canHarvestBlock(state);
@ -235,89 +233,50 @@ public class ForgeHooks
return player.canHarvestBlock(state);
}
return toolLevel >= block.getHarvestLevel(state);
return toolLevel >= state.getHarvestLevel();
}
public static boolean canToolHarvestBlock(IWorldReader world, BlockPos pos, @Nonnull ItemStack stack)
{
IBlockState state = world.getBlockState(pos);
state = state.getBlock().getActualState(state, world, pos);
String tool = state.getBlock().getHarvestTool(state);
//state = state.getActualState(world, pos);
ToolType tool = state.getHarvestTool();
if (stack.isEmpty() || tool == null) return false;
return stack.getItem().getHarvestLevel(stack, tool, null, null) >= state.getBlock().getHarvestLevel(state);
}
public static float blockStrength(@Nonnull IBlockState state, @Nonnull EntityPlayer player, @Nonnull World world, @Nonnull BlockPos pos)
{
float hardness = state.getBlockHardness(world, pos);
if (hardness < 0.0F)
{
return 0.0F;
}
if (!canHarvestBlock(state.getBlock(), player, world, pos))
{
return player.getDigSpeed(state, pos) / hardness / 100F;
}
else
{
return player.getDigSpeed(state, pos) / hardness / 30F;
}
return stack.getHarvestLevel(tool, null, null) >= state.getHarvestLevel();
}
public static boolean isToolEffective(IWorldReader world, BlockPos pos, @Nonnull ItemStack stack)
{
IBlockState state = world.getBlockState(pos);
state = state.getBlock().getActualState(state, world, pos);
for (String type : stack.getItem().getToolClasses(stack))
//state = state.getActualState(world, pos);
for (ToolType type : stack.getToolTypes())
{
if (state.getBlock().isToolEffective(type, state))
if (state.isToolEffective(type))
return true;
}
return false;
}
private static boolean toolInit = false;
static void initTools()
{
if (toolInit)
{
return;
}
toolInit = true;
Set<Block> blocks = ReflectionHelper.getPrivateValue(ItemPickaxe.class, null, 0);
for (Block block : blocks)
{
block.setHarvestLevel("pickaxe", 0);
}
Set<Block> blocks = getPrivateValue(ItemPickaxe.class, null, 0);
blocks.forEach(block -> blockToolSetter.accept(block, ToolType.PICKAXE, 0));
blocks = getPrivateValue(ItemSpade.class, null, 0);
blocks.forEach(block -> blockToolSetter.accept(block, ToolType.SHOVEL, 0));
blocks = getPrivateValue(ItemAxe.class, null, 0);
blocks.forEach(block -> blockToolSetter.accept(block, ToolType.AXE, 0));
blocks = ReflectionHelper.getPrivateValue(ItemSpade.class, null, 0);
for (Block block : blocks)
{
block.setHarvestLevel("shovel", 0);
}
blocks = ReflectionHelper.getPrivateValue(ItemAxe.class, null, 0);
for (Block block : blocks)
{
block.setHarvestLevel("axe", 0);
}
Blocks.OBSIDIAN.setHarvestLevel("pickaxe", 3);
Blocks.ENCHANTING_TABLE.setHarvestLevel("pickaxe", 0);
Block[] oreBlocks = new Block[] {
Blocks.EMERALD_ORE, Blocks.EMERALD_BLOCK, Blocks.DIAMOND_ORE, Blocks.DIAMOND_BLOCK,
Blocks.GOLD_ORE, Blocks.GOLD_BLOCK, Blocks.REDSTONE_ORE, Blocks.LIT_REDSTONE_ORE
};
for (Block block : oreBlocks)
{
block.setHarvestLevel("pickaxe", 2);
}
Blocks.IRON_ORE.setHarvestLevel("pickaxe", 1);
Blocks.IRON_BLOCK.setHarvestLevel("pickaxe", 1);
Blocks.LAPIS_ORE.setHarvestLevel("pickaxe", 1);
Blocks.LAPIS_BLOCK.setHarvestLevel("pickaxe", 1);
Blocks.QUARTZ_ORE.setHarvestLevel("pickaxe", 0);
//This is taken from ItemAxe, if that changes update here.
blockToolSetter.accept(Blocks.OBSIDIAN, ToolType.PICKAXE, 3);
for (Block block : new Block[]{Blocks.DIAMOND_BLOCK, Blocks.DIAMOND_ORE, Blocks.EMERALD_ORE, Blocks.EMERALD_BLOCK, Blocks.GOLD_BLOCK, Blocks.GOLD_ORE, Blocks.REDSTONE_ORE})
blockToolSetter.accept(block, ToolType.PICKAXE, 2);
for (Block block : new Block[]{Blocks.IRON_BLOCK, Blocks.IRON_ORE, Blocks.LAPIS_BLOCK, Blocks.LAPIS_ORE})
blockToolSetter.accept(block, ToolType.PICKAXE, 1);
}
public static int getTotalArmorValue(EntityPlayer player)
@ -723,7 +682,7 @@ public class ForgeHooks
public static float getEnchantPower(@Nonnull World world, @Nonnull BlockPos pos)
{
return world.getBlockState(pos).getBlock().getEnchantPowerBonus(world, pos);
return world.getBlockState(pos).getEnchantPowerBonus(world, pos);
}
@Nullable
@ -841,9 +800,7 @@ public class ForgeHooks
// Tell client the block is gone immediately then process events
if (world.getTileEntity(pos) == null)
{
SPacketBlockChange packet = new SPacketBlockChange(world, pos);
packet.blockState = Blocks.AIR.getDefaultState();
entityPlayer.connection.sendPacket(packet);
entityPlayer.connection.sendPacket(new SPacketBlockChange(DUMMY_WORLD, pos));
}
// Post the block break event
@ -872,6 +829,7 @@ public class ForgeHooks
return event.isCanceled() ? -1 : event.getExpToDrop();
}
/* TODO: Talk to Sponge folk about World rollbacks.
public static EnumActionResult onPlaceItemIntoWorld(@Nonnull ItemUseContext context)
{
ItemStack itemstack = context.func_195996_i();
@ -969,6 +927,7 @@ public class ForgeHooks
return ret;
}
*/
public static boolean onAnvilChange(ContainerRepair container, @Nonnull ItemStack left, @Nonnull ItemStack right, IInventory outputSlot, String name, int baseCost)
{
@ -989,18 +948,6 @@ public class ForgeHooks
return e.getBreakChance();
}
public static boolean onNoteChange(TileEntityNote te, byte old)
{
NoteBlockEvent.Change e = new NoteBlockEvent.Change(te.getWorld(), te.getPos(), te.getWorld().getBlockState(te.getPos()), old, te.note);
if (MinecraftForge.EVENT_BUS.post(e))
{
te.note = old;
return false;
}
te.note = (byte)e.getVanillaNoteId();
return true;
}
private static ThreadLocal<EntityPlayer> craftingPlayer = new ThreadLocal<EntityPlayer>();
public static void setCraftingPlayer(EntityPlayer player)
{
@ -1285,16 +1232,6 @@ public class ForgeHooks
MinecraftForge.EVENT_BUS.post(new BlockEvent.CropGrowEvent.Post(worldIn, pos, state, worldIn.getBlockState(pos)));
}
public static boolean loadAdvancements(Map<ResourceLocation, Advancement.Builder> map)
{
boolean errored = false;
for (ModFileInfo mod : ModList.get().getModFiles())
{
errored |= !loadAdvancements(map, mod.getFile());
}
return errored;
}
@Nullable
public static CriticalHitEvent getCriticalHit(EntityPlayer player, Entity target, boolean vanillaCritical, float damageModifier)
{
@ -1307,56 +1244,6 @@ public class ForgeHooks
return null;
}
private static boolean loadAdvancements(Map<ResourceLocation, Advancement.Builder> map, ModFile mod)
{
if (Loader.instance().getLoaderState() != LoaderState.NOINIT) //Unit Tests..
Loader.instance().setActiveModContainer(mod);
}
private static boolean loadAdvancements(Map<ResourceLocation, Advancement.Builder> map, ModContainer mod)
{
return CraftingHelper.findFiles(mod, "assets/" + mod.getModId() + "/advancements", null,
(root, file) ->
{
String relative = root.relativize(file).toString();
if (!"json".equals(FilenameUtils.getExtension(file.toString())) || relative.startsWith("_"))
return true;
String name = FilenameUtils.removeExtension(relative).replaceAll("\\\\", "/");
ResourceLocation key = new ResourceLocation(mod.getModId(), name);
if (!map.containsKey(key))
{
BufferedReader reader = null;
try
{
reader = Files.newBufferedReader(file);
Advancement.Builder builder = JsonUtils.fromJson(AdvancementManager.GSON, reader, Advancement.Builder.class);
map.put(key, builder);
}
catch (JsonParseException jsonparseexception)
{
LOGGER.error("Parsing error loading built-in advancement " + key, (Throwable)jsonparseexception);
return false;
}
catch (IOException ioexception)
{
LOGGER.error("Couldn't read advancement " + key + " from " + file, (Throwable)ioexception);
return false;
}
finally
{
IOUtils.closeQuietly(reader);
}
}
return true;
},
true, true
);
}
/* TODO this should be unnecessary now?
public static void sendRecipeBook(NetHandlerPlayServer connection, State state, List<IRecipe> recipes, List<IRecipe> display, boolean isGuiOpen, boolean isFilteringCraftable)
{
@ -1439,4 +1326,52 @@ public class ForgeHooks
}
return false;
}
public static String getServerModName()
{
//TODO: Branding Properties: snooperbranding
return "forge";
}
private static TriConsumer<Block, ToolType, Integer> blockToolSetter;
//Internal use only Modders, this is specifically hidden from you, as you shouldn't be editing other people's blocks.
public static void setBlockToolSetter(TriConsumer<Block, ToolType, Integer> setter)
{
blockToolSetter = setter;
}
@SuppressWarnings("unchecked")
private static <T, E> T getPrivateValue(Class <? super E > classToAccess, @Nullable E instance, int fieldIndex)
{
try
{
Field f = classToAccess.getDeclaredFields()[fieldIndex];
f.setAccessible(true);
return (T) f.get(instance);
}
catch (Exception e)
{
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
private static final DummyBlockReader DUMMY_WORLD = new DummyBlockReader();
private static class DummyBlockReader implements IBlockReader {
@Override
public TileEntity getTileEntity(BlockPos pos) {
return null;
}
@Override
public IBlockState getBlockState(BlockPos pos) {
return Blocks.AIR.getDefaultState();
}
@Override
public IFluidState func_204610_c(BlockPos p_204610_1_) {
return Fluids.field_204541_a.func_207188_f();
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common;
import java.util.Map;
import java.util.regex.Pattern;
import com.google.common.collect.Maps;
public final class ToolType
{
public static final ToolType AXE = get("axe");
public static final ToolType PICKAXE = get("pickaxe");
public static final ToolType SHOVEL = get("shovel");
private static final Map<String, ToolType> values = Maps.newHashMap();
private static final Pattern VALID_NAME = Pattern.compile("[^a-z_]"); //Only a-z and _ are allowed, meaning names must be lower case. And use _ to separate words.
public static ToolType get(String name)
{
if (VALID_NAME.matcher(name).find())
throw new IllegalArgumentException("ToolType.create() called with invalid name: " + name);
return values.putIfAbsent(name, new ToolType(name));
}
private final String name;
private ToolType(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}

View File

@ -40,7 +40,6 @@ import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.IProperty;
import net.minecraft.state.properties.BedPart;
import net.minecraft.util.*;
@ -52,19 +51,20 @@ import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.IWorldWriter;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.EnumPlantType;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.ToolType;
public interface IForgeBlock
{
default Block getBlock()
{
return (Block) this;
}
/**
@ -170,7 +170,7 @@ public interface IForgeBlock
return this.getBlock().hasTileEntity();
}
boolean canSilkHarvest(IWorldReader world, BlockPos pos, IBlockState state, EntityPlayer player);
boolean canSilkHarvest(IBlockState state, IWorldReader world, BlockPos pos, EntityPlayer player);
/**
* Determines if this block is classified as a Bed, Allowing
@ -198,6 +198,7 @@ public interface IForgeBlock
* @param type The Mob Category Type
* @return True to allow a mob of the specified category to spawn, false to prevent it.
*/
@SuppressWarnings("deprecation")
default boolean canCreatureSpawn(IBlockState state, IWorldReader world, BlockPos pos, EntitySpawnPlacementRegistry.SpawnPlacementType type)
{
return this.getBlock().isTopSolid(state);
@ -225,19 +226,18 @@ public interface IForgeBlock
/**
* Called when a user either starts or stops sleeping in the bed.
* @param state
*
* @param world The current world
* @param pos Block position in world
* @param player The player or camera entity, null in some cases.
* @param occupied True if we are occupying the bed, or false if they are stopping use of the bed
*/
default void setBedOccupied(IWorldReader world, BlockPos pos, EntityPlayer player, boolean occupied)
default void setBedOccupied(IBlockState state, IWorldReader world, BlockPos pos, EntityPlayer player, boolean occupied)
{
if (world instanceof World)
if (world instanceof IWorldWriter)
{
IBlockState state = world.getBlockState(pos);
state.func_206870_a(BlockBed.OCCUPIED,occupied);
((World) world).setBlockState(pos, state, 4);
((IWorldWriter)world).setBlockState(pos, state.func_206870_a(BlockBed.OCCUPIED,occupied), 4);
}
}
@ -336,7 +336,7 @@ public interface IForgeBlock
* @param pos Block position in world
* @return true if the block is wood (logs)
*/
default boolean isWood(IWorldReader world, BlockPos pos)
default boolean isWood(IBlockState state, IWorldReader world, BlockPos pos)
{
return false;
}
@ -365,7 +365,7 @@ public interface IForgeBlock
* @param explosion The explosion
* @return The amount of the explosion absorbed.
*/
default float getExplosionResistance(IWorld world, BlockPos pos, @Nullable Entity exploder, Explosion explosion)
default float getExplosionResistance(IBlockState state, IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion)
{
return this.getBlock().getExplosionResistance();
}
@ -379,7 +379,7 @@ public interface IForgeBlock
* @param pos Block position in world
* @param explosion The explosion instance affecting the block
*/
void onBlockExploded(World world, BlockPos pos, Explosion explosion);
void onBlockExploded(IBlockState state, World world, BlockPos pos, Explosion explosion);
/**
* Determine if this block can make a redstone connection on the side provided,
@ -395,7 +395,7 @@ public interface IForgeBlock
{
return state.canProvidePower() && side != null;
}
/**
* Determines if a torch can be placed on the top surface of this block.
* Useful for creating your own block that torches can be on, such as fences.
@ -408,44 +408,39 @@ public interface IForgeBlock
default boolean canPlaceTorchOnTop(IBlockState state, IWorldReader world, BlockPos pos)
{
if (state.isTopSolid() || state.getBlockFaceShape(world, pos, EnumFacing.UP) == BlockFaceShape.SOLID)
{
return this.getBlock() != Blocks.END_GATEWAY && this.getBlock() != Blocks.field_196628_cT;
}
else
{
return this.getBlock() instanceof BlockFence || this.getBlock() == Blocks.COBBLESTONE_WALL || this.getBlock() instanceof BlockGlass;
}
}
/**
*
*
* Called when A user uses the creative pick block button on this block
*
*
* @param target The full target the player is looking at
* @return A ItemStack to add to the player's inventory, empty itemstack if nothing should be added.
*/
default ItemStack getPickBlock(IBlockState state, RayTraceResult target, IBlockReader world, BlockPos pos, EntityPlayer player)
{
return this.getBlock().getItem(world, pos, state);
return this.getBlock().getItem(world, pos, state);
}
/**
* Used by getTopSoilidOrLiquidBlock while placing biome decorations, villages, etc
* Also used to determine if the player can spawn in this block.
*
*
* @return False to disallow spawning.
*/
default boolean isFoilage(IWorldReader world, BlockPos pos)
default boolean isFoliage(IBlockState state, IWorldReader world, BlockPos pos)
{
return false;
return false;
}
/**
* Allows a block to override the standard EntityLivingBase.updateFallState
* particles, this is a server side method that spawns particles with
* WorldServer.spawnParticle.
*
*
* @param worldserver The current Server World
* @param pos The position of the block.
* @param state2 The state at the specific world/pos
@ -453,9 +448,9 @@ public interface IForgeBlock
* @param numberOfParticles That vanilla world have spawned
* @return True to prevent vanilla landing particles from spawning
*/
default boolean addLandingEffects(IBlockState state1, WorldServer worldserver, BlockPos pos, IBlockState state2, EntityLivingBase entity, int numberOfParticles)
default boolean addLandingEffects(IBlockState state1, WorldServer worldserver, BlockPos pos, IBlockState state2, EntityLivingBase entity, int numberOfParticles)
{
return false;
return false;
}
/**
* Allows a block to override the standard vanilla running particles.
@ -486,7 +481,7 @@ public interface IForgeBlock
* @return True to prevent vanilla break particles from spawning.
*/
@OnlyIn(Dist.CLIENT)
default boolean addDestroyEffects(World world, BlockPos pos, ParticleManager manager)
default boolean addDestroyEffects(IBlockState state, World world, BlockPos pos, ParticleManager manager)
{
return false;
}
@ -568,9 +563,7 @@ public interface IForgeBlock
default void onPlantGrow(IBlockState state, World world, BlockPos pos, BlockPos source)
{
if (this.getBlock() == Blocks.GRASS || this.getBlock() == Blocks.FARMLAND)
{
world.setBlockState(pos, Blocks.DIRT.getDefaultState(), 2);
}
}
/**
@ -582,12 +575,10 @@ public interface IForgeBlock
* @param pos Block position in world
* @return True if the soil should be considered fertile.
*/
default boolean isFertile(World world, BlockPos pos)
default boolean isFertile(IBlockState state, IWorldReader world, BlockPos pos)
{
if (this.getBlock() == Blocks.FARMLAND)
{
return world.getBlockState(pos).getValue(BlockFarmland.MOISTURE) > 0;
}
return state.getValue(BlockFarmland.MOISTURE) > 0;
return false;
}
@ -618,7 +609,7 @@ public interface IForgeBlock
* @param beacon Beacon position in world
* @return True, to support the beacon, and make it active with this block.
*/
default boolean isBeaconBase(IWorldReader world, BlockPos pos, BlockPos beacon)
default boolean isBeaconBase(IBlockState state, IWorldReader world, BlockPos pos, BlockPos beacon)
{
return this.getBlock() == Blocks.EMERALD_BLOCK || this.getBlock() == Blocks.GOLD_BLOCK ||
this.getBlock() == Blocks.DIAMOND_BLOCK || this.getBlock() == Blocks.IRON_BLOCK;
@ -637,10 +628,8 @@ public interface IForgeBlock
return 0;
}
default boolean rotateBlock(World world, BlockPos pos, EnumFacing axis)
default boolean rotateBlock(IBlockState state, IWorld world, BlockPos pos, EnumFacing axis)
{
IBlockState state = world.getBlockState(pos);
state.func_206871_b().keySet().forEach(prop ->
{
if (prop.getName().equals("facing") || prop.getName().equals("rotation") && prop.getValueClass() == EnumFacing.class)
@ -673,7 +662,7 @@ public interface IForgeBlock
}
}
world.setBlockState(pos, newState);
world.setBlockState(pos, newState, 3);
}
}
@ -688,7 +677,7 @@ public interface IForgeBlock
* @param pos Block position in world
* @return The amount of enchanting power this block produces.
*/
default float getEnchantPowerBouns(World world, BlockPos pos)
default float getEnchantPowerBonus(IBlockState state, IWorldReader world, BlockPos pos)
{
return this.getBlock() == Blocks.BOOKSHELF ? 1: 0;
}
@ -703,7 +692,7 @@ public interface IForgeBlock
* @param fortune
* @return Amount of XP from breaking this block.
*/
default boolean recolorBlock(World world, BlockPos pos, EnumFacing facing, EnumDyeColor color)
default boolean recolorBlock(IBlockState state, IWorld world, BlockPos pos, EnumFacing facing, EnumDyeColor color)
{
return false;
}
@ -714,7 +703,7 @@ public interface IForgeBlock
* @param pos Block position in world
* @param neighbor Block position of neighbor
*/
default void onNeighborChange(IWorldReader world, BlockPos pos, BlockPos neighbor){}
default void onNeighborChange(IBlockState state, IWorldReader world, BlockPos pos, BlockPos neighbor){}
/**
* Called on an Observer block whenever an update for an Observer is received.
@ -748,7 +737,7 @@ public interface IForgeBlock
* @param pos Block position in world
* @return true To be notified of changes
*/
default boolean getWeakChanges(IWorldReader world, BlockPos pos)
default boolean getWeakChanges(IBlockState state, IWorldReader world, BlockPos pos)
{
return false;
}
@ -756,7 +745,7 @@ public interface IForgeBlock
* Queries the class of tool required to harvest this block, if null is returned
* we assume that anything can harvest this block.
*/
String getHarvestTool(IBlockState state);
ToolType getHarvestTool(IBlockState state);
/**
* Queries the harvest level of this item stack for the specified tool class,
@ -770,14 +759,11 @@ public interface IForgeBlock
* Checks if the specified tool type is efficient on this block,
* meaning that it digs at full speed.
*/
default boolean isToolEffective(String type, IBlockState state)
default boolean isToolEffective(IBlockState state, ToolType tool)
{
if ("pickaxe".equals(type) && (this.getBlock() == Blocks.REDSTONE_ORE || this.getBlock() == Blocks.REDSTONE_LAMP
|| this.getBlock() == Blocks.OBSIDIAN))
{
if (tool == ToolType.PICKAXE && (this.getBlock() == Blocks.REDSTONE_ORE || this.getBlock() == Blocks.REDSTONE_LAMP || this.getBlock() == Blocks.OBSIDIAN))
return false;
}
return type != null && type.equals(getHarvestTool(state));
return tool == getHarvestTool(state);
}
/**
@ -794,7 +780,6 @@ public interface IForgeBlock
*
* @param world that is being tested.
* @param blockpos position thats being tested.
* @param iblockstate state at world/blockpos
* @param entity that is being tested.
* @param yToTest, primarily for testingHead, which sends the the eye level of the entity, other wise it sends a y that can be tested vs liquid height.
* @param materialIn to test for.
@ -802,7 +787,7 @@ public interface IForgeBlock
* @return null for default behavior, true if the entity is within the material, false if it was not.
*/
@Nullable
default Boolean isEntityInsideMaterial(IWorldReader world, BlockPos blockpos, IBlockState iblockstate, Entity entity, double yToTest, Material materialIn, boolean testingHead)
default Boolean isEntityInsideMaterial(IBlockState state, IWorldReader world, BlockPos blockpos, Entity entity, double yToTest, Material materialIn, boolean testingHead)
{
return null;
}
@ -818,7 +803,7 @@ public interface IForgeBlock
* @return null for default behavior, true if the box is within the material, false if it was not.
*/
@Nullable
default Boolean isAABBInsideMaterial(World world, BlockPos pos, AxisAlignedBB boundingBox, Material materialIn)
default Boolean isAABBInsideMaterial(IBlockState state, IWorldReader world, BlockPos pos, AxisAlignedBB boundingBox, Material materialIn)
{
return null;
}
@ -832,7 +817,7 @@ public interface IForgeBlock
* @return null for default behavior, true if the box is within the material, false if it was not.
*/
@Nullable
default Boolean isAABBInsideLiquid(World world, BlockPos pos, AxisAlignedBB boundingBox)
default Boolean isAABBInsideLiquid(IBlockState state, IWorldReader world, BlockPos pos, AxisAlignedBB boundingBox)
{
return null;
}
@ -855,7 +840,7 @@ public interface IForgeBlock
* @param entity The entity that is breaking/stepping on/placing/hitting/falling on this block, or null if no entity is in this context
* @return A SoundType to use
*/
default SoundType getSoundType(IBlockState state, World world, BlockPos pos, @Nullable Entity entity)
default SoundType getSoundType(IBlockState state, IWorldReader world, BlockPos pos, @Nullable Entity entity)
{
return this.getBlock().getSoundType();
}
@ -868,7 +853,7 @@ public interface IForgeBlock
* @return A float RGB [0.0, 1.0] array to be averaged with a beacon's existing beam color, or null to do nothing to the beam
*/
@Nullable
default float[] getBeaconColorMultiplier(IBlockState state, World world, BlockPos pos, BlockPos beaconPos)
default float[] getBeaconColorMultiplier(IBlockState state, IWorldReader world, BlockPos pos, BlockPos beaconPos)
{
return null;
}
@ -885,7 +870,7 @@ public interface IForgeBlock
* @return The new fog color.
*/
@OnlyIn(Dist.CLIENT)
default Vec3d getFogColor(World world, BlockPos pos, IBlockState state, Entity entity, Vec3d originalColor, float partialTicks)
default Vec3d getFogColor(IBlockState state, IWorldReader world, BlockPos pos, Entity entity, Vec3d originalColor, float partialTicks)
{
if (state.getMaterial() == Material.WATER)
{
@ -939,6 +924,7 @@ public interface IForgeBlock
* @param hand The player hand used to place this block
* @return The state to be placed in the world
*/
@SuppressWarnings("deprecation")
default IBlockState getStateForPlacement(IBlockState state, EnumFacing facing, IBlockState state2, IWorld world, BlockPos pos1, BlockPos pos2, EnumHand hand)
{
return this.getBlock().func_196271_a(state, facing, state2, world, pos1, pos2);
@ -953,7 +939,7 @@ public interface IForgeBlock
* @param facing The side the connecting block is on
* @return True to allow another block to connect to this block
*/
default boolean canBeConnectedTo(IWorldReader world, BlockPos pos, EnumFacing facing)
default boolean canBeConnectedTo(IBlockState state, IWorldReader world, BlockPos pos, EnumFacing facing)
{
return false;
}
@ -976,6 +962,7 @@ public interface IForgeBlock
* @param side The side of this block that the chest lid is trying to open into
* @return true if the chest should be prevented from opening by this block
*/
@SuppressWarnings("deprecation")
default boolean doesSideBlockChestOpening(IBlockState blockState, IWorldReader world, BlockPos pos, EnumFacing side)
{
ResourceLocation registryName = this.getBlock().getRegistryName();

View File

@ -0,0 +1,820 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.common.extensions;
import java.util.function.Predicate;
import javax.annotation.Nullable;
import net.minecraft.block.*;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.particle.ParticleManager;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.EntitySpawnPlacementRegistry.SpawnPlacementType;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Explosion;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.common.ToolType;
public interface IForgeBlockState
{
default IBlockState getBlockState()
{
return (IBlockState)this;
}
/**
* Gets the slipperiness at the given location at the given state. Normally
* between 0 and 1.
* <p>
* Note that entities may reduce slipperiness by a certain factor of their own;
* for {@link net.minecraft.entity.EntityLivingBase}, this is {@code .91}.
* {@link net.minecraft.entity.item.EntityItem} uses {@code .98}, and
* {@link net.minecraft.entity.projectile.EntityFishHook} uses {@code .92}.
*
* @param world the world
* @param pos the position in the world
* @param entity the entity in question
* @return the factor by which the entity's motion should be multiplied
*/
default float getSlipperiness(IWorldReader world, BlockPos pos, @Nullable Entity entity)
{
return getBlockState().getBlock().getSlipperiness(getBlockState(), world, pos, entity);
}
/**
* Get a light value for this block, taking into account the given state and coordinates, normal ranges are between 0 and 15
*/
default int getLightValue(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().getLightValue(getBlockState(), world, pos);
}
/**
* Checks if a player or entity can use this block to 'climb' like a ladder.
*
* @param world The current world
* @param pos Block position in world
* @param entity The entity trying to use the ladder, CAN be null.
* @return True if the block should act like a ladder
*/
default boolean isLadder(IWorldReader world, BlockPos pos, EntityLivingBase entity)
{
return getBlockState().getBlock().isLadder(getBlockState(), world, pos, entity);
}
/**
* Return true if the block is a normal, solid cube. This
* determines indirect power state, entity ejection from blocks, and a few
* others.
*
* @param world The current world
* @param pos Block position in world
* @return True if the block is a full cube
*/
default boolean isNormalCube(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().isNormalCube(getBlockState(), world, pos);
}
/**
* Check if the face of a block should block rendering.
*
* Faces which are fully opaque should return true, faces with transparency
* or faces which do not span the full size of the block should return false.
*
* @param world The current world
* @param pos Block position in world
* @param face The side to check
* @return True if the block is opaque on the specified side.
*/
default boolean doesSideBlockRendering(IWorldReader world, BlockPos pos, EnumFacing face)
{
return getBlockState().getBlock().doesSideBlockRendering(getBlockState(), world, pos, face);
}
/**
* Called throughout the code as a replacement for block instanceof BlockContainer
* Moving this to the Block base class allows for mods that wish to extend vanilla
* blocks, and also want to have a tile entity on that block, may.
*
* Return true from this function to specify this block has a tile entity.
*
* @return True if block has a tile entity, false otherwise
*/
default boolean hasTileEntity()
{
return getBlockState().getBlock().hasTileEntity(getBlockState());
}
default boolean canSilkHarvest(IWorldReader world, BlockPos pos, EntityPlayer player)
{
return getBlockState().getBlock().canSilkHarvest(getBlockState(), world, pos, player);
}
/**
* Determines if this block is classified as a Bed, Allowing
* players to sleep in it, though the block has to specifically
* perform the sleeping functionality in it's activated event.
*
* @param world The current world
* @param pos Block position in world
* @param player The player or camera entity, null in some cases.
* @return True to treat this as a bed
*/
default boolean isBed(IWorldReader world, BlockPos pos, @Nullable EntityPlayer player)
{
return getBlockState().getBlock().isBed(getBlockState(), world, pos, player);
}
/**
* Determines if a specified mob type can spawn on this block, returning false will
* prevent any mob from spawning on the block.
*
* @param world The current world
* @param pos Block position in world
* @param type The Mob Category Type
* @return True to allow a mob of the specified category to spawn, false to prevent it.
*/
default boolean canCreatureSpawn(IWorldReader world, BlockPos pos, SpawnPlacementType type)
{
return getBlockState().getBlock().canCreatureSpawn(getBlockState(), world, pos, type);
}
/**
* Returns the position that the player is moved to upon
* waking up, or respawning at the bed.
*
* @param world The current world
* @param pos Block position in world
* @param player The player or camera entity, null in some cases.
* @return The spawn position
*/
@Nullable
default BlockPos getBedSpawnPosition(IWorldReader world, BlockPos pos, @Nullable EntityPlayer player)
{
return getBlockState().getBlock().getBedSpawnPosition(getBlockState(), world, pos, player);
}
/**
* Called when a user either starts or stops sleeping in the bed.
*
* @param world The current world
* @param pos Block position in world
* @param player The player or camera entity, null in some cases.
* @param occupied True if we are occupying the bed, or false if they are stopping use of the bed
*/
default void setBedOccupied(IWorldReader world, BlockPos pos, EntityPlayer player, boolean occupied)
{
getBlockState().getBlock().setBedOccupied(getBlockState(), world, pos, player, occupied);
}
/**
* Returns the direction of the block. Same values that
* are returned by BlockDirectional
*
* @param world The current world
* @param pos Block position in world
* @return Bed direction
*/
default EnumFacing getBedDirection(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().getBedDirection(getBlockState(), world, pos);
}
/**
* Determines if the current block is the foot half of the bed.
*
* @param world The current world
* @param pos Block position in world
* @return True if the current block is the foot side of a bed.
*/
default boolean isBedFoot(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().isBedFoot(getBlockState(), world, pos);
}
/**
* Called when a leaf should start its decay process.
*
* @param world The current world
* @param pos Block position in world
*/
default void beginLeaveDecay(IWorldReader world, BlockPos pos)
{
getBlockState().getBlock().beginLeaveDecay(getBlockState(), world, pos);
}
/**
* Determines if this block can prevent leaves connected to it from decaying.
* @param world The current world
* @param pos Block position in world
* @return true if the presence this block can prevent leaves from decaying.
*/
default boolean canSustainLeaves(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().canSustainLeaves(getBlockState(), world, pos);
}
/**
* Determines if this block is considered a leaf block, used to apply the leaf decay and generation system.
*
* @param world The current world
* @param pos Block position in world
* @return true if this block is considered leaves.
*/
default boolean isLeaves(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().isLeaves(getBlockState(), world, pos);
}
/**
* Determines this block should be treated as an air block
* by the rest of the code. This method is primarily
* useful for creating pure logic-blocks that will be invisible
* to the player and otherwise interact as air would.
*
* @param world The current world
* @param pos Block position in world
* @return True if the block considered air
*/
default boolean isAir(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().isAir(getBlockState(), world, pos);
}
/**
* Used during tree growth to determine if newly generated leaves can replace this block.
*
* @param world The current world
* @param pos Block position in world
* @return true if this block can be replaced by growing leaves.
*/
default boolean canBeReplacedByLeaves(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().canBeReplacedByLeaves(getBlockState(), world, pos);
}
/**
*
* @param world The current world
* @param pos Block position in world
* @return true if the block is wood (logs)
*/
default boolean isWood(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().isWood(getBlockState(), world, pos);
}
/**
* Determines if the current block is replaceable by Ore veins during world generation.
*
* @param world The current world
* @param pos Block position in world
* @param target The generic target block the gen is looking for, Standards define stone
* for overworld generation, and neatherack for the nether.
* @return True to allow this block to be replaced by a ore
*/
default boolean isReplaceableOreGen(IWorldReader world, BlockPos pos, Predicate<IBlockState> target)
{
return getBlockState().getBlock().isReplaceableOreGen(getBlockState(), world, pos, target);
}
/**
* Location sensitive version of getExplosionResistance
*
* @param world The current world
* @param pos Block position in world
* @param exploder The entity that caused the explosion, can be null
* @param explosion The explosion
* @return The amount of the explosion absorbed.
*/
default float getExplosionResistance(IWorldReader world, BlockPos pos, @Nullable Entity exploder, Explosion explosion)
{
return getBlockState().getBlock().getExplosionResistance(getBlockState(), world, pos, exploder, explosion);
}
/**
* Called when the block is destroyed by an explosion.
* Useful for allowing the block to take into account tile entities,
* state, etc. when exploded, before it is removed.
*
* @param world The current world
* @param pos Block position in world
* @param explosion The explosion instance affecting the block
*/
default void onBlockExploded(World world, BlockPos pos, Explosion explosion)
{
getBlockState().getBlock().onBlockExploded(getBlockState(), world, pos, explosion);
}
/**
* Determine if this block can make a redstone connection on the side provided,
* Useful to control which sides are inputs and outputs for redstone wires.
*
* @param world The current world
* @param pos Block position in world
* @param side The side that is trying to make the connection, CAN BE NULL
* @return True to make the connection
*/
default boolean canConnectRedstone(IWorldReader world, BlockPos pos, @Nullable EnumFacing side)
{
return getBlockState().getBlock().canConnectRedstone(getBlockState(), world, pos, side);
}
/**
* Determines if a torch can be placed on the top surface of this block.
* Useful for creating your own block that torches can be on, such as fences.
*
* @param world The current world
* @param pos Block position in world
* @return True to allow the torch to be placed
*/
default boolean canPlaceTorchOnTop(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().canPlaceTorchOnTop(getBlockState(), world, pos);
}
/**
*
* Called when A user uses the creative pick block button on this block
*
* @param target The full target the player is looking at
* @return A ItemStack to add to the player's inventory, empty itemstack if nothing should be added.
*/
default ItemStack getPickBlock(RayTraceResult target, IBlockReader world, BlockPos pos, EntityPlayer player)
{
return getBlockState().getBlock().getPickBlock(getBlockState(), target, world, pos, player);
}
/**
* Used by getTopSoilidOrLiquidBlock while placing biome decorations, villages, etc
* Also used to determine if the player can spawn in this block.
*
* @return False to disallow spawning.
*/
default boolean isFoliage(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().isFoliage(getBlockState(), world, pos);
}
/**
* Allows a block to override the standard EntityLivingBase.updateFallState
* particles, this is a server side method that spawns particles with
* WorldServer.spawnParticle.
*
* @param worldserver The current Server World
* @param pos The position of the block.
* @param state2 The state at the specific world/pos
* @param entity The entity that hit landed on the block
* @param numberOfParticles That vanilla world have spawned
* @return True to prevent vanilla landing particles from spawning
*/
default boolean addLandingEffects(WorldServer worldserver, BlockPos pos, IBlockState state2, EntityLivingBase entity, int numberOfParticles)
{
return getBlockState().getBlock().addLandingEffects(getBlockState(), worldserver, pos, state2, entity, numberOfParticles);
}
/**
* Allows a block to override the standard vanilla running particles.
* This is called from {@link Entity#spawnRunningParticles} and is called both,
* Client and server side, it's up to the implementor to client check / server check.
* By default vanilla spawns particles only on the client and the server methods no-op.
*
* @param world The world.
* @param pos The position at the entities feet.
* @param entity The entity running on the block.
* @return True to prevent vanilla running particles from spawning.
*/
default boolean addRunningEffects(World world, BlockPos pos, Entity entity)
{
return getBlockState().getBlock().addRunningEffects(getBlockState(), world, pos, entity);
}
/**
* Spawn particles for when the block is destroyed. Due to the nature
* of how this is invoked, the x/y/z locations are not always guaranteed
* to host your block. So be sure to do proper sanity checks before assuming
* that the location is this block.
*
* @param world The current world
* @param pos Position to spawn the particle
* @param manager A reference to the current particle manager.
* @return True to prevent vanilla break particles from spawning.
*/
@OnlyIn(Dist.CLIENT)
default boolean addDestroyEffects(World world, BlockPos pos, ParticleManager manager)
{
return getBlockState().getBlock().addDestroyEffects(getBlockState(), world, pos, manager);
}
/**
* Determines if this block can support the passed in plant, allowing it to be planted and grow.
* Some examples:
* Reeds check if its a reed, or if its sand/dirt/grass and adjacent to water
* Cacti checks if its a cacti, or if its sand
* Nether types check for soul sand
* Crops check for tilled soil
* Caves check if it's a solid surface
* Plains check if its grass or dirt
* Water check if its still water
*
* @param world The current world
* @param facing The direction relative to the given position the plant wants to be, typically its UP
* @param plantable The plant that wants to check
* @return True to allow the plant to be planted/stay.
*/
default boolean canSustainPlant(IWorldReader world, BlockPos pos, EnumFacing facing, IPlantable plantable)
{
return getBlockState().getBlock().canSustainPlant(getBlockState(), world, pos, facing, plantable);
}
/**
* Called when a plant grows on this block, only implemented for saplings using the WorldGen*Trees classes right now.
* Modder may implement this for custom plants.
* This does not use ForgeDirection, because large/huge trees can be located in non-representable direction,
* so the source location is specified.
* Currently this just changes the block to dirt if it was grass.
*
* Note: This happens DURING the generation, the generation may not be complete when this is called.
*
* @param world Current world
* @param pos Block position in world
* @param source Source plant's position in world
*/
default void onPlantGrow(World world, BlockPos pos, BlockPos source)
{
getBlockState().getBlock().onPlantGrow(getBlockState(), world, pos, source);
}
/**
* Checks if this soil is fertile, typically this means that growth rates
* of plants on this soil will be slightly sped up.
* Only vanilla case is tilledField when it is within range of water.
*
* @param world The current world
* @param pos Block position in world
* @return True if the soil should be considered fertile.
*/
default boolean isFertile(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().isFertile(getBlockState(), world, pos);
}
/**
* Location aware and overrideable version of the lightOpacity array,
* return the number to subtract from the light value when it passes through this block.
*
* This is not guaranteed to have the tile entity in place before this is called, so it is
* Recommended that you have your tile entity call relight after being placed if you
* rely on it for light info.
*
* @param state The Block state
* @param world The current world
* @param pos Block position in world
* @return The amount of light to block, 0 for air, 255 for fully opaque.
*/
default int getLightOpacity(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().getLightOpacity(getBlockState(), world, pos);
}
/**
* Determines if this block can be used as the base of a beacon.
*
* @param world The current world
* @param pos Block position in world
* @param beacon Beacon position in world
* @return True, to support the beacon, and make it active with this block.
*/
default boolean isBeaconBase(IWorldReader world, BlockPos pos, BlockPos beacon)
{
return getBlockState().getBlock().isBeaconBase(getBlockState(), world, pos, beacon);
}
/**
* Gathers how much experience this block drops when broken.
*
* @param world The world
* @param pos Block position
* @param fortune
* @return Amount of XP from breaking this block.
*/
default int getExpDrop(IWorldReader world, BlockPos pos, int fortune)
{
return getBlockState().getBlock().getExpDrop(getBlockState(), world, pos, fortune);
}
default boolean rotateBlock(IWorld world, BlockPos pos, EnumFacing axis)
{
return getBlockState().getBlock().rotateBlock(getBlockState(), world, pos, axis);
}
/**
* Determines the amount of enchanting power this block can provide to an enchanting table.
* @param world The World
* @param pos Block position in world
* @return The amount of enchanting power this block produces.
*/
default float getEnchantPowerBonus(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().getEnchantPowerBonus(getBlockState(), world, pos);
}
default boolean recolorBlock(IWorld world, BlockPos pos, EnumFacing facing, EnumDyeColor color)
{
return getBlockState().getBlock().recolorBlock(getBlockState(), world, pos, facing, color);
}
/**
* Called when a tile entity on a side of this block changes is created or is destroyed.
* @param world The world
* @param pos Block position in world
* @param neighbor Block position of neighbor
*/
default void onNeighborChange(IWorldReader world, BlockPos pos, BlockPos neighbor)
{
getBlockState().getBlock().onNeighborChange(getBlockState(), world, pos, neighbor);
}
/**
* Called on an Observer block whenever an update for an Observer is received.
*
* @param observerState The Observer block's state.
* @param world The current world.
* @param pos The Observer block's position.
* @param changed The updated block.
* @param changedPos The updated block's position.
*/
default void observedNeighborChange(World world, BlockPos pos, Block changed, BlockPos changedPos)
{
getBlockState().getBlock().observedNeighborChange(getBlockState(), world, pos, changed, changedPos);
}
/**
* Called to determine whether to allow the a block to handle its own indirect power rather than using the default rules.
* @param world The world
* @param pos Block position in world
* @param side The INPUT side of the block to be powered - ie the opposite of this block's output side
* @return Whether Block#isProvidingWeakPower should be called when determining indirect power
*/
default boolean shouldCheckWeakPower(IWorldReader world, BlockPos pos, EnumFacing side)
{
return getBlockState().getBlock().shouldCheckWeakPower(getBlockState(), world, pos, side);
}
/**
* If this block should be notified of weak changes.
* Weak changes are changes 1 block away through a solid block.
* Similar to comparators.
*
* @param world The current world
* @param pos Block position in world
* @return true To be notified of changes
*/
default boolean getWeakChanges(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().getWeakChanges(getBlockState(), world, pos);
}
/**
* Queries the class of tool required to harvest this block, if null is returned
* we assume that anything can harvest this block.
*/
default ToolType getHarvestTool()
{
return getBlockState().getBlock().getHarvestTool(getBlockState());
}
default int getHarvestLevel()
{
return getBlockState().getBlock().getHarvestLevel(getBlockState());
}
/**
* Checks if the specified tool type is efficient on this block,
* meaning that it digs at full speed.
*/
default boolean isToolEffective(ToolType tool)
{
return getBlockState().getBlock().isToolEffective(getBlockState(), tool);
}
/**
* Can return IExtendedBlockState
*/
default IBlockState getExtendedState(IBlockReader world, BlockPos pos)
{
return getBlockState().getBlock().getExtendedState(getBlockState(), world, pos);
}
/**
* Called when the entity is inside this block, may be used to determined if the entity can breathing,
* display material overlays, or if the entity can swim inside a block.
*
* @param world that is being tested.
* @param pos position thats being tested.
* @param entity that is being tested.
* @param yToTest, primarily for testingHead, which sends the the eye level of the entity, other wise it sends a y that can be tested vs liquid height.
* @param material to test for.
* @param testingHead when true, its testing the entities head for vision, breathing ect... otherwise its testing the body, for swimming and movement adjustment.
* @return null for default behavior, true if the entity is within the material, false if it was not.
*/
@Nullable
default Boolean isEntityInsideMaterial(IWorldReader world, BlockPos pos, Entity entity, double yToTest, Material material, boolean testingHead)
{
return getBlockState().getBlock().isEntityInsideMaterial(getBlockState(), world, pos, entity, yToTest, material, testingHead);
}
/**
* Called when boats or fishing hooks are inside the block to check if they are inside
* the material requested.
*
* @param world world that is being tested.
* @param pos block thats being tested.
* @param boundingBox box to test, generally the bounds of an entity that are besting tested.
* @param material to check for.
* @return null for default behavior, true if the box is within the material, false if it was not.
*/
@Nullable
default Boolean isAABBInsideMaterial(IWorldReader world, BlockPos pos, AxisAlignedBB boundingBox, Material material)
{
return getBlockState().getBlock().isAABBInsideMaterial(getBlockState(), world, pos, boundingBox, material);
}
/**
* Called when entities are moving to check if they are inside a liquid
*
* @param world world that is being tested.
* @param pos block thats being tested.
* @param boundingBox box to test, generally the bounds of an entity that are besting tested.
* @return null for default behavior, true if the box is within the material, false if it was not.
*/
@Nullable
default Boolean isAABBInsideLiquid(IWorldReader world, BlockPos pos, AxisAlignedBB boundingBox)
{
return getBlockState().getBlock().isAABBInsideLiquid(getBlockState(), world, pos, boundingBox);
}
/**
* Queries if this block should render in a given layer.
* ISmartBlockModel can use {@link net.minecraftforge.client.MinecraftForgeClient#getRenderLayer()} to alter their model based on layer.
*/
default boolean canRenderInLayer(BlockRenderLayer layer)
{
return getBlockState().getBlock().canRenderInLayer(getBlockState(), layer);
}
/**
* Sensitive version of getSoundType
* @param world The world
* @param pos The position. Note that the world may not necessarily have {@code state} here!
* @param entity The entity that is breaking/stepping on/placing/hitting/falling on this block, or null if no entity is in this context
* @return A SoundType to use
*/
default SoundType getSoundType(IWorldReader world, BlockPos pos, @Nullable Entity entity)
{
return getBlockState().getBlock().getSoundType(getBlockState(), world, pos, entity);
}
/**
* @param world The world
* @param pos The position of this state
* @param beaconPos The position of the beacon
* @return A float RGB [0.0, 1.0] array to be averaged with a beacon's existing beam color, or null to do nothing to the beam
*/
@Nullable
default float[] getBeaconColorMultiplier(IWorldReader world, BlockPos pos, BlockPos beacon)
{
return getBlockState().getBlock().getBeaconColorMultiplier(getBlockState(), world, pos, beacon);
}
/**
* Use this to change the fog color used when the entity is "inside" a material.
* Vec3d is used here as "r/g/b" 0 - 1 values.
*
* @param world The world.
* @param pos The position at the entity viewport.
* @param entity the entity
* @param originalColor The current fog color, You are not expected to use this, Return as the default if applicable.
* @return The new fog color.
*/
@OnlyIn(Dist.CLIENT)
default Vec3d getFogColor(IWorldReader world, BlockPos pos, Entity entity, Vec3d originalColor, float partialTicks)
{
return getBlockState().getBlock().getFogColor(getBlockState(), world, pos, entity, originalColor, partialTicks);
}
/**
* Used to determine the state 'viewed' by an entity (see
* {@link ActiveRenderInfo#getBlockStateAtEntityViewpoint(World, Entity, float)}).
* Can be used by fluid blocks to determine if the viewpoint is within the fluid or not.
*
* @param world the world
* @param pos the position
* @param viewpoint the viewpoint
* @return the block state that should be 'seen'
*/
default IBlockState getStateAtViewpoint(IWorldReader world, BlockPos pos, Vec3d viewpoint)
{
return getBlockState().getBlock().getStateAtViewpoint(getBlockState(), world, pos, viewpoint);
}
/** //TODO: Re-Evaluate
* Gets the {@link IBlockState} to place
* @param world The world the block is being placed in
* @param pos The position the block is being placed at
* @param facing The side the block is being placed on
* @param hitX The X coordinate of the hit vector
* @param hitY The Y coordinate of the hit vector
* @param hitZ The Z coordinate of the hit vector
* @param meta The metadata of {@link ItemStack} as processed by {@link Item#getMetadata(int)}
* @param placer The entity placing the block
* @param hand The player hand used to place this block
* @return The state to be placed in the world
*/
default IBlockState getStateForPlacement(EnumFacing facing, IBlockState state2, IWorld world, BlockPos pos1, BlockPos pos2, EnumHand hand)
{
return getBlockState().getBlock().getStateForPlacement(getBlockState(), facing, state2, world, pos1, pos2, hand);
}
/**
* Determines if another block can connect to this block
*
* @param world The current world
* @param pos The position of this block
* @param facing The side the connecting block is on
* @return True to allow another block to connect to this block
*/
default boolean canBeConnectedTo(IWorldReader world, BlockPos pos, EnumFacing facing)
{
return getBlockState().getBlock().canBeConnectedTo(getBlockState(), world, pos, facing);
}
/**
* Get the {@code PathNodeType} for this block. Return {@code null} for vanilla behavior.
*
* @return the PathNodeType
*/
@Nullable
default PathNodeType getAiPathNodeType(IWorldReader world, BlockPos pos)
{
return getBlockState().getBlock().getAiPathNodeType(getBlockState(), world, pos);
}
/**
* @param blockState The state for this block
* @param world The world this block is in
* @param pos The position of this block
* @param side The side of this block that the chest lid is trying to open into
* @return true if the chest should be prevented from opening by this block
*/
default boolean doesSideBlockChestOpening(IWorldReader world, BlockPos pos, EnumFacing side)
{
return getBlockState().getBlock().doesSideBlockChestOpening(getBlockState(), world, pos, side);
}
/**
* @param state The state
* @return true if the block is sticky block which used for pull or push adjacent blocks (use by piston)
*/
default boolean isStickyBlock()
{
return getBlockState().getBlock().isStickyBlock(getBlockState());
}
}

View File

@ -1,14 +1,18 @@
package net.minecraftforge.common.extensions;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.collect.Multimap;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.passive.EntityHorse;
import net.minecraft.entity.passive.HorseArmorType;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
@ -30,6 +34,7 @@ import net.minecraft.world.GameType;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.ToolType;
// TODO review most of the methods in this "patch"
public interface IForgeItem
@ -43,6 +48,7 @@ public interface IForgeItem
/**
* ItemStack sensitive version of getItemAttributeModifiers
*/
@SuppressWarnings("deprecation")
default Multimap<String, AttributeModifier> getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack)
{
return getItem().getItemAttributeModifiers(slot);
@ -87,7 +93,7 @@ public interface IForgeItem
/**
* Called by CraftingManager to determine if an item is reparable.
*
*
* @return True if reparable
*/
boolean isRepairable();
@ -114,7 +120,7 @@ public interface IForgeItem
/**
* Override this method to decide what to do with the NBT data received from
* getNBTShareTag().
*
*
* @param stack The stack that received NBT
* @param nbt Received NBT, can be null
*/
@ -141,7 +147,7 @@ public interface IForgeItem
/**
* Called each tick while using an item.
*
*
* @param stack The Item being used
* @param player The Player using the item
* @param count The amount of time in tick the item has been used for
@ -184,10 +190,11 @@ public interface IForgeItem
/**
* ItemStack sensitive version of hasContainerItem
*
*
* @param stack The current item stack
* @return True if this item has a 'container'
*/
@SuppressWarnings("deprecation")
default boolean hasContainerItem(ItemStack stack)
{
return getItem().hasContainerItem();
@ -220,7 +227,7 @@ public interface IForgeItem
{
return false;
}
/**
* This function should return a new entity to replace the dropped item.
* Returning null here will not kill the EntityItem and will leave it to
@ -476,6 +483,7 @@ public interface IForgeItem
* @param stack The itemstack that is damaged
* @return the damage value
*/
@SuppressWarnings("deprecation")
default int getMaxDamage(ItemStack stack)
{
return getItem().getMaxDamage();
@ -484,7 +492,7 @@ public interface IForgeItem
/**
* Return if this itemstack is damaged. Note only called if
* {@link #isDamageable()} is true.
*
*
* @param stack the stack
* @return if the stack is damaged
*/
@ -496,7 +504,7 @@ public interface IForgeItem
/**
* Set the damage for this itemstack. Note, this method is responsible for zero
* checking.
*
*
* @param stack the stack
* @param damage the new damage value
*/
@ -512,7 +520,7 @@ public interface IForgeItem
* a block with this item. Also checked from
* {@link net.minecraftforge.common.ForgeHooks#onBlockBreakEvent(World, GameType, EntityPlayerMP, BlockPos)
* ForgeHooks.onBlockBreakEvent()} to prevent sending an event.
*
*
* @return true if the given player can destroy specified block in creative mode
* with this item
*/
@ -523,12 +531,12 @@ public interface IForgeItem
/**
* ItemStack sensitive version of {@link #canHarvestBlock(IBlockState)}
*
* @param state The block trying to harvest
*
* @param stack The itemstack used to harvest the block
* @param state The block trying to harvest
* @return true if can harvest the block
*/
default boolean canHarvestBlock(IBlockState state, ItemStack stack)
default boolean canHarvestBlock(ItemStack stack, IBlockState state)
{
return getItem().canHarvestBlock(state);
}
@ -540,12 +548,13 @@ public interface IForgeItem
* @param stack The ItemStack
* @return The maximum number this item can be stacked to
*/
@SuppressWarnings("deprecation")
default int getItemStackLimit(ItemStack stack)
{
return getItem().getItemStackLimit();
}
java.util.Set<String> getToolClasses(ItemStack stack);
Set<ToolType> getToolTypes(ItemStack stack);
/**
* Queries the harvest level of this item stack for the specified tool class,
@ -557,7 +566,7 @@ public interface IForgeItem
* @param blockState The block to harvest
* @return Harvest level, or -1 if not the specified tool type.
*/
int getHarvestLevel(ItemStack stack, String toolClass, @Nullable EntityPlayer player, @Nullable IBlockState blockState);
int getHarvestLevel(ItemStack stack, ToolType tool, @Nullable EntityPlayer player, @Nullable IBlockState blockState);
/**
* ItemStack sensitive version of getItemEnchantability
@ -578,7 +587,7 @@ public interface IForgeItem
* {@link net.minecraft.enchantment.Enchantment#canApplyAtEnchantingTable(ItemStack)};
* check the individual implementation for reference. By default this will check
* if the enchantment type is valid for this item type.
*
*
* @param stack the item stack to be enchanted
* @param enchantment the enchantment to be applied
* @return true if the enchantment can be applied to this item
@ -590,7 +599,7 @@ public interface IForgeItem
/**
* Whether this Item can be used as a payment to activate the vanilla beacon.
*
*
* @param stack the ItemStack
* @return true if this Item can be used
*/
@ -601,7 +610,7 @@ public interface IForgeItem
/**
* Determine if the player switching between these two item stacks
*
*
* @param oldStack The old stack that was equipped
* @param newStack The new stack
* @param slotChanged If the current equipped slot was changed, Vanilla does not
@ -617,7 +626,7 @@ public interface IForgeItem
/**
* Called when the player is mining a block and the item in his hand changes.
* Allows to not reset blockbreaking if only NBT or similar changes.
*
*
* @param oldStack The old stack that was used for mining. Item in players main
* hand
* @param newStack The new stack
@ -684,7 +693,7 @@ public interface IForgeItem
/**
* Can this Item disable a shield
*
*
* @param stack The ItemStack
* @param shield The shield in question
* @param entity The EntityLivingBase holding the shield
@ -698,7 +707,7 @@ public interface IForgeItem
/**
* Is this Item a shield
*
*
* @param stack The ItemStack
* @param entity The Entity holding the ItemStack
* @return True if the ItemStack is considered a shield
@ -713,7 +722,7 @@ public interface IForgeItem
* it not act as a fuel. Return -1 to let the default vanilla logic
* decide.
*/
default int getItemBurnTime(ItemStack itemStack)
default int getBurnTime(ItemStack itemStack)
{
return -1;
}
@ -722,17 +731,17 @@ public interface IForgeItem
* Returns an enum constant of type {@code HorseArmorType}. The returned enum
* constant will be used to determine the armor value and texture of this item
* when equipped.
*
*
* @param stack the armor stack
* @return an enum constant of type {@code HorseArmorType}. Return
* HorseArmorType.NONE if this is not horse armor
*/
default net.minecraft.entity.passive.HorseArmorType getHorseArmorType(ItemStack stack)
default HorseArmorType getHorseArmorType(ItemStack stack)
{
return net.minecraft.entity.passive.HorseArmorType.getByItem(stack.getItem());
return HorseArmorType.getByItem(stack.getItem());
}
default String getHorseArmorTexture(net.minecraft.entity.EntityLiving wearer, ItemStack stack)
default String getHorseArmorTexture(EntityLiving wearer, ItemStack stack)
{
return getHorseArmorType(stack).getTextureName();
}
@ -740,12 +749,12 @@ public interface IForgeItem
/**
* Called every tick from {@link EntityHorse#onUpdate()} on the item in the
* armor slot.
*
*
* @param world the world the horse is in
* @param horse the horse wearing this armor
* @param armor the armor itemstack
*/
default void onHorseArmorTick(World world, net.minecraft.entity.EntityLiving horse, ItemStack armor)
default void onHorseArmorTick(World world, EntityLiving horse, ItemStack armor)
{
}

View File

@ -1,11 +1,20 @@
package net.minecraftforge.common.extensions;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.ToolType;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
/*
* Extension added to ItemStack that bounces to ItemSack sensitive Item methods. Typically this is just for convince.
*/
public interface IForgeItemStack
public interface IForgeItemStack extends ICapabilitySerializable<NBTTagCompound>
{
// Helpers for accessing Item data
default ItemStack getStack()
@ -36,4 +45,33 @@ public interface IForgeItemStack
return getStack().getItem().hasContainerItem(getStack());
}
/**
* @return the fuel burn time for this itemStack in a furnace. Return 0 to make
* it not act as a fuel. Return -1 to let the default vanilla logic
* decide.
*/
default int getBurnTime()
{
return getStack().getItem().getBurnTime(getStack());
}
/**
* Queries the harvest level of this item stack for the specified tool class,
* Returns -1 if this tool is not of the specified type
*
* @param stack This item stack instance
* @param toolClass Tool Class
* @param player The player trying to harvest the given blockstate
* @param state The block to harvest
* @return Harvest level, or -1 if not the specified tool type.
*/
default int getHarvestLevel(ToolType tool, @Nullable EntityPlayer player, @Nullable IBlockState state)
{
return getStack().getItem().getHarvestLevel(getStack(), tool, player, state);
}
default Set<ToolType> getToolTypes() {
return getStack().getItem().getToolTypes(getStack());
}
}

View File

@ -45,7 +45,7 @@ public class FakePlayer extends EntityPlayerMP
@Override public void sendStatusMessage(ITextComponent chatComponent, boolean actionBar){}
@Override public void sendMessage(ITextComponent component) {}
@Override public void addStat(StatBase par1StatBase, int par2){}
@Override public void openGui(Object mod, int modGuiId, World world, int x, int y, int z){}
//@Override public void openGui(Object mod, int modGuiId, World world, int x, int y, int z){}
@Override public boolean isEntityInvulnerable(DamageSource source){ return true; }
@Override public boolean canAttackPlayer(EntityPlayer player){ return false; }
@Override public void onDeath(DamageSource source){ return; }

View File

@ -1,69 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2018.
*
* This library 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 version 2.1
* of the License.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.event;
import net.minecraft.command.CommandHandler;
import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
/**
* CommandEvent is fired whenever a command is scheduled to be executed.
* This event is fired during the invocation of {@link CommandHandler#executeCommand(ICommandSender, String)}
* and {@link ClientCommandHandler#executeCommand(ICommandSender, String)}. <br>
* <br>
* {@link #command} contains the instance of ICommand which is representative of the currently executing command.<br>
* {@link #sender} contains the instance of ICommandSender for the given command sender.<br>
* {@link #parameters} contains the arguments passed for the command execution.<br>
* {@link #exception} begins null, but can be populated with an exception to be thrown within the command.<br>
* <br>
* This event is {@link Cancelable}. <br>
* If the event is canceled, the execution of the command does not occur.<br>
* <br>
* This event does not have a result. {@link HasResult}<br>
* <br>
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.<br>
**/
@Cancelable
public class CommandEvent extends net.minecraftforge.eventbus.api.Event
{
private final ICommand command;
private final ICommandSender sender;
private String[] parameters;
private Throwable exception;
public CommandEvent(ICommand command, ICommandSender sender, String[] parameters)
{
this.command = command;
this.sender = sender;
this.setParameters(parameters);
}
public ICommand getCommand() { return command; }
public ICommandSender getSender() { return sender; }
public String[] getParameters() { return parameters; }
public void setParameters(String[] parameters) { this.parameters = parameters; }
public Throwable getException() { return exception; }
public void setException(Throwable exception) { this.exception = exception; }
}

View File

@ -89,7 +89,6 @@ import net.minecraftforge.event.entity.EntityMountEvent;
import net.minecraftforge.event.entity.EntityStruckByLightningEvent;
import net.minecraftforge.event.entity.PlaySoundAtEntityEvent;
import net.minecraftforge.event.entity.ProjectileImpactEvent;
import net.minecraftforge.event.entity.ThrowableImpactEvent;
import net.minecraftforge.event.entity.item.ItemExpireEvent;
import net.minecraftforge.event.entity.living.AnimalTameEvent;
import net.minecraftforge.event.entity.living.LivingDestroyBlockEvent;
@ -127,7 +126,6 @@ import net.minecraftforge.event.world.BlockEvent.PlaceEvent;
import net.minecraftforge.event.world.ExplosionEvent;
import net.minecraftforge.event.world.GetCollisionBoxesEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
import net.minecraftforge.eventbus.api.Event;
import net.minecraftforge.eventbus.api.Event.Result;
import net.minecraftforge.fml.common.registry.GameRegistry;
@ -180,27 +178,6 @@ public class ForgeEventFactory
MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(player, stack, hand));
}
/**
* @deprecated use {@link #canEntitySpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} instead
*/
@Deprecated // TODO remove in 1.13
public static Result canEntitySpawn(EntityLiving entity, World world, float x, float y, float z)
{
return canEntitySpawn(entity, world, x, y, z, true);
}
/**
* @deprecated use {@link #canEntitySpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} instead
*/
@Deprecated // Still used in base game for non-spawner spawns, which is safe
public static Result canEntitySpawn(EntityLiving entity, World world, float x, float y, float z, boolean isSpawner)
{
if (entity == null)
return Result.DEFAULT;
LivingSpawnEvent.CheckSpawn event = new LivingSpawnEvent.CheckSpawn(entity, world, x, y, z, isSpawner); // TODO: replace isSpawner with null in 1.13
MinecraftForge.EVENT_BUS.post(event);
return event.getResult();
}
public static Result canEntitySpawn(EntityLiving entity, World world, float x, float y, float z, MobSpawnerBaseLogic spawner)
{
if (entity == null)
@ -223,32 +200,6 @@ public class ForgeEventFactory
}
}
/**
* @deprecated Use {@link #canEntitySpawnSpawner(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)}
*/
@Deprecated // TODO remove in 1.13
public static boolean canEntitySpawnSpawner(EntityLiving entity, World world, float x, float y, float z)
{
Result result = canEntitySpawn(entity, world, x, y, z, true);
if (result == Result.DEFAULT)
{
return entity.getCanSpawnHere() && entity.isNotColliding(); // vanilla logic
}
else
{
return result == Result.ALLOW;
}
}
/**
* @deprecated Use {@link #canEntitySpawnSpawner(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)}
*/
@Deprecated // Still used in base game for non-spawner spawns, which is safe
public static boolean doSpecialSpawn(EntityLiving entity, World world, float x, float y, float z)
{
return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z, null));
}
public static boolean doSpecialSpawn(EntityLiving entity, World world, float x, float y, float z, MobSpawnerBaseLogic spawner)
{
return MinecraftForge.EVENT_BUS.post(new LivingSpawnEvent.SpecialSpawn(entity, world, x, y, z, spawner));
@ -261,21 +212,10 @@ public class ForgeEventFactory
return event.getResult();
}
public static int getItemBurnTime(@Nonnull ItemStack itemStack)
public static int getItemBurnTime(@Nonnull ItemStack itemStack, int burnTime)
{
Item item = itemStack.getItem();
int burnTime = item.getItemBurnTime(itemStack);
FurnaceFuelBurnTimeEvent event = new FurnaceFuelBurnTimeEvent(itemStack, burnTime);
MinecraftForge.EVENT_BUS.post(event);
if (event.getBurnTime() < 0)
{
// legacy handling
int fuelValue = GameRegistry.getFuelValueLegacy(itemStack);
if (fuelValue > 0)
{
return fuelValue;
}
}
return event.getBurnTime();
}
@ -393,9 +333,7 @@ public class ForgeEventFactory
public static void firePlayerLoadingEvent(EntityPlayer player, IPlayerFileData playerFileData, String uuidString)
{
SaveHandler sh = (SaveHandler) playerFileData;
File dir = sh.getPlayersDirectory();
MinecraftForge.EVENT_BUS.post(new PlayerEvent.LoadFromFile(player, dir, uuidString));
MinecraftForge.EVENT_BUS.post(new PlayerEvent.LoadFromFile(player, ((SaveHandler)playerFileData).playersDirectory, uuidString));
}
@Nullable
@ -624,13 +562,13 @@ public class ForgeEventFactory
{
return MinecraftForge.EVENT_BUS.post(new RenderBlockOverlayEvent(player, renderPartialTicks, type, block, pos));
}
@Nullable
public static <T extends ICapabilityProvider> CapabilityDispatcher gatherCapabilities(Class<? extends T> type, T provider)
{
return gatherCapabilities(type, provider, null);
}
@SuppressWarnings("unchecked")
@Nullable
public static <T extends ICapabilityProvider> CapabilityDispatcher gatherCapabilities(Class<? extends T> type, T provider, @Nullable ICapabilityProvider parent)
@ -705,9 +643,7 @@ public class ForgeEventFactory
public static boolean onProjectileImpact(EntityThrowable throwable, RayTraceResult ray)
{
boolean oldEvent = MinecraftForge.EVENT_BUS.post(new ThrowableImpactEvent(throwable, ray));
boolean newEvent = MinecraftForge.EVENT_BUS.post(new ProjectileImpactEvent.Throwable(throwable, ray));
return oldEvent || newEvent; // TODO: clean up when old event is removed
return MinecraftForge.EVENT_BUS.post(new ProjectileImpactEvent.Throwable(throwable, ray));
}
public static boolean onReplaceBiomeBlocks(IChunkGenerator gen, int x, int z, ChunkPrimer primer, World world)

View File

@ -23,13 +23,12 @@ import javax.annotation.Nullable;
import net.minecraft.tileentity.MobSpawnerBaseLogic;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.eventbus.api.Cancelable;
import net.minecraftforge.eventbus.api.Event;
import net.minecraft.entity.EntityLiving;
import net.minecraft.world.World;
/**
* LivingSpawnEvent is fired for any events associated with Living Enttnies spawn status. <br>
* LivingSpawnEvent is fired for any events associated with Living Entities spawn status. <br>
* If a method utilizes this {@link Event} as its parameter, the method will
* receive every child event of this class.<br>
* <br>
@ -72,7 +71,6 @@ public class LivingSpawnEvent extends LivingEvent
@HasResult
public static class CheckSpawn extends LivingSpawnEvent
{
private final boolean isSpawner; // TODO: remove in 1.13
@Nullable
private final MobSpawnerBaseLogic spawner;
@ -90,42 +88,12 @@ public class LivingSpawnEvent extends LivingEvent
public CheckSpawn(EntityLiving entity, World world, float x, float y, float z, @Nullable MobSpawnerBaseLogic spawner)
{
super(entity, world, x, y, z);
this.isSpawner = spawner != null;
this.spawner = spawner;
}
/**
* @deprecated Use {@link CheckSpawn##CheckSpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)}
* with a spawner instance, or null if not a spawner
* CheckSpawn is fired when an Entity is about to be spawned.
* @param entity the spawning entity
* @param world the world to spawn in
* @param x x coordinate
* @param y y coordinate
* @param z z coordinate
* @param isSpawner true if this spawn is done by a MobSpawner,
* false if it this spawn is coming from a WorldSpawner
*/
@Deprecated // TODO: Remove in 1.13
public CheckSpawn(EntityLiving entity, World world, float x, float y, float z, boolean isSpawner)
{
super(entity, world, x, y, z);
this.isSpawner = isSpawner;
spawner = null;
}
/**
* @deprecated Use {@link CheckSpawn#CheckSpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)} instead
*/
@Deprecated // TODO: Remove in 1.13
public CheckSpawn(EntityLiving entity, World world, float x, float y, float z)
{
this(entity, world, x, y, z, true);
}
public boolean isSpawner()
{
return isSpawner; // TODO: replace with spawner null check in 1.13
return spawner != null; // TODO: replace with spawner null check in 1.13
}
@Nullable
@ -154,17 +122,6 @@ public class LivingSpawnEvent extends LivingEvent
@Nullable
private final MobSpawnerBaseLogic spawner;
/**
* @deprecated Use {@link SpecialSpawn#SpecialSpawn(EntityLiving, World, float, float, float, MobSpawnerBaseLogic)}
* with originating spawner instance or null
*/
@Deprecated // TODO: remove in 1.13
public SpecialSpawn(EntityLiving entity, World world, float x, float y, float z)
{
super(entity, world, x, y, z);
spawner = null;
}
/**
* @param spawner the position of a tileentity or approximate position of an entity that initiated the spawn if any
*/
@ -203,4 +160,4 @@ public class LivingSpawnEvent extends LivingEvent
}
}
}
}

View File

@ -31,7 +31,7 @@ import net.minecraftforge.eventbus.api.Event;
/**
* {@link FurnaceFuelBurnTimeEvent} is fired when determining the fuel value for an ItemStack. <br>
* <br>
* To set the burn time of your own item, use {@link Item#getItemBurnTime(ItemStack)} instead.<br>
* To set the burn time of your own item, use {@link Item#getBurnTime(ItemStack)} instead.<br>
* <br>
* This event is fired from {@link ForgeEventFactory#getItemBurnTime(ItemStack)}.<br>
* <br>
@ -66,18 +66,19 @@ public class FurnaceFuelBurnTimeEvent extends Event
/**
* Set the burn time for the given ItemStack.
* Setting it to 0 will prevent the item from being used as fuel, overriding vanilla's decision.
* Setting it to -1 will let vanilla decide on the fuel value, this is the default.
*/
public void setBurnTime(int burnTime)
{
this.burnTime = burnTime;
setCanceled(true);
if (burnTime >= 0)
{
this.burnTime = burnTime;
setCanceled(true);
}
}
/**
* The resulting value of this event, the burn time for the ItemStack.
* A value of 0 will prevent the item from being used as fuel, overriding vanilla's decision.
* A value of -1 will let vanilla decide on the fuel value, this is the default for {@link Item#getItemBurnTime(ItemStack)}.
*/
public int getBurnTime()
{

View File

@ -127,8 +127,8 @@ public class BlockEvent extends Event
super(world, pos, state);
this.player = player;
if (state == null || !ForgeHooks.canHarvestBlock(state.getBlock(), player, world, pos) || // Handle empty block or player unable to break block scenario
(state.getBlock().canSilkHarvest(world, pos, world.getBlockState(pos), player) && EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, player.getHeldItemMainhand()) > 0)) // If the block is being silk harvested, the exp dropped is 0
if (state == null || !ForgeHooks.canHarvestBlock(state, player, world, pos) || // Handle empty block or player unable to break block scenario
(state.canSilkHarvest(world, pos, player) && EnchantmentHelper.getEnchantmentLevel(Enchantments.SILK_TOUCH, player.getHeldItemMainhand()) > 0)) // If the block is being silk harvested, the exp dropped is 0
{
this.exp = 0;
}

View File

@ -88,7 +88,7 @@ public class WorldEvent extends Event
* This event is fired when a world is unloaded in
* {@link Minecraft#loadWorld(WorldClient, String)},
* {@link MinecraftServer#stopServer()},
* {@link DimensionManager#unloadWorlds(Hashtable)},
* {@link DimensionManager#unloadWorlds()},
* {@link ForgeInternalHandler#onDimensionUnload(Unload)}. <br>
* <br>
* This event is not {@link Cancelable}.<br>

View File

@ -27,6 +27,7 @@ import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemBucket;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
@ -98,13 +99,13 @@ public class FluidUtil
{
return player.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
.map(playerInventory -> {
FluidActionResult fluidActionResult = tryFillContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true);
if (!fluidActionResult.isSuccess())
{
fluidActionResult = tryEmptyContainerAndStow(heldItem, handler, playerInventory, Integer.MAX_VALUE, player, true);
}
if (fluidActionResult.isSuccess())
{
player.setHeldItem(hand, fluidActionResult.getResult());
@ -151,7 +152,7 @@ public class FluidUtil
{
containerFluidHandler.fill(simulatedTransfer, true);
}
ItemStack resultContainer = containerFluidHandler.getContainer();
return new FluidActionResult(resultContainer);
}
@ -615,11 +616,13 @@ public class FluidUtil
return false;
}
BlockItemUseContext context = new BlockItemUseContext(world, player, ItemStack.EMPTY, pos, EnumFacing.UP, 0, 0, 0); //TODO: This neds proper context...
// check that we can place the fluid at the destination
IBlockState destBlockState = world.getBlockState(pos);
Material destMaterial = destBlockState.getMaterial();
boolean isDestNonSolid = !destMaterial.isSolid();
boolean isDestReplaceable = destBlockState.getBlock().isReplaceable(world, pos);
boolean isDestReplaceable = destBlockState.func_196953_a(context);
if (!world.isAirBlock(pos) && !isDestNonSolid && !isDestReplaceable)
{
return false; // Non-air, solid, unreplacable block. We can't put fluid here.
@ -688,7 +691,7 @@ public class FluidUtil
IBlockState destBlockState = world.getBlockState(pos);
Material destMaterial = destBlockState.getMaterial();
boolean isDestNonSolid = !destMaterial.isSolid();
boolean isDestReplaceable = destBlockState.getBlock().isReplaceable(world, pos);
boolean isDestReplaceable = false; //TODO: Needs BlockItemUseContext destBlockState.getBlock().isReplaceable(world, pos);
if ((isDestNonSolid || isDestReplaceable) && !destMaterial.isLiquid())
{
world.destroyBlock(pos, true);

View File

@ -359,7 +359,7 @@ public net.minecraft.item.crafting.Ingredient$TagList <init>(Lnet/minecraft/tags
public net.minecraft.client.Minecraft func_193986_ar()V # populateSearchTreeManager
# Advancements
public net.minecraft.advancements.AdvancementManager field_192783_b # GSON
public net.minecraft.advancements.AdvancementManager func_195439_b(Lnet/minecraft/resources/IResourceManager;)Ljava/util/Map; # loadCustomAdvancements
public net.minecraft.advancements.CriteriaTriggers func_192118_a(Lnet/minecraft/advancements/ICriterionTrigger;)Lnet/minecraft/advancements/ICriterionTrigger; # register
# BiomeProvider
@ -367,3 +367,9 @@ public net.minecraft.world.biome.provider.BiomeProvider field_201540_a # BIOMES_
# BlockTags.Wrapper
public net.minecraft.tags.BlockTags$Wrapper
#SaveHandler
public net.minecraft.world.storage.SaveHandler field_75771_c # playersDirectory
#BlockItemUseContext
public net.minecraft.item.BlockItemUseContext <init>(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;FFF)V