public EntityData.PackedEntity serialize(
      EntityRef entityRef,
      Set<Class<? extends Component>> added,
      Set<Class<? extends Component>> changed,
      Set<Class<? extends Component>> removed,
      FieldSerializeCheck<Component> fieldCheck) {
    EntityData.PackedEntity.Builder entity = EntityData.PackedEntity.newBuilder();

    ByteString.Output fieldIds = ByteString.newOutput();
    ByteString.Output componentFieldCounts = ByteString.newOutput();
    for (Class<? extends Component> componentType : added) {
      Component component = entityRef.getComponent(componentType);
      if (component == null) {
        logger.error("Non-existent component marked as added: {}", componentType);
      }
      serializeComponentFull(
          entityRef.getComponent(componentType),
          false,
          fieldCheck,
          entity,
          fieldIds,
          componentFieldCounts,
          true);
    }
    for (Class<? extends Component> componentType : changed) {
      Component comp = entityRef.getComponent(componentType);
      if (comp != null) {
        serializeComponentFull(
            comp, true, fieldCheck, entity, fieldIds, componentFieldCounts, false);
      } else {
        logger.error("Non-existent component marked as changed: {}", componentType);
      }
    }
    for (Class<? extends Component> componentType : removed) {
      entity.addRemovedComponent(idTable.get(componentType));
    }
    entity.setFieldIds(fieldIds.toByteString());
    entity.setComponentFieldCounts(componentFieldCounts.toByteString());
    if (entity.getFieldIds().isEmpty() && entity.getRemovedComponentCount() == 0) {
      return null;
    } else {
      return entity.build();
    }
  }
  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;
  }