diff --git a/build.gradle b/build.gradle index 07a859483..937414810 100644 --- a/build.gradle +++ b/build.gradle @@ -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() diff --git a/patches/minecraft/net/minecraft/block/Block.java.patch b/patches/minecraft/net/minecraft/block/Block.java.patch index d34c8239d..7d66e87c2 100644 --- a/patches/minecraft/net/minecraft/block/Block.java.patch +++ b/patches/minecraft/net/minecraft/block/Block.java.patch @@ -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 REGISTRY = new RegistryNamespacedDefaultedByKey(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 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 captureDrops = ThreadLocal.withInitial(() -> false); + protected static ThreadLocal> capturedDrops = ThreadLocal.withInitial(NonNullList::create); + protected NonNullList 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 ======================================*/ } diff --git a/patches/minecraft/net/minecraft/block/state/IBlockState.java.patch b/patches/minecraft/net/minecraft/block/state/IBlockState.java.patch new file mode 100644 index 000000000..1a47ddc3f --- /dev/null +++ b/patches/minecraft/net/minecraft/block/state/IBlockState.java.patch @@ -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 { ++public interface IBlockState extends IStateHolder, net.minecraftforge.common.extensions.IForgeBlockState { + ThreadLocal> field_208776_a = ThreadLocal.>withInitial(() -> { + Object2ByteOpenHashMap object2byteopenhashmap = new Object2ByteOpenHashMap(); + object2byteopenhashmap.defaultReturnValue((byte)127); diff --git a/patches/minecraft/net/minecraft/client/gui/GuiBossOverlay.java.patch b/patches/minecraft/net/minecraft/client/gui/GuiBossOverlay.java.patch new file mode 100644 index 000000000..961bb956c --- /dev/null +++ b/patches/minecraft/net/minecraft/client/gui/GuiBossOverlay.java.patch @@ -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; + } diff --git a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch index 76755772e..87b7d42f8 100644 --- a/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch +++ b/patches/minecraft/net/minecraft/entity/player/EntityPlayer.java.patch @@ -9,3 +9,24 @@ private static final DataParameter ABSORPTION = EntityDataManager.createKey(EntityPlayer.class, DataSerializers.FLOAT); private static final DataParameter PLAYER_SCORE = EntityDataManager.createKey(EntityPlayer.class, DataSerializers.VARINT); protected static final DataParameter PLAYER_MODEL_FLAG = EntityDataManager.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; + } + diff --git a/patches/minecraft/net/minecraft/item/Item.java.patch b/patches/minecraft/net/minecraft/item/Item.java.patch index f1ced1570..332ec11f5 100644 --- a/patches/minecraft/net/minecraft/item/Item.java.patch +++ b/patches/minecraft/net/minecraft/item/Item.java.patch @@ -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 teisr; + -+ private final java.util.Map toolClasses = new java.util.HashMap(); ++ private final java.util.Map toolClasses = Maps.newHashMap(); + + protected final boolean canRepair; + @@ -98,16 +98,15 @@ + } + + @Override -+ public java.util.Set getToolClasses(ItemStack stack) ++ public java.util.Set 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 toolClasses = new java.util.HashMap(); ++ private java.util.Map toolClasses = Maps.newHashMap(); + private java.util.function.Supplier> 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> teisr) { ++ this.teisr = teisr; ++ return this; + } } } diff --git a/patches/minecraft/net/minecraft/item/ItemPickaxe.java.patch b/patches/minecraft/net/minecraft/item/ItemPickaxe.java.patch new file mode 100644 index 000000000..f6baf7109 --- /dev/null +++ b/patches/minecraft/net/minecraft/item/ItemPickaxe.java.patch @@ -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) { diff --git a/patches/minecraft/net/minecraft/item/ItemStack.java.patch b/patches/minecraft/net/minecraft/item/ItemStack.java.patch index 08545dc94..89ec66f43 100644 --- a/patches/minecraft/net/minecraft/item/ItemStack.java.patch +++ b/patches/minecraft/net/minecraft/item/ItemStack.java.patch @@ -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, 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) { diff --git a/patches/minecraft/net/minecraft/item/crafting/BannerDuplicateRecipe.java.patch b/patches/minecraft/net/minecraft/item/crafting/BannerDuplicateRecipe.java.patch index 884dddf58..47402590b 100644 --- a/patches/minecraft/net/minecraft/item/crafting/BannerDuplicateRecipe.java.patch +++ b/patches/minecraft/net/minecraft/item/crafting/BannerDuplicateRecipe.java.patch @@ -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; } diff --git a/patches/minecraft/net/minecraft/network/ServerStatusResponse.java.patch b/patches/minecraft/net/minecraft/network/ServerStatusResponse.java.patch new file mode 100644 index 000000000..82d081e43 --- /dev/null +++ b/patches/minecraft/net/minecraft/network/ServerStatusResponse.java.patch @@ -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; diff --git a/patches/minecraft/net/minecraft/network/status/server/SPacketServerInfo.java.patch b/patches/minecraft/net/minecraft/network/status/server/SPacketServerInfo.java.patch new file mode 100644 index 000000000..e764b7823 --- /dev/null +++ b/patches/minecraft/net/minecraft/network/status/server/SPacketServerInfo.java.patch @@ -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) { diff --git a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch index 11bfdf5e9..2b44a129e 100644 --- a/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch +++ b/patches/minecraft/net/minecraft/server/MinecraftServer.java.patch @@ -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 worldTickTimes = new java.util.Hashtable(); 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 list = Lists.newArrayList(); + Set set = Sets.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) { diff --git a/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch b/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch index 9af4b4fa7..0df7fd433 100644 --- a/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch +++ b/patches/minecraft/net/minecraft/server/integrated/IntegratedServer.java.patch @@ -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)) { diff --git a/patches/minecraft/net/minecraft/tileentity/TileEntityFurnace.java.patch b/patches/minecraft/net/minecraft/tileentity/TileEntityFurnace.java.patch new file mode 100644 index 000000000..8c5b7d1a0 --- /dev/null +++ b/patches/minecraft/net/minecraft/tileentity/TileEntityFurnace.java.patch @@ -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.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[] handlers = ++ net.minecraftforge.items.wrapper.SidedInvWrapper.create(this, EnumFacing.UP, EnumFacing.DOWN, EnumFacing.NORTH); ++ ++ @Override ++ public net.minecraftforge.common.capabilities.OptionalCapabilityInstance getCapability(net.minecraftforge.common.capabilities.Capability 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(); ++ } + } diff --git a/patches/minecraft/net/minecraft/world/WorldServer.java.patch b/patches/minecraft/net/minecraft/world/WorldServer.java.patch index daab116f4..bc33e5d1f 100644 --- a/patches/minecraft/net/minecraft/world/WorldServer.java.patch +++ b/patches/minecraft/net/minecraft/world/WorldServer.java.patch @@ -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; ++ } + } diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index c4863a13b..8fa57f1d5 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -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)); } diff --git a/src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java b/src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java index ba4c792ae..7fef442b3 100644 --- a/src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java +++ b/src/main/java/net/minecraftforge/client/model/pipeline/ForgeBlockModelRenderer.java @@ -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; diff --git a/src/main/java/net/minecraftforge/common/DimensionManager.java b/src/main/java/net/minecraftforge/common/DimensionManager.java index dc04d501d..b62d5d43c 100644 --- a/src/main/java/net/minecraftforge/common/DimensionManager.java +++ b/src/main/java/net/minecraftforge/common/DimensionManager.java @@ -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 worldTickTimes) + public static void unloadWorlds() { IntIterator queueIterator = unloadQueue.iterator(); while (queueIterator.hasNext()) diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index a64bf3d30..444a1b575 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -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 toolEffectiveness = new HashSet(); - - 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 blocks = ReflectionHelper.getPrivateValue(ItemPickaxe.class, null, 0); - for (Block block : blocks) - { - block.setHarvestLevel("pickaxe", 0); - } + Set 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 craftingPlayer = new ThreadLocal(); 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 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 map, ModFile mod) - { - if (Loader.instance().getLoaderState() != LoaderState.NOINIT) //Unit Tests.. - Loader.instance().setActiveModContainer(mod); - } - - private static boolean loadAdvancements(Map 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 recipes, List 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 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 setter) + { + blockToolSetter = setter; + } + @SuppressWarnings("unchecked") + private static T getPrivateValue(Class 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(); + } + + } } diff --git a/src/main/java/net/minecraftforge/common/ToolType.java b/src/main/java/net/minecraftforge/common/ToolType.java new file mode 100644 index 000000000..cbab8b948 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/ToolType.java @@ -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 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; + } +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java index 97327b602..f17f8f4aa 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java @@ -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(); diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java new file mode 100644 index 000000000..d591ab2f1 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java @@ -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. + *

+ * 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 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()); + } + +} diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java index b90506926..45b75a59a 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeItem.java @@ -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 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 getToolClasses(ItemStack stack); + Set 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) { } diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java b/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java index 801ea8a61..83553b641 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeItemStack.java @@ -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 { // 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 getToolTypes() { + return getStack().getItem().getToolTypes(getStack()); + } + } diff --git a/src/main/java/net/minecraftforge/common/util/FakePlayer.java b/src/main/java/net/minecraftforge/common/util/FakePlayer.java index 639c6731e..c530e51d8 100644 --- a/src/main/java/net/minecraftforge/common/util/FakePlayer.java +++ b/src/main/java/net/minecraftforge/common/util/FakePlayer.java @@ -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; } diff --git a/src/main/java/net/minecraftforge/event/CommandEvent.java b/src/main/java/net/minecraftforge/event/CommandEvent.java deleted file mode 100644 index a93bd2833..000000000 --- a/src/main/java/net/minecraftforge/event/CommandEvent.java +++ /dev/null @@ -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)}.
- *
- * {@link #command} contains the instance of ICommand which is representative of the currently executing command.
- * {@link #sender} contains the instance of ICommandSender for the given command sender.
- * {@link #parameters} contains the arguments passed for the command execution.
- * {@link #exception} begins null, but can be populated with an exception to be thrown within the command.
- *
- * This event is {@link Cancelable}.
- * If the event is canceled, the execution of the command does not occur.
- *
- * This event does not have a result. {@link HasResult}
- *
- * This event is fired on the {@link MinecraftForge#EVENT_BUS}.
- **/ -@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; } -} diff --git a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java index 98f91cbf8..c669b89c0 100644 --- a/src/main/java/net/minecraftforge/event/ForgeEventFactory.java +++ b/src/main/java/net/minecraftforge/event/ForgeEventFactory.java @@ -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 CapabilityDispatcher gatherCapabilities(Class type, T provider) { return gatherCapabilities(type, provider, null); } - + @SuppressWarnings("unchecked") @Nullable public static CapabilityDispatcher gatherCapabilities(Class 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) diff --git a/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java b/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java index a83924935..7ed85e92d 100644 --- a/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java +++ b/src/main/java/net/minecraftforge/event/entity/living/LivingSpawnEvent.java @@ -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.
+ * LivingSpawnEvent is fired for any events associated with Living Entities spawn status.
* If a method utilizes this {@link Event} as its parameter, the method will * receive every child event of this class.
*
@@ -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 } } -} \ No newline at end of file +} diff --git a/src/main/java/net/minecraftforge/event/furnace/FurnaceFuelBurnTimeEvent.java b/src/main/java/net/minecraftforge/event/furnace/FurnaceFuelBurnTimeEvent.java index 53fbec13c..5e3dc9854 100644 --- a/src/main/java/net/minecraftforge/event/furnace/FurnaceFuelBurnTimeEvent.java +++ b/src/main/java/net/minecraftforge/event/furnace/FurnaceFuelBurnTimeEvent.java @@ -31,7 +31,7 @@ import net.minecraftforge.eventbus.api.Event; /** * {@link FurnaceFuelBurnTimeEvent} is fired when determining the fuel value for an ItemStack.
*
- * To set the burn time of your own item, use {@link Item#getItemBurnTime(ItemStack)} instead.
+ * To set the burn time of your own item, use {@link Item#getBurnTime(ItemStack)} instead.
*
* This event is fired from {@link ForgeEventFactory#getItemBurnTime(ItemStack)}.
*
@@ -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() { diff --git a/src/main/java/net/minecraftforge/event/world/BlockEvent.java b/src/main/java/net/minecraftforge/event/world/BlockEvent.java index d529777d0..41ec2a21c 100644 --- a/src/main/java/net/minecraftforge/event/world/BlockEvent.java +++ b/src/main/java/net/minecraftforge/event/world/BlockEvent.java @@ -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; } diff --git a/src/main/java/net/minecraftforge/event/world/WorldEvent.java b/src/main/java/net/minecraftforge/event/world/WorldEvent.java index ed00fc6d7..83754b479 100644 --- a/src/main/java/net/minecraftforge/event/world/WorldEvent.java +++ b/src/main/java/net/minecraftforge/event/world/WorldEvent.java @@ -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)}.
*
* This event is not {@link Cancelable}.
diff --git a/src/main/java/net/minecraftforge/fluids/FluidUtil.java b/src/main/java/net/minecraftforge/fluids/FluidUtil.java index b2d606549..9d7f54834 100644 --- a/src/main/java/net/minecraftforge/fluids/FluidUtil.java +++ b/src/main/java/net/minecraftforge/fluids/FluidUtil.java @@ -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); diff --git a/src/main/resources/forge_at.cfg b/src/main/resources/forge_at.cfg index ba7d93f56..62423d73b 100644 --- a/src/main/resources/forge_at.cfg +++ b/src/main/resources/forge_at.cfg @@ -359,7 +359,7 @@ public net.minecraft.item.crafting.Ingredient$TagList (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 (Lnet/minecraft/world/World;Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;FFF)V