@@ -1723,96 +1723,106 @@ public void dropExpOrb(Vector3f source, int exp, Vector3f motion, int delay) {
17231723 }
17241724 }
17251725
1726- public ItemStack useItemOn (Vector3i vector , ItemStack item , Direction face , Vector3f clickPos ) {
1727- return this .useItemOn (vector , item , face , clickPos , null );
1728- }
1729-
1730- public ItemStack useItemOn (Vector3i vector , ItemStack item , Direction face , Vector3f clickPos , Player player ) {
1731- return this .useItemOn (vector , item , face , clickPos , player , true );
1732- }
1733-
1734-
1735- public ItemStack useItemOn (Vector3i vector , ItemStack item , Direction face , Vector3f clickPos , Player player , boolean playSound ) {
1736- if (item == null || item .isEmpty ()) {
1737- item = ItemStack .EMPTY ;
1738- }
1739- Block target = this .getBlock (vector );
1726+ /**
1727+ * Attempts to interact with the target block.
1728+ * Does not require an item in hand.
1729+ *
1730+ * @return true if the block consumed the interaction
1731+ */
1732+ public boolean tryUseBlock (Block target , Block side , Direction face , ItemStack item , Player player ) {
17401733 ComponentMap targetBehaviors = target .getComponents ();
1741- Block block = target .getSide (face );
1742- ComponentMap behaviors = block .getComponents ();
1743- Vector3i blockPos = block .getPosition ();
1744-
1745- if (blockPos .getY () >= 320 || blockPos .getY () < -64 ) {
1746- return null ;
1747- }
17481734
1749- if (target .getState ().getType () == BlockTypes .AIR ) {
1750- return null ;
1751- }
1752-
1753- ComponentMap itemBehaviors = item .isEmpty () ? null : this .itemRegistry .getComponents (item .getType ());
17541735 if (player != null ) {
17551736 PlayerInteractEvent ev = new PlayerInteractEvent (player , item , target , face , PlayerInteractEvent .Action .RIGHT_CLICK_BLOCK );
1756-
17571737 if (player .getGamemode () == GameMode .SPECTATOR ) {
17581738 ev .setCancelled ();
17591739 }
17601740
17611741 if (!player .isOp () && isInSpawnRadius (target .getPosition ())) {
17621742 ev .setCancelled ();
17631743 }
1764-
17651744 this .server .getEventManager ().fire (ev );
1766- if (!ev .isCancelled ()) {
1767- targetBehaviors .get (BlockComponents .ON_TICK ).execute (target , new Random ());
17681745
1769- boolean blockUsed = (!player .isSneaking () || player .getInventory ().getSelectedItem ().isEmpty ()) && targetBehaviors .get (BlockComponents .CAN_BE_USED ).execute (target ) && targetBehaviors .get (BlockComponents .USE ).execute (target , player , face );
1770- if (blockUsed ) { //TODO: update the item from the behavior
1771- if (this .itemRegistry .getComponent (item .getType (), ItemComponents .IS_TOOL ).execute (item ) && item .get (ItemKeys .DAMAGE ) >= itemBehaviors .get (ItemComponents .GET_MAX_DAMAGE ).execute (item )) {
1772- item = ItemStack .EMPTY ;
1773- }
1774- return item ;
1775- }
1776-
1777- boolean itemCanBeUsed = itemBehaviors != null && itemBehaviors .get (ItemComponents .CAN_BE_USED ).execute (item );
1778- if (itemCanBeUsed ) {
1779- var result = itemBehaviors .get (ItemComponents .USE_ON ).execute (item , player , target .getPosition (), face , clickPos );
1780- // if (item.getCount() <= 0) {
1781- // item = ItemStack.AIR;
1782- // return item;
1783- // }
1784- item = Objects .requireNonNullElse (result , ItemStack .EMPTY );
1785- }
1786- } else {
1787- if (item .getType () == ItemTypes .BUCKET && item .get (ItemKeys .BUCKET_DATA ) == Bucket .WATER ) {
1788- ((CloudLevel ) player .getLevel ()).sendBlocks (new Player []{player }, new Block []{new CloudBlock (this , block .getPosition (), new BlockState []{BlockStates .AIR , BlockStates .AIR })}, UpdateBlockPacket .FLAG_ALL_PRIORITY );
1746+ if (ev .isCancelled ()) {
1747+ if (!item .isEmpty () && item .getType () == ItemTypes .BUCKET && item .get (ItemKeys .BUCKET_DATA ) == Bucket .WATER ) {
1748+ sendBlocks (new Player []{player }, new Block []{new CloudBlock (this , side .getPosition (), new BlockState []{BlockStates .AIR , BlockStates .AIR })}, UpdateBlockPacket .FLAG_ALL_PRIORITY );
17891749 }
1790- return null ;
1791- }
1792- } else if (targetBehaviors .get (BlockComponents .CAN_BE_USED ).execute (target ) && targetBehaviors .get (BlockComponents .USE ).execute (target , null , face )) {
1793- if (this .itemRegistry .getComponent (item .getType (), ItemComponents .IS_TOOL ).execute (item ) &&
1794- item .get (ItemKeys .DAMAGE ) >= itemBehaviors .get (ItemComponents .GET_MAX_DAMAGE ).execute (item )) {
1795- item = ItemStack .EMPTY ; //TODO: update the item from the behavior
1750+ return false ;
17961751 }
1797- return item ;
1752+
1753+ targetBehaviors .get (BlockComponents .ON_TICK ).execute (target , new Random ());
1754+
1755+ boolean canUse = (!player .isSneaking () || player .getInventory ().getSelectedItem ().isEmpty ()) && targetBehaviors .get (BlockComponents .CAN_BE_USED ).execute (target );
1756+ return canUse && targetBehaviors .get (BlockComponents .USE ).execute (target , player , face );
1757+ } else {
1758+ return targetBehaviors .get (BlockComponents .CAN_BE_USED ).execute (target ) && targetBehaviors .get (BlockComponents .USE ).execute (target , null , face );
1759+ }
1760+ }
1761+
1762+ /**
1763+ * Attempts to activate the item's USE_ON handler against the target block.
1764+ * Requires a non-empty item.
1765+ *
1766+ * @return the updated ItemStack if the item was consumed/used, or null if not handled
1767+ */
1768+ public ItemStack tryUseItem (Block target , Direction face , Vector3f clickPos , ItemStack item , Player player ) {
1769+ ComponentMap itemBehaviors = this .itemRegistry .getComponents (item .getType ());
1770+ if (itemBehaviors == null || !itemBehaviors .get (ItemComponents .CAN_BE_USED ).execute (item )) {
1771+ return null ;
1772+ }
1773+
1774+ ItemStack result = itemBehaviors .get (ItemComponents .USE_ON ).execute (item , player , target .getPosition (), face , clickPos );
1775+ return Objects .requireNonNullElse (result , item );
1776+ }
1777+
1778+ /**
1779+ * Attempts to activate an item used in the air.
1780+ * Calls the item's {@code USE_ON} handler with the player's own position as the notional target.
1781+ *
1782+ * @return the updated {@link ItemStack} if the item was consumed/activated, or {@code null} if not handled
1783+ */
1784+ public ItemStack tryActivateItem (ItemStack item , Player player ) {
1785+ ComponentMap itemBehaviors = this .itemRegistry .getComponents (item .getType ());
1786+ if (itemBehaviors == null || !itemBehaviors .get (ItemComponents .CAN_BE_USED ).execute (item )) {
1787+ return null ;
17981788 }
1789+
1790+ Vector3i playerBlockPos = player .getPosition ().toInt ();
1791+ ItemStack result = itemBehaviors .get (ItemComponents .USE_ON ).execute (item , player , playerBlockPos , null , null );
1792+ return Objects .requireNonNullElse (result , item );
1793+ }
1794+
1795+ /**
1796+ * Attempts to place a block from the held item against the target block.
1797+ * Requires a non-empty item.
1798+ *
1799+ * @return the updated ItemStack after placement, or null if placement was rejected
1800+ */
1801+ public ItemStack tryPlaceBlock (Block target , Block side , Direction face , Vector3f clickPos , ItemStack item , Player player , boolean playSound ) {
1802+ ComponentMap itemBehaviors = this .itemRegistry .getComponents (item .getType ());
1803+ if (itemBehaviors == null ) {
1804+ return null ;
1805+ }
1806+
17991807 @ SuppressWarnings ("unchecked" )
18001808 BlockState hand = ((Optional <BlockState >) itemBehaviors .get (ItemComponents .GET_BLOCK ).execute (item )).orElse (null );
1801-
18021809 if (hand == null ) {
18031810 return null ;
18041811 }
18051812
1806- if (!(this .blockRegistry .getComponent (block .getState ().getType (), BlockComponents .REPLACEABLE ).get ()
1807- || (hand .hasTag (BlockTags .SLAB ) && (block .getState ().hasTag (BlockTags .SLAB ) || target .getState ().hasTag (BlockTags .SLAB ))))) {
1813+ Vector3i blockPos = side .getPosition ();
1814+ if (!(this .blockRegistry .getComponent (side .getState ().getType (), BlockComponents .REPLACEABLE ).get ()
1815+ || (hand .hasTag (BlockTags .SLAB ) && (side .getState ().hasTag (BlockTags .SLAB ) || target .getState ().hasTag (BlockTags .SLAB ))))) {
18081816 return null ;
18091817 }
18101818
1819+ Block block = side ;
18111820 if (this .blockRegistry .getComponent (target .getState ().getType (), BlockComponents .REPLACEABLE ).get ()) {
18121821 block = target ;
1822+ blockPos = block .getPosition ();
18131823 }
18141824
1815- var handBehaviors = this .blockRegistry .getComponents (hand .getType ());
1825+ ComponentMap handBehaviors = this .blockRegistry .getComponents (hand .getType ());
18161826 AxisAlignedBB handBB = handBehaviors .get (BlockComponents .GET_BOUNDING_BOX ).execute (hand );
18171827
18181828 if (!handBehaviors .get (BlockComponents .CAN_PASS_THROUGH ).execute (hand ) && handBB != null ) {
@@ -1842,7 +1852,7 @@ public ItemStack useItemOn(Vector3i vector, ItemStack item, Direction face, Vect
18421852 }
18431853
18441854 if (realCount > 0 ) {
1845- return null ; // Entity in block
1855+ return null ;
18461856 }
18471857 }
18481858
@@ -1851,69 +1861,63 @@ public ItemStack useItemOn(Vector3i vector, ItemStack item, Direction face, Vect
18511861 if (player .getGamemode () == GameMode .ADVENTURE && !itemRegistry .getComponent (item .getType (), ItemComponents .CAN_BE_PLACED_ON ).execute (item , target )) {
18521862 event .setCancelled ();
18531863 }
1864+
18541865 if (!player .isOp () && isInSpawnRadius (target .getPosition ())) {
18551866 event .setCancelled ();
18561867 }
1868+
18571869 this .server .getEventManager ().fire (event );
18581870 if (event .isCancelled ()) {
18591871 return null ;
18601872 }
18611873 }
18621874
1863- // Behavior liquidBehavior = block.getState().getBehavior();
1864- var blockBehaviors = blockRegistry .getComponents (block .getState ().getType ());
1875+ ComponentMap blockBehaviors = blockRegistry .getComponents (block .getState ().getType ());
18651876 BlockState air = block .getExtra ();
1877+ Vector3i waterlogPos = null ;
18661878
1867- Vector3i pos = null ;
1868-
1869- // TODO Water logging?
1870- if ( air == BlockStates . AIR && this . blockRegistry . getComponent ( block . getState (). getType (), BlockComponents . LIQUID ). get () && this .blockRegistry .getComponent (block .getState ().getType (), BlockComponents .USES_WATERLOGGING ).get ()
1871- && (block .getState ().ensureTrait (BlockTraits .FLUID_LEVEL ) == 0 ) // Remove this line when MCPE-33345 is resolved
1879+ // TODO: Water logging
1880+ if ( air == BlockStates . AIR
1881+ && this . blockRegistry . getComponent ( block . getState (). getType (), BlockComponents . LIQUID ). get ()
1882+ && this .blockRegistry .getComponent (block .getState ().getType (), BlockComponents .USES_WATERLOGGING ).get ()
1883+ && (block .getState ().ensureTrait (BlockTraits .FLUID_LEVEL ) == 0 ) // Remove when MCPE-33345 is resolved
18721884 ) {
1873- pos = block .getPosition ();
1874-
1885+ waterlogPos = block .getPosition ();
18751886 block .set (block .getState (), 1 , false , false );
18761887 block .set (air , false , false );
1877-
18781888 this .scheduleUpdate (block , 1 );
18791889 }
18801890
18811891 try {
18821892 if (!handBehaviors .get (BlockComponents .ON_PLACE ).execute (hand , player , block .getPosition (), face , clickPos )) {
1883- if (pos != null ) {
1884- this .setBlockState (pos , 0 , block .getState (), false , false );
1885- this .setBlockState (pos , 1 , air , false , false );
1893+ if (waterlogPos != null ) {
1894+ this .setBlockState (waterlogPos , 0 , block .getState (), false , false );
1895+ this .setBlockState (waterlogPos , 1 , air , false , false );
18861896 }
18871897 return null ;
18881898 }
18891899 } catch (Exception e ) {
1890- if (pos != null ) {
1891- this .setBlockState (pos , 0 , block .getState (), false , false );
1892- this .setBlockState (pos , 1 , air , false , false );
1900+ if (waterlogPos != null ) {
1901+ this .setBlockState (waterlogPos , 0 , block .getState (), false , false );
1902+ this .setBlockState (waterlogPos , 1 , air , false , false );
18931903 }
18941904 throw e ;
18951905 }
18961906
1897- if (player != null ) {
1898- if (!player .isCreative ()) {
1899- item = item .decreaseCount ();
1900- }
1907+ if (player != null && !player .isCreative ()) {
1908+ item = item .decreaseCount ();
19011909 }
19021910
19031911 if (playSound ) {
19041912 this .addLevelSoundEvent (block .getPosition (), SoundEvent .PLACE , CloudBlockRegistry .REGISTRY .getRuntimeId (hand ));
19051913 }
19061914
1907- if (item .getCount () <= 0 ) {
1908- item = ItemStack .EMPTY ;
1909- }
1910- return item ;
1915+ return item .getCount () <= 0 ? ItemStack .EMPTY : item ;
19111916 }
19121917
19131918 public boolean isInSpawnRadius (Vector3i vector3 ) {
19141919 int distance = this .server .getSpawnRadius ();
19151920 if (distance > -1 ) {
1916-
19171921 Vector2i t = vector3 .toVector2 (true );
19181922 Vector2i s = this .getSpawnLocation ().toInt ().toVector2 (true );
19191923 return t .distance (s ) <= distance ;
0 commit comments