Package org.terasology.persistence.serializers

Source Code of org.terasology.persistence.serializers.EntitySerializer

/*
* Copyright 2013 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.persistence.serializers;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.terasology.entitySystem.Component;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.entity.internal.EngineEntityManager;
import org.terasology.entitySystem.entity.internal.EntityInfoComponent;
import org.terasology.entitySystem.metadata.ComponentLibrary;
import org.terasology.entitySystem.metadata.ComponentMetadata;
import org.terasology.entitySystem.prefab.Prefab;
import org.terasology.entitySystem.prefab.PrefabManager;
import org.terasology.persistence.typeHandling.TypeSerializationLibrary;
import org.terasology.protobuf.EntityData;

import java.util.Map;
import java.util.Set;

/**
* Provides the ability to serialize and deserialize entities to the EntityData.Entity proto buffer format.
* <p/>
* As with the component serializer, a component id mapping can be provided to have components serialized against
* ids rather than name strings.
* <p/>
* It is also possible to set whether entity ids will be handled or ignored - if ignored then deserialized entities will
* be given new ids.
*
* @author Immortius
*/
public class EntitySerializer {
    private EngineEntityManager entityManager;
    private PrefabManager prefabManager;
    private ComponentLibrary componentLibrary;
    private ComponentSerializer componentSerializer;

    private ComponentSerializeCheck componentSerializeCheck = ComponentSerializeCheck.NullCheck.create();
    private boolean ignoringEntityId;

    /**
     * @param entityManager The entityManager that deserialized entities will be placed in.
     */
    public EntitySerializer(EngineEntityManager entityManager) {
        this(entityManager, entityManager.getComponentLibrary(), entityManager.getTypeSerializerLibrary());
    }

    public EntitySerializer(EngineEntityManager entityManager, ComponentLibrary componentLibrary, TypeSerializationLibrary typeSerializationLibrary) {
        this.entityManager = entityManager;
        this.prefabManager = entityManager.getPrefabManager();
        this.componentLibrary = componentLibrary;
        this.componentSerializer = new ComponentSerializer(componentLibrary, typeSerializationLibrary);
    }

    /**
     * @return Whether entity ids are being ignored during serialization/deserialization
     */
    public boolean isIgnoringEntityId() {
        return ignoringEntityId;
    }

    public boolean isUsingFieldIds() {
        return componentSerializer.isUsingFieldIds();
    }

    public void setUsingFieldIds(boolean usingFieldIds) {
        componentSerializer.setUsingFieldIds(usingFieldIds);
    }

    public void setComponentSerializeCheck(ComponentSerializeCheck check) {
        this.componentSerializeCheck = check;
    }

    /**
     * Sets whether entity ids should be ignored during serialization and deserialization.
     * If ignored, then they will not be stored in the protobuf, and deserialized entities will be given new ids. This
     * may break entity references, depending on how they are being handled (see: EntityRefTypeHandler)
     *
     * @param ignoringEntityId
     */
    public void setIgnoringEntityId(boolean ignoringEntityId) {
        this.ignoringEntityId = ignoringEntityId;
    }

    /**
     * Sets the mapping between component classes and the ids that are used for serialization
     *
     * @param table
     */
    public void setComponentIdMapping(Map<Class<? extends Component>, Integer> table) {
        componentSerializer.setIdMapping(table);
    }

    /**
     * @return An immutable copy of the component id mapping
     */
    public Map<Class<? extends Component>, Integer> getComponentIdMapping() {
        return componentSerializer.getIdMapping();
    }

    /**
     * Clears the mapping between component classes and ids. This causes components to be serialized with their component
     * class name instead.
     */
    public void removeComponentIdMapping() {
        componentSerializer.removeIdMapping();
    }

    /**
     * @param entityRef
     * @return The serialized entity
     */
    public EntityData.Entity serialize(EntityRef entityRef) {
        return serialize(entityRef, true, FieldSerializeCheck.NullCheck.<Component>newInstance());
    }

    /**
     * @param entityRef
     * @param deltaAgainstPrefab Whether the serialized entity should be a delta against its prefab (if any)
     * @return The serialized entity
     */
    public EntityData.Entity serialize(EntityRef entityRef, boolean deltaAgainstPrefab) {
        return serialize(entityRef, deltaAgainstPrefab, FieldSerializeCheck.NullCheck.<Component>newInstance());
    }

    /**
     * @param entityRef
     * @param fieldCheck Used to check whether each field in each component of the entity should be serialized.
     * @return The serialized entity
     */
    public EntityData.Entity serialize(EntityRef entityRef, FieldSerializeCheck<Component> fieldCheck) {
        return serialize(entityRef, true, fieldCheck);
    }

    /**
     * @param entityRef
     * @param fieldCheck Used to check whether each field in each component of the entity should be serialized.
     * @return The serialized entity
     */
    public EntityData.Entity serialize(EntityRef entityRef, boolean deltaAgainstPrefab, FieldSerializeCheck<Component> fieldCheck) {
        Prefab prefab = entityRef.getParentPrefab();
        if (prefab != null && deltaAgainstPrefab) {
            return serializeEntityDelta(entityRef, prefab, fieldCheck);
        } else {
            return serializeEntityFull(entityRef, fieldCheck);
        }
    }

    /**
     * @param entityData
     * @return The deserialized entity
     */
    public EntityRef deserialize(EntityData.Entity entityData) {
        Map<Class<? extends Component>, Component> componentMap = createInitialComponents(entityData);
        deserializeOntoComponents(entityData, componentMap);
        if (ignoringEntityId) {
            return entityManager.create(componentMap.values());
        } else {
            return entityManager.createEntityWithId(entityData.getId(), componentMap.values());
        }
    }

