All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.vrspace.server.obj.VRObject Maven / Gradle / Ivy

The newest version!
package org.vrspace.server.obj;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.data.annotation.Transient;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.schema.Relationship;
import org.vrspace.server.dto.VREvent;
import org.vrspace.server.types.ID;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonMerge;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

/**
 * Basic VR Object encapsulates minimal spatial and other properties.
 * 
 * @author joe
 *
 */
@Data
@NoArgsConstructor
@JsonInclude(Include.NON_EMPTY)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@EqualsAndHashCode(callSuper = true, onlyExplicitlyIncluded = true)
@Node
@ToString(callSuper = true, onlyExplicitlyIncluded = true)
@Slf4j
public class VRObject extends Entity {

  private List children;

  /* World this object is in, only id is persisted */
  @JsonIgnore
  private Long worldId;
  @Transient
  @Setter(AccessLevel.NONE)
  @JsonIgnore
  /* World this object is in, not persisted to avoid deadlocks */
  private transient World world;

  public void setWorld(World world) {
    if (world == null) {
      this.setWorldId(null);
    } else {
      this.setWorldId(world.getId());
    }
    this.world = world;
  }

  /**
   * Position in 3D space, used for spatial operations.
   */
  @JsonMerge
  @Relationship(type = "HAS_POSITION", direction = Relationship.Direction.OUTGOING)
  private Point position;

  @JsonMerge
  private Rotation rotation;

  @JsonMerge
  @Relationship(type = "HAS_SCALE", direction = Relationship.Direction.OUTGOING)
  private Point scale;

  /** Permanent objects are always present (e.g. sky) */
  private Boolean permanent;

  /**
   * Temporary objects will be deleted from the database along with their owner
   */
  @Transient
  private transient Boolean temporary;

  /**
   * Whether an object is active (can send events). E.g. online users, robots.
   */
  // @JsonIgnore CHECKME: should we publish that?
  private Boolean active;

  /**
   * URL of the file containing the mesh.
   */
  private String mesh;

  /**
   * Script that client runs. To prevent cross-site scripting, this is a read-only
   * property.
   */
  @JsonProperty
  private String script;

  /** Currently active animation */
  @JsonMerge
  @Relationship(type = "CURRENT_ANIMATION", direction = Relationship.Direction.OUTGOING)
  private Animation animation;

  /** Custom object properties */
  @Transient
  private transient Map properties;

  @JsonIgnore
  @Transient
  private transient ConcurrentHashMap listeners;

  public VRObject(World world) {
    setWorldId(world.getId());
  }

  public VRObject(Long id, VRObject... vrObjects) {
    super(id);
    addChildren(vrObjects);
  }

  public VRObject(Long id, double x, double y, double z, VRObject... vrObjects) {
    this(id, vrObjects);
    this.position = new Point(x, y, z);
  }

  public VRObject(double x, double y, double z) {
    setPosition(new Point(x, y, z));
  }

  public VRObject(World world, double x, double y, double z) {
    this(world);
    setPosition(new Point(x, y, z));
  }

  public void addChildren(VRObject... vrObjects) {
    if (children == null) {
      children = new LinkedList();
    }
    for (VRObject obj : vrObjects) {
      if (equals(obj)) {
        // weak protection against circular references
        throw new IllegalArgumentException("Can't have self as member");
      }
      children.add(obj);
    }
  }

  public boolean isPermanent() {
    return permanent != null && permanent;
  }

  public void addListener(VRObject obj) {
    if (listeners == null) {
      listeners = new ConcurrentHashMap();
    }
    listeners.put(new ID(obj), obj);
  }

  public void removeListener(VRObject obj) {
    if (listeners != null) {
      listeners.remove(new ID(obj));
    }
  }

  public void notifyListeners(VREvent event) {
    if (listeners != null) {
      for (VRObject listener : listeners.values()) {
        try {
          listener.processEvent(event);
        } catch (Exception e) {
          log.error("Error processing event " + event, e);
        }
      }
    }
  }

  /**
   * This implementation does nothing
   * 
   * @param event Whatever has changed
   */
  public void processEvent(VREvent event) {
  }

  public VRObject active() {
    this.active = Boolean.TRUE;
    return this;
  }

  public VRObject passive() {
    this.active = Boolean.FALSE;
    return this;
  }

  public boolean isActive() {
    return active != null && active;
  }

  public boolean isTemporary() {
    return temporary != null && temporary;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy