private EntityData.PackedEntity.Builder serializeEntityDelta(
      EntityRef entityRef, Prefab prefab, FieldSerializeCheck<Component> fieldCheck) {
    EntityData.PackedEntity.Builder entity = EntityData.PackedEntity.newBuilder();
    entity.setParentPrefabUri(prefab.getName());
    Set<Class<? extends Component>> presentClasses = Sets.newHashSet();

    ByteString.Output fieldIds = ByteString.newOutput();
    ByteString.Output componentFieldCounts = ByteString.newOutput();
    for (Component component : entityRef.iterateComponents()) {
      if (!componentSerializeCheck.serialize(componentLibrary.getMetadata(component.getClass()))) {
        continue;
      }

      presentClasses.add(component.getClass());

      Component prefabComponent = prefab.getComponent(component.getClass());

      if (prefabComponent == null) {
        serializeComponentFull(
            component, false, fieldCheck, entity, fieldIds, componentFieldCounts, true);
      } else {
        serializeComponentDelta(
            prefabComponent, component, fieldCheck, entity, fieldIds, componentFieldCounts, true);
      }
    }
    entity.setFieldIds(fieldIds.toByteString());
    entity.setComponentFieldCounts(componentFieldCounts.toByteString());

    for (Component prefabComponent : prefab.iterateComponents()) {
      if (!presentClasses.contains(prefabComponent.getClass())
          && componentSerializeCheck.serialize(
              componentLibrary.getMetadata(prefabComponent.getClass()))) {
        entity.addRemovedComponent(idTable.get(prefabComponent.getClass()));
      }
    }
    return entity;
  }
  private EntityData.PackedEntity.Builder serializeEntityFull(
      EntityRef entityRef, FieldSerializeCheck<Component> fieldCheck) {
    EntityData.PackedEntity.Builder entity = EntityData.PackedEntity.newBuilder();
    ByteString.Output fieldIds = ByteString.newOutput();
    ByteString.Output componentFieldCounts = ByteString.newOutput();
    for (Component component : entityRef.iterateComponents()) {
      if (!componentSerializeCheck.serialize(componentLibrary.getMetadata(component.getClass()))) {
        continue;
      }

      serializeComponentFull(
          component, false, fieldCheck, entity, fieldIds, componentFieldCounts, true);
    }
    entity.setFieldIds(fieldIds.toByteString());
    entity.setComponentFieldCounts(componentFieldCounts.toByteString());

    return entity;
  }
  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());
      }
    }
  }