Skip to content

Commit e04b661

Browse files
authored
Craft status rewrite (#674)
* Stat rewrite * More WIP * WIP * Clean up * Update buildlogic.java-conventions.gradle.kts * Update StatusManager.java * Update StatusManager.java * Update Movecraft.java * Call event as an effect * Fix race condition in WorldManager * Fix multiple status updates * Fix speed
1 parent 09f23f9 commit e04b661

13 files changed

Lines changed: 242 additions & 237 deletions

File tree

Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import net.countercraft.movecraft.features.contacts.ContactsCommand;
2727
import net.countercraft.movecraft.features.contacts.ContactsManager;
2828
import net.countercraft.movecraft.features.contacts.ContactsSign;
29+
import net.countercraft.movecraft.features.status.StatusManager;
30+
import net.countercraft.movecraft.features.status.StatusSign;
2931
import net.countercraft.movecraft.listener.BlockListener;
3032
import net.countercraft.movecraft.listener.InteractListener;
3133
import net.countercraft.movecraft.listener.PlayerListener;
@@ -217,17 +219,21 @@ public void onEnable() {
217219
getServer().getPluginManager().registerEvents(new ReleaseSign(), this);
218220
getServer().getPluginManager().registerEvents(new RemoteSign(), this);
219221
getServer().getPluginManager().registerEvents(new SpeedSign(), this);
220-
getServer().getPluginManager().registerEvents(new StatusSign(), this);
221222
getServer().getPluginManager().registerEvents(new SubcraftRotateSign(), this);
222223
getServer().getPluginManager().registerEvents(new TeleportSign(), this);
223224
getServer().getPluginManager().registerEvents(new ScuttleSign(), this);
224225

225226
var contactsManager = new ContactsManager();
226227
contactsManager.runTaskTimerAsynchronously(this, 0, 20);
227228
getServer().getPluginManager().registerEvents(contactsManager, this);
228-
getServer().getPluginManager().registerEvents(new ContactsSign(contactsManager), this);
229+
getServer().getPluginManager().registerEvents(new ContactsSign(), this);
229230
getCommand("contacts").setExecutor(new ContactsCommand());
230231

232+
var statusManager = new StatusManager();
233+
statusManager.runTaskTimerAsynchronously(this, 0, 1);
234+
getServer().getPluginManager().registerEvents(statusManager, this);
235+
getServer().getPluginManager().registerEvents(new StatusSign(), this);
236+
231237
logger.info("[V " + getDescription().getVersion() + "] has been enabled.");
232238
}
233239

Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java

Lines changed: 2 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -24,44 +24,23 @@
2424
import net.countercraft.movecraft.async.rotation.RotationTask;
2525
import net.countercraft.movecraft.async.translation.TranslationTask;
2626
import net.countercraft.movecraft.config.Settings;
27-
import net.countercraft.movecraft.craft.Craft;
28-
import net.countercraft.movecraft.craft.CraftManager;
29-
import net.countercraft.movecraft.craft.CraftStatus;
30-
import net.countercraft.movecraft.craft.PilotedCraft;
31-
import net.countercraft.movecraft.craft.PlayerCraft;
32-
import net.countercraft.movecraft.craft.SinkingCraft;
27+
import net.countercraft.movecraft.craft.*;
3328
import net.countercraft.movecraft.craft.type.CraftType;
34-
import net.countercraft.movecraft.craft.type.RequiredBlockEntry;
3529
import net.countercraft.movecraft.events.CraftReleaseEvent;
36-
import net.countercraft.movecraft.exception.EmptyHitBoxException;
37-
import net.countercraft.movecraft.localisation.I18nSupport;
3830
import net.countercraft.movecraft.mapUpdater.MapUpdateManager;
3931
import net.countercraft.movecraft.mapUpdater.update.BlockCreateCommand;
4032
import net.countercraft.movecraft.mapUpdater.update.UpdateCommand;
41-
import net.countercraft.movecraft.util.Counter;
42-
import net.countercraft.movecraft.util.Tags;
4333
import net.countercraft.movecraft.util.hitboxes.HitBox;
44-
import net.kyori.adventure.key.Key;
45-
import net.kyori.adventure.sound.Sound;
4634
import net.kyori.adventure.text.Component;
47-
import org.bukkit.Bukkit;
4835
import org.bukkit.Location;
4936
import org.bukkit.Material;
5037
import org.bukkit.World;
5138
import org.bukkit.block.data.BlockData;
5239
import org.bukkit.entity.Player;
53-
import org.bukkit.inventory.InventoryHolder;
54-
import org.bukkit.inventory.ItemStack;
5540
import org.bukkit.scheduler.BukkitRunnable;
5641
import org.jetbrains.annotations.NotNull;
5742

58-
import java.util.ArrayList;
59-
import java.util.HashMap;
60-
import java.util.HashSet;
61-
import java.util.List;
62-
import java.util.Map;
63-
import java.util.Set;
64-
import java.util.WeakHashMap;
43+
import java.util.*;
6544
import java.util.concurrent.BlockingQueue;
6645
import java.util.concurrent.LinkedBlockingQueue;
6746

@@ -319,40 +298,6 @@ else if (dive) {
319298
}
320299
}
321300

