@Override
  public boolean validateBeforeStart(
      EntityRef instigator, EntityRef workstation, EntityRef processEntity) {
    if (!workstation.hasComponent(WorkstationInventoryComponent.class)) {
      return false;
    }

    // Defer the heat calculation until it is actually needed
    Float heat = null;

    for (int slot : WorkstationInventoryUtils.getAssignedSlots(workstation, "INPUT")) {
      HeatProcessedComponent processed =
          InventoryUtils.getItemAt(workstation, slot).getComponent(HeatProcessedComponent.class);
      if (processed != null) {
        float heatRequired = processed.heatRequired;
        if (heat == null) {
          heat =
              HeatUtils.calculateHeatForEntity(
                  workstation, CoreRegistry.get(BlockEntityRegistry.class));
        }
        if (heatRequired <= heat) {
          final String result =
              processed.blockResult != null ? processed.blockResult : processed.itemResult;
          if (canOutputResult(workstation, result)) {
            processEntity.addComponent(new SpecificInputSlotComponent(slot));
            processEntity.addComponent(new OutputTypeComponent(result));
            return true;
          }
        }
      }
    }

    return false;
  }
  @Test
  public void allComponentsNotMarkedAsRetainedRemovedOnBlockChange() {
    worldStub.setBlock(Vector3i.zero(), blockWithString);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new ForceBlockActiveComponent());
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    worldProvider.setBlock(Vector3i.zero(), BlockManager.getAir());

    assertTrue(entity.hasComponent(RetainedOnBlockChangeComponent.class));
    assertFalse(entity.hasComponent(ForceBlockActiveComponent.class));
  }
  @Override
  public boolean step() {
    EntityManager entityManager = context.get(EntityManager.class);
    WorldRenderer worldRenderer = context.get(WorldRenderer.class);

    Iterator<EntityRef> worldEntityIterator =
        entityManager.getEntitiesWith(WorldComponent.class).iterator();
    // TODO: Move the world renderer bits elsewhere
    if (worldEntityIterator.hasNext()) {
      EntityRef worldEntity = worldEntityIterator.next();
      worldRenderer.getChunkProvider().setWorldEntity(worldEntity);

      // get the world generator config from the world entity
      // replace the world generator values from the components in the world entity
      WorldGenerator worldGenerator = context.get(WorldGenerator.class);
      WorldConfigurator worldConfigurator = worldGenerator.getConfigurator();
      Map<String, Component> params = worldConfigurator.getProperties();
      for (Map.Entry<String, Component> entry : params.entrySet()) {
        Class<? extends Component> clazz = entry.getValue().getClass();
        Component comp = worldEntity.getComponent(clazz);
        if (comp != null) {
          worldConfigurator.setProperty(entry.getKey(), comp);
        }
      }
    } else {
      EntityRef worldEntity = entityManager.create();
      worldEntity.addComponent(new WorldComponent());
      worldRenderer.getChunkProvider().setWorldEntity(worldEntity);

      // transfer all world generation parameters from Config to WorldEntity
      WorldGenerator worldGenerator = context.get(WorldGenerator.class);
      SimpleUri generatorUri = worldGenerator.getUri();
      Config config = context.get(Config.class);

      // get the map of properties from the world generator.
      // Replace its values with values from the config set by the UI.
      // Also set all the components to the world entity.
      WorldConfigurator worldConfigurator = worldGenerator.getConfigurator();
      Map<String, Component> params = worldConfigurator.getProperties();
      for (Map.Entry<String, Component> entry : params.entrySet()) {
        Class<? extends Component> clazz = entry.getValue().getClass();
        Component comp = config.getModuleConfig(generatorUri, entry.getKey(), clazz);
        if (comp != null) {
          worldEntity.addComponent(comp);
          worldConfigurator.setProperty(entry.getKey(), comp);
        } else {
          worldEntity.addComponent(entry.getValue());
        }
      }
    }

    return true;
  }
 private boolean processOutputForSetResetGate(EntityRef blockEntity) {
   SignalConsumerAdvancedStatusComponent consumerAdvancedStatusComponent =
       blockEntity.getComponent(SignalConsumerAdvancedStatusComponent.class);
   EnumSet<Side> signals = SideBitFlag.getSides(consumerAdvancedStatusComponent.sidesWithSignals);
   SignalProducerComponent producerComponent =
       blockEntity.getComponent(SignalProducerComponent.class);
   int resultSignal = producerComponent.signalStrength;
   if (signals.contains(Side.TOP) || signals.contains(Side.BOTTOM)) {
     resultSignal = 0;
   } else if (signals.size() > 0) {
     resultSignal = -1;
   }
   if (producerComponent.signalStrength != resultSignal) {
     producerComponent.signalStrength = resultSignal;
     blockEntity.saveComponent(producerComponent);
     if (resultSignal != 0) {
       if (!blockEntity.hasComponent(SignalProducerModifiedComponent.class)) {
         blockEntity.addComponent(new SignalProducerModifiedComponent());
       }
     } else if (blockEntity.hasComponent(SignalProducerModifiedComponent.class)) {
       blockEntity.removeComponent(SignalProducerModifiedComponent.class);
     }
     return true;
   }
   return false;
 }
  /**
   * 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);
    }
  }
  private void cleanUpTemporaryEntity(EntityRef entity) {
    Prefab prefab = entity.getParentPrefab();

    for (Component comp : entity.iterateComponents()) {
      if (!COMMON_BLOCK_COMPONENTS.contains(comp.getClass())
          && (prefab == null || !prefab.hasComponent(comp.getClass()))) {
        entity.removeComponent(comp.getClass());
      }
    }
    entity.removeComponent(NetworkComponent.class);

    if (prefab != null) {
      for (Component comp : prefab.iterateComponents()) {
        Component currentComp = entity.getComponent(comp.getClass());
        if (currentComp == null) {
          entity.addComponent(entityManager.getComponentLibrary().copy(comp));
        } else {
          ComponentMetadata<?> metadata =
              entityManager.getComponentLibrary().getMetadata(comp.getClass());
          boolean changed = false;
          for (FieldMetadata field : metadata.getFields()) {
            Object expected = field.getValue(comp);
            if (!Objects.equal(expected, field.getValue(currentComp))) {
              field.setValue(currentComp, expected);
              changed = true;
            }
          }
          if (changed) {
            entity.saveComponent(currentComp);
          }
        }
      }
    }
    entityManager.destroyEntityWithoutEvents(entity);
  }
 @Test
 public void testEntityNotRemovedIfForceBlockActiveComponentAdded() {
   EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
   blockEntity.addComponent(new ForceBlockActiveComponent());
   worldProvider.update(1.0f);
   assertTrue(blockEntity.exists());
   assertTrue(blockEntity.isActive());
 }
 @Test
 public void componentUntouchedIfRetainRequested() {
   worldProvider.setBlock(Vector3i.zero(), blockInFamilyOne);
   EntityRef entity = worldProvider.getBlockEntityAt(Vector3i.zero());
   entity.addComponent(new IntegerComponent());
   worldProvider.setBlockRetainComponent(Vector3i.zero(), blockWithString, IntegerComponent.class);
   assertNotNull(entity.getComponent(IntegerComponent.class));
 }
 @Test
 public void componentsAlteredIfBlockInSameFamilyWhenForced() {
   worldProvider.setBlock(Vector3i.zero(), blockInFamilyOne);
   EntityRef entity = worldProvider.getBlockEntityAt(Vector3i.zero());
   entity.addComponent(new IntegerComponent());
   worldProvider.setBlockForceUpdateEntity(Vector3i.zero(), blockInFamilyTwo);
   assertNull(entity.getComponent(IntegerComponent.class));
 }
  @Test
  public void retainedComponentsNotAltered() {
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    worldProvider.setBlock(Vector3i.zero(), blockWithRetainedComponent);

    assertEquals(2, entity.getComponent(RetainedOnBlockChangeComponent.class).value);
  }
 @Test
 public void testEntityBecomesTemporaryIfForceBlockActiveComponentRemoved() {
   EntityRef blockEntity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
   blockEntity.addComponent(new ForceBlockActiveComponent());
   worldProvider.update(1.0f);
   blockEntity.removeComponent(ForceBlockActiveComponent.class);
   worldProvider.update(1.0f);
   assertFalse(blockEntity.exists());
   assertFalse(blockEntity.isActive());
 }
 @Override
 public void onEntityComponentAdded(EntityRef entity, Class<? extends Component> component) {
   if (temporaryBlockEntities.contains(entity)
       && entityManager.getComponentLibrary().getMetadata(component).isForceBlockActive()) {
     temporaryBlockEntities.remove(entity);
     if (!entity.hasComponent(NetworkComponent.class)) {
       entity.addComponent(new NetworkComponent());
     }
   }
 }
 private boolean startProducingSignal(EntityRef entity, int signalStrength) {
   final SignalProducerComponent producer = entity.getComponent(SignalProducerComponent.class);
   if (producer.signalStrength != signalStrength) {
     producer.signalStrength = signalStrength;
     entity.saveComponent(producer);
     entity.addComponent(new SignalProducerModifiedComponent());
     return true;
   }
   return false;
 }
  private void signalButtonActivated(EntityRef block, SignalProducerComponent producerComponent) {
    if (block.hasComponent(SignalDelayedActionComponent.class)) {
      block.removeComponent(SignalDelayedActionComponent.class);
    }

    SignalDelayedActionComponent actionComponent = new SignalDelayedActionComponent();
    actionComponent.executeTime = time.getGameTimeInMs() + BUTTON_PRESS_TIME;
    block.addComponent(actionComponent);

    startProducingSignal(block, -1);
  }
 @SuppressWarnings("unchecked")
 private <T extends Component> void copyIntoPrefab(
     EntityRef blockEntity, T comp, Set<Class<? extends Component>> retainComponents) {
   ComponentMetadata<T> metadata =
       entityManager.getComponentLibrary().getMetadata((Class<T>) comp.getClass());
   if (!blockEntity.hasComponent(comp.getClass())) {
     blockEntity.addComponent(metadata.copyRaw(comp));
   } else if (!metadata.isRetainUnalteredOnBlockChange()
       && !retainComponents.contains(metadata.getType())) {
     updateComponent(blockEntity, metadata, comp);
   }
 }
  @Override
  public void applyEffect(EntityRef instigator, EntityRef entity, float magnitude, long duration) {
    StunComponent stun = entity.getComponent(StunComponent.class);
    if (stun == null) {
      stun = new StunComponent();
      entity.addComponent(stun);
    }

    if (duration != AlterationEffects.DURATION_INDEFINITE) {
      delayManager.addDelayedAction(
          entity, AlterationEffects.EXPIRE_TRIGGER_PREFIX + AlterationEffects.STUN, duration);
    }
  }
  @ReceiveEvent(components = {BlockComponent.class, SignalTimeDelayComponent.class})
  public void configureTimeDelay(SetSignalDelayEvent event, EntityRef entity) {
    SignalTimeDelayComponent timeDelayComponent =
        entity.getComponent(SignalTimeDelayComponent.class);
    timeDelayComponent.delaySetting = Math.min(500, event.getTime());

    entity.saveComponent(timeDelayComponent);
    if (timeDelayComponent.delaySetting == 1000
        && entity.hasComponent(SignalTimeDelayModifiedComponent.class)) {
      entity.removeComponent(SignalTimeDelayModifiedComponent.class);
    } else if (!entity.hasComponent(SignalTimeDelayModifiedComponent.class)) {
      entity.addComponent(new SignalTimeDelayModifiedComponent());
    }
  }
  @Test
  public void networkComponentAddedWhenChangedToNonTemporary() {
    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), NetworkComponent.class);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    assertEquals(
        Lists.newArrayList(
            new EventInfo(OnAddedComponent.newInstance(), entity),
            new EventInfo(OnActivatedComponent.newInstance(), entity)),
        checker.receivedEvents);
    assertTrue(entity.hasComponent(NetworkComponent.class));
  }
  @Test
  public void testEntityExtraComponentsRemovedBeforeCleanUp() {
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new StringComponent("test"));

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), StringComponent.class);

    worldProvider.update(1.0f);
    assertEquals(
        Lists.newArrayList(
            new EventInfo(BeforeDeactivateComponent.newInstance(), entity),
            new EventInfo(BeforeRemoveComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
  @Test
  public void testEntityExtraComponentsRemovedBeforeCleanUpForBlocksWithPrefabs() {
    worldStub.setBlock(Vector3i.zero(), blockWithString);
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new IntegerComponent(1));

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), IntegerComponent.class);

    worldProvider.update(1.0f);
    assertEquals(
        Lists.newArrayList(
            new EventInfo(BeforeDeactivateComponent.newInstance(), entity),
            new EventInfo(BeforeRemoveComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
 private void signalChangedForDelayOnGate(
     EntityRef entity, SignalConsumerStatusComponent consumerStatusComponent) {
   SignalTimeDelayComponent delay = entity.getComponent(SignalTimeDelayComponent.class);
   if (consumerStatusComponent.hasSignal) {
     // Schedule for the gate to be looked at when the time passes
     SignalDelayedActionComponent delayedAction = new SignalDelayedActionComponent();
     delayedAction.executeTime = time.getGameTimeInMs() + delay.delaySetting;
     entity.addComponent(delayedAction);
   } else {
     // Remove any signal-delayed actions on the entity and turn off signal from it, if it has any
     if (entity.hasComponent(SignalDelayedActionComponent.class)) {
       entity.removeComponent(SignalDelayedActionComponent.class);
     }
     stopProducingSignal(entity);
   }
 }
  @Test
  public void networkComponentRemovedWhenTemporaryCleanedUp() {
    EntityRef entity = worldProvider.getBlockEntityAt(new Vector3i(0, 0, 0));
    entity.addComponent(new RetainedOnBlockChangeComponent(2));

    LifecycleEventChecker checker =
        new LifecycleEventChecker(entityManager.getEventSystem(), NetworkComponent.class);
    entity.removeComponent(RetainedOnBlockChangeComponent.class);

    worldProvider.update(1.0f);

    assertEquals(
        Lists.newArrayList(
            new EventInfo(BeforeDeactivateComponent.newInstance(), entity),
            new EventInfo(BeforeRemoveComponent.newInstance(), entity)),
        checker.receivedEvents);
  }
 private void delayGateSignalChangeIfNeeded(EntityRef entity) {
   if (!entity.hasComponent(SignalDelayedActionComponent.class)) {
     // Schedule for the gate to be looked either immediately (during "update" method) or at least
     // GATE_MINIMUM_SIGNAL_CHANGE_INTERVAL from the time it has last changed, whichever is later
     SignalDelayedActionComponent delayedAction = new SignalDelayedActionComponent();
     long whenToLookAt;
     final ImmutableBlockLocation location =
         new ImmutableBlockLocation(entity.getComponent(BlockComponent.class).getPosition());
     if (gateLastSignalChangeTime.containsKey(location)) {
       whenToLookAt = gateLastSignalChangeTime.get(location) + GATE_MINIMUM_SIGNAL_CHANGE_INTERVAL;
     } else {
       whenToLookAt = time.getGameTimeInMs();
     }
     delayedAction.executeTime = whenToLookAt;
     entity.addComponent(delayedAction);
   }
 }
  @Override
  public void applyEffect(EntityRef instigator, EntityRef entity, float magnitude, long duration) {
    boolean add = false;
    WalkSpeedComponent walkSpeed = entity.getComponent(WalkSpeedComponent.class);
    if (walkSpeed == null) {
      add = true;
      walkSpeed = new WalkSpeedComponent();
    }
    walkSpeed.multiplier = magnitude;

    if (add) {
      entity.addComponent(walkSpeed);
    } else {
      entity.saveComponent(walkSpeed);
    }

    CoreRegistry.get(DelayManager.class)
        .addDelayedAction(
            entity,
            AlterationEffects.EXPIRE_TRIGGER_PREFIX + AlterationEffects.WALK_SPEED,
            duration);
  }