Jumping and 1.14

This should mark 2.0.6
This commit is contained in:
Minecon724 2024-09-22 11:05:05 +02:00
parent 64318c7a20
commit dcdf9a880e
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
7 changed files with 200 additions and 20 deletions

View file

@ -1,3 +1,11 @@
# Giants
This plugin adds naturally spawning Giants with AI to your Minecraft server.
This plugin adds naturally spawning Giants with AI to your Minecraft server.
### Requested features
- Texture variation \
I think this can be done, but would require a texture pack
- Boss bar \
I don't want to get buried in that, so this would require an API, which, for performance reasons, should not be mandatory
- Hitboxes \
I don't know if this is still a major issue, but a person reported that the hitbox doesn't cover the whole body

17
pom.xml
View file

@ -24,8 +24,23 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.21.1-R0.1-SNAPSHOT</version>
<version>1.14.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<!-- fix vulnerabilities complaints -->
<exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

View file

@ -20,14 +20,16 @@ public class Configuration {
private final Logger logger;
boolean ai;
boolean attack;
double chance;
double attackDamage;
int attackDelay;
Vector attackReach;
int jumpMode;
int jumpCondition;
int jumpDelay;
double jumpHeight = -1;
double chance;
List<String> worldBlacklist;
Set<PotionEffect> effects = new HashSet<>();
Set<Drop> drops = new HashSet<>();
@ -41,15 +43,28 @@ public class Configuration {
YamlConfiguration config = YamlConfiguration.loadConfiguration(file);
ai = config.getBoolean("ai");
attack = config.getBoolean("attack");
chance = config.getDouble("chance");
attackDamage = config.getDouble("attackDamage");
attackDelay = config.getInt("attackDelay");
jumpMode = config.getInt("jumpMode");
jumpCondition = config.getInt("jumpCondition");
jumpDelay = config.getInt("jumpDelay");
if (jumpMode != 0) {
jumpHeight = config.getDouble("jumpHeight", -1);
if (jumpHeight == -1) {
jumpHeight = defaultJumpHeight();
}
logger.info("Jumping is experimental.");
logger.info("Jump mode: " + jumpMode);
logger.info("Jump condition: " + jumpCondition);
logger.info("Jump height: " + jumpHeight);
}
double _attackReach = config.getDouble("attackReach");
double _expandUp = config.getDouble("expandUp");
attackReach = new Vector(_attackReach, _expandUp, _attackReach);
double _attackVerticalReach = config.getDouble("attackVerticalReach");
attackReach = new Vector(_attackReach, _attackVerticalReach, _attackReach);
worldBlacklist = config.getStringList("blacklist");
@ -99,4 +114,17 @@ public class Configuration {
}
}
}
public double defaultJumpHeight() {
switch (jumpMode) {
case 1:
case 2:
return 0.42;
case 3:
case 4:
return 1.2;
}
return -1;
}
}

View file

