Skip to content

Commit 1343af8

Browse files
committed
/lrconfig command
1 parent 99caf1a commit 1343af8

File tree

11 files changed

+356
-3
lines changed

11 files changed

+356
-3
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
}
88

99
group = "com.solarrabbit"
10-
version = "1.11.6"
10+
version = "1.11.7"
1111
description = "LargeRaids"
1212
val mcVersion = "1.21.5"
1313

docs/user-guide.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Refer to the [Configuration Guide](configurations.html).
1818
- `/lrglow` - outline all raiders in the current raid
1919
- `/lrshow` - displays the current wave
2020
- `/lrattack [prio] [target_thru_walls] [entity_class]` - makes all raiders of the current wave attack an entity type
21+
- `/lrconfig spawn <x> <y> <z>` - for the current large raid, make all future waves spawn from this location
22+
- `/lrconfig target <x> <y> <z> <radius>` - for the current large raid, make raiders path-find to this location within range of this radius
2123

2224
## Placeholders
2325

src/main/java/com/solarrabbit/largeraids/LargeRaids.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77

88
import com.solarrabbit.largeraids.PluginLogger.Level;
99
import com.solarrabbit.largeraids.command.*;
10-
import com.solarrabbit.largeraids.command.completer.StartStopRaidCommandCompleter;
11-
import com.solarrabbit.largeraids.command.completer.VillageCentersCommandCompleter;
10+
import com.solarrabbit.largeraids.command.completer.*;
1211
import com.solarrabbit.largeraids.config.MiscConfig;
1312
import com.solarrabbit.largeraids.config.PlaceholderConfig;
1413
import com.solarrabbit.largeraids.config.RaidConfig;
@@ -142,6 +141,8 @@ private void loadCommands() {
142141
getCommand("lrcenters").setTabCompleter(new VillageCentersCommandCompleter(db));
143142
getCommand("lrglow").setExecutor(new OutlineRaidersCommand(this));
144143
getCommand("lrattack").setExecutor(new RaiderAttackCommand(this));
144+
getCommand("lrconfig").setExecutor(new RaidConfigCommand(this));
145+
getCommand("lrconfig").setTabCompleter(new RaidConfigCommandCompleter());
145146
}
146147

