Skip to content

Commit

Permalink
feature: rework location change event (#4705)
Browse files Browse the repository at this point in the history
Co-authored-by: Tobias Nett <skaldarnar@googlemail.com>
  • Loading branch information
pollend and skaldarnar authored May 30, 2021
1 parent 7958b66 commit da80c8c
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,95 @@
// SPDX-License-Identifier: Apache-2.0
package org.terasology.engine.logic.location;

import com.google.common.base.Preconditions;
import org.joml.Quaternionf;
import org.joml.Quaternionfc;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.terasology.engine.entitySystem.event.Event;

/**
* A <i>notification event</i> that the location and/or rotation of the associated entity has changed.
* <p>
* This is similar to a {@link org.terasology.engine.entitySystem.event.BeforeAfterEvent BeforeAfterEvent} but holds the
* last and current values for both {@code position} and {@code rotation}.
*/
public class LocationChangedEvent implements Event {
public final LocationComponent component;
public final Vector3fc oldPosition;
public final Quaternionfc oldRotation;
public final Vector3fc newPosition;
public final Quaternionfc newRotation;
protected Vector3f lastPosition = new Vector3f();
protected Quaternionf lastRotation = new Quaternionf();
protected Vector3f currentPosition = new Vector3f();
protected Quaternionf currentRotation = new Quaternionf();

public LocationChangedEvent(LocationComponent newLocation) {
this(newLocation, newLocation.position, newLocation.rotation, newLocation.position, newLocation.rotation);
/**
* INTERNAL: default constructor for de-/serialization.
*/
protected LocationChangedEvent() {
}

public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition) {
this(newLocation, oPosition, newLocation.rotation, newLocation.position, newLocation.rotation);
}

public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Vector3f nPosition) {
this(newLocation, oPosition, newLocation.rotation, nPosition, newLocation.rotation);
}

public LocationChangedEvent(LocationComponent newLocation, Quaternionfc oRotation) {
this(newLocation, newLocation.position, oRotation, newLocation.position, newLocation.rotation);
}
/**
* Create a new <i>notification event</i> about a location and/or rotation change.
*
* @param lastPosition the previous position; must not be {@code null}
* @param lastRotation the previous rotation; must not be {@code null}
* @param currentPosition the current position; must not be {@code null}
* @param currentRotation the current rotation; must not be {@code null}
*/
public LocationChangedEvent(Vector3fc lastPosition, Quaternionfc lastRotation,
Vector3fc currentPosition, Quaternionfc currentRotation) {
Preconditions.checkNotNull(lastPosition);
Preconditions.checkNotNull(lastRotation);
Preconditions.checkNotNull(currentPosition);
Preconditions.checkNotNull(currentRotation);

public LocationChangedEvent(LocationComponent newLocation, Quaternionfc oRotation, Quaternionfc nRotation) {
this(newLocation, newLocation.position, oRotation, newLocation.position, nRotation);
this.lastPosition.set(lastPosition);
this.lastRotation.set(lastRotation);
this.currentPosition.set(currentPosition);
this.currentRotation.set(currentRotation);
}

public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quaternionfc oRotation) {
this(newLocation, oPosition, oRotation, newLocation.position, newLocation.rotation);
public Vector3fc lastPosition() {
return lastPosition;
}

public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quaternionfc oRotation,
Vector3f nPosition) {
this(newLocation, oPosition, oRotation, nPosition, newLocation.rotation);
public Quaternionfc lastRotation() {
return lastRotation;
}

public LocationChangedEvent(LocationComponent newLocation, Vector3f oPosition, Quaternionfc oRotation,
Quaternionfc nRotation) {
this(newLocation, oPosition, oRotation, newLocation.position, nRotation);
public Vector3fc currentPosition() {
return currentPosition;
}

public LocationChangedEvent(LocationComponent nComponent, Vector3fc oPosition, Quaternionfc oRotation,
Vector3fc nPosition, Quaternionfc nRotation) {
oldPosition = new Vector3f(oPosition);
oldRotation = new Quaternionf(oRotation);
newPosition = new Vector3f(nPosition);
newRotation = new Quaternionf(nRotation);
component = nComponent;
public Quaternionfc currentRotation() {
return currentRotation;
}

public Vector3f vectorMoved(Vector3f dest) {
return oldPosition != null ? newPosition.sub(oldPosition, dest) : dest.set(0, 0, 0);
/**
* Compute the vector that has to be added to get from {@link #lastPosition()} to {@link #currentPosition()} and
* store the result in {@code dest}.
* <p>
* If V is the computed difference between {@code last} and {@code current}, then the following equation holds:
* <p>
* <code>last + V = current</code>
*
* @param dest will hold the result
* @return {@code dest}
*/
public Vector3f positionDelta(Vector3f dest) {
return currentPosition.sub(lastPosition, dest);
}

public float distanceMoved() {
return oldPosition != null ? newPosition.distance(oldPosition) : 0.0F;
/**
* Compute the rotation that has to be applied to get from {@link #lastRotation()} to {@link #currentRotation()} and
* store the result in {@code dest}.
* <p>
* If D is the computed difference between {@code last} and {@code current}, then the following equation holds:
* <p>
* <code>last * D = current</code>
*
* @param dest will hold the result
* @return {@code dest}
*/
public Quaternionf rotationDelta(Quaternionf dest) {
return lastRotation.difference(currentRotation, dest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,45 @@
// SPDX-License-Identifier: Apache-2.0
package org.terasology.engine.logic.location;

import com.google.common.collect.Sets;
import org.terasology.engine.entitySystem.entity.EntityRef;
import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnAddedComponent;
import org.terasology.engine.entitySystem.entity.lifecycleEvents.OnChangedComponent;
import org.terasology.engine.entitySystem.event.ReceiveEvent;
import org.terasology.engine.entitySystem.systems.BaseComponentSystem;
import org.terasology.engine.entitySystem.systems.RegisterMode;
import org.terasology.engine.entitySystem.systems.RegisterSystem;
import org.terasology.engine.entitySystem.systems.UpdateSubscriberSystem;

import java.util.Set;

@RegisterSystem(RegisterMode.AUTHORITY)
public class LocationChangedSystem extends BaseComponentSystem {
public class LocationChangedSystem extends BaseComponentSystem implements UpdateSubscriberSystem {
private Set<EntityRef> process = Sets.newHashSet();

@ReceiveEvent(components = {LocationComponent.class})
public void locationChanged(OnAddedComponent event, EntityRef entity, LocationComponent lc) {
lc.clearDirtyFlag();
}

@ReceiveEvent(components = {LocationComponent.class})
public void locationChanged(OnChangedComponent event, EntityRef entity, LocationComponent lc) {
if (lc.isDirty() && (!lc.position.equals(lc.lastPosition) || !lc.rotation.equals(lc.lastRotation))) {
process.add(entity);
} else {
lc.clearDirtyFlag();
}
}

@ReceiveEvent(components = LocationComponent.class)
public void onItemUpdate(OnChangedComponent event, EntityRef entity) {
LocationComponent lc = entity.getComponent(LocationComponent.class);
if (!lc.lastPosition.equals(lc.position) || !lc.lastRotation.equals(lc.rotation)) {
entity.send(new LocationChangedEvent(lc, lc.lastPosition, lc.lastRotation));
lc.lastPosition.set(lc.position);
lc.lastRotation.set(lc.rotation);
@Override
public void update(float delta) {
for (EntityRef entity : process) {
LocationComponent lc = entity.getComponent(LocationComponent.class);
if (lc != null) {
entity.send(new LocationChangedEvent(lc.lastPosition, lc.lastRotation, lc.position, lc.rotation));
lc.clearDirtyFlag();
}
}
process.clear();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.joml.Vector3f;
import org.joml.Vector3fc;
import org.terasology.engine.entitySystem.Component;
import org.terasology.engine.entitySystem.DoNotPersist;
import org.terasology.engine.entitySystem.entity.EntityRef;
import org.terasology.engine.math.Direction;
import org.terasology.engine.network.Replicate;
Expand All @@ -26,6 +27,7 @@
public final class LocationComponent implements Component, ReplicationCheck {

public boolean replicateChanges = true;
private boolean isDirty = false;

// Relative to
@Replicate
Expand All @@ -47,13 +49,30 @@ public final class LocationComponent implements Component, ReplicationCheck {
@Replicate
Quaternionf lastRotation = new Quaternionf();


public LocationComponent() {
}

public LocationComponent(Vector3fc position) {
setLocalPosition(position);
}

private void dirty() {
if (!isDirty && parent == EntityRef.NULL) {
lastRotation.set(rotation);
lastPosition.set(position);
isDirty = true;
}
}

boolean isDirty() {
return this.isDirty;
}

void clearDirtyFlag() {
isDirty = false;
}

/**
* @return local rotation of location component
*/
Expand All @@ -71,7 +90,7 @@ public void setLocalRotation(Quaternionfc rot) {
}

public void setLocalRotation(float x, float y, float z, float w) {
lastRotation.set(rotation);
dirty();
rotation.set(x, y, z, w);
}

Expand All @@ -92,7 +111,7 @@ public void setLocalPosition(Vector3fc pos) {
}

public void setLocalPosition(float x, float y, float z) {
lastPosition.set(position);
dirty();
position.set(x, y, z);
}

Expand Down Expand Up @@ -195,7 +214,8 @@ public float getWorldScale() {
* @param pos position to set
*/
public void setWorldPosition(Vector3fc pos) {
setLocalPosition(pos);
dirty();
position.set(pos);
LocationComponent parentLoc = parent.getComponent(LocationComponent.class);
if (parentLoc != null) {
this.position.sub(parentLoc.getWorldPosition(new Vector3f()));
Expand All @@ -210,7 +230,8 @@ public void setWorldPosition(Vector3fc pos) {
* @param value position to set
*/
public void setWorldRotation(Quaternionfc value) {
setLocalRotation(value);
dirty();
rotation.set(value);
LocationComponent parentLoc = parent.getComponent(LocationComponent.class);
if (parentLoc != null) {
Quaternionf worldRot = parentLoc.getWorldRotation(new Quaternionf()).conjugate();
Expand Down

0 comments on commit da80c8c

Please sign in to comment.