let the entities be aware of their world

This commit is contained in:
Tofaa 2024-01-29 13:19:45 +04:00
parent 522e31ef12
commit 3183a3140d
9 changed files with 280 additions and 53 deletions

View file

@ -5,16 +5,15 @@
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment=""> <list default="true" id="9d5d9b6f-43c8-41a4-bb42-a66ffc96c9b0" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/CompatibilityIndex.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APISettings.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/APIConfig.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/WorldWrapper.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/UsedVersion.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/EntityLibAPI.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/meta/VersionCompatCheck.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/Platform.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/tick/Tickable.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractEntityLibAPI.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/WrapperEntity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractPlatform.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" beforeDir="false" afterPath="$PROJECT_DIR$/api/src/main/java/me/tofaa/entitylib/wrapper/ai/goals/RandomHeadMovementGoal.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibAPI.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" beforeDir="false" afterPath="$PROJECT_DIR$/common/src/main/java/me/tofaa/entitylib/common/AbstractWorldWrapper.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" beforeDir="false" afterPath="$PROJECT_DIR$/platforms/spigot/src/main/java/me/tofaa/entitylib/spigot/SpigotEntityLibPlatform.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/testentitylib/TestEntityLibPlugin.java" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -256,7 +255,8 @@
<workItem from="1706248178234" duration="17096000" /> <workItem from="1706248178234" duration="17096000" />
<workItem from="1706284605696" duration="11691000" /> <workItem from="1706284605696" duration="11691000" />
<workItem from="1706371324325" duration="1187000" /> <workItem from="1706371324325" duration="1187000" />
<workItem from="1706443875388" duration="3245000" /> <workItem from="1706443875388" duration="4827000" />
<workItem from="1706513591682" duration="2661000" />
</task> </task>
<servers /> <servers />
</component> </component>

View file

@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.world.Dimension; import com.github.retrooper.packetevents.protocol.world.Dimension;
import com.github.retrooper.packetevents.protocol.world.Location; import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState; import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
import me.tofaa.entitylib.tick.TickContainer;
import me.tofaa.entitylib.wrapper.WrapperEntity; import me.tofaa.entitylib.wrapper.WrapperEntity;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;

View file

@ -0,0 +1,9 @@
package me.tofaa.entitylib.meta;
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataType;
public interface CompatibilityIndex {
byte getOffSet(byte latestOffset, EntityDataType<?> type);
}

View file

@ -1,9 +0,0 @@
package me.tofaa.entitylib.meta;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
public @interface UsedVersion {
ServerVersion[] value();
}

View file

@ -1,15 +0,0 @@
package me.tofaa.entitylib.meta;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.manager.server.VersionComparison;
import me.tofaa.entitylib.EntityLib;
public final class VersionCompatCheck {
private VersionCompatCheck() {}
static boolean isVersion(ServerVersion version) {
return version.is(VersionComparison.EQUALS, EntityLib.getApi().getPacketEvents().getServerManager().getVersion());
}
}

View file

@ -2,6 +2,21 @@ package me.tofaa.entitylib.tick;
public interface Tickable { public interface Tickable {
/**
* @return if the entity is ticking.
*/
boolean isTicking();
/**
* Sets the entities ticking status, incase you want to stop ticking for a moment then continue
* @param ticking if the entity should tick.
*/
void setTicking(boolean ticking);
/**
* Ticks this entity. This method will not be called if {@link #isTicking()} returns false.
* @param time the current time in milliseconds.
*/
void tick(long time); void tick(long time);
} }

View file