147148
private void loadCustomConfigs() {
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package com.solarrabbit.largeraids.command;
2+
3+
import com.solarrabbit.largeraids.LargeRaids;
4+
import com.solarrabbit.largeraids.raid.LargeRaid;
5+
import com.solarrabbit.largeraids.raid.RaidManager;
6+
7+
import java.util.Optional;
8+
9+
import org.bukkit.ChatColor;
10+
import org.bukkit.Location;
11+
import org.bukkit.command.Command;
12+
import org.bukkit.command.CommandExecutor;
13+
import org.bukkit.command.CommandSender;
14+
import org.bukkit.entity.Player;
15+
16+
/**
17+
* Configures some settings of the current large raid.
18+
*/
19+
public class RaidConfigCommand implements CommandExecutor {
20+
private final LargeRaids plugin;
21+
private final RaidManager manager;
22+
23+
public RaidConfigCommand(LargeRaids plugin) {
24+
this.plugin = plugin;
25+
manager = plugin.getRaidManager();
26+
}
27+
28+
@Override
29+
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
30+
if (!(sender instanceof Player)) {
31+
sender.sendMessage(ChatColor.RED + this.plugin.getMessage("sender-player"));
32+
return false;
33+
}
34+
35+
if (args.length < 1)
36+
return false;
37+
38+
Location location = ((Player) sender).getLocation();
39+
Optional<LargeRaid> largeRaid = manager.getLargeRaid(location);
40+
if (!largeRaid.isPresent()) {
41+
sender.sendMessage(ChatColor.RED + this.plugin.getMessage("raid-config.no-large-raid"));
42+
return true;
43+
}
44+
45+
switch (args[0]) {
46+
case "spawn":
47+
if (args.length == 1) {
48+
Location spawn = largeRaid.get().getSpawnLocation();
49+
if (spawn == null) {
50+
sender.sendMessage(ChatColor.YELLOW + this.plugin.getMessage("raid-config.no-custom-spawn"));
51+
} else {
52+
sender.sendMessage(ChatColor.GREEN + String.format(this.plugin.getMessage("raid-config.current-custom-spawn"),
53+
Math.round(spawn.getX()), Math.round(spawn.getY()), Math.round(spawn.getZ())));
54+
}
55+
return true;
56+
}
57+
58+
if (args.length == 2 && args[1].equals("clear")) {
59+
largeRaid.get().setSpawnLocation(null);
60+
sender.sendMessage(ChatColor.GREEN + this.plugin.getMessage("raid-config.custom-spawn-cleared"));
61+
return true;
62+
}
63+
if (args.length < 4)
64+
return false;
65+
66+
try {
67+
double x = parseDoubleOrRelative(args[1], location, 0);
68+
double y = parseDoubleOrRelative(args[2], location, 1);
69+
double z = parseDoubleOrRelative(args[3], location, 2);
70+
Location spawn = new Location(location.getWorld(), x, y, z);
71+
largeRaid.get().setSpawnLocation(spawn);
72+
sender.sendMessage(ChatColor.GREEN + String.format(this.plugin.getMessage("raid-config.custom-spawn-set"),
73+
Math.round(spawn.getX()), Math.round(spawn.getY()), Math.round(spawn.getZ())));
74+
return true;
75+
} catch (NumberFormatException e) {
76+
sender.sendMessage(ChatColor.RED + this.plugin.getMessage("raid-config.invalid-coordinates"));
77+
return false;
78+
}
79+
case "target":
80+
if (args.length == 1) {
81+
Location target = largeRaid.get().getRaidTarget();
82+
if (target == null) {
83+
sender.sendMessage(ChatColor.YELLOW + this.plugin.getMessage("raid-config.no-target"));
84+
} else {
85+
sender.sendMessage(ChatColor.GREEN + String.format(this.plugin.getMessage("raid-config.current-center"),
86+
Math.round(target.getX()), Math.round(target.getY()), Math.round(target.getZ()),
87+
largeRaid.get().getRaidTargetRadius()));
88+
}
89+
return true;
90+
}
91+
92+
if (args.length == 2 && args[1].equals("clear")) {
93+
largeRaid.get().setRaidTarget(null, 0);
94+
sender.sendMessage(ChatColor.GREEN + this.plugin.getMessage("raid-config.center-cleared"));
95+
return true;
96+
}
97+
if (args.length < 5)
98+
return false;
99+
100+
double x;
101+
double y;
102+
double z;
103+
try {
104+
x = parseDoubleOrRelative(args[1], location, 0);
105+
y = parseDoubleOrRelative(args[2], location, 1);
106+
z = parseDoubleOrRelative(args[3], location, 2);
107+
} catch (NumberFormatException e) {
108+
sender.sendMessage(ChatColor.RED + this.plugin.getMessage("raid-config.invalid-coordinates"));
109+
return false;
110+
}
111+
112+
try {
113+
double radius = Double.parseDouble(args[4]);
114+
if (radius < 0) {
115+
sender.sendMessage(ChatColor.RED + this.plugin.getMessage("raid-config.invalid-radius"));
116+
return false;
117+
}
118+
Location target = new Location(location.getWorld(), x, y, z);
119+
largeRaid.get().setRaidTarget(target, radius);
120+
sender.sendMessage(ChatColor.GREEN + String.format(this.plugin.getMessage("raid-config.target-set"),
121+
Math.round(target.getX()), Math.round(target.getY()), Math.round(target.getZ()), radius));
122+
return true;
123+
} catch (NumberFormatException e) {
124+
sender.sendMessage(ChatColor.RED + this.plugin.getMessage("raid-config.invalid-radius"));
125+
return false;
126+
}
127+
default:
128+
return false;
129+
}
130+
}
131+
132+
private double parseDoubleOrRelative(String pos, Location loc, int type) {
133+
if (loc == null || pos.length() == 0 || pos.charAt(0) != '~')
134+
return Double.parseDouble(pos);
135+
double relative = pos.length() == 1 ? 0 : Double.parseDouble(pos.substring(1));
136+
switch (type) {
137+
case 0:
138+
return relative + Math.round(loc.getX() * 1000) / 1000D;
139+
case 1:
140+
return relative + Math.round(loc.getY() * 1000) / 1000D;
141+
case 2:
142+
return relative + Math.round(loc.getZ() * 1000) / 1000D;
143+
default:
144+
return 0;
145+
}
146+
}
147+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.solarrabbit.largeraids.command.completer;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import org.bukkit.command.Command;
7+
import org.bukkit.command.CommandSender;
8+
import org.bukkit.command.TabCompleter;
9+
10+
public class RaidConfigCommandCompleter implements TabCompleter {
11+
@Override
12+
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
13+
List<String> list = new ArrayList<>();
14+
switch (args.length) {
15+
case 1:
16+
list.add("spawn");
17+
list.add("target");
18+
break;
19+
default:
20+
break;
21+
}
22+
return list;
23+
}
24+
25+
}

src/main/java/com/solarrabbit/largeraids/nms/AbstractRaiderWrapper.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
public interface AbstractRaiderWrapper {
44
AbstractRaidWrapper getCurrentRaid();
55

6+
void setRaiderTarget(AbstractBlockPositionWrapper pos, double radius);
7+
68
boolean addAttackGoal(int prio, boolean mustSee, Class<?> entityClass);
79
}

src/main/java/com/solarrabbit/largeraids/raid/LargeRaid.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public class LargeRaid {
6060
private Raid currentRaid;
6161
private int currentWave;
6262
private boolean raidersOutlined;
63+
private Location raidSpawn;
64+
private Location raidTarget;
65+
private double raidTargetRadius;
6366

6467
/**
6568
* Constructs a large raid object.
@@ -168,6 +171,9 @@ void spawnWave() {
168171
}
169172
}
170173
}
174+
if (raidTarget != null) {
175+
setRaiderTarget();
176+
}
171177
Bukkit.getScheduler().runTaskLater(JavaPlugin.getPlugin(LargeRaids.class), () -> {
172178
for (Raider raider : newRaiders)
173179
raider.setInvulnerable(false);
@@ -421,6 +427,9 @@ private void playSoundToPlayersInRadius(Sound sound) {
421427
}
422428

423429
private Location getWaveSpawnLocation() {
430+
if (raidSpawn != null)
431+
return raidSpawn;
432+
424433
List<Raider> list = this.currentRaid.getRaiders();
425434
return list.isEmpty() ? null : list.get(0).getLocation();
426435
}
@@ -440,6 +449,37 @@ private AbstractRaidWrapper getNMSRaidAtCenter() {
440449
return level.getRaidAt(blkPos);
441450
}
442451

452+
public Location getSpawnLocation() {
453+
return raidSpawn;
454+
}
455+
456+
public void setSpawnLocation(Location raidSpawn) {
457+
this.raidSpawn = raidSpawn;
458+
}
459+
460+
public Location getRaidTarget() {
461+
return raidTarget;
462+
}
463+
464+
public double getRaidTargetRadius() {
465+
return raidTargetRadius;
466+
}
467+
468+
public void setRaidTarget(Location target, double radius) {
469+
this.raidTarget = target;
470+
this.raidTargetRadius = radius;
471+
if (currentRaid != null) {
472+
setRaiderTarget();
473+
}
474+
}
475+
476+
private void setRaiderTarget() {
477+
for (Raider raider : currentRaid.getRaiders()) {
478+
AbstractRaiderWrapper wrapper = VersionUtil.getCraftRaiderWrapper(raider).getHandle();
479+
wrapper.setRaiderTarget(raidTarget == null ? null : VersionUtil.getBlockPositionWrapper(raidTarget), raidTargetRadius);
480+
}
481+
}
482+
443483
public boolean addAttackGoal(int prio, boolean mustSee, Class<?> entityClass) {
444484
for (Raider raider : currentRaid.getRaiders()) {
445485
AbstractRaiderWrapper wrapper = VersionUtil.getCraftRaiderWrapper(raider).getHandle();
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package com.solarrabbit.largeraids.versioned.nms;
2+
3+
import com.google.common.collect.Sets;
4+
5+
import java.util.EnumSet;
6+
import java.util.List;
7+
import java.util.Set;
8+
9+
import net.minecraft.core.BlockPos;
10+
import net.minecraft.server.level.ServerLevel;
11+
import net.minecraft.world.entity.ai.goal.Goal;
12+
import net.minecraft.world.entity.ai.goal.PathfindToRaidGoal;
13+
import net.minecraft.world.entity.ai.util.DefaultRandomPos;
14+
import net.minecraft.world.entity.raid.Raid;
15+
import net.minecraft.world.entity.raid.Raider;
16+
import net.minecraft.world.entity.raid.Raids;
17+
import net.minecraft.world.phys.Vec3;
18+
19+
public class PathfindToTargetGoal<T extends Raider> extends PathfindToRaidGoal<T> {
20+
private static final int RECRUITMENT_SEARCH_TICK_DELAY = 20;
21+
private static final float SPEED_MODIFIER = 1.0F;
22+
private final T mob;
23+
private int recruitmentTick;
24+
private BlockPos targetPos;
25+
private double targetRadius;
26+
27+
public PathfindToTargetGoal(T mob) {
28+
super(mob);
29+
this.mob = mob;
30+
this.setFlags(EnumSet.of(Goal.Flag.MOVE));
31+
}
32+
33+
public void setTargetPos(BlockPos pos, double radius) {
34+
this.targetPos = pos;
35+
this.targetRadius = radius;
36+
}
37+
38+
private boolean isCloseToGoal() {
39+
if (targetPos == null)
40+
return getServerLevel(this.mob.level()).isVillage(this.mob.blockPosition());
41+
42+
return targetPos.closerToCenterThan(this.mob.position(), targetRadius);
43+
}
44+
45+
@Override
46+
public boolean canUse() {
47+
return this.mob.getTarget() == null
48+
&& !this.mob.hasControllingPassenger()
49+
&& this.mob.hasActiveRaid()
50+
&& !this.mob.getCurrentRaid().isOver()
51+
&& !isCloseToGoal();
52+
}
53+
54+
@Override
55+
public boolean canContinueToUse() {
56+
return this.mob.hasActiveRaid() && !this.mob.getCurrentRaid().isOver() && !isCloseToGoal();
57+
}
58+
59+
@Override
60+
public void tick() {
61+
if (this.mob.hasActiveRaid()) {
62+
Raid currentRaid = this.mob.getCurrentRaid();
63+
if (this.mob.tickCount > this.recruitmentTick) {
64+
this.recruitmentTick = this.mob.tickCount + RECRUITMENT_SEARCH_TICK_DELAY;
65+
this.recruitNearby(currentRaid);
66+
}
67+
68+
if (!this.mob.isPathFinding() || targetPos != null) {
69+
Vec3 posTowards = DefaultRandomPos.getPosTowards(this.mob, 15, 4, Vec3.atBottomCenterOf(
70+
targetPos != null ? targetPos : currentRaid.getCenter()), (float) (Math.PI / 2));
71+
if (posTowards != null) {
72+
this.mob.getNavigation().moveTo(posTowards.x, posTowards.y, posTowards.z, SPEED_MODIFIER);
73+
}
74+
}
75+
}
76+
}
77+
78+
private void recruitNearby(Raid raid) {
79+
if (raid.isActive()) {
80+
ServerLevel serverLevel = getServerLevel(this.mob.level());
81+
Set<Raider> set = Sets.newHashSet();
82+
List<Raider> entitiesOfClass = serverLevel.getEntitiesOfClass(
83+
Raider.class, this.mob.getBoundingBox().inflate(16.0), raider1 -> !raider1.hasActiveRaid() && Raids.canJoinRaid(raider1)
84+
);
85+
set.addAll(entitiesOfClass);
86+
87+
for (Raider raider : set) {
88+
raid.joinRaid(serverLevel, raid.getGroupsSpawned(), raider, null, true);
89+
}
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)