I think i finished goal selectors

This commit is contained in:
Tofaa 2024-01-18 07:38:24 +03:00
parent 41da2e4c8e
commit 76efbdcb1f
13 changed files with 404 additions and 44 deletions

View file

@ -5,21 +5,19 @@
</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$/src/main/java/me/tofaa/entitylib/Tickable.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelectorList.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/TickingContainer.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/goals/RandomHeadMovementGoal.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperEntityCreature.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/extras/CoordinateUtil.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperExperienceOrbEntity.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/AIGroup.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelector.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/TargetSelector.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/world/WrapperWorld.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/SpawnClickableFrogCommand.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$/src/main/java/me/tofaa/entitylib/EntityLib.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/EntityLib.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/TickingContainer.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/TickingContainer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperEntity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperEntityCreature.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperEntityCreature.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/WrapperLivingEntity.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/java/me/tofaa/entitylib/EntityLibPlugin.java" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/AIGroup.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/AIGroup.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" beforeDir="false" afterPath="$PROJECT_DIR$/test-plugin/src/main/resources/plugin.yml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelector.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/GoalSelector.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/entity/ai/TargetSelector.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/me/tofaa/entitylib/world/WrapperWorld.java" beforeDir="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" />
@ -221,7 +219,7 @@
<workItem from="1704485939274" duration="2440000" /> <workItem from="1704485939274" duration="2440000" />
<workItem from="1704502790346" duration="6191000" /> <workItem from="1704502790346" duration="6191000" />
<workItem from="1705192736239" duration="496000" /> <workItem from="1705192736239" duration="496000" />
<workItem from="1705534524814" duration="8652000" /> <workItem from="1705534524814" duration="13073000" />
</task> </task>
<servers /> <servers />
</component> </component>

View file

