This commit is contained in:
2022-07-06 01:46:20 +02:00
parent 3f986b424d
commit c65d15096a
42 changed files with 625 additions and 195 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
Binary file not shown.
@@ -6,6 +6,9 @@ import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.advancements.FrameType;
import net.minestom.server.advancements.notifications.Notification;
import net.minestom.server.advancements.notifications.NotificationCenter;
import net.minestom.server.adventure.audience.Audiences; import net.minestom.server.adventure.audience.Audiences;
import net.minestom.server.command.CommandManager; import net.minestom.server.command.CommandManager;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
@@ -14,6 +17,7 @@ import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin; import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.event.GlobalEventHandler; import net.minestom.server.event.GlobalEventHandler;
import net.minestom.server.event.player.PlayerChatEvent; import net.minestom.server.event.player.PlayerChatEvent;
import net.minestom.server.event.player.PlayerDeathEvent;
import net.minestom.server.event.player.PlayerLoginEvent; import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.event.player.PlayerSpawnEvent; import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.event.server.ServerTickMonitorEvent; import net.minestom.server.event.server.ServerTickMonitorEvent;
@@ -21,6 +25,8 @@ import net.minestom.server.extras.lan.OpenToLAN;
import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.InstanceManager; import net.minestom.server.instance.InstanceManager;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.monitoring.TickMonitor; import net.minestom.server.monitoring.TickMonitor;
import net.minestom.server.potion.Potion; import net.minestom.server.potion.Potion;
import net.minestom.server.potion.PotionEffect; import net.minestom.server.potion.PotionEffect;
@@ -49,6 +55,15 @@ public class Main {
playerLoginEvent.setSpawningInstance(Lobby.INSTANCE); playerLoginEvent.setSpawningInstance(Lobby.INSTANCE);
NotificationCenter.send(
new Notification(
Component.text("Test", NamedTextColor.GOLD),
FrameType.GOAL,
ItemStack.of(Material.TOTEM_OF_UNDYING)
),
p
);
if(!p.getName().toString().equals("MineTec")) p.setReducedDebugScreenInformation(true); //TODO remove condition if(!p.getName().toString().equals("MineTec")) p.setReducedDebugScreenInformation(true); //TODO remove condition
p.setRespawnPoint(new Pos(0,5,0)); p.setRespawnPoint(new Pos(0,5,0));
p.setGameMode(GameMode.CREATIVE); p.setGameMode(GameMode.CREATIVE);
@@ -61,8 +76,14 @@ public class Main {
.append(Component.text(event.getMessage(), NamedTextColor.WHITE)))); .append(Component.text(event.getMessage(), NamedTextColor.WHITE))));
}); });
events.addListener(PlayerDeathEvent.class, playerDeathEvent -> {
playerDeathEvent.setDeathText(null);
playerDeathEvent.setChatMessage(null);
});
events.addListener(PlayerSpawnEvent.class, playerSpawnEvent -> { events.addListener(PlayerSpawnEvent.class, playerSpawnEvent -> {
playerSpawnEvent.getPlayer().addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 1, 30)); playerSpawnEvent.getPlayer().addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 1, 30));
playerSpawnEvent.getPlayer().refreshCommands();
}); });
@@ -79,10 +100,6 @@ public class Main {
Collection<Player> players = MinecraftServer.getConnectionManager().getOnlinePlayers(); Collection<Player> players = MinecraftServer.getConnectionManager().getOnlinePlayers();
if (players.isEmpty()) return; if (players.isEmpty()) return;
for(Player p : players) {
p.refreshCommands(); //TODO this is a dumb idea
}
final Runtime runtime = Runtime.getRuntime(); final Runtime runtime = Runtime.getRuntime();
final TickMonitor tickMonitor = lastTick.get(); final TickMonitor tickMonitor = lastTick.get();
final long ramUsage = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024; final long ramUsage = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
@@ -1,46 +1,38 @@
package eu.mhsl.minenet.minestom.pve.arena; package eu.mhsl.minenet.minestom.pve.arena;
import eu.mhsl.minenet.minestom.pve.Lobby; import eu.mhsl.minenet.minestom.pve.Lobby;
import eu.mhsl.minenet.minestom.pve.arena.mob.Zombie; import eu.mhsl.minenet.minestom.pve.arena.mob.ArenaMob;
import eu.mhsl.minenet.minestom.pve.arena.mob.MobType;
import eu.mhsl.minenet.minestom.pve.arena.mob.creature.Vex;
import eu.mhsl.minenet.minestom.pve.util.FullbrightDimension; import eu.mhsl.minenet.minestom.pve.util.FullbrightDimension;
import eu.mhsl.minenet.minestom.pve.util.Knockback;
import eu.mhsl.minenet.minestom.pve.util.Mapping;
import eu.mhsl.minenet.minestom.pve.util.PaneGenerator; import eu.mhsl.minenet.minestom.pve.util.PaneGenerator;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.*; import net.minestom.server.entity.Entity;
import net.minestom.server.entity.ai.EntityAIGroup; import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.ai.EntityAIGroupBuilder; import net.minestom.server.entity.Player;
import net.minestom.server.entity.ai.goal.DoNothingGoal;
import net.minestom.server.entity.ai.goal.FollowTargetGoal;
import net.minestom.server.entity.ai.goal.RandomLookAroundGoal;
import net.minestom.server.entity.ai.goal.RandomStrollGoal;
import net.minestom.server.entity.ai.target.ClosestEntityTarget;
import net.minestom.server.entity.damage.DamageType; import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.entity.EntityAttackEvent; import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.entity.EntityDamageEvent;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.instance.AddEntityToInstanceEvent; import net.minestom.server.event.instance.AddEntityToInstanceEvent;
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent; import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
import net.minestom.server.instance.Explosion;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack; import net.minestom.server.particle.Particle;
import net.minestom.server.item.Material; import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.potion.Potion;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.sound.SoundEvent; import net.minestom.server.sound.SoundEvent;
import net.minestom.server.timer.Task; import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.*;
import java.util.UUID; import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
public class Arena extends InstanceContainer { public class Arena extends InstanceContainer {
private UUID arenaId; private UUID arenaId;
@@ -70,33 +62,43 @@ public class Arena extends InstanceContainer {
eventNode().addListener(EntityAttackEvent.class, entityAttackEvent -> { eventNode().addListener(EntityAttackEvent.class, entityAttackEvent -> {
//Player attacks Mob //Player attacks Mob
if(!(entityAttackEvent.getEntity() instanceof Player)) return; if(!(entityAttackEvent.getEntity() instanceof Player)) return;
sendMessage(Component.text("EntityAttackEvent " + System.currentTimeMillis()));
Player attacker = (Player) entityAttackEvent.getEntity(); Player attacker = (Player) entityAttackEvent.getEntity();
LivingEntity target = (LivingEntity) entityAttackEvent.getTarget(); ArenaMob target = (ArenaMob) entityAttackEvent.getTarget();
target.damage(DamageType.fromPlayer(attacker), 20); Collection<Entity> nearby = getNearbyEntities(entityAttackEvent.getTarget().getPosition(), 3);
double knockbackX = Math.sin(attacker.getPosition().yaw() * (Math.PI / 180)); if(nearby.size() > 1)
double knockbackZ = -Math.cos(attacker.getPosition().yaw() * (Math.PI / 180)); target.particle(Particle.SWEEP_ATTACK, target.getPosition(), 0.5f, (int) Mapping.map(nearby.size(), 1, 10, 1, 5));
entityAttackEvent.getTarget().takeKnockback(
0.5f, for(Entity entity : nearby) {
knockbackX, if(!(entity instanceof ArenaMob)) continue; //Only damage ArenaMobs
knockbackZ
ArenaMob secondaryTarget = (ArenaMob) entity;
secondaryTarget.damage(
DamageType.fromPlayer(attacker),
(float) Mapping.map(secondaryTarget.getDistance(target),
3,
0,
0,
5
)
); );
Knockback knb = Knockback.calc(attacker);
knb.apply(secondaryTarget, (float) Mapping.map(secondaryTarget.getDistance(target), 3, 0, 0.1, 0.5));
secondaryTarget.particle(Particle.FALLING_OBSIDIAN_TEAR, secondaryTarget.getPosition(), new Vec(knb.x(), 0, knb.z()), 10);
scheduler().scheduleNextTick(() -> { scheduler().scheduleNextTick(() -> {
if(target.isDead()) { if(secondaryTarget.isDead()) knb.apply(secondaryTarget, 1f);
target.takeKnockback(
1f,
knockbackX,
knockbackZ
);
} else
target.setVelocity(new Vec(0, 10, 0));
}); });
}
}); });
} }
public void stop() { public void stop() {
@@ -119,9 +121,42 @@ public class Arena extends InstanceContainer {
isRunning = true; isRunning = true;
this.spawner = scheduler().scheduleTask(() -> { this.spawner = scheduler().scheduleTask(() -> {
if(this.getEntities().size() > 100) return;
new Zombie().setInstance(this, new Pos(0, 5, 0)); try {
}, TaskSchedule.seconds(1), TaskSchedule.seconds(1)); spawnMob((ArenaMob) MobType.getRandom().instance());
} catch (Exception e) {
throw new RuntimeException(e);
}
}, TaskSchedule.seconds(3), TaskSchedule.seconds(2));
}
public void spawnMob(ArenaMob mob) {
this.spawnMob(mob, new Pos(0, 5, 0), 10);
}
public void spawnMob(ArenaMob mob, Pos pos, int area) {
if(getEntities().size() >= 150) return;
if(getEntities().stream().filter(entity -> mob.getClass().isInstance(entity)).count() > 10) return;
Random rnd = new Random();
mob.setInstance(this, pos.add(rnd.nextInt(-area, area), 0, rnd.nextInt(-area, area)));
}
public void explosiveDamage(Pos pos, float offset, int damage, int range) {
sendGroupedPacket(ParticleCreator.createParticlePacket(
Particle.EXPLOSION, pos.x(), pos.y(), pos.z(),
offset, offset, offset, 5
));
playSound(
Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.NEUTRAL, 0.5f, 1),
pos.x(), pos.y(), pos.z()
);
for (Entity entity : getNearbyEntities(pos, range)) {
if (entity instanceof LivingEntity livingEntity)
livingEntity.damage(DamageType.GRAVITY, (float) Mapping.map(damage, entity.getDistance(pos), 0, 0, damage));
}
} }
@@ -1,126 +0,0 @@
package eu.mhsl.minenet.minestom.pve.arena;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.ai.EntityAIGroupBuilder;
import net.minestom.server.entity.ai.goal.MeleeAttackGoal;
import net.minestom.server.entity.ai.goal.RandomLookAroundGoal;
import net.minestom.server.entity.ai.goal.RandomStrollGoal;
import net.minestom.server.entity.ai.target.ClosestEntityTarget;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.entity.EntityDamageEvent;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.entity.EntitySpawnEvent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.potion.Potion;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class ArenaMob extends EntityCreature {
public ArenaMob(@NotNull EntityType entityType) {
super(entityType);
setCustomName(generateHealthBar(getMaxHealth(), getHealth()));
setCustomNameVisible(true);
setRemovalAnimationDelay(3500);
addAIGroup(
new EntityAIGroupBuilder()
.addGoalSelector(new MeleeAttackGoal(this, 1.2, 20, TimeUnit.SERVER_TICK))
.addTargetSelector(new ClosestEntityTarget(this, 32, Player.class))
.addGoalSelector(new RandomLookAroundGoal(this, 30))
.addGoalSelector(new RandomStrollGoal(this, 5))
.build()
);
eventNode().addListener(EntitySpawnEvent.class, entitySpawnEvent -> {
Pos position = entitySpawnEvent.getEntity().getPosition();
if(entitySpawnEvent.getEntity() == this) ParticleCreator.createParticlePacket(Particle.FIREWORK,
position.x(),
position.y(),
position.z(),
(float) position.sub(1).x(),
(float) position.sub(1).y(),
(float) position.sub(1).z(),
10);
});
eventNode().addListener(EntityAttackEvent.class, entityAttackEvent -> {
//Mob attacks Player
if(entityAttackEvent.getEntity() instanceof Player) return;
instance.sendMessage(Component.text("EntityAttackEvent " + System.currentTimeMillis()));
entityAttackEvent.getTarget().takeKnockback(
0.2f,
Math.sin(entityAttackEvent.getEntity().getPosition().yaw() * (Math.PI / 180)),
-Math.cos(entityAttackEvent.getEntity().getPosition().yaw() * (Math.PI / 180))
);
((LivingEntity) entityAttackEvent.getTarget()).damage(DamageType.fromEntity(entityAttackEvent.getEntity()), 1);
((EntityCreature) entityAttackEvent.getEntity()).swingMainHand();
});
eventNode().addListener(EntityDamageEvent.class, entityDamageEvent -> {
instance.sendMessage(Component.text("EntityDamageEvent " + System.currentTimeMillis()));
entityDamageEvent.setSound(SoundEvent.BLOCK_AMETHYST_BLOCK_STEP);
setCustomName(generateHealthBar(getMaxHealth(), getHealth()));
lookAt(new Pos(0,0,0));
});
eventNode().addListener(EntityDeathEvent.class, entityDeathEvent -> {
instance.sendMessage(Component.text("EntityDeathEvent " + System.currentTimeMillis()));
setCustomNameVisible(false);
setCustomName(null);
scheduler().scheduleTask(() -> {
teleport(getPosition().sub(0, 0.1, 0));
}, TaskSchedule.seconds(3), TaskSchedule.stop());
});
}
private static final int BLOCK_LENGTH = 6;
private static final List<String> CHARACTERS = List.of(
"", "", "", "",
"", "", "", ""
);
private static final String FULL_BLOCK_CHAR = "";
private static @NotNull Component generateHealthBar(float maxHealth, float currentHealth) {
// Converts the health percentage into a number from 0-{blockLength} -- only 0 if the mob's health is 0
final double charHealth = (currentHealth / maxHealth) * BLOCK_LENGTH;
return Component.text()
.append(Component.text(
FULL_BLOCK_CHAR.repeat((int) Math.floor(charHealth)),
NamedTextColor.DARK_RED
)).append(Component.text(CHARACTERS.get((int) Math.round(
(charHealth - Math.floor(charHealth)) // number from 0-1
* (CHARACTERS.size() - 1) // indexes start at 0
)), NamedTextColor.GOLD))
.build();
}
}
@@ -0,0 +1,198 @@
package eu.mhsl.minenet.minestom.pve.arena.mob;
import eu.mhsl.minenet.minestom.pve.util.Knockback;
import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.*;
import net.minestom.server.entity.ai.EntityAIGroupBuilder;
import net.minestom.server.entity.ai.goal.MeleeAttackGoal;
import net.minestom.server.entity.ai.goal.RandomLookAroundGoal;
import net.minestom.server.entity.ai.goal.RandomStrollGoal;
import net.minestom.server.entity.ai.target.ClosestEntityTarget;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.metadata.LivingEntityMeta;
import net.minestom.server.event.entity.*;
import net.minestom.server.event.item.PickupExperienceEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Random;
public class ArenaMob extends EntityCreature {
private int damage = 1;
private int experience = 10;
public ArenaMob(@NotNull EntityType entityType) {
super(entityType);
setCustomName(generateHealthBar(getMaxHealth(), getHealth()));
setCustomNameVisible(true);
setRemovalAnimationDelay(3500);
aiGroup();
eventNode().addListener(EntitySpawnEvent.class, this::onSpawn);
eventNode().addListener(EntityAttackEvent.class, this::onAttack);
eventNode().addListener(EntityDamageEvent.class, this::onDamage);
eventNode().addListener(EntityDeathEvent.class, this::onDeath);
eventNode().addListener(EntityTickEvent.class, ArenaMob::onTick);
eventNode().addListener(PickupExperienceEvent.class, pickupExperienceEvent -> {
pickupExperienceEvent.setCancelled(true);
Knockback knb = Knockback.calc(pickupExperienceEvent.getPlayer());
pickupExperienceEvent.getExperienceOrb().setVelocity(new Vec(knb.x(), 0, knb.z()));
});
}
public void particle(Particle particle, Pos pos, Vec offset, int count) {
instance.sendGroupedPacket(
ParticleCreator.createParticlePacket(
particle,
pos.x(),
pos.y(),
pos.z(),
(float) offset.x(),
(float) offset.y(),
(float) offset.z(),
count
)
);
}
public void particle(Particle particle, Pos pos, float offset, int count) {
this.particle(particle, pos, new Vec(offset, offset, offset), count);
}
protected void aiGroup() {
addAIGroup(
new EntityAIGroupBuilder()
.addGoalSelector(new MeleeAttackGoal(this, 1.2, 20, TimeUnit.SERVER_TICK))
.addTargetSelector(new ClosestEntityTarget(this, 32, Player.class))
.addGoalSelector(new RandomLookAroundGoal(this, 30))
.addGoalSelector(new RandomStrollGoal(this, 5))
.build()
);
}
private static void onTick(@NotNull EntityTickEvent entityTickEvent) {
}
protected void onSpawn(@NotNull EntitySpawnEvent entitySpawnEvent) {
particle(Particle.POOF, entitySpawnEvent.getEntity().getPosition(), 1, 3);
}
protected void onAttack(@NotNull EntityAttackEvent entityAttackEvent) {
//Mob attacks Player
if (entityAttackEvent.getEntity() instanceof Player) return;
ArenaMob attacker = (ArenaMob) entityAttackEvent.getEntity();
Player target = (Player) entityAttackEvent.getTarget();
particle(Particle.LANDING_LAVA, target.getPosition(), 0.5f, 10);
Knockback.calc(attacker).apply(target, 0.2f);
target.damage(DamageType.fromEntity(entityAttackEvent.getEntity()), damage);
attacker.swingMainHand();
}
protected void onDamage(@NotNull EntityDamageEvent entityDamageEvent) {
particle(Particle.DAMAGE_INDICATOR, entityDamageEvent.getEntity().getPosition(), 1, 5);
entityDamageEvent.setSound(SoundEvent.BLOCK_AMETHYST_BLOCK_STEP);
updateHealthBar();
lookAt(new Pos(0, 0, 0));
}
protected void onDeath(@NotNull EntityDeathEvent entityDeathEvent) {
particle(Particle.SOUL, entityDeathEvent.getEntity().getPosition(), 0.5f, 3);
setCustomNameVisible(false);
setCustomName(null);
Random rnd = new Random();
short value = 1;
//TODO prevent to many orbs
for(int i = 0; i <= experience; i++) {
ExperienceOrb orb = new ExperienceOrb(value);
orb.setInstance(instance, entityDeathEvent.getEntity().getPosition().add(0, 0.1, 0));
orb.setVelocity(new Vec(rnd.nextFloat(-5, 5), rnd.nextFloat(1, 3), rnd.nextFloat(-5, 5)));
orb.spawn();
orb.setGravity(0, 0);
instance.scheduler().scheduleTask(() -> {
particle(Particle.LAVA, orb.getPosition(), 0, 1);
orb.remove();
}, TaskSchedule.millis(rnd.nextInt(1000, 5000)), TaskSchedule.stop());
}
scheduler().scheduleTask(() -> {
teleport(getPosition().sub(0, 0.1, 0));
}, TaskSchedule.seconds(3), TaskSchedule.stop());
}
public void updateHealthBar() {
setCustomName(generateHealthBar(getMaxHealth(), getHealth()));
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public int getExperience() {
return experience;
}
public void setExperience(int experience) {
this.experience = experience;
}
@Override
public void setHealth(float health) {
super.setHealth(health);
updateHealthBar();
}
private static final int BLOCK_LENGTH = 6;
private static final List<String> CHARACTERS = List.of(
"", "", "", "",
"", "", "", ""
);
private static final String FULL_BLOCK_CHAR = "";
private static @NotNull Component generateHealthBar(float maxHealth, float currentHealth) {
// Converts the health percentage into a number from 0-{blockLength} -- only 0 if the mob's health is 0
final double charHealth = (currentHealth / maxHealth) * BLOCK_LENGTH;
return Component.text()
.append(Component.text(
FULL_BLOCK_CHAR.repeat((int) Math.floor(charHealth)),
NamedTextColor.DARK_RED
)).append(Component.text(CHARACTERS.get((int) Math.round(
(charHealth - Math.floor(charHealth)) // number from 0-1
* (CHARACTERS.size() - 1) // indexes start at 0
)), NamedTextColor.GOLD))
.build();
}
}
@@ -0,0 +1,31 @@
package eu.mhsl.minenet.minestom.pve.arena.mob;
import eu.mhsl.minenet.minestom.pve.arena.mob.creature.Evoker;
import eu.mhsl.minenet.minestom.pve.arena.mob.creature.Pillager;
import eu.mhsl.minenet.minestom.pve.arena.mob.creature.Spider;
import eu.mhsl.minenet.minestom.pve.arena.mob.creature.Zombie;
import java.lang.reflect.InvocationTargetException;
import java.util.Random;
public enum MobType {
ZOMBIE(Zombie.class),
PILLAGER(Pillager.class),
EVOKER(Evoker.class),
SPIDER(Spider.class);
private Class clazz;
MobType(Class<? extends ArenaMob> type) {
this.clazz = type;
}
public Object instance() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
return this.clazz.getDeclaredConstructor().newInstance();
}
public static MobType getRandom() {
int random = new Random().nextInt(values().length);
return values()[random];
}
}
@@ -1,19 +0,0 @@
package eu.mhsl.minenet.minestom.pve.arena.mob;
import eu.mhsl.minenet.minestom.pve.arena.ArenaMob;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;
public class Zombie extends ArenaMob {
public Zombie() {
super(EntityType.ZOMBIE);
setItemInHand(Player.Hand.MAIN, ItemStack.builder(Material.TNT).build());
setItemInHand(Player.Hand.OFF, ItemStack.builder(Material.FLINT_AND_STEEL).build());
}
}
@@ -0,0 +1,134 @@
package eu.mhsl.minenet.minestom.pve.arena.mob.creature;
import eu.mhsl.minenet.minestom.pve.arena.Arena;
import eu.mhsl.minenet.minestom.pve.arena.mob.ArenaMob;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityCreature;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.ai.EntityAIGroupBuilder;
import net.minestom.server.entity.ai.GoalSelector;
import net.minestom.server.entity.ai.goal.RangedAttackGoal;
import net.minestom.server.entity.ai.target.ClosestEntityTarget;
import net.minestom.server.entity.metadata.EntityMeta;
import net.minestom.server.entity.metadata.monster.raider.EvokerMeta;
import net.minestom.server.entity.metadata.monster.raider.SpellcasterIllagerMeta;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.entity.EntitySpawnEvent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.particle.Particle;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.tag.Tag;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.utils.time.Cooldown;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
import java.util.Random;
import java.util.function.Consumer;
public class Evoker extends ArenaMob {
public Evoker() {
super(EntityType.EVOKER);
}
@Override
protected void aiGroup() {
Random rnd = new Random();
int range = rnd.nextInt(3, 16);
addAIGroup(
new EntityAIGroupBuilder()
.addGoalSelector(new ActionGoal(this, Duration.ofSeconds(20), target -> {
lookAt(target);
((EvokerMeta) getEntityMeta()).setSpell(SpellcasterIllagerMeta.Spell.ATTACK);
scheduler().scheduleTask(() -> {
for(int i = 0; i < rnd.nextInt(2, 5); i++) {
((Arena) instance).spawnMob(new Vex(), position.add(0, 2, 0), 3);
}
((EvokerMeta) getEntityMeta()).setSpell(SpellcasterIllagerMeta.Spell.NONE);
}, TaskSchedule.seconds(2), TaskSchedule.stop());
}))
.addGoalSelector(new RangedAttackGoal(this, Duration.ofDays(1), range, range, true, 0, 0))
.addTargetSelector(new ClosestEntityTarget(this, 32, Player.class))
.build()
);
}
@Override
protected void onSpawn(@NotNull EntitySpawnEvent entitySpawnEvent) {
super.onSpawn(entitySpawnEvent);
setTag(Tag.Boolean("revived"), Math.random() < 0.5);
}
@Override
protected void onDeath(@NotNull EntityDeathEvent entityDeathEvent) {
if(getTag(Tag.Boolean("revived"))) {
super.onDeath(entityDeathEvent);
return;
}
particle(Particle.TOTEM_OF_UNDYING, entityDeathEvent.getEntity().getPosition(), 2, 60);
instance.playSound(Sound.sound(SoundEvent.ITEM_TOTEM_USE, Sound.Source.MASTER, 0.5f, 1));
setTag(Tag.Boolean("revived"), true);
setHealth(getMaxHealth()/2);
updateHealthBar();
refreshIsDead(false);
}
private static final class ActionGoal extends GoalSelector {
private final Duration cooldown;
private final Consumer<Entity> consumer;
private long lastSummon;
private Entity target;
public ActionGoal(@NotNull EntityCreature entityCreature, @NotNull Duration cooldown, Consumer<Entity> consumer) {
super(entityCreature);
this.cooldown = cooldown;
this.consumer = consumer;
}
@Override
public boolean shouldStart() {
Entity target = entityCreature.getTarget();
if (target == null) target = findTarget();
if (target == null) return false;
if (Cooldown.hasCooldown(System.currentTimeMillis(), lastSummon, cooldown)) return false;
this.target = target;
return true;
}
@Override
public void start() {
if (target == null) return;
entityCreature.setTarget(target);
}
@Override
public void tick(long time) {
if (!Cooldown.hasCooldown(time, lastSummon, cooldown) && entityCreature.getTarget() != null) {
lastSummon = time;
consumer.accept(entityCreature.getTarget());
}
}
@Override
public boolean shouldEnd() {
final Entity target = entityCreature.getTarget();
return target == null || target.isRemoved() ||
Cooldown.hasCooldown(System.currentTimeMillis(), lastSummon, cooldown);
}
@Override
public void end() {}
}
}
@@ -0,0 +1,14 @@
package eu.mhsl.minenet.minestom.pve.arena.mob.creature;
import eu.mhsl.minenet.minestom.pve.arena.mob.ArenaMob;
import net.minestom.server.entity.EntityType;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
public class Pillager extends ArenaMob {
public Pillager() {
super(EntityType.PILLAGER);
setItemInMainHand(ItemStack.of(Material.STONE_AXE));
}
}
@@ -0,0 +1,22 @@
package eu.mhsl.minenet.minestom.pve.arena.mob.creature;
import eu.mhsl.minenet.minestom.pve.arena.mob.ArenaMob;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.metadata.EntityMeta;
import net.minestom.server.entity.metadata.LivingEntityMeta;
import net.minestom.server.entity.metadata.monster.SpiderMeta;
import net.minestom.server.event.entity.EntityDamageEvent;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.entity.EntitySpawnEvent;
import net.minestom.server.sound.SoundEvent;
import org.jetbrains.annotations.NotNull;
public class Spider extends ArenaMob {
public Spider() {
super(EntityType.SPIDER);
setHealth(3);
}
}
@@ -0,0 +1,19 @@
package eu.mhsl.minenet.minestom.pve.arena.mob.creature;
import eu.mhsl.minenet.minestom.pve.arena.mob.ArenaMob;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.ai.EntityAIGroupBuilder;
import net.minestom.server.entity.ai.target.ClosestEntityTarget;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;
public class Vex extends ArenaMob {
public Vex() {
super(EntityType.VEX);
setItemInMainHand(ItemStack.of(Material.GOLDEN_SWORD));
}
}
@@ -0,0 +1,56 @@
package eu.mhsl.minenet.minestom.pve.arena.mob.creature;
import eu.mhsl.minenet.minestom.pve.arena.Arena;
import eu.mhsl.minenet.minestom.pve.arena.mob.ArenaMob;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.event.entity.EntityDeathEvent;
import net.minestom.server.event.entity.EntitySpawnEvent;
import net.minestom.server.instance.Explosion;
import net.minestom.server.instance.Instance;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.tag.Tag;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class Zombie extends ArenaMob {
public Zombie() {
super(EntityType.ZOMBIE);
}
@Override
protected void onSpawn(@NotNull EntitySpawnEvent entitySpawnEvent) {
super.onSpawn(entitySpawnEvent);
setTag(Tag.Boolean("exploder"), Math.random() < 0.1);
if(getTag(Tag.Boolean("exploder"))) {
setItemInHand(Player.Hand.MAIN, ItemStack.builder(Material.TNT).build());
setItemInHand(Player.Hand.OFF, ItemStack.builder(Material.FLINT_AND_STEEL).build());
}
if(Math.random() < 0.1) {
setItemInMainHand(ItemStack.of(Material.EXPERIENCE_BOTTLE));
setExperience(50);
}
}
@Override
protected void onDeath(@NotNull EntityDeathEvent entityDeathEvent) {
super.onDeath(entityDeathEvent);
if(getTag(Tag.Boolean("exploder"))) {
Pos pos = entityDeathEvent.getEntity().getPosition();
((Arena) instance).explosiveDamage(pos, 5, 10, 3);
}
}
}
@@ -0,0 +1,31 @@
package eu.mhsl.minenet.minestom.pve.util;
import net.minestom.server.entity.LivingEntity;
import javax.swing.text.html.parser.Entity;
public class Knockback {
double x = 0;
double z = 0;
public static Knockback calc(LivingEntity attacker) {
return new Knockback(attacker);
}
private Knockback(LivingEntity attacker) {
this.x= Math.sin(attacker.getPosition().yaw() * (Math.PI / 180));
this.z = -Math.cos(attacker.getPosition().yaw() * (Math.PI / 180));
}
public void apply(LivingEntity victim, float strength) {
victim.takeKnockback(strength, x, z);
}
public double x() {
return x;
}
public double z() {
return z;
}
}
@@ -0,0 +1,12 @@
package eu.mhsl.minenet.minestom.pve.util;
public class Mapping {
public static double map(double input, double in_min, double in_max, double out_min, double out_max) {
// if(input > in_max) in_max = input;
// if(in_min > in_max) in_max = in_min;
// if(out_min > out_max) out_max = out_min;
return (input - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
}