2020-05-02 20:44:05 +00:00
/ *
2022-01-01 19:03:05 +00:00
* Copyright ( c ) 2019 - 2022 GeyserMC . http : //geysermc.org
2020-05-02 20:44:05 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*
* @author GeyserMC
* @link https : //github.com/GeyserMC/Geyser
* /
2021-11-20 23:29:46 +00:00
package org.geysermc.geyser.entity.type ;
2020-05-02 20:44:05 +00:00
import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata ;
import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack ;
2021-11-18 03:02:38 +00:00
import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata ;
import com.github.steveice10.mc.protocol.data.game.entity.object.Direction ;
2022-02-25 03:49:10 +00:00
import com.github.steveice10.mc.protocol.data.game.entity.player.Hand ;
2021-11-18 03:02:38 +00:00
import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType ;
2022-10-30 00:23:21 +00:00
import org.cloudburstmc.math.vector.Vector3f ;
import org.cloudburstmc.math.vector.Vector3i ;
2020-07-05 20:58:43 +00:00
import com.nukkitx.nbt.NbtMap ;
import com.nukkitx.nbt.NbtMapBuilder ;
2022-10-30 00:23:21 +00:00
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData ;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket ;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket ;
2021-05-09 19:44:41 +00:00
import lombok.Getter ;
2021-11-20 23:29:46 +00:00
import org.geysermc.geyser.entity.EntityDefinition ;
2021-11-22 19:52:26 +00:00
import org.geysermc.geyser.session.GeyserSession ;
2021-11-20 23:29:46 +00:00
import org.geysermc.geyser.translator.inventory.item.ItemTranslator ;
2022-02-25 03:49:10 +00:00
import org.geysermc.geyser.util.InteractionResult ;
import org.geysermc.geyser.util.InventoryUtils ;
2020-05-02 20:44:05 +00:00
2021-11-18 03:02:38 +00:00
import java.util.UUID ;
2020-05-02 20:44:05 +00:00
/ * *
* Item frames are an entity in Java but a block entity in Bedrock .
* /
public class ItemFrameEntity extends Entity {
/ * *
* Used for getting the Bedrock block position .
* Blocks deal with integers whereas entities deal with floats .
* /
2021-11-18 03:02:38 +00:00
private final Vector3i bedrockPosition ;
2020-05-02 20:44:05 +00:00
/ * *
* Specific block ' state ' we are emulating in Bedrock .
* /
2021-11-18 03:02:38 +00:00
private final int bedrockRuntimeId ;
2020-05-02 20:44:05 +00:00
/ * *
* Rotation of item in frame .
* /
private float rotation = 0 . 0f ;
/ * *
* Cached item frame ' s Bedrock compound tag .
* /
2020-07-05 20:58:43 +00:00
private NbtMap cachedTag ;
2021-05-09 19:44:41 +00:00
/ * *
* The item currently in the item frame . Used for block picking .
* /
@Getter
private ItemStack heldItem = null ;
2021-11-18 03:02:38 +00:00
/ * *
* Determines if this entity needs updated on the client end /
* /
private boolean changed = true ;
2020-05-02 20:44:05 +00:00
2022-05-24 23:16:40 +00:00
public ItemFrameEntity ( GeyserSession session , int entityId , long geyserId , UUID uuid , EntityDefinition < ? > definition , Vector3f position , Vector3f motion , float yaw , float pitch , float headYaw , Direction direction ) {
super ( session , entityId , geyserId , uuid , definition , position , motion , yaw , pitch , headYaw ) ;
2021-03-09 17:51:48 +00:00
2020-07-05 20:58:43 +00:00
NbtMapBuilder blockBuilder = NbtMap . builder ( )
2021-11-18 03:02:38 +00:00
. putString ( " name " , this . definition . entityType ( ) = = EntityType . GLOW_ITEM_FRAME ? " minecraft:glow_frame " : " minecraft:frame " )
2021-07-13 01:19:40 +00:00
. putInt ( " version " , session . getBlockMappings ( ) . getBlockStateVersion ( ) ) ;
2021-09-21 20:50:06 +00:00
NbtMapBuilder statesBuilder = NbtMap . builder ( )
2020-07-05 20:58:43 +00:00
. putInt ( " facing_direction " , direction . ordinal ( ) )
2022-02-09 03:57:03 +00:00
. putByte ( " item_frame_map_bit " , ( byte ) 0 )
. putByte ( " item_frame_photo_bit " , ( byte ) 0 ) ;
2021-09-21 20:50:06 +00:00
blockBuilder . put ( " states " , statesBuilder . build ( ) ) ;
2021-07-13 01:19:40 +00:00
bedrockRuntimeId = session . getBlockMappings ( ) . getItemFrame ( blockBuilder . build ( ) ) ;
2020-05-02 20:44:05 +00:00
bedrockPosition = Vector3i . from ( position . getFloorX ( ) , position . getFloorY ( ) , position . getFloorZ ( ) ) ;
2021-05-09 19:44:41 +00:00
session . getItemFrameCache ( ) . put ( bedrockPosition , this ) ;
2021-11-18 03:02:38 +00:00
}
@Override
protected void initializeMetadata ( ) {
// lol nah don't do anything
// This isn't a real entity for Bedrock so it isn't going to do anything
}
2021-05-09 19:44:41 +00:00
2021-11-18 03:02:38 +00:00
@Override
public void spawnEntity ( ) {
2021-11-19 01:44:03 +00:00
updateBlock ( true ) ;
2021-11-20 21:34:30 +00:00
session . getGeyser ( ) . getLogger ( ) . debug ( " Spawned item frame at location " + bedrockPosition + " with java id " + entityId ) ;
2020-05-02 20:44:05 +00:00
valid = true ;
}
2021-11-20 19:25:21 +00:00
public void setItemInFrame ( EntityMetadata < ItemStack , ? > entityMetadata ) {
2021-11-18 03:02:38 +00:00
if ( entityMetadata . getValue ( ) ! = null ) {
this . heldItem = entityMetadata . getValue ( ) ;
2021-05-09 19:44:41 +00:00
ItemData itemData = ItemTranslator . translateToBedrock ( session , heldItem ) ;
2022-07-02 16:50:16 +00:00
2022-10-30 00:23:21 +00:00
String customIdentifier = session . getItemMappings ( ) . getCustomIdMappings ( ) . get ( itemData . getDefinition ( ) . getRuntimeId ( ) ) ;
2022-07-02 16:50:16 +00:00
2020-07-05 20:58:43 +00:00
NbtMapBuilder builder = NbtMap . builder ( ) ;
2020-05-02 20:44:05 +00:00
2020-07-05 20:58:43 +00:00
builder . putByte ( " Count " , ( byte ) itemData . getCount ( ) ) ;
2020-05-02 20:44:05 +00:00
if ( itemData . getTag ( ) ! = null ) {
2021-05-09 19:44:41 +00:00
builder . put ( " tag " , itemData . getTag ( ) ) ;
2020-05-02 20:44:05 +00:00
}
2021-04-06 04:14:06 +00:00
builder . putShort ( " Damage " , ( short ) itemData . getDamage ( ) ) ;
2022-07-02 16:50:16 +00:00
builder . putString ( " Name " , customIdentifier ! = null ? customIdentifier : session . getItemMappings ( ) . getMapping ( entityMetadata . getValue ( ) ) . getBedrockIdentifier ( ) ) ;
2020-07-05 20:58:43 +00:00
NbtMapBuilder tag = getDefaultTag ( ) . toBuilder ( ) ;
tag . put ( " Item " , builder . build ( ) ) ;
tag . putFloat ( " ItemDropChance " , 1 . 0f ) ;
tag . putFloat ( " ItemRotation " , rotation ) ;
cachedTag = tag . build ( ) ;
2021-11-18 03:02:38 +00:00
changed = true ;
} else if ( cachedTag ! = null ) {
2020-05-02 20:44:05 +00:00
cachedTag = getDefaultTag ( ) ;
2021-11-18 03:02:38 +00:00
changed = true ;
2020-05-02 20:44:05 +00:00
}
2021-11-18 03:02:38 +00:00
}
2021-11-20 19:25:21 +00:00
public void setItemRotation ( IntEntityMetadata entityMetadata ) {
rotation = entityMetadata . getPrimitiveValue ( ) * 45 ;
2021-11-18 03:02:38 +00:00
if ( cachedTag = = null ) {
return ;
2020-05-02 20:44:05 +00:00
}
2021-11-18 03:02:38 +00:00
NbtMapBuilder builder = cachedTag . toBuilder ( ) ;
builder . putFloat ( " ItemRotation " , rotation ) ;
cachedTag = builder . build ( ) ;
changed = true ;
2020-05-02 20:44:05 +00:00
}
@Override
2021-11-18 03:02:38 +00:00
public boolean despawnEntity ( ) {
2020-05-02 20:44:05 +00:00
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket ( ) ;
updateBlockPacket . setDataLayer ( 0 ) ;
updateBlockPacket . setBlockPosition ( bedrockPosition ) ;
2022-10-30 00:23:21 +00:00
updateBlockPacket . setRuntimeId ( session . getBlockMappings ( ) . getBedrockAir ( ) . getRuntimeId ( ) ) ; //TODO maybe set this to the world block or another item frame?
2020-05-02 20:44:05 +00:00
updateBlockPacket . getFlags ( ) . add ( UpdateBlockPacket . Flag . PRIORITY ) ;
2020-07-05 04:03:51 +00:00
updateBlockPacket . getFlags ( ) . add ( UpdateBlockPacket . Flag . NETWORK ) ;
2020-05-02 20:44:05 +00:00
updateBlockPacket . getFlags ( ) . add ( UpdateBlockPacket . Flag . NEIGHBORS ) ;
2020-05-05 15:51:43 +00:00
session . sendUpstreamPacket ( updateBlockPacket ) ;
2021-05-09 19:44:41 +00:00
session . getItemFrameCache ( ) . remove ( bedrockPosition , this ) ;
2020-05-02 20:44:05 +00:00
valid = false ;
return true ;
}
2020-07-05 20:58:43 +00:00
private NbtMap getDefaultTag ( ) {
NbtMapBuilder builder = NbtMap . builder ( ) ;
builder . putInt ( " x " , bedrockPosition . getX ( ) ) ;
builder . putInt ( " y " , bedrockPosition . getY ( ) ) ;
builder . putInt ( " z " , bedrockPosition . getZ ( ) ) ;
builder . putByte ( " isMovable " , ( byte ) 1 ) ;
2021-11-18 03:02:38 +00:00
builder . putString ( " id " , this . definition . entityType ( ) = = EntityType . GLOW_ITEM_FRAME ? " GlowItemFrame " : " ItemFrame " ) ;
2020-07-05 20:58:43 +00:00
return builder . build ( ) ;
2020-05-02 20:44:05 +00:00
}
2021-11-18 03:02:38 +00:00
@Override
public void updateBedrockMetadata ( ) {
2021-11-19 01:44:03 +00:00
updateBlock ( false ) ;
2021-11-18 03:02:38 +00:00
}
2020-05-02 20:44:05 +00:00
/ * *
* Updates the item frame as a block
* /
2021-11-19 01:44:03 +00:00
public void updateBlock ( boolean force ) {
if ( ! changed & & ! force ) {
2021-11-18 03:02:38 +00:00
// Don't send a block update packet - nothing changed
return ;
}
2020-05-24 04:14:29 +00:00
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket ( ) ;
updateBlockPacket . setDataLayer ( 0 ) ;
updateBlockPacket . setBlockPosition ( bedrockPosition ) ;
updateBlockPacket . setRuntimeId ( bedrockRuntimeId ) ;
updateBlockPacket . getFlags ( ) . add ( UpdateBlockPacket . Flag . PRIORITY ) ;
2020-07-05 04:03:51 +00:00
updateBlockPacket . getFlags ( ) . add ( UpdateBlockPacket . Flag . NETWORK ) ;
2020-05-24 04:14:29 +00:00
updateBlockPacket . getFlags ( ) . add ( UpdateBlockPacket . Flag . NEIGHBORS ) ;
session . sendUpstreamPacket ( updateBlockPacket ) ;
2020-05-02 20:44:05 +00:00
2020-05-24 04:14:29 +00:00
BlockEntityDataPacket blockEntityDataPacket = new BlockEntityDataPacket ( ) ;
blockEntityDataPacket . setBlockPosition ( bedrockPosition ) ;
if ( cachedTag ! = null ) {
blockEntityDataPacket . setData ( cachedTag ) ;
} else {
blockEntityDataPacket . setData ( getDefaultTag ( ) ) ;
}
session . sendUpstreamPacket ( blockEntityDataPacket ) ;
2021-11-18 03:02:38 +00:00
changed = false ;
2020-05-02 20:44:05 +00:00
}
2022-02-25 03:49:10 +00:00
@Override
public InteractionResult interact ( Hand hand ) {
return InventoryUtils . isEmpty ( heldItem ) & & session . getPlayerInventory ( ) . getItemInHand ( hand ) . isEmpty ( ) ? InteractionResult . PASS : InteractionResult . SUCCESS ;
}
2020-05-02 20:44:05 +00:00
/ * *
* Finds the Java entity ID of an item frame from its Bedrock position .
* @param position position of item frame in Bedrock .
2021-11-22 19:52:26 +00:00
* @param session GeyserConnection .
2020-05-02 20:44:05 +00:00
* @return Java entity ID or - 1 if not found .
* /
2021-11-22 19:52:26 +00:00
public static ItemFrameEntity getItemFrameEntity ( GeyserSession session , Vector3i position ) {
2021-05-09 19:44:41 +00:00
return session . getItemFrameCache ( ) . get ( position ) ;
2020-05-02 20:44:05 +00:00
}
}