Jumping and 1.14
This should mark 2.0.6
This commit is contained in:
parent
64318c7a20
commit
dcdf9a880e
7 changed files with 200 additions and 20 deletions
10
README.md
10
README.md
|
@ -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
17
pom.xml
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
###
|
||||
|
||||
|
|
Loading…
Reference in a new issue