@ -2,52 +2,106 @@ package me.tofaa.entitylib.wrapper;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.protocol.player.User; import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
import com.github.retrooper.packetevents.protocol.world.Location; import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.util.Vector3d; import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.wrapper.PacketWrapper; import com.github.retrooper.packetevents.wrapper.PacketWrapper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDestroyEntities; import com.github.retrooper.packetevents.wrapper.play.server.*;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityRotation;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityVelocity;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSpawnEntity;
import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.EntityLib;
import me.tofaa.entitylib.WorldWrapper;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.meta.types.ObjectData;
import me.tofaa.entitylib.tick.Tickable; import me.tofaa.entitylib.tick.Tickable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.text.html.parser.Entity; import javax.swing.text.html.parser.Entity;
import java.util.Collections; import java.util.*;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
public class WrapperEntity implements Tickable { public class WrapperEntity implements Tickable {
private final UUID uuid; private final UUID uuid;
private final int entityId; private final int entityId;
private EntityType entityType; private EntityType entityType;
private EntityMeta entityMeta; private EntityMeta entityMeta;
private boolean ticking;
private Location location; private Location location;
private Location preRidingLocation;
private Set<UUID> viewers; private Set<UUID> viewers;
private boolean onGround; private boolean onGround;
private boolean spawned; private boolean spawned;
private Vector3d velocity; private Vector3d velocity;
private int riding = -1;
private Set<Integer> passengers = new HashSet<>();
private WorldWrapper<?> world;
public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) { public WrapperEntity(int entityId, UUID uuid, EntityType entityType, EntityMeta entityMeta) {
this.entityId = entityId; this.entityId = entityId;
this.uuid = uuid; this.uuid = uuid;
this.entityType = entityType; this.entityType = entityType;
this.entityMeta = entityMeta; this.entityMeta = entityMeta;
this.ticking = true;
} }
public void spawn() {} public boolean spawn(WorldWrapper<?> world, Location location) {
if (spawned) return false;
public void despawn() {}
public void teleport(@NotNull Location location) {
this.location = location; this.location = location;
this.world = world;
this.spawned = true;
int data = 0;
Optional<Vector3d> velocity;
double veloX = 0, veloY = 0, veloZ = 0;
if (entityMeta instanceof ObjectData) {
ObjectData od = (ObjectData) entityMeta;
data = od.getObjectData();
if (od.requiresVelocityPacketAtSpawn()) {
final WrapperPlayServerEntityVelocity veloPacket = getVelocityPacket();
veloX = veloPacket.getVelocity().getX();
veloY = veloPacket.getVelocity().getY();
veloZ = veloPacket.getVelocity().getZ();
}
}
if (veloX == 0 && veloY == 0 && veloZ == 0) {
velocity = Optional.empty();
} else {
velocity = Optional.of(new Vector3d(veloX, veloY, veloZ));
}
sendPacketToViewers(
new WrapperPlayServerSpawnEntity(
entityId,
Optional.of(this.uuid),
entityType,
location.getPosition(),
location.getPitch(),
location.getYaw(),
location.getYaw(),
data,
velocity
)
);
sendPacketToViewers(entityMeta.createPacket());
return true;
}
public void despawn() {
if (!spawned) return;
spawned = false;
sendPacketToViewers(new WrapperPlayServerDestroyEntities(entityId));
}
public void teleport(WorldWrapper<?> world, @NotNull Location location) {
this.location = location;
this.world = world;
sendPacketToViewers(
new WrapperPlayServerEntityTeleport(
entityId,
location.getPosition(),
location.getYaw(),
location.getPitch(),
onGround
)
);
} }
public boolean addViewer(UUID uuid) { public boolean addViewer(UUID uuid) {
@ -131,12 +185,44 @@ public class WrapperEntity implements Tickable {
return entityType; return entityType;
} }
/**
* Returns an unmodifiable set of the passengers of the entity.
* @return the passengers of the entity
*/
public Set<Integer> getPassengers() {
return Collections.unmodifiableSet(passengers);
}
public WrapperEntity getRiding() {
return world.getEntity(riding);
}
protected WrapperPlayServerSetPassengers createPassengerPacket() {
return new WrapperPlayServerSetPassengers(entityId, passengers.stream().mapToInt(i -> i).toArray());
}
private WrapperPlayServerEntityVelocity getVelocityPacket() { private WrapperPlayServerEntityVelocity getVelocityPacket() {
Vector3d velocity = this.velocity.multiply(8000.0f / 20.0f); Vector3d velocity = this.velocity.multiply(8000.0f / 20.0f);
return new WrapperPlayServerEntityVelocity(entityId, velocity); return new WrapperPlayServerEntityVelocity(entityId, velocity);
} }
public boolean isSpawned() {
return spawned;
}
@Override
public boolean isTicking() {
return ticking;
}
@Override
public void setTicking(boolean ticking) {
this.ticking = ticking;
}
public boolean hasVelocity() { public boolean hasVelocity() {
if (isOnGround()) { if (isOnGround()) {
// if the entity is on the ground and only "moves" downwards, it does not have a velocity. // if the entity is on the ground and only "moves" downwards, it does not have a velocity.
@ -189,6 +275,135 @@ public class WrapperEntity implements Tickable {
refresh(); refresh();
} }
/**
* Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
* @param passenger the entity id of the passenger
*/
public void addPassenger(int passenger) {
if (passengers.contains(passenger)) {
throw new IllegalArgumentException("Passenger already exists");
}
passengers.add(passenger);
sendPacketToViewers(createPassengerPacket());
WrapperEntity e = world.getEntity(passenger);
if (e != null) {
e.riding = this.entityId;
e.preRidingLocation = e.location;
}
}
public @Nullable Location getPreRidingLocation() {
return preRidingLocation;
}
/**
* @return the entity id of the entity that the entity is riding, -1 if the entity is not riding
*/
public int getRidingId() {
return riding;
}
/**
* Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
* @param passengers the entity ids of the passengers
*/
public void addPassengers(int... passengers) {
for (int passenger : passengers) {
addPassenger(passenger);
}
}
/**
* Adds a passenger to the entity. The passenger will be visible to all viewers of the entity.
* @param passenger the wrapper entity passenger
*/
public void addPassenger(WrapperEntity passenger) {
addPassenger(passenger.getEntityId());
}
/**
* Adds multiple passengers to the entity. The passengers will be visible to all viewers of the entity.
* @param passengers the wrapper entity passengers
*/
public void addPassengers(WrapperEntity... passengers) {
for (WrapperEntity passenger : passengers) {
addPassenger(passenger);
}
}
/**
* Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
* @param passenger the entity id of the passenger
*/
public void removePassenger(int passenger) {
if (!passengers.contains(passenger)) {
throw new IllegalArgumentException("Passenger does not exist");
}
passengers.remove(passenger);
sendPacketToViewers(createPassengerPacket());
WrapperEntity e = world.getEntity(passenger);
if (e != null) {
e.riding = -1;
e.teleport(world, e.preRidingLocation);
}
}
public WorldWrapper<?> getWorld() {
return world;
}
/**
* @param passenger the entity id of the passenger
* @return true if the entity has the passenger, false otherwise
*/
public boolean hasPassenger(int passenger) {
return passengers.contains(passenger);
}
/**
* @param passenger the passenger wrapper entity
* @return true if the entity has the passenger, false otherwise
*/
public boolean hasPassenger(WrapperEntity passenger) {
return hasPassenger(passenger.getEntityId());
}
/**
* Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
* @param passengers the entity ids of the passengers
*/
public void removePassengers(int... passengers) {
for (int passenger : passengers) {
removePassenger(passenger);
}
}
/**
* Removes a passenger from the entity. The passenger will be removed from the view of all viewers of the entity.
* @param passenger the wrapper entity passenger
*/
public void removePassenger(WrapperEntity passenger) {
removePassenger(passenger.getEntityId());
}
/**
* Removes multiple passengers from the entity. The passengers will be removed from the view of all viewers of the entity.
* @param passengers the wrapper entity passengers
*/
public void removePassengers(WrapperEntity... passengers) {
for (WrapperEntity passenger : passengers) {
removePassenger(passenger);
}
}
/**
* @return true if the entity has passengers, false otherwise
*/
public boolean isRiding() {
return riding != -1;
}
public @NotNull Set<UUID> getViewers() { public @NotNull Set<UUID> getViewers() {
return Collections.unmodifiableSet(viewers); return Collections.unmodifiableSet(viewers);
} }
@ -199,6 +414,18 @@ public class WrapperEntity implements Tickable {
@Override @Override
public void tick(long time) { public void tick(long time) {
if (isRiding()) {
WrapperEntity riding = getRiding();
if (riding != null) {
Location l = riding.getLocation();
location = new Location(
l.getX(),
l.getY() + 1,
l.getZ(),
l.getYaw(),
l.getPitch()
);
}
}
} }
} }

View file

@ -66,7 +66,7 @@ public class RandomHeadMovementGoal extends GoalSelector {
@Override @Override
public void tick(long time) { public void tick(long time) {
--lookTime; --lookTime;
entity.teleport(CoordinateUtil.withDirection(entity.getLocation(), lookDirection)); entity.teleport(entity.getWorld(), CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
} }
@Override @Override

View file

@ -37,8 +37,7 @@ public abstract class AbstractWorldWrapper<W> implements WorldWrapper<W> {
@Override @Override
public <T extends WrapperEntity> @NotNull T spawnEntity(@NotNull T entity, @NotNull Location location) { public <T extends WrapperEntity> @NotNull T spawnEntity(@NotNull T entity, @NotNull Location location) {
entity.teleport(location); entity.spawn(this, location);
entity.spawn();
entities.put(entity.getUuid(), entity); entities.put(entity.getUuid(), entity);
entitiesById.put(entity.getEntityId(), entity); entitiesById.put(entity.getEntityId(), entity);
return entity; return entity;