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);
  }
  private Class<? extends Component> getComponentClass(EntityData.Component componentData) {
    if (componentData.hasTypeIndex()) {
      ComponentMetadata metadata =
          componentLibrary.getMetadata(componentIdTable.get(componentData.getTypeIndex()));
      if (metadata == null) {
        logger.log(
            Level.WARNING,
            "Unable to deserialise unknown component with id: " + componentData.getTypeIndex());
        return null;
      }
      return metadata.getType();
    } else if (componentData.hasType()) {
      ComponentMetadata metadata =
          componentLibrary.getMetadata(componentData.getType().toLowerCase(Locale.ENGLISH));
      if (metadata == null) {
        logger.log(
            Level.WARNING,
            "Unable to deserialise unknown component type: " + componentData.getType());
        return null;
      }
      return metadata.getType();
    }
    logger.log(Level.WARNING, "Unable to deserialise component, no type provided.");

    return null;
  }
  @Override
  public void deserializeWorld(EntityData.World world) {
    entityManager.setNextId(world.getNextEntityId());
    for (Integer deadId : world.getFreedEntityIdList()) {
      entityManager.getFreedIds().add(deadId);
    }

    for (EntityData.Prefab prefabData : world.getPrefabList()) {
      if (!prefabManager.exists(prefabData.getName())) {
        deserializePrefab(prefabData);
      }
    }

    for (int index = 0; index < world.getComponentClassCount(); ++index) {
      ComponentMetadata componentMetadata =
          componentLibrary.getMetadata(world.getComponentClass(index));
      if (componentMetadata != null) {
        componentIdTable.put(index, componentMetadata.getType());
      }
    }

    for (EntityData.Entity entityData : world.getEntityList()) {
      deserializeEntity(entityData);
    }
  }
 private void writeComponentTypeTable(EntityData.World.Builder world) {
   for (ComponentMetadata<?> componentMetadata : componentLibrary) {
     int index = componentIdTable.size();
     componentIdTable.put(index, componentMetadata.getType());
     world.addComponentClass(ComponentUtil.getComponentClassName(componentMetadata.getType()));
   }
 }
  private void serializeComponentFull(
      Component component,
      boolean ignoreIfNoFields,
      FieldSerializeCheck<Component> fieldCheck,
      EntityData.PackedEntity.Builder entityData,
      ByteString.Output entityFieldIds,
      ByteString.Output componentFieldCounts,
      boolean componentInitial) {
    ComponentMetadata<?> componentMetadata = componentLibrary.getMetadata(component.getClass());
    if (componentMetadata == null) {
      logger.error("Unregistered component type: {}", component.getClass());
      return;
    }

    Serializer serializer = typeSerializationLibrary.getSerializerFor(componentMetadata);
    byte fieldCount = 0;
    for (ReplicatedFieldMetadata field : componentMetadata.getFields()) {
      if (fieldCheck.shouldSerializeField(field, component, componentInitial)) {
        PersistedData fieldValue = serializer.serialize(field, component, serializationContext);
        if (!fieldValue.isNull()) {
          entityFieldIds.write(field.getId());

          entityData.addFieldValue(((ProtobufPersistedData) fieldValue).getValue());
          fieldCount++;
        }
      }
    }

    if (fieldCount != 0 || !ignoreIfNoFields) {
      entityData.addComponentId(idTable.get(component.getClass()));
      componentFieldCounts.write(fieldCount);
    }
  }
 @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 Component deserializeComponent(EntityData.Component componentData) {
   Class<? extends Component> componentClass = getComponentClass(componentData);
   if (componentClass != null) {
     ComponentMetadata componentMetadata = componentLibrary.getMetadata(componentClass);
     Component component = componentMetadata.newInstance();
     return deserializeOnto(component, componentData, componentMetadata);
   } else {
     logger.log(
         Level.WARNING,
         "Unable to deserialise unknown component type: " + componentData.getType());
   }
   return null;
 }
  private boolean isTemporaryBlock(
      ComponentContainer entity, Block block, Class<? extends Component> ignoreComponent) {
    if (block.isKeepActive()) {
      return false;
    }

    for (ComponentMetadata<?> metadata :
        entityManager.getComponentLibrary().iterateComponentMetadata()) {
      if (metadata.isForceBlockActive() && ignoreComponent != metadata.getType()) {
        if (entity.hasComponent(metadata.getType())) {
          return false;
        }
      }
    }
    return true;
  }
 private <T extends Component> void updateComponent(
     EntityRef blockEntity, ComponentMetadata<T> metadata, T targetComponent) {
   T currentComp = blockEntity.getComponent(metadata.getType());
   if (currentComp != null) {
     boolean changed = false;
     for (FieldMetadata<T, ?> field : metadata.getFields()) {
       Object newVal = field.getValue(targetComponent);
       if (!Objects.equal(field.getValue(currentComp), newVal)) {
         field.setValue(currentComp, newVal);
         changed = true;
       }
     }
     if (changed) {
       blockEntity.saveComponent(currentComp);
     }
   }
 }
  private void serializeComponentDelta(
      Component oldComponent,
      Component newComponent,
      FieldSerializeCheck<Component> fieldCheck,
      EntityData.PackedEntity.Builder entityData,
      ByteString.Output entityFieldIds,
      ByteString.Output componentFieldCounts,
      boolean componentInitial) {
    ComponentMetadata<?> componentMetadata = componentLibrary.getMetadata(oldComponent.getClass());
    if (componentMetadata == null) {
      logger.error("Unregistered component type: {}", oldComponent.getClass());
      return;
    }

    byte fieldCount = 0;
    Serializer serializer = typeSerializationLibrary.getSerializerFor(componentMetadata);
    for (ReplicatedFieldMetadata field : componentMetadata.getFields()) {
      if (fieldCheck.shouldSerializeField(field, newComponent, componentInitial)) {
        Object oldValue = field.getValue(oldComponent);
        Object newValue = field.getValue(newComponent);
        if (!Objects.equal(oldValue, newValue)) {
          PersistedData data = serializer.serializeValue(field, newValue, serializationContext);
          if (!data.isNull()) {
            entityFieldIds.write(field.getId());
            entityData.addFieldValue(((ProtobufPersistedData) data).getValue());
            fieldCount++;
          } else {
            logger.error(
                "Exception serializing component type: {}, field: {} - returned null",
                componentMetadata,
                field);
          }
        }
      }
    }

    if (fieldCount > 0) {
      entityData.addComponentId(idTable.get(newComponent.getClass()));
      componentFieldCounts.write(fieldCount);
    }
  }
  private EntityData.Component serializeComponent(Component base, Component delta) {
    ComponentMetadata<?> componentMetadata = componentLibrary.getMetadata(base.getClass());
    if (componentMetadata == null) {
      logger.log(Level.SEVERE, "Unregistered component type: " + base.getClass());
      return null;
    }

    EntityData.Component.Builder componentMessage = EntityData.Component.newBuilder();
    if (useLookupTables) {
      componentMessage.setTypeIndex(componentIdTable.inverse().get(base.getClass()));
    } else {
      componentMessage.setType(ComponentUtil.getComponentClassName(delta));
    }

    boolean changed = false;
    for (FieldMetadata field : componentMetadata.iterateFields()) {
      try {
        Object origValue = field.getValue(base);
        Object deltaValue = field.getValue(delta);

        if (!Objects.equal(origValue, deltaValue)) {
          EntityData.Value value = field.serialize(deltaValue);
          componentMessage.addField(
              EntityData.NameValue.newBuilder().setName(field.getName()).setValue(value).build());
          changed = true;
        }
      } catch (IllegalAccessException e) {
        logger.log(
            Level.SEVERE, "Exception during serializing component type: " + base.getClass(), e);
      } catch (InvocationTargetException e) {
        logger.log(
            Level.SEVERE, "Exception during serializing component type: " + base.getClass(), e);
      }
    }
    if (changed) {
      return componentMessage.build();
    }
    return null;
  }
  @Override
  public EntityData.Component serializeComponent(Component component) {
    ComponentMetadata<?> componentMetadata = componentLibrary.getMetadata(component.getClass());
    if (componentMetadata == null) {
      logger.log(Level.SEVERE, "Unregistered component type: " + component.getClass());
      return null;
    }
    EntityData.Component.Builder componentMessage = EntityData.Component.newBuilder();
    if (useLookupTables) {
      componentMessage.setTypeIndex(componentIdTable.inverse().get(component.getClass()));
    } else {
      componentMessage.setType(ComponentUtil.getComponentClassName(component));
    }

    for (FieldMetadata field : componentMetadata.iterateFields()) {
      try {
        Object rawValue = field.getValue(component);
        if (rawValue == null) continue;

        EntityData.Value value = field.serialize(rawValue);
        if (value == null) continue;

        componentMessage.addField(
            EntityData.NameValue.newBuilder().setName(field.getName()).setValue(value).build());
      } catch (IllegalAccessException e) {
        logger.log(
            Level.SEVERE,
            "Exception during serializing component type: " + component.getClass(),
            e);
      } catch (InvocationTargetException e) {
        logger.log(
            Level.SEVERE,
            "Exception during serializing component type: " + component.getClass(),
            e);
      }
    }

    return componentMessage.build();
  }
  private Component deserializeOnto(
      Component component,
      EntityData.Component componentData,
      ComponentMetadata componentMetadata) {
    try {
      for (EntityData.NameValue field : componentData.getFieldList()) {
        FieldMetadata fieldInfo = componentMetadata.getField(field.getName());
        if (fieldInfo == null) continue;

        Object value = fieldInfo.deserialize(field.getValue());
        if (value == null) continue;
        fieldInfo.setValue(component, value);
      }
      return component;
    } catch (InvocationTargetException e) {
      logger.log(
          Level.SEVERE, "Exception during serializing component type: " + component.getClass(), e);
    } catch (IllegalAccessException e) {
      logger.log(
          Level.SEVERE, "Exception during serializing component type: " + component.getClass(), e);
    }
    return null;
  }
  public void deserializeOnto(
      MutableComponentContainer entity,
      EntityData.PackedEntity entityData,
      FieldSerializeCheck<Component> fieldCheck) {
    int fieldPos = 0;
    for (int componentIndex = 0;
        componentIndex < entityData.getComponentIdCount();
        ++componentIndex) {
      Class<? extends Component> componentClass =
          idTable.inverse().get((Integer) entityData.getComponentId(componentIndex));
      ComponentMetadata<?> metadata = componentLibrary.getMetadata(componentClass);
      if (metadata == null) {
        logger.warn("Skipping unknown component {}", entityData.getComponentId(componentIndex));
        fieldPos +=
            UnsignedBytes.toInt(entityData.getComponentFieldCounts().byteAt(componentIndex));
        continue;
      }
      if (!componentSerializeCheck.serialize(metadata)) {
        fieldPos +=
            UnsignedBytes.toInt(entityData.getComponentFieldCounts().byteAt(componentIndex));
        continue;
      }

      Component component = entity.getComponent(metadata.getType());
      boolean createdNewComponent = false;
      if (component == null) {
        createdNewComponent = true;
        component = metadata.newInstance();
      }
      Serializer serializer = typeSerializationLibrary.getSerializerFor(metadata);
      for (int fieldIndex = 0;
          fieldIndex
              < UnsignedBytes.toInt(entityData.getComponentFieldCounts().byteAt(componentIndex));
          ++fieldIndex) {
        byte fieldId = entityData.getFieldIds().byteAt(fieldPos);
        ReplicatedFieldMetadata fieldMetadata = metadata.getField(fieldId);
        if (fieldMetadata != null && fieldCheck.shouldDeserialize(metadata, fieldMetadata)) {
          logger.trace(
              "Deserializing field {} of component {} as value {}",
              fieldMetadata,
              metadata,
              entityData.getFieldValue(fieldPos));
          serializer.deserializeOnto(
              component,
              fieldMetadata,
              new ProtobufPersistedData(entityData.getFieldValue(fieldPos)),
              deserializationContext);
        }
        fieldPos++;
      }
      if (createdNewComponent) {
        entity.addComponent(component);
      } else {
        entity.saveComponent(component);
      }
    }

    for (int componentId : entityData.getRemovedComponentList()) {
      Class<? extends Component> componentClass = idTable.inverse().get(componentId);
      ComponentMetadata<?> metadata = componentLibrary.getMetadata(componentClass);
      if (componentSerializeCheck.serialize(metadata)) {
        entity.removeComponent(metadata.getType());
      }
    }
  }