/**
   * Transforms a block entity with the change of block type. This is driven from the delta between
   * the old and new block type prefabs, but takes into account changes made to the block entity.
   *
   * @param blockEntity The entity to update
   * @param oldType The previous type of the block
   * @param type The new type of the block
   */
  private void updateBlockEntityComponents(
      EntityRef blockEntity,
      Block oldType,
      Block type,
      Set<Class<? extends Component>> retainComponents) {
    BlockComponent blockComponent = blockEntity.getComponent(BlockComponent.class);

    Optional<Prefab> oldPrefab = oldType.getPrefab();
    EntityBuilder oldEntityBuilder = entityManager.newBuilder(oldPrefab.orElse(null));
    oldEntityBuilder.addComponent(
        new BlockComponent(oldType, new Vector3i(blockComponent.getPosition())));
    BeforeEntityCreated oldEntityEvent =
        new BeforeEntityCreated(oldPrefab.orElse(null), oldEntityBuilder.iterateComponents());
    blockEntity.send(oldEntityEvent);
    for (Component comp : oldEntityEvent.getResultComponents()) {
      oldEntityBuilder.addComponent(comp);
    }

    Optional<Prefab> newPrefab = type.getPrefab();
    EntityBuilder newEntityBuilder = entityManager.newBuilder(newPrefab.orElse(null));
    newEntityBuilder.addComponent(
        new BlockComponent(type, new Vector3i(blockComponent.getPosition())));
    BeforeEntityCreated newEntityEvent =
        new BeforeEntityCreated(newPrefab.orElse(null), newEntityBuilder.iterateComponents());
    blockEntity.send(newEntityEvent);
    for (Component comp : newEntityEvent.getResultComponents()) {
      newEntityBuilder.addComponent(comp);
    }

    for (Component component : blockEntity.iterateComponents()) {
      if (!COMMON_BLOCK_COMPONENTS.contains(component.getClass())
          && !entityManager
              .getComponentLibrary()
              .getMetadata(component.getClass())
              .isRetainUnalteredOnBlockChange()
          && !newEntityBuilder.hasComponent(component.getClass())
          && !retainComponents.contains(component.getClass())) {
        blockEntity.removeComponent(component.getClass());
      }
    }

    blockComponent.setBlock(type);
    blockEntity.saveComponent(blockComponent);

    HealthComponent health = blockEntity.getComponent(HealthComponent.class);
    if (health == null && type.isDestructible()) {
      blockEntity.addComponent(
          new HealthComponent(type.getHardness(), type.getHardness() / BLOCK_REGEN_SECONDS, 1.0f));
    } else if (health != null && !type.isDestructible()) {
      blockEntity.removeComponent(HealthComponent.class);
    } else if (health != null && type.isDestructible()) {
      health.maxHealth = type.getHardness();
      health.currentHealth = Math.min(health.currentHealth, health.maxHealth);
      blockEntity.saveComponent(health);
    }

    for (Component comp : newEntityBuilder.iterateComponents()) {
      copyIntoPrefab(blockEntity, comp, retainComponents);
    }
  }
  @ReceiveEvent(components = {FenceGateComponent.class})
  public void onActivate(ActivateEvent event, EntityRef entity) {
    FenceGateComponent fenceGateComponent = entity.getComponent(FenceGateComponent.class);
    fenceGateComponent.isClosed = !fenceGateComponent.isClosed;
    entity.saveComponent(fenceGateComponent);

    BlockComponent blockComp = entity.getComponent(BlockComponent.class);
    if (blockComp == null) {
      event.cancel();
      return;
    }

    Vector3i primePos = new Vector3i(blockComp.getPosition());
    Block primeBlock = worldProvider.getBlock(primePos);

    Block newBlock = null;
    if (fenceGateComponent.isClosed) {
      newBlock =
          BlockManager.getInstance()
              .getBlockFamily("fences:FenceGateClosed")
              .getBlockForPlacing(worldProvider, primePos, primeBlock.getDirection(), Side.FRONT);
    } else {
      newBlock =
          BlockManager.getInstance()
              .getBlockFamily("fences:FenceGateOpen")
              .getBlockForPlacing(worldProvider, primePos, primeBlock.getDirection(), Side.FRONT);
    }

    if (newBlock != null) {
      blockEntityRegistry.setBlock(primePos, newBlock, primeBlock, entity);
    }
  }
 private void updateEntity(NetData.UpdateEntityMessage updateEntity) {
   EntityRef currentEntity = networkSystem.getEntity(updateEntity.getNetId());
   if (currentEntity.exists()) {
     NetworkComponent netComp = currentEntity.getComponent(NetworkComponent.class);
     if (netComp == null) {
       logger.error(
           "Updating entity with no network component: {}, expected netId {}",
           currentEntity,
           updateEntity.getNetId());
       return;
     }
     if (netComp.getNetworkId() != updateEntity.getNetId()) {
       logger.error("Network ID wrong before update");
     }
     boolean blockEntityBefore = currentEntity.hasComponent(BlockComponent.class);
     entitySerializer.deserializeOnto(currentEntity, updateEntity.getEntity());
     BlockComponent blockComponent = currentEntity.getComponent(BlockComponent.class);
     if (blockComponent != null && !blockEntityBefore) {
       if (!blockEntityRegistry
           .getExistingBlockEntityAt(blockComponent.getPosition())
           .equals(currentEntity)) {
         logger.error("Failed to associated new block entity");
       }
     }
     if (netComp.getNetworkId() != updateEntity.getNetId()) {
       logger.error(
           "Network ID lost in update: {}, {} -> {}",
           currentEntity,
           updateEntity.getNetId(),
           netComp.getNetworkId());
     }
   } else {
     logger.warn("Received update for non-existent entity {}", updateEntity.getNetId());
   }
 }
 @ReceiveEvent(components = {BlockComponent.class})
 public void onDeactivateBlock(BeforeDeactivateComponent event, EntityRef entity) {
   BlockComponent block = entity.getComponent(BlockComponent.class);
   Vector3i pos = new Vector3i(block.getPosition());
   if (blockEntityLookup.get(pos) == entity) {
     blockEntityLookup.remove(pos);
   }
 }
 @ReceiveEvent(components = {BlockComponent.class})
 public void onActivateBlock(OnActivatedComponent event, EntityRef entity) {
   BlockComponent block = entity.getComponent(BlockComponent.class);
   EntityRef oldEntity = blockEntityLookup.put(new Vector3i(block.getPosition()), entity);
   // If this is a client, then an existing block entity may exist. Destroy it.
   if (oldEntity != null && !Objects.equal(oldEntity, entity)) {
     oldEntity.destroy();
   }
 }
 @Override
 public void onEntityComponentRemoved(EntityRef entity, Class<? extends Component> component) {
   if (entityManager.getComponentLibrary().getMetadata(component).isForceBlockActive()) {
     BlockComponent blockComp = entity.getComponent(BlockComponent.class);
     if (blockComp != null) {
       Block block =
           getBlock(
               blockComp.getPosition().x, blockComp.getPosition().y, blockComp.getPosition().z);
       if (isTemporaryBlock(entity, block, component)) {
         temporaryBlockEntities.add(entity);
       }
     }
   }
 }
  @Override
  public void initialise() {
    this.entityManager = CoreRegistry.get(EntityManager.class);
    for (EntityRef blockComp : entityManager.iteratorEntities(BlockComponent.class)) {
      BlockComponent comp = blockComp.getComponent(BlockComponent.class);
      blockComponentLookup.put(new Vector3i(comp.getPosition()), blockComp);
    }

    for (EntityRef entity : entityManager.iteratorEntities(BlockComponent.class)) {
      BlockComponent blockComp = entity.getComponent(BlockComponent.class);
      if (blockComp.temporary) {
        HealthComponent health = entity.getComponent(HealthComponent.class);
        if (health == null
            || health.currentHealth == health.maxHealth
            || health.currentHealth == 0) {
          entity.destroy();
        }
      }
    }
  }
 @ReceiveEvent(components = {BlockComponent.class})
 public void onDestroy(RemovedComponentEvent event, EntityRef entity) {
   BlockComponent block = entity.getComponent(BlockComponent.class);
   blockComponentLookup.remove(new Vector3i(block.getPosition()));
 }
 @ReceiveEvent(components = {BlockComponent.class})
 public void onCreate(AddComponentEvent event, EntityRef entity) {
   BlockComponent block = entity.getComponent(BlockComponent.class);
   blockComponentLookup.put(new Vector3i(block.getPosition()), entity);
 }