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);
   }
 }
  private void handleDelayedActionsEvents() {
    long worldTime = time.getGameTimeInMs();
    BlockAtLocationDelayedAction action;
    while ((action = delayedActions.peek()) != null && action.executeTime <= worldTime) {
      action = delayedActions.poll();

      final Vector3i actionLocation = action.blockLocation.toVector3i();
      if (worldProvider.isBlockRelevant(actionLocation)) {
        final Block block = worldProvider.getBlock(actionLocation);
        final BlockFamily blockFamily = block.getBlockFamily();

        final EntityRef blockEntity = blockEntityRegistry.getBlockEntityAt(actionLocation);

        if (blockFamily == signalOnDelayGate) {
          startProducingSignal(blockEntity, -1);
        } else if (blockFamily == signalOffDelayGate) {
          stopProducingSignal(blockEntity);
        } else if (blockFamily == signalOrGate
            || blockFamily == signalAndGate
            || blockFamily == signalXorGate) {
          if (processOutputForNormalGate(blockEntity)) {
            gateLastSignalChangeTime.put(new ImmutableBlockLocation(actionLocation), worldTime);
          }
        } else if (blockFamily == signalNandGate) {
          if (processOutputForRevertedGate(blockEntity)) {
            gateLastSignalChangeTime.put(new ImmutableBlockLocation(actionLocation), worldTime);
          }
        } else if (blockFamily == signalSetResetGate) {
          if (processOutputForSetResetGate(blockEntity)) {
            gateLastSignalChangeTime.put(new ImmutableBlockLocation(actionLocation), worldTime);
          }
        } else if (block == signalButton) {
          stopProducingSignal(blockEntity);
        }

        blockEntity.removeComponent(SignalDelayedActionComponent.class);
      } else {
        // TODO Remove this workaround when BlockEntities will be stored with the chunk they belong
        // to
        action.executeTime += NOT_LOADED_BLOCK_RETRY_DELAY;
        delayedActions.add(action);
      }
    }
  }
 private void deleteOldSignalChangesForGates() {
   long worldTime = time.getGameTimeInMs();
   if (lastSignalCleanupExecuteTime + SIGNAL_CLEANUP_INTERVAL < worldTime) {
     final TObjectLongIterator<ImmutableBlockLocation> iterator =
         gateLastSignalChangeTime.iterator();
     while (iterator.hasNext()) {
       iterator.advance();
       if (iterator.value() + GATE_MINIMUM_SIGNAL_CHANGE_INTERVAL < worldTime) {
         iterator.remove();
       }
     }
     lastSignalCleanupExecuteTime = worldTime;
   }
 }