    /**
     * Creates the components for the entity being deserialized based on its prefab (if any)
     *
     * @param entityData
     * @return The mapping of components
     */
    private Map<Class<? extends Component>, Component> createInitialComponents(EntityData.Entity entityData) {
        Set<ComponentMetadata<?>> removedComponents = Sets.newHashSet();
        for (String removedComp : entityData.getRemovedComponentList()) {
            ComponentMetadata<?> removedMetadata = componentLibrary.resolve(removedComp);
            if (removedMetadata != null) {
                removedComponents.add(removedMetadata);
            }
        }

        Map<Class<? extends Component>, Component> componentMap = Maps.newHashMap();
        if (entityData.hasParentPrefab() && !entityData.getParentPrefab().isEmpty() && prefabManager.exists(entityData.getParentPrefab())) {
            Prefab prefab = prefabManager.getPrefab(entityData.getParentPrefab());
            for (Component component : prefab.iterateComponents()) {
                ComponentMetadata<?> metadata = componentLibrary.getMetadata(component);
                if (!removedComponents.contains(metadata)) {
                    componentMap.put(component.getClass(), componentLibrary.copy(component));
                }
            }
            componentMap.put(EntityInfoComponent.class, new EntityInfoComponent(entityData.getParentPrefab(), true, prefab.isAlwaysRelevant()));
        }
        return componentMap;
    }

    /**
     * Deserializes the components from an EntityData onto a map of components
     *
     * @param entityData
     * @param componentMap
     */
    private void deserializeOntoComponents(EntityData.Entity entityData, Map<Class<? extends Component>, Component> componentMap) {
        EntityInfoComponent entityInfo = (EntityInfoComponent) componentMap.get(EntityInfoComponent.class);
        if (entityInfo == null) {
            entityInfo = new EntityInfoComponent();
            componentMap.put(EntityInfoComponent.class, entityInfo);
        }
        if (entityData.hasOwner()) {
            entityInfo.owner = entityManager.getEntity(entityData.getOwner());
        }
        if (entityData.hasAlwaysRelevant()) {
            entityInfo.alwaysRelevant = entityData.getAlwaysRelevant();
        }

        for (EntityData.Component componentData : entityData.getComponentList()) {
            ComponentMetadata<? extends Component> metadata = componentSerializer.getComponentMetadata(componentData);
            if (metadata == null || !componentSerializeCheck.serialize(metadata)) {
                continue;
            }

            Component existingComponent = componentMap.get(metadata.getType());
            if (existingComponent == null) {
                Component newComponent = componentSerializer.deserialize(componentData);
                componentMap.put(metadata.getType(), newComponent);
            } else {
                componentSerializer.deserializeOnto(existingComponent, componentData, FieldSerializeCheck.NullCheck.<Component>newInstance());
            }
        }
    }

    private EntityData.Entity serializeEntityFull(EntityRef entityRef, FieldSerializeCheck<Component> fieldCheck) {
        EntityData.Entity.Builder entity = EntityData.Entity.newBuilder();
        if (!ignoringEntityId) {
            entity.setId(entityRef.getId());
        }
        entity.setAlwaysRelevant(entityRef.isAlwaysRelevant());
        EntityRef owner = entityRef.getOwner();
        if (owner.exists()) {
            entity.setOwner(owner.getId());
        }
        for (Component component : entityRef.iterateComponents()) {
            if (!componentSerializeCheck.serialize(componentLibrary.getMetadata(component.getClass()))) {
                continue;
            }

            EntityData.Component componentData = componentSerializer.serialize(component, fieldCheck);
            if (componentData != null) {
                entity.addComponent(componentData);
            }
        }
        return entity.build();
    }

    private EntityData.Entity serializeEntityDelta(EntityRef entityRef, Prefab prefab, FieldSerializeCheck<Component> fieldCheck) {
        EntityData.Entity.Builder entity = EntityData.Entity.newBuilder();
        if (!ignoringEntityId) {
            entity.setId(entityRef.getId());
        }
        entity.setParentPrefab(prefab.getName());
        if (entityRef.isAlwaysRelevant() != prefab.isAlwaysRelevant()) {
            entity.setAlwaysRelevant(entityRef.isAlwaysRelevant());
        }
        EntityRef owner = entityRef.getOwner();
        if (owner.exists()) {
            entity.setOwner(owner.getId());
        }
        Set<Class<? extends Component>> presentClasses = Sets.newHashSet();
        for (Component component : entityRef.iterateComponents()) {
            if (!componentSerializeCheck.serialize(componentLibrary.getMetadata(component.getClass()))) {
                continue;
            }

            presentClasses.add(component.getClass());

            Component prefabComponent = prefab.getComponent(component.getClass());
            EntityData.Component componentData;
            if (prefabComponent == null) {
                componentData = componentSerializer.serialize(component, fieldCheck);
            } else {
                componentData = componentSerializer.serialize(prefabComponent, component, fieldCheck);
            }

            if (componentData != null) {
                entity.addComponent(componentData);
            }
        }
        for (Component prefabComponent : prefab.iterateComponents()) {
            ComponentMetadata<?> metadata = componentLibrary.getMetadata(prefabComponent.getClass());
            if (!presentClasses.contains(prefabComponent.getClass()) && componentSerializeCheck.serialize(metadata)) {
                // TODO: Use component ids here
                entity.addRemovedComponent(metadata.getUri().toString());
            }
        }
        return entity.build();
    }

}
TOP

Related Classes of org.terasology.persistence.serializers.EntitySerializer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.