@ -1,12 +1,14 @@
package eu.m724.giants;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntitySpawnEvent;
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.persistence.PersistentDataType;
@ -14,6 +16,7 @@ import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
@ -32,6 +35,8 @@ public class GiantProcessor implements Listener {
// private final Set<Giant> trackedGiants = new HashSet<>();
private final Set<Husk> trackedHusks = new HashSet<>();
private final Map<Entity, Location> giantLocationMap = new HashMap<>();
private final Map<Entity, Long> giantLastJump = new HashMap<>();
private final ThreadLocalRandom random = ThreadLocalRandom.current();
private final NamespacedKey huskKey;
@ -50,7 +55,7 @@ public class GiantProcessor implements Listener {
public void run() {
for (Husk husk : Set.copyOf(trackedHusks)) {
if (husk.isValid()) {
Location location = husk.getLocation();
Location huskLocation = husk.getLocation();
Entity giant = husk.getVehicle();
if (giant instanceof Giant) {
@ -59,7 +64,23 @@ public class GiantProcessor implements Listener {
giant.getBoundingBox().expand(configuration.attackReach),
e -> (e instanceof Player && !e.isInvulnerable())
).forEach(p -> ((Player) p).damage(configuration.attackDamage, giant));
giant.setRotation(location.getYaw(), location.getPitch());
giant.setRotation(huskLocation.getYaw(), huskLocation.getPitch());
// jumping
if (configuration.jumpMode != 0) {
// tracking location is only required for jumping
Location prevLocation = giantLocationMap.get(giant);
Location location = giant.getLocation();
if (prevLocation == null) {
prevLocation = location;
}
giantLocationMap.put(giant, location);
LivingEntity target = husk.getTarget();
if (target != null) {
processJump(giant, prevLocation, location, target.getLocation());
}
}
}
} else {
// no vehicle means the giant doesn't exist anymore and the husk should also not exist
@ -80,6 +101,41 @@ public class GiantProcessor implements Listener {
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
private void processJump(Entity giant, Location prevLocation, Location location, Location targetLocation) {
long now = System.currentTimeMillis();
if (now - giantLastJump.getOrDefault(giant, 0L) < configuration.jumpDelay) {
return;
}
if (giant.isOnGround()) {
giantLastJump.put(giant, now);
if (configuration.jumpCondition == 0) {
if (targetLocation.subtract(location).getY() > 0) {
jump(giant);
}
} else if (configuration.jumpCondition == 1) {
Location delta = prevLocation.subtract(location);
if (targetLocation.subtract(location).getY() > 0 && (delta.getX() == 0 || delta.getZ() == 0)) {
jump(giant);
}
} else if (configuration.jumpCondition == 2) {
Location delta = prevLocation.subtract(location);
if (delta.getX() == 0 || delta.getZ() == 0) {
jump(giant);
}
} // I could probably simplify that code
}
}
private void jump(Entity giant) {
if (configuration.jumpMode == 1) {
giant.setVelocity(new Vector(0, configuration.jumpHeight, 0));
} else if (configuration.jumpMode == 2) {
giant.teleport(giant.getLocation().add(0, configuration.jumpHeight, 0));
}
} // TODO those should be moved
public LivingEntity spawnGiant(Location pos) {
LivingEntity entity = (LivingEntity) pos.getWorld().spawnEntity(pos, EntityType.GIANT);
@ -92,6 +148,7 @@ public class GiantProcessor implements Listener {
passenger.getPersistentDataContainer().set(huskKey, PersistentDataType.INTEGER, VERSION);
entity.addPassenger(passenger);
trackedHusks.add((Husk) passenger);
}
@ -109,7 +166,7 @@ public class GiantProcessor implements Listener {
logger.fine("Chunk loaded: " + event.getChunk().getX() + " " + event.getChunk().getZ());
Husk[] husks = Arrays.stream(entities)
.filter(entity -> entity instanceof Husk && entity.getPersistentDataContainer().has(huskKey))
.filter(entity -> entity instanceof Husk && entity.getPersistentDataContainer().has(huskKey, PersistentDataType.INTEGER))
.map(Husk.class::cast)
.toArray(Husk[]::new);
@ -167,7 +224,7 @@ public class GiantProcessor implements Listener {
}
for (Entity passenger : entity.getPassengers()) {
if (passenger.getPersistentDataContainer().has(huskKey)) {
if (passenger.getPersistentDataContainer().has(huskKey, PersistentDataType.INTEGER)) {
((LivingEntity) passenger).setHealth(0);
logger.fine("Killed a Husk");
}

View file

@ -9,6 +9,8 @@ import org.bukkit.inventory.ItemStack;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@ -16,9 +18,11 @@ import java.util.Map;
public class GiantsCommand implements CommandExecutor {
private final GiantsPlugin plugin;
private final Configuration configuration;
public GiantsCommand(GiantsPlugin plugin) {
public GiantsCommand(GiantsPlugin plugin, Configuration configuration) {
this.plugin = plugin;
this.configuration = configuration;
}
@Override
@ -57,22 +61,73 @@ public class GiantsCommand implements CommandExecutor {
list.add(map);
YamlConfiguration yamlConfiguration = new YamlConfiguration();
yamlConfiguration.set("v", list);
yamlConfiguration.setInlineComments("v", List.of("Copy the below content to your config.yml"));
try {
Method method = yamlConfiguration.getClass().getMethod("setInlineComments", String.class, List.class);
yamlConfiguration.set("v", list);
method.invoke(yamlConfiguration, "v", List.of("Copy the below content to your config.yml"));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
yamlConfiguration.set("v", null); // two latter exceptions happen after setting
yamlConfiguration.set("copy_everything_below_to_config_yml", list);
}
long now = System.currentTimeMillis();
String name = "item-" + now + ".yml";
File file = new File(plugin.getDataFolder(), name);
try {
yamlConfiguration.save(new File(plugin.getDataFolder(), name));
yamlConfiguration.save(file);
sender.sendMessage("Saved to plugins/Giants/" + name + ". To add it as a drop, see instructions in the file.");
} catch (IOException e) {
e.printStackTrace();
sender.sendMessage("Error saving file. See console for details.");
throw new RuntimeException("Error saving file to " + file.getName(), e);
}
} else {
sender.sendMessage("Only players can use this command.");
}
} else if (action.equals("jm")) { // TODO remove
if (args.length > 1) {
int mode = Integer.parseInt(args[1]);
configuration.jumpMode = mode;
sender.sendMessage("Jump mode set to " + mode);
sender.sendMessage("This command doesn't check if it's valid, an invalid value turns off jumping.");
if (configuration.jumpHeight == -1) {
configuration.jumpHeight = configuration.defaultJumpHeight();
sender.sendMessage("Jump height set to " + configuration.jumpHeight + ". Modify it with /giants jumpheight");
}
} else {
sender.sendMessage("Jump mode: " + configuration.jumpMode);
}
} else if (action.equals("jh")) {
if (args.length > 1) {
double height = Double.parseDouble(args[1]);
configuration.jumpHeight = height;
sender.sendMessage("Jump height set to " + height);
} else {
sender.sendMessage("Jump height: " + configuration.jumpHeight);
}
} else if (action.equals("jc")) {
if (args.length > 1) {
int condition = Integer.parseInt(args[1]);
configuration.jumpCondition = condition;
sender.sendMessage("Jump condition set to " + condition);
} else {
sender.sendMessage("Jump condition: " + configuration.jumpCondition);
}
} else if (action.equals("jd")) {
if (args.length > 1) {
int delay = Integer.parseInt(args[1]);
configuration.jumpDelay = delay;
sender.sendMessage("Jump delay set to " + delay);
} else {
sender.sendMessage("Jump delay: " + configuration.jumpDelay);
}
}
return true;

View file

@ -22,7 +22,7 @@ public class GiantsPlugin extends JavaPlugin implements CommandExecutor {
configuration.load();
getCommand("giants").setExecutor(new GiantsCommand(this));
getCommand("giants").setExecutor(new GiantsCommand(this, configuration));
giantProcessor.start();
}

View file

@ -4,6 +4,23 @@
# If disabled, the giant will not move or attack
ai: true
# Makes giants jump. Very experimental.
# I prefer velocity mode
# 0 - disabled
# 1 - velocity mode
# 2 - tp mode
jumpMode: 0
# 0 - when target is higher
# 1 - when target is higher and giant is stuck
# 2 - when giant is stuck
jumpCondition: 1
# Delay before jumping again, counted from hitting the ground. In milliseconds
jumpDelay: 200
# If velocity mode, y blocks/tick (default 0.42)
# If tp mode, +y to teleport (default 1.2)
# -1: auto
jumpHeight: -1
# In hearts, 0.5 is half a heart
attackDamage: 1.0
@ -15,8 +32,8 @@ attackDelay: 20
# There's no wall check yet, so it will hit through walls
attackReach: 2
# The value above does not modify vertical reach, this value extends it upwards
expandUp: 0
# Vertical reach
attackVerticalReach: 1
###