@ -1,5 +1,6 @@
# EntityLib # EntityLib
EntityLib is a PacketEvents addon that provides an abstraction over raw entity data and packets to make it easier to work with entities as a whole. EntityLib is a PacketEvents addon that provides an abstraction over raw entity data and packets to make it easier to work with entities as a whole.
Currently EntityLib is only stable for 1.18+, but it will support all versions that PacketEvents supports in the future.
```groovy ```groovy
//https://jitpack.io/#Tofaa2/EntityLib/ //https://jitpack.io/#Tofaa2/EntityLib/
repositories { repositories {
@ -99,7 +100,7 @@ Once this list is complete, i will release a stable version of the library.
- [ ] Add support for more actions using WrapperEntities. - [ ] Add support for more actions using WrapperEntities.
- [ ] More javadocs. - [ ] More javadocs.
- [x] Make ObjectData actually useful. - [x] Make ObjectData actually useful.
- [ ] Multi-version support - [ ] Multi-version support, currently only 1.18+ is stable.
- [ ] Make class names match the protocol specified names. - [ ] Make class names match the protocol specified names.
### Credits ### Credits

View file

@ -1,5 +1,10 @@
package me.tofaa.entitylib; package me.tofaa.entitylib;
/**
* A container that can hold and tick {@link Tickable}s.
* This is for specific users to extend if they want ticking functionality.
*
*/
public interface TickingContainer { public interface TickingContainer {
void addTickable(Tickable tickable); void addTickable(Tickable tickable);

View file

@ -24,7 +24,7 @@ public class WrapperEntity implements Tickable {
private Location location; private Location location;
private boolean onGround; private boolean onGround;
private boolean spawned; private boolean spawned;
private Vector3d velocity = Vector3d.zero(); protected Vector3d velocity = Vector3d.zero();
public WrapperEntity(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) { public WrapperEntity(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
this.uuid = Optional.of(uuid); this.uuid = Optional.of(uuid);

View file

@ -1,10 +1,14 @@
package me.tofaa.entitylib.entity; package me.tofaa.entitylib.entity;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import me.tofaa.entitylib.entity.ai.AIGroup;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.EntityLib; import me.tofaa.entitylib.EntityLib;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
@ -18,9 +22,55 @@ import java.util.UUID;
* The {@link WrapperEntityCreature} can be inherited to create custom entities. * The {@link WrapperEntityCreature} can be inherited to create custom entities.
* </p> * </p>
*/ */
public class WrapperEntityCreature extends WrapperLivingEntity{ public class WrapperEntityCreature extends WrapperLivingEntity {
private final Set<AIGroup> aiGroups;
public WrapperEntityCreature(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) { public WrapperEntityCreature(int entityId, @NotNull UUID uuid, EntityType entityType, EntityMeta meta) {
super(entityId, uuid, entityType, meta); super(entityId, uuid, entityType, meta);
this.aiGroups = new HashSet<>();
} }
@Override
public void kill() {
super.kill();
}
/**
* Adds an {@link AIGroup} to the entity.
* <p>
* The AIGroup will be updated every tick.
* </p>
*
* @param aiGroup The AIGroup to add.
*/
public void addAIGroup(AIGroup aiGroup) {
aiGroups.add(aiGroup);
}
/**
* Removes an {@link AIGroup} from the entity.
*
* @param aiGroup The AIGroup to remove.
*/
public void removeAIGroup(AIGroup aiGroup) {
aiGroups.remove(aiGroup);
}
/**
* Removes all {@link AIGroup}s from the entity.
*/
public void clearAIGroups() {
aiGroups.clear();
}
/**
* Gets the {@link AIGroup}s of the entity.
*
* @return The AIGroups of the entity.
*/
public Set<AIGroup> getAIGroups() {
return Collections.unmodifiableSet(aiGroups);
}
} }

View file

@ -1,6 +1,9 @@
package me.tofaa.entitylib.entity; package me.tofaa.entitylib.entity;
import com.github.retrooper.packetevents.protocol.entity.type.EntityType; import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
import com.github.retrooper.packetevents.util.Vector3d;
import com.github.retrooper.packetevents.util.Vector3f;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityStatus;
import me.tofaa.entitylib.meta.EntityMeta; import me.tofaa.entitylib.meta.EntityMeta;
import me.tofaa.entitylib.meta.types.LivingEntityMeta; import me.tofaa.entitylib.meta.types.LivingEntityMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -18,6 +21,16 @@ public class WrapperLivingEntity extends WrapperEntity{
} }
public void kill() {
sendStatus((byte) 3);
setHealth(0);
this.velocity = Vector3d.zero();
}
public void sendStatus(byte status) {
sendPacketsToViewers(new WrapperPlayServerEntityStatus(getEntityId(), status));
}
public float getHealth() { public float getHealth() {
return getMeta().getHealth(); return getMeta().getHealth();
} }

View file

@ -1,4 +1,69 @@
package me.tofaa.entitylib.entity.ai; package me.tofaa.entitylib.entity.ai;
public interface AIGroup { import me.tofaa.entitylib.Tickable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
public class AIGroup implements Tickable {
private final List<GoalSelector> goalSelectors = new GoalSelectorList(this);
private GoalSelector currentGoalSelector;
public @NotNull Collection<GoalSelector> getGoalSelectors() {
return goalSelectors;
}
public @Nullable GoalSelector getCurrentGoal() {
return currentGoalSelector;
}
/**
* Adds a goal selector to the end of the list. Might be potentially unsafe to use after the entity has been spawned.
*
* @param goalSelector the goal selector to add
*/
public void addGoalSelector(@NotNull GoalSelector goalSelector) {
this.goalSelectors.add(goalSelector);
}
public void setCurrentGoal(@Nullable GoalSelector goalSelector) {
if (goalSelector != null && goalSelector.getAIGroup() != this) {
throw new IllegalArgumentException("GoalSelector is not in this AIGroup");
}
currentGoalSelector = goalSelector;
}
@Override
public void update(long time) {
GoalSelector currentGoalSelector = getCurrentGoal();
if (currentGoalSelector != null && currentGoalSelector.shouldEnd()) {
currentGoalSelector.end();
currentGoalSelector = null;
setCurrentGoal(null);
}
for (GoalSelector selector : getGoalSelectors()) {
if (selector == currentGoalSelector) {
break;
}
if (selector.shouldStart()) {
if (currentGoalSelector != null) {
currentGoalSelector.end();
}
currentGoalSelector = selector;
setCurrentGoal(currentGoalSelector);
currentGoalSelector.start();
break;
}
}
if (currentGoalSelector != null) {
currentGoalSelector.tick(time);
}
}
} }

View file

@ -1,4 +1,85 @@
package me.tofaa.entitylib.entity.ai; package me.tofaa.entitylib.entity.ai;
public class GoalSelector { import me.tofaa.entitylib.entity.WrapperEntityCreature;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.ref.WeakReference;
/**
* Goals represent tasks that a {@link me.tofaa.entitylib.entity.WrapperEntityCreature} can perform.
*/
public abstract class GoalSelector {
private WeakReference<AIGroup> aiGroupRef;
protected WrapperEntityCreature entity;
public GoalSelector(WrapperEntityCreature entity) {
this.entity = entity;
}
/**
* Whether this {@link GoalSelector} should start.
*
* @return true to start
*/
public abstract boolean shouldStart();
/**
* Starts this {@link GoalSelector}.
*/
public abstract void start();
/**
* Called every tick when this {@link GoalSelector} is running.
*
* @param time the time of the update in milliseconds
*/
public abstract void tick(long time);
/**
* Whether this {@link GoalSelector} should end.
*
* @return true to end
*/
public abstract boolean shouldEnd();
/**
* Ends this {@link GoalSelector}.
*/
public abstract void end();
/**
* Gets the entity behind the goal selector.
*
* @return the entity
*/
@NotNull
public WrapperEntityCreature getEntityCreature() {
return entity;
}
/**
* Changes the entity affected by the goal selector.
* <p>
* WARNING: this does not add the goal selector to {@code entityCreature},
* this only change the internal entity AI group's field. Be sure to remove the goal from
* the previous entity AI group and add it to the new one using {@link AIGroup#getGoalSelectors()}.
*
* @param entity the new affected entity
*/
public void setEntityCreature(@NotNull WrapperEntityCreature entity) {
this.entity = entity;
}
void setAIGroup(@NotNull AIGroup group) {
this.aiGroupRef = new WeakReference<>(group);
}
@Nullable
protected AIGroup getAIGroup() {
return this.aiGroupRef.get();
}
} }

View file

@ -0,0 +1,54 @@
package me.tofaa.entitylib.entity.ai;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.UnaryOperator;
final class GoalSelectorList extends ArrayList<GoalSelector> {
final AIGroup aiGroup;
GoalSelectorList(AIGroup aiGroup) {
this.aiGroup = aiGroup;
}
@Override
public GoalSelector set(int index, GoalSelector element) {
element.setAIGroup(aiGroup);
return super.set(index, element);
}
@Override
public boolean add(GoalSelector element) {
element.setAIGroup(aiGroup);
return super.add(element);
}
@Override
public void add(int index, GoalSelector element) {
element.setAIGroup(aiGroup);
super.add(index, element);
}
@Override
public boolean addAll(Collection<? extends GoalSelector> c) {
c.forEach(goalSelector -> goalSelector.setAIGroup(aiGroup));
return super.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends GoalSelector> c) {
c.forEach(goalSelector -> goalSelector.setAIGroup(aiGroup));
return super.addAll(index, c);
}
@Override
public void replaceAll(UnaryOperator<GoalSelector> operator) {
super.replaceAll(goalSelector -> {
goalSelector = operator.apply(goalSelector);
goalSelector.setAIGroup(aiGroup);
return goalSelector;
});
}
}

View file

@ -1,4 +0,0 @@
package me.tofaa.entitylib.entity.ai;
public class TargetSelector {
}

View file

@ -0,0 +1,81 @@
package me.tofaa.entitylib.entity.ai.goals;
import com.github.retrooper.packetevents.util.Vector3d;
import me.tofaa.entitylib.entity.WrapperEntityCreature;
import me.tofaa.entitylib.entity.ai.GoalSelector;
import me.tofaa.entitylib.extras.CoordinateUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
import java.util.function.Function;
import java.util.function.Supplier;
public class RandomHeadMovementGoal extends GoalSelector {
private static final Random RANDOM = new Random();
private final int chancePerTick;
private final Supplier<Integer> minimalLookTimeSupplier;
private final Function<WrapperEntityCreature, Vector3d> randomDirectionFunction;
private Vector3d lookDirection;
private int lookTime = 0;
public RandomHeadMovementGoal(WrapperEntityCreature entityCreature, int chancePerTick) {
this(entityCreature, chancePerTick,
// These two functions act similarly enough to how MC randomly looks around.
// Look in one direction for at most 40 ticks and at minimum 20 ticks.
() -> 20 + RANDOM.nextInt(20),
// Look at a random block
(creature) -> {
final double n = Math.PI * 2 * RANDOM.nextDouble();
return new Vector3d(
(float) Math.cos(n),
0,
(float) Math.sin(n)
);
});
}
/**
* @param entityCreature Creature that should randomly look around.
* @param chancePerTick The chance (per tick) that the entity looks around. Setting this to N would mean there is a 1 in N chance.
* @param minimalLookTimeSupplier A supplier that returns the minimal amount of time an entity looks in a direction.
* @param randomDirectionFunction A function that returns a random vector that the entity will look in/at.
*/
public RandomHeadMovementGoal(
WrapperEntityCreature entityCreature,
int chancePerTick,
@NotNull Supplier<Integer> minimalLookTimeSupplier,
@NotNull Function<WrapperEntityCreature, Vector3d> randomDirectionFunction) {
super(entityCreature);
this.chancePerTick = chancePerTick;
this.minimalLookTimeSupplier = minimalLookTimeSupplier;
this.randomDirectionFunction = randomDirectionFunction;
}
@Override
public boolean shouldStart() {
return RANDOM.nextInt(chancePerTick) == 0;
}
@Override
public void start() {
lookTime = minimalLookTimeSupplier.get();
lookDirection = randomDirectionFunction.apply(entity);
}
@Override
public void tick(long time) {
--lookTime;
entity.teleport(CoordinateUtil.withDirection(entity.getLocation(), lookDirection));
}
@Override
public boolean shouldEnd() {
return this.lookTime < 0;
}
@Override
public void end() {
}
}

View file

@ -0,0 +1,38 @@
package me.tofaa.entitylib.extras;
import com.github.retrooper.packetevents.protocol.world.Location;
import com.github.retrooper.packetevents.util.Vector3d;
public final class CoordinateUtil {
private CoordinateUtil() {}
public static Location withDirection(Location location, Vector3d direction) {
/*
* Sin = Opp / Hyp
* Cos = Adj / Hyp
* Tan = Opp / Adj
*
* x = -Opp
* z = Adj
*/
final double x = direction.getX();
final double z = direction.getZ();
if (x == 0 && z == 0) {
float pitch = direction.getY() > 0 ? -90f : 90f;
return new Location(location.getX(), location.getY(), location.getZ(), location.getYaw(), pitch);
}
final double theta = Math.atan2(-x, z);
final double xz = Math.sqrt(square(x) + square(z));
final double _2PI = 2 * Math.PI;
return new Location(location.getX(), location.getY(), location.getZ(),
(float) Math.toDegrees((theta + _2PI) % _2PI),
(float) Math.toDegrees(Math.atan(-direction.getY() / xz)));
}
public static double square(double in) {
return in * in;
}
}

View file

@ -1,22 +0,0 @@
package me.tofaa.entitylib.world;
import com.github.retrooper.packetevents.protocol.player.User;
import me.tofaa.entitylib.entity.WrapperEntity;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class WrapperWorld {
private final UUID uuid;
private final Set<WrapperEntity> entities;
private final Set<User> players;
public WrapperWorld(UUID uuid) {
this.uuid = uuid;
this.entities = new HashSet<>();
this.players = new HashSet<>();
}
}