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.

BIN
.gradle/workspace-id.txt Normal file

Binary file not shown.

Binary file not shown.

6
.idea/vcs.xml generated Normal file
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>

View File

@@ -6,6 +6,9 @@ import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
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.command.CommandManager;
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.event.GlobalEventHandler;
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.PlayerSpawnEvent;
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.InstanceManager;
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.potion.Potion;
import net.minestom.server.potion.PotionEffect;
@@ -49,6 +55,15 @@ public class Main {
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
p.setRespawnPoint(new Pos(0,5,0));
p.setGameMode(GameMode.CREATIVE);
@@ -61,8 +76,14 @@ public class Main {
.append(Component.text(event.getMessage(), NamedTextColor.WHITE))));
});
events.addListener(PlayerDeathEvent.class, playerDeathEvent -> {
playerDeathEvent.setDeathText(null);
playerDeathEvent.setChatMessage(null);
});
events.addListener(PlayerSpawnEvent.class, playerSpawnEvent -> {
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();
if (players.isEmpty()) return;
for(Player p : players) {
p.refreshCommands(); //TODO this is a dumb idea
}
final Runtime runtime = Runtime.getRuntime();
final TickMonitor tickMonitor = lastTick.get();
final long ramUsage = (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;

View File

@@ -1,46 +1,38 @@
package eu.mhsl.minenet.minestom.pve.arena;
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.Knockback;
import eu.mhsl.minenet.minestom.pve.util.Mapping;
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.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.*;
import net.minestom.server.entity.ai.EntityAIGroup;
import net.minestom.server.entity.ai.EntityAIGroupBuilder;
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.Entity;
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.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.RemoveEntityFromInstanceEvent;
import net.minestom.server.instance.Explosion;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.potion.Potion;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class Arena extends InstanceContainer {
private UUID arenaId;
@@ -70,33 +62,43 @@ public class Arena extends InstanceContainer {
eventNode().addListener(EntityAttackEvent.class, entityAttackEvent -> {
//Player attacks Mob
if(!(entityAttackEvent.getEntity() instanceof Player)) return;
sendMessage(Component.text("EntityAttackEvent " + System.currentTimeMillis()));
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));
double knockbackZ = -Math.cos(attacker.getPosition().yaw() * (Math.PI / 180));
if(nearby.size() > 1)
target.particle(Particle.SWEEP_ATTACK, target.getPosition(), 0.5f, (int) Mapping.map(nearby.size(), 1, 10, 1, 5));
entityAttackEvent.getTarget().takeKnockback(
0.5f,
knockbackX,
knockbackZ
);
scheduler().scheduleNextTick(() -> {
if(target.isDead()) {
target.takeKnockback(
1f,
knockbackX,
knockbackZ
);
} else
target.setVelocity(new Vec(0, 10, 0));
});
for(Entity entity : nearby) {
if(!(entity instanceof ArenaMob)) continue; //Only damage ArenaMobs
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(() -> {
if(secondaryTarget.isDead()) knb.apply(secondaryTarget, 1f);
});
}
});
}
public void stop() {
@@ -119,9 +121,42 @@ public class Arena extends InstanceContainer {
isRunning = true;
this.spawner = scheduler().scheduleTask(() -> {
if(this.getEntities().size() > 100) return;
new Zombie().setInstance(this, new Pos(0, 5, 0));
}, TaskSchedule.seconds(1), TaskSchedule.seconds(1));
try {
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));
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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];
}
}

View File

@@ -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());
}
}

View File

@@ -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() {}
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}