322-
private void detectSinking(){
323-
for(Craft craft : CraftManager.getInstance()) {
324-
if (craft instanceof SinkingCraft)
325-
continue;
326-
if (craft.getType().getDoubleProperty(CraftType.SINK_PERCENT) == 0.0 || !craft.isNotProcessing())
327-
continue;
328-
long ticksElapsed = (System.currentTimeMillis() - craft.getLastBlockCheck()) / 50;
329-
330-
if (ticksElapsed <= Settings.SinkCheckTicks)
331-
continue;
332-
333-
CraftStatus status = checkCraftStatus(craft);
334-
//If the craft is disabled, play a sound and disable it.
335-
//Only do this if the craft isn't already disabled.
336-
if (status.isDisabled() && craft.isNotProcessing() && !craft.getDisabled()) {
337-
craft.setDisabled(true);
338-
craft.getAudience().playSound(Sound.sound(Key.key("entity.iron_golem.death"), Sound.Source.NEUTRAL, 5.0f, 5.0f));
339-
}
340-
341-
342-
// if the craft is sinking, let the player
343-
// know and release the craft. Otherwise
344-
// update the time for the next check
345-
if (status.isSinking() && craft.isNotProcessing()) {
346-
craft.getAudience().sendMessage(I18nSupport.getInternationalisedComponent("Player - Craft is sinking"));
347-
craft.setCruising(false);
348-
CraftManager.getInstance().sink(craft);
349-
}
350-
else {
351-
craft.setLastBlockCheck(System.currentTimeMillis());
352-
}
353-
}
354-
}
355-
356301
//Controls sinking crafts
357302
private void processSinking() {
358303
//copy the crafts before iteration to prevent concurrent modifications
@@ -440,7 +385,6 @@ public void run() {
440385
clearAll();
441386

442387
processCruise();
443-
detectSinking();
444388
processSinking();
445389
processFadingBlocks();
446390
processAlgorithmQueue();
@@ -472,95 +416,4 @@ private void clearAll() {
472416

473417
clearanceSet.clear();
474418
}
475-
476-
public CraftStatus checkCraftStatus(@NotNull Craft craft) {
477-
boolean isSinking = false;
478-
boolean isDisabled = false;
479-
480-
// Create counters and populate with required block entries
481-
Counter<RequiredBlockEntry> flyBlocks = new Counter<>();
482-
flyBlocks.putAll(craft.getType().getRequiredBlockProperty(CraftType.FLY_BLOCKS));
483-
Counter<RequiredBlockEntry> moveBlocks = new Counter<>();
484-
moveBlocks.putAll(craft.getType().getRequiredBlockProperty(CraftType.MOVE_BLOCKS));
485-
486-
Counter<Material> materials = new Counter<>();
487-
var v = craft.getType().getObjectProperty(CraftType.FUEL_TYPES);
488-
if(!(v instanceof Map<?, ?>))
489-
throw new IllegalStateException("FUEL_TYPES must be of type Map");
490-
var fuelTypes = (Map<?, ?>) v;
491-
for(var e : fuelTypes.entrySet()) {
492-
if(!(e.getKey() instanceof Material))
493-
throw new IllegalStateException("Keys in FUEL_TYPES must be of type Material");
494-
if(!(e.getValue() instanceof Double))
495-
throw new IllegalStateException("Values in FUEL_TYPES must be of type Double");
496-
}
497-
498-
// go through each block in the HitBox, and if it's in the FlyBlocks or MoveBlocks, increment the counter
499-
int totalNonNegligibleBlocks = 0;
500-
int totalNonNegligibleWaterBlocks = 0;
501-
double fuel = 0;
502-
for (MovecraftLocation l : craft.getHitBox()) {
503-
Material type = craft.getWorld().getBlockAt(l.getX(), l.getY(), l.getZ()).getType();
504-
for(RequiredBlockEntry entry : flyBlocks.getKeySet()) {
505-
if(entry.contains(type))
506-
flyBlocks.add(entry);
507-
}
508-
for(RequiredBlockEntry entry : moveBlocks.getKeySet()) {
509-
if(entry.contains(type))
510-
moveBlocks.add(entry);
511-
}
512-
materials.add(type);
513-
514-
if (type != Material.FIRE && !type.isAir()) {
515-
totalNonNegligibleBlocks++;
516-
}
517-
if (type != Material.FIRE && !type.isAir() && !Tags.FLUID.contains(type)) {
518-
totalNonNegligibleWaterBlocks++;
519-
}
520-
521-
if(Tags.FURNACES.contains(type)) {
522-
InventoryHolder inventoryHolder = (InventoryHolder) craft.getWorld().getBlockAt(l.getX(), l.getY(), l.getZ()).getState();
523-
for (ItemStack iStack : inventoryHolder.getInventory()) {
524-
if (iStack == null || !fuelTypes.containsKey(iStack.getType()))
525-
continue;
526-
fuel += iStack.getAmount() * (double) fuelTypes.get(iStack.getType());
527-
}
528-
}
529-
}
530-
531-
// now see if any of the resulting percentages
532-
// are below the threshold specified in sinkPercent
533-
double sinkPercent = craft.getType().getDoubleProperty(CraftType.SINK_PERCENT) / 100.0;
534-
for(RequiredBlockEntry entry : flyBlocks.getKeySet()) {
535-
if(!entry.check(flyBlocks.get(entry), totalNonNegligibleBlocks, sinkPercent))
536-
isSinking = true;
537-
}
538-
for(RequiredBlockEntry entry : moveBlocks.getKeySet()) {
539-
if(!entry.check(moveBlocks.get(entry), totalNonNegligibleBlocks, sinkPercent))
540-
isDisabled = !craft.getDisabled() && craft.isNotProcessing();
541-
}
542-
543-
// And check the OverallSinkPercent
544-
if (craft.getType().getDoubleProperty(CraftType.OVERALL_SINK_PERCENT) != 0.0) {
545-
double percent;
546-
if (craft.getType().getBoolProperty(CraftType.BLOCKED_BY_WATER)) {
547-
percent = (double) totalNonNegligibleBlocks
548-
/ (double) craft.getOrigBlockCount();
549-
}
550-
else {
551-
percent = (double) totalNonNegligibleWaterBlocks
552-
/ (double) craft.getOrigBlockCount();
553-
}
554-
if (percent * 100.0 < craft.getType().getDoubleProperty(CraftType.OVERALL_SINK_PERCENT))
555-
isSinking = true;
556-
}
557-
558-
if (totalNonNegligibleBlocks == 0)
559-
isSinking = true;
560-
561-
craft.updateMaterials(materials);
562-
craft.setTotalFuel(fuel);
563-
564-
return CraftStatus.of(isSinking, isDisabled);
565-
}
566419
}

Movecraft/src/main/java/net/countercraft/movecraft/craft/BaseCraft.java

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ public abstract class BaseCraft implements Craft {
4242
@NotNull
4343
protected final MutableHitBox collapsedHitBox;
4444
@NotNull
45-
protected Counter<Material> materials;
46-
@NotNull
4745
private final AtomicBoolean processing = new AtomicBoolean();
4846
private final long origPilotTime;
4947
@NotNull
@@ -65,7 +63,6 @@ public abstract class BaseCraft implements Craft {
6563
private int currentGear = 1;
6664
private double burningFuel;
6765
private int origBlockCount;
68-
private double totalFuel = 0;
6966
@NotNull
7067
private Audience audience;
7168
@NotNull
@@ -85,7 +82,6 @@ public BaseCraft(@NotNull CraftType type, @NotNull World world) {
8582
cruising = false;
8683
disabled = false;
8784
origPilotTime = System.currentTimeMillis();
88-
materials = new Counter<>();
8985
audience = Audience.empty();
9086
}
9187

@@ -324,17 +320,15 @@ public int getTickCooldown() {
324320
if (this instanceof SinkingCraft)
325321
return type.getIntProperty(CraftType.SINK_RATE_TICKS);
326322

327-
if (materials.isEmpty()) {
328-
for (MovecraftLocation location : hitBox) {
329-
materials.add(location.toBukkit(w).getBlock().getType());
330-
}
331-
}
323+
Counter<Material> materials = getDataTag(Craft.MATERIALS);
332324

333325
int chestPenalty = 0;
334-
for (Material m : Tags.CHESTS) {
335-
chestPenalty += materials.get(m);
326+
if (!materials.isEmpty()) {
327+
for (Material m : Tags.CHESTS) {
328+
chestPenalty += materials.get(m);
329+
}
336330
}
337-
chestPenalty *= type.getDoubleProperty(CraftType.CHEST_PENALTY);
331+
chestPenalty *= (int) type.getDoubleProperty(CraftType.CHEST_PENALTY);
338332
if (!cruising)
339333
return ((int) type.getPerWorldProperty(CraftType.PER_WORLD_TICK_COOLDOWN, w) + chestPenalty) * (type.getBoolProperty(CraftType.GEAR_SHIFTS_AFFECT_TICK_COOLDOWN) ? currentGear : 1);
340334

@@ -345,6 +339,9 @@ public int getTickCooldown() {
345339
// Dynamic Fly Block Speed
346340
int cruiseTickCooldown = (int) type.getPerWorldProperty(CraftType.PER_WORLD_CRUISE_TICK_COOLDOWN, w);
347341
if (type.getDoubleProperty(CraftType.DYNAMIC_FLY_BLOCK_SPEED_FACTOR) != 0) {
342+
if (materials.isEmpty()) {
343+
return ((int) type.getPerWorldProperty(CraftType.PER_WORLD_TICK_COOLDOWN, w) + chestPenalty) * (type.getBoolProperty(CraftType.GEAR_SHIFTS_AFFECT_TICK_COOLDOWN) ? currentGear : 1);
344+
}
348345
EnumSet<Material> flyBlockMaterials = type.getMaterialSetProperty(CraftType.DYNAMIC_FLY_BLOCK);
349346
double count = 0;
350347
for (Material m : flyBlockMaterials) {
@@ -536,25 +533,6 @@ public void setAudience(@NotNull Audience audience) {
536533
this.audience = audience;
537534
}
538535

539-
public void updateMaterials (Counter<Material> counter) {
540-
materials = counter;
541-
}
542-
543-
@Override
544-
public Counter<Material> getMaterials() {
545-
return materials;
546-
}
547-
548-
@Override
549-
public void setTotalFuel(double fuel) {
550-
totalFuel = fuel;
551-
}
552-
553-
@Override
554-
public double getTotalFuel() {
555-
return totalFuel;
556-
}
557-
558536
@Override
559537
public CraftDataTagContainer getDataTagContainer() {
560538
return dataTagContainer;

Movecraft/src/main/java/net/countercraft/movecraft/features/contacts/ContactsCommand.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command
5757
ComponentPaginator paginator = new ComponentPaginator(
5858
I18nSupport.getInternationalisedComponent("Contacts"),
5959
(pageNumber) -> "/contacts " + pageNumber);
60-
for (Craft target : base.getDataTag(ContactsManager.CONTACTS)) {
60+
for (Craft target : base.getDataTag(Craft.CONTACTS)) {
6161
if (target.getHitBox().isEmpty())
6262
continue;
6363

Movecraft/src/main/java/net/countercraft/movecraft/features/contacts/ContactsManager.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.*;
2828

2929
public class ContactsManager extends BukkitRunnable implements Listener {
30-
public static final CraftDataTagKey<List<Craft>> CONTACTS = CraftDataTagContainer.tryRegisterTagKey(new NamespacedKey("movecraft", "contacts"), craft -> new ArrayList<>(0));
3130
private static final CraftDataTagKey<Map<Craft, Long>> RECENT_CONTACTS = CraftDataTagContainer.tryRegisterTagKey(new NamespacedKey("movecraft", "recent-contacts"), craft -> new WeakHashMap<>());
3231

3332
@Override
@@ -52,7 +51,7 @@ private void runContacts() {
5251
}
5352

5453
private void update(@NotNull Craft base, @NotNull Set<Craft> craftsInWorld) {
55-
List<Craft> previousContacts = base.getDataTag(CONTACTS);
54+
List<Craft> previousContacts = base.getDataTag(Craft.CONTACTS);
5655
if (previousContacts == null)
5756
previousContacts = new ArrayList<>(0);
5857
List<Craft> futureContacts = get(base, craftsInWorld);
@@ -71,7 +70,7 @@ private void update(@NotNull Craft base, @NotNull Set<Craft> craftsInWorld) {
7170
Bukkit.getServer().getPluginManager().callEvent(event);
7271
}
7372

74-
base.setDataTag(CONTACTS, futureContacts);
73+
base.setDataTag(Craft.CONTACTS, futureContacts);
7574
}
7675

7776
private @NotNull List<Craft> get(Craft base, @NotNull Set<Craft> craftsInWorld) {
@@ -126,7 +125,7 @@ private void runRecentContacts() {
126125
if (base.getHitBox().isEmpty())
127126
continue;
128127

129-
for (Craft target : base.getDataTag(CONTACTS)) {
128+
for (Craft target : base.getDataTag(Craft.CONTACTS)) {
130129
// has the craft not been seen in the last minute?
131130
if (System.currentTimeMillis() - base.getDataTag(RECENT_CONTACTS).getOrDefault(target, 0L) <= 60000)
132131
continue;
@@ -235,12 +234,12 @@ public void onCraftSink(@NotNull CraftSinkEvent e) {
235234

236235
private void remove(Craft base) {
237236
for (Craft other : CraftManager.getInstance().getCrafts()) {
238-
List<Craft> contacts = other.getDataTag(CONTACTS);
237+
List<Craft> contacts = other.getDataTag(Craft.CONTACTS);
239238
if (contacts.contains(base))
240239
continue;
241240

242241
contacts.remove(base);
243-
other.setDataTag(CONTACTS, contacts);
242+
other.setDataTag(Craft.CONTACTS, contacts);
244243
}
245244

246245
for (Craft other : CraftManager.getInstance().getCrafts()) {

Movecraft/src/main/java/net/countercraft/movecraft/features/contacts/ContactsSign.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@
2020

2121
public class ContactsSign implements Listener {
2222
private static final String HEADER = "Contacts:";
23-
private final ContactsManager contactsManager;
24-
25-
public ContactsSign(ContactsManager contactsManager) {
26-
this.contactsManager = contactsManager;
27-
}
2823

2924
@EventHandler
3025
public void onCraftDetect(@NotNull CraftDetectEvent event) {
@@ -55,7 +50,7 @@ public final void onSignTranslateEvent(@NotNull SignTranslateEvent event) {
5550

5651
Craft base = event.getCraft();
5752
int line = 1;
58-
for (Craft target : base.getDataTag(ContactsManager.CONTACTS)) {
53+
for (Craft target : base.getDataTag(Craft.CONTACTS)) {
5954
if (line > 3)
6055
break;
6156

0 commit comments

Comments
 (0)