mirror of
https://github.com/Minestom/Minestom.git
synced 2025-01-01 05:58:00 +01:00
Basic goal selector API
This commit is contained in:
parent
20e78afb40
commit
3fd1efb120
@ -1,5 +1,6 @@
|
||||
package fr.themode.demo;
|
||||
|
||||
import fr.themode.demo.entity.ChickenCreature;
|
||||
import fr.themode.demo.generator.ChunkGeneratorDemo;
|
||||
import fr.themode.demo.generator.NoiseTestGenerator;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
@ -148,9 +149,8 @@ public class PlayerInit {
|
||||
p.teleport(player.getPosition());
|
||||
}*/
|
||||
|
||||
/*ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
|
||||
ChickenCreature chickenCreature = new ChickenCreature(player.getPosition());
|
||||
chickenCreature.setInstance(player.getInstance());
|
||||
chickenCreature.setAttribute(Attribute.MOVEMENT_SPEED, 0.4f);*/
|
||||
|
||||
/*EntityZombie zombie = new EntityZombie(player.getPosition());
|
||||
zombie.setAttribute(Attribute.MOVEMENT_SPEED, 0.25f);
|
||||
@ -230,6 +230,7 @@ public class PlayerInit {
|
||||
AdvancementRoot root = new AdvancementRoot(ColoredText.of("title"), ColoredText.of(ChatColor.BLUE + "description"),
|
||||
Material.APPLE, FrameType.TASK, 0, 0,
|
||||
"minecraft:textures/block/red_wool.png");
|
||||
root.setAchieved(true);
|
||||
AdvancementTab tab = advancementManager.createTab("root", root);
|
||||
Advancement advancement = new Advancement(ColoredText.of("adv"), ColoredText.of("desc"),
|
||||
Material.WOODEN_AXE, FrameType.CHALLENGE, 1, 0)
|
||||
@ -240,7 +241,8 @@ public class PlayerInit {
|
||||
|
||||
root.setTitle(ColoredText.of("test ttlechange"));
|
||||
|
||||
Advancement advancement2 = new Advancement(ColoredText.of("adv"), ColoredText.of("desc"),
|
||||
Advancement advancement2 = new Advancement(ColoredText.of(ChatColor.BLUE + "Title"),
|
||||
ColoredText.of("description of the advancement"),
|
||||
Material.GOLD_BLOCK, FrameType.CHALLENGE, 3, 0)
|
||||
.showToast(true).setHidden(false);
|
||||
tab.createAdvancement("second2", advancement2, root);
|
||||
|
@ -1,83 +1,19 @@
|
||||
package fr.themode.demo.entity;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.ai.goal.DoNothingGoal;
|
||||
import net.minestom.server.entity.type.EntityChicken;
|
||||
import net.minestom.server.entity.vehicle.PlayerVehicleInformation;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
|
||||
public class ChickenCreature extends EntityChicken {
|
||||
|
||||
public ChickenCreature(Position defaultPosition) {
|
||||
super(defaultPosition);
|
||||
|
||||
goalSelectors.add(new DoNothingGoal(this, 500, 0.1f));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawn() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(long time) {
|
||||
super.update(time);
|
||||
float speed = 0.075f;
|
||||
|
||||
if (hasPassenger()) {
|
||||
Entity passenger = getPassengers().iterator().next();
|
||||
if (passenger instanceof Player) {
|
||||
Player player = (Player) passenger;
|
||||
PlayerVehicleInformation vehicleInformation = player.getVehicleInformation();
|
||||
float sideways = vehicleInformation.getSideways();
|
||||
float forward = vehicleInformation.getForward();
|
||||
|
||||
boolean jump = vehicleInformation.shouldJump();
|
||||
boolean unmount = vehicleInformation.shouldUnmount();
|
||||
|
||||
if (jump && isOnGround()) {
|
||||
setVelocity(new Vector(0, 6, 0));
|
||||
}
|
||||
|
||||
boolean updateView = forward > 0;
|
||||
if (sideways == 0f && forward == 0f)
|
||||
return;
|
||||
|
||||
float yaw = player.getPosition().getYaw();
|
||||
yaw %= 360;
|
||||
|
||||
sideways = yaw + (updateView ? -sideways * 90 : sideways * 90);
|
||||
|
||||
if (forward > 0) {
|
||||
forward = yaw * forward;
|
||||
} else {
|
||||
forward = yaw + forward * 360;
|
||||
}
|
||||
yaw = (forward + sideways) / 2 % 360;
|
||||
double radian = Math.toRadians(yaw + 90);
|
||||
double cos = Math.cos(radian);
|
||||
double sin = Math.sin(radian);
|
||||
float x = (float) cos * speed;
|
||||
float z = (float) sin * speed;
|
||||
|
||||
/*BlockPosition blockPosition = getPosition().toBlockPosition();
|
||||
BlockPosition belowPosition = blockPosition.clone().add(0, -1, 0);
|
||||
BlockPosition upPosition = blockPosition.clone().add(0, 1, 0);
|
||||
boolean airCurrent = getInstance().getBlockId(blockPosition) == 0;
|
||||
boolean airBelow = getInstance().getBlockId(belowPosition) == 0;
|
||||
boolean airUp = getInstance().getBlockId(upPosition) == 0;
|
||||
boolean shouldJump = false;
|
||||
int boundingBoxY = (int) Math.ceil(getBoundingBox().getY());
|
||||
for (int i = 0; i < boundingBoxY; i++) {
|
||||
|
||||
}*/
|
||||
|
||||
//System.out.println("test: "+player.isVehicleJump());
|
||||
//System.out.println(getInstance().getBlockId(getPosition().toBlockPosition()));
|
||||
|
||||
move(x, 0, z, updateView);
|
||||
}
|
||||
} else {
|
||||
//move(-0.5f * speed, 0, 0.5f * speed, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +133,25 @@ public class BossBar implements Viewable {
|
||||
updateStyle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bossbar flags
|
||||
*
|
||||
* @return the flags
|
||||
*/
|
||||
public byte getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bossbar flags
|
||||
*
|
||||
* @param flags the bossbar flags
|
||||
* @see <a href="https://wiki.vg/Protocol#Boss_Bar">Boss bar packet</a>
|
||||
*/
|
||||
public void setFlags(byte flags) {
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the boss bar and remove all of its viewers
|
||||
*/
|
||||
|
@ -5,6 +5,8 @@ import com.extollit.gaming.ai.path.model.PathObject;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.attribute.Attribute;
|
||||
import net.minestom.server.collision.CollisionUtils;
|
||||
import net.minestom.server.entity.ai.GoalSelector;
|
||||
import net.minestom.server.entity.ai.TargetSelector;
|
||||
import net.minestom.server.entity.pathfinding.PFPathingEntity;
|
||||
import net.minestom.server.event.entity.EntityAttackEvent;
|
||||
import net.minestom.server.event.item.ArmorEquipEvent;
|
||||
@ -19,12 +21,22 @@ import net.minestom.server.utils.item.ItemStackUtils;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
import net.minestom.server.utils.validate.Check;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class EntityCreature extends LivingEntity {
|
||||
|
||||
private PFPathingEntity pathingEntity = new PFPathingEntity(this);
|
||||
private HydrazinePathFinder pathFinder;
|
||||
private PathObject path;
|
||||
|
||||
protected List<GoalSelector> goalSelectors = new ArrayList<>();
|
||||
protected List<TargetSelector> targetSelectors = new ArrayList<>();
|
||||
private GoalSelector currentGoalSelector;
|
||||
|
||||
private Entity target;
|
||||
|
||||
// Equipments
|
||||
private ItemStack mainHandItem;
|
||||
private ItemStack offHandItem;
|
||||
@ -51,6 +63,49 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
|
||||
@Override
|
||||
public void update(long time) {
|
||||
|
||||
{
|
||||
// Supplier used to get the next goal selector which should start
|
||||
// (null if not found)
|
||||
final Supplier<GoalSelector> goalSelectorSupplier = () -> {
|
||||
for (GoalSelector goalSelector : goalSelectors) {
|
||||
final boolean start = goalSelector.shouldStart();
|
||||
if (start) {
|
||||
return goalSelector;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// true if the goal selector changed this tick
|
||||
boolean newGoalSelector = false;
|
||||
|
||||
if (currentGoalSelector == null) {
|
||||
// No goal selector, get a new one
|
||||
this.currentGoalSelector = goalSelectorSupplier.get();
|
||||
newGoalSelector = currentGoalSelector != null;
|
||||
} else {
|
||||
final boolean stop = currentGoalSelector.shouldEnd();
|
||||
if (stop) {
|
||||
// The current goal selector stopped, find a new one
|
||||
this.currentGoalSelector.end();
|
||||
this.currentGoalSelector = goalSelectorSupplier.get();
|
||||
newGoalSelector = currentGoalSelector != null;
|
||||
}
|
||||
}
|
||||
|
||||
// Start the new goal selector
|
||||
if (newGoalSelector) {
|
||||
this.currentGoalSelector.start();
|
||||
}
|
||||
|
||||
// Execute tick for the goal selector
|
||||
if (currentGoalSelector != null) {
|
||||
currentGoalSelector.tick();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Path finding
|
||||
path = pathFinder.update();
|
||||
if (path != null) {
|
||||
@ -180,6 +235,42 @@ public abstract class EntityCreature extends LivingEntity {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the goal selectors of this entity
|
||||
*
|
||||
* @return a modifiable list containing the entity goal selectors
|
||||
*/
|
||||
public List<GoalSelector> getGoalSelectors() {
|
||||
return goalSelectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target selectors of this entity
|
||||
*
|
||||
* @return a modifiable list containing the entity target selectors
|
||||
*/
|
||||
public List<TargetSelector> getTargetSelectors() {
|
||||
return targetSelectors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entity target
|
||||
*
|
||||
* @return the entity target
|
||||
*/
|
||||
public Entity getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the entity target
|
||||
*
|
||||
* @param target the new entity target
|
||||
*/
|
||||
public void setTarget(Entity target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemInMainHand() {
|
||||
return mainHandItem;
|
||||
|
@ -0,0 +1,66 @@
|
||||
package net.minestom.server.entity.ai;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.EntityCreature;
|
||||
|
||||
public abstract class GoalSelector {
|
||||
|
||||
private EntityCreature entityCreature;
|
||||
|
||||
public GoalSelector(EntityCreature entityCreature) {
|
||||
this.entityCreature = entityCreature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this {@link GoalSelector} should start.
|
||||
*
|
||||
* @return true to start
|
||||
*/
|
||||
public abstract boolean shouldStart();
|
||||
|
||||
/**
|
||||
* Start this {@link GoalSelector}
|
||||
*/
|
||||
public abstract void start();
|
||||
|
||||
/**
|
||||
* Called every tick when this {@link GoalSelector} is running
|
||||
*/
|
||||
public abstract void tick();
|
||||
|
||||
/**
|
||||
* Whether or not this {@link GoalSelector} should end.
|
||||
*
|
||||
* @return true to end
|
||||
*/
|
||||
public abstract boolean shouldEnd();
|
||||
|
||||
/**
|
||||
* End this {@link GoalSelector}
|
||||
*/
|
||||
public abstract void end();
|
||||
|
||||
/**
|
||||
* Get the entity linked to this goal selector
|
||||
*
|
||||
* @return the entity
|
||||
*/
|
||||
public EntityCreature getEntityCreature() {
|
||||
return entityCreature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a target based on the entity {@link TargetSelector}
|
||||
*
|
||||
* @return the target entity, null if not found
|
||||
*/
|
||||
public Entity findTarget() {
|
||||
for (TargetSelector targetSelector : entityCreature.getTargetSelectors()) {
|
||||
final Entity entity = targetSelector.findTarget();
|
||||
if (entity != null) {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package net.minestom.server.entity.ai;
|
||||
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.EntityCreature;
|
||||
|
||||
/**
|
||||
* The target selector is called each time the entity receives an "attack" instruction
|
||||
* without having a target
|
||||
*/
|
||||
public abstract class TargetSelector {
|
||||
|
||||
private final EntityCreature entityCreature;
|
||||
|
||||
public TargetSelector(EntityCreature entityCreature) {
|
||||
this.entityCreature = entityCreature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the target
|
||||
* <p>
|
||||
* returning null means that this target selector didn't find any entity,
|
||||
* the next {@link TargetSelector} will be called until the end of the list or an entity is found
|
||||
*
|
||||
* @return the target, null if not any
|
||||
*/
|
||||
public abstract Entity findTarget();
|
||||
|
||||
/**
|
||||
* Get the entity linked to this target selector
|
||||
*
|
||||
* @return the entity
|
||||
*/
|
||||
public EntityCreature getEntityCreature() {
|
||||
return entityCreature;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package net.minestom.server.entity.ai.goal;
|
||||
|
||||
import net.minestom.server.entity.EntityCreature;
|
||||
import net.minestom.server.entity.ai.GoalSelector;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class DoNothingGoal extends GoalSelector {
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
private long time;
|
||||
private float chance;
|
||||
private long startTime;
|
||||
|
||||
/**
|
||||
* Create a DoNothing goal
|
||||
*
|
||||
* @param entityCreature the entity
|
||||
* @param time the time in milliseconds where nothing happen
|
||||
* @param chance the chance to do nothing (0-1)
|
||||
*/
|
||||
public DoNothingGoal(EntityCreature entityCreature, long time, float chance) {
|
||||
super(entityCreature);
|
||||
this.time = time;
|
||||
this.chance = MathUtils.setBetween(chance, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end() {
|
||||
this.startTime = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldEnd() {
|
||||
return System.currentTimeMillis() - startTime >= time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStart() {
|
||||
return RANDOM.nextFloat() <= chance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ public class ChunkBatch implements InstanceBatch {
|
||||
}
|
||||
|
||||
private void addBlockData(byte x, int y, byte z, boolean customBlock, short blockId, short customBlockId, Data data) {
|
||||
// TODO store a single long with bitwise operators (xyz;boolean,short,short,boolean) with the data in a map
|
||||
BlockData blockData = new BlockData();
|
||||
blockData.x = x;
|
||||
blockData.y = y;
|
||||
|
@ -23,10 +23,10 @@ public class ChunkUtils {
|
||||
* @return true if the chunk is unloaded, false otherwise
|
||||
*/
|
||||
public static boolean isChunkUnloaded(Instance instance, float x, float z) {
|
||||
int chunkX = getChunkCoordinate((int) x);
|
||||
int chunkZ = getChunkCoordinate((int) z);
|
||||
final int chunkX = getChunkCoordinate((int) x);
|
||||
final int chunkZ = getChunkCoordinate((int) z);
|
||||
|
||||
Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||
final Chunk chunk = instance.getChunk(chunkX, chunkZ);
|
||||
return isChunkUnloaded(chunk);
|
||||
}
|
||||
|
||||
@ -53,8 +53,8 @@ public class ChunkUtils {
|
||||
* @return an array containing both the chunk X and Z (index 0 = X; index 1 = Z)
|
||||
*/
|
||||
public static int[] getChunkCoord(long index) {
|
||||
int chunkX = (int) (index >> 32);
|
||||
int chunkZ = (int) index;
|
||||
final int chunkX = (int) (index >> 32);
|
||||
final int chunkZ = (int) index;
|
||||
return new int[]{chunkX, chunkZ};
|
||||
}
|
||||
|
||||
@ -74,8 +74,8 @@ public class ChunkUtils {
|
||||
int counter = 0;
|
||||
for (int x = startLoop; x < endLoop; x++) {
|
||||
for (int z = startLoop; z < endLoop; z++) {
|
||||
int chunkX = getChunkCoordinate((int) (position.getX() + Chunk.CHUNK_SIZE_X * x));
|
||||
int chunkZ = getChunkCoordinate((int) (position.getZ() + Chunk.CHUNK_SIZE_Z * z));
|
||||
final int chunkX = getChunkCoordinate((int) (position.getX() + Chunk.CHUNK_SIZE_X * x));
|
||||
final int chunkZ = getChunkCoordinate((int) (position.getZ() + Chunk.CHUNK_SIZE_Z * z));
|
||||
visibleChunks[counter] = getChunkIndex(chunkX, chunkZ);
|
||||
counter++;
|
||||
}
|
||||
@ -106,7 +106,7 @@ public class ChunkUtils {
|
||||
* @return the instance position of the block located in {@code index}
|
||||
*/
|
||||
public static BlockPosition getBlockPosition(int index, int chunkX, int chunkZ) {
|
||||
int[] pos = indexToPosition(index, chunkX, chunkZ);
|
||||
final int[] pos = indexToPosition(index, chunkX, chunkZ);
|
||||
return new BlockPosition(pos[0], pos[1], pos[2]);
|
||||
}
|
||||
|
||||
@ -119,7 +119,7 @@ public class ChunkUtils {
|
||||
*/
|
||||
public static int[] indexToPosition(int index, int chunkX, int chunkZ) {
|
||||
int z = (byte) (index >> 12 & 0xF);
|
||||
int y = (index >>> 4 & 0xFF);
|
||||
final int y = (index >>> 4 & 0xFF);
|
||||
int x = (byte) (index >> 0 & 0xF);
|
||||
|
||||
x += 16 * chunkX;
|
||||
|
Loading…
Reference in New Issue
Block a user