Merge pull request 'BauSystem/SimulatorStabGenerator' (#47) from BauSystem/SimulatorStabGenerator into main

Reviewed-on: SteamWar/SteamWar#47
This commit is contained in:
2025-04-19 23:21:45 +02:00
9 changed files with 441 additions and 14 deletions
@@ -76,7 +76,7 @@ public class SimulatorCommand extends SWCommand {
@Register(value = "start", description = "SIMULATOR_START_HELP") @Register(value = "start", description = "SIMULATOR_START_HELP")
public void start(@Validator Player p, @ErrorMessage("SIMULATOR_NOT_EXISTS") Simulator simulator) { public void start(@Validator Player p, @ErrorMessage("SIMULATOR_NOT_EXISTS") Simulator simulator) {
SimulatorExecutor.run(simulator); SimulatorExecutor.run(simulator, () -> {});
} }
@Register(value = "rename", description = "SIMULATOR_RENAME_HELP") @Register(value = "rename", description = "SIMULATOR_RENAME_HELP")
@@ -168,9 +168,19 @@ public class SimulatorCursor implements Listener {
} }
return; return;
} }
Simulator simulator = SimulatorStorage.getSimulator(player);
SimulatorWatcher.show(simulator, player);
Simulator simulator = SimulatorStorage.getSimulator(player);
if (simulator != null && simulator.getStabGenerator() != null) {
removeCursor(player);
SimulatorWatcher.show(null, player);
SWUtils.sendToActionbar(player, "§cGenerating Stab");
synchronized (calculating) {
calculating.remove(player);
}
return;
}
SimulatorWatcher.show(simulator, player);
List<REntity> entities = SimulatorWatcher.getEntitiesOfSimulator(simulator); List<REntity> entities = SimulatorWatcher.getEntitiesOfSimulator(simulator);
RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities); RayTraceUtils.RRayTraceResult rayTraceResult = RayTraceUtils.traceREntity(player, player.getLocation(), entities);
if (rayTraceResult == null) { if (rayTraceResult == null) {
@@ -357,7 +367,7 @@ public class SimulatorCursor implements Listener {
if (simulator == null) { if (simulator == null) {
return; return;
} }
SimulatorExecutor.run(simulator); SimulatorExecutor.run(simulator, () -> {});
return; return;
} }
@@ -20,6 +20,7 @@
package de.steamwar.bausystem.features.simulator.data; package de.steamwar.bausystem.features.simulator.data;
import de.steamwar.bausystem.features.simulator.execute.SimulatorAction; import de.steamwar.bausystem.features.simulator.execute.SimulatorAction;
import de.steamwar.bausystem.features.simulator.execute.SimulatorStabGenerator;
import de.steamwar.inventory.InvCallback; import de.steamwar.inventory.InvCallback;
import de.steamwar.inventory.SWItem; import de.steamwar.inventory.SWItem;
import lombok.Getter; import lombok.Getter;
@@ -30,13 +31,13 @@ import org.bukkit.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
@Getter @Getter
@Setter @Setter
@RequiredArgsConstructor @RequiredArgsConstructor
public final class Simulator { public final class Simulator {
private SimulatorStabGenerator stabGenerator = null;
private Material material = Material.BARREL; private Material material = Material.BARREL;
private final String name; private final String name;
private boolean autoTrace = false; private boolean autoTrace = false;
@@ -46,7 +46,7 @@ public class SimulatorExecutor implements Listener {
private static Map<Long, Map<Integer, List<SimulatorAction>>> tickStartActions = new HashMap<>(); private static Map<Long, Map<Integer, List<SimulatorAction>>> tickStartActions = new HashMap<>();
private static Map<Long, List<SimulatorAction>> tickEndActions = new HashMap<>(); private static Map<Long, List<SimulatorAction>> tickEndActions = new HashMap<>();
public static boolean run(Simulator simulator) { public static boolean run(Simulator simulator, Runnable onEnd) {
if (currentlyRunning.contains(simulator)) return false; if (currentlyRunning.contains(simulator)) return false;
currentlyRunning.add(simulator); currentlyRunning.add(simulator);
@@ -69,7 +69,7 @@ public class SimulatorExecutor implements Listener {
public void accept(World world) { public void accept(World world) {
currentlyRunning.remove(simulator); currentlyRunning.remove(simulator);
if (simulator.isAutoTrace()) { if (simulator.isAutoTrace() && onEnd == null) {
simulator.getGroups() simulator.getGroups()
.stream() .stream()
.map(SimulatorGroup::getElements) .map(SimulatorGroup::getElements)
@@ -82,10 +82,12 @@ public class SimulatorExecutor implements Listener {
TraceRecorder.instance.stopRecording(region); TraceRecorder.instance.stopRecording(region);
}); });
} }
onEnd.run();
} }
}); });
if (simulator.isAutoTrace()) { if (simulator.isAutoTrace() && onEnd == null) {
simulator.getGroups() simulator.getGroups()
.stream() .stream()
.map(SimulatorGroup::getElements) .map(SimulatorGroup::getElements)
@@ -0,0 +1,386 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.features.simulator.execute;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
import de.steamwar.bausystem.features.tracer.TNTPoint;
import de.steamwar.bausystem.features.tracer.Trace;
import de.steamwar.bausystem.features.tracer.TraceManager;
import de.steamwar.bausystem.features.tracer.TraceRecorder;
import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.region.flags.flagvalues.ColorMode;
import de.steamwar.bausystem.region.utils.RegionExtensionType;
import de.steamwar.bausystem.region.utils.RegionType;
import de.steamwar.bausystem.utils.FlatteningWrapper;
import de.steamwar.bausystem.utils.PasteBuilder;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import de.steamwar.bausystem.utils.bossbar.BossBarService;
import lombok.AllArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.util.Vector;
import java.util.*;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.stream.Collectors;
public class SimulatorStabGenerator implements Listener {
// Lupfstichs sind noch nicht perfekt
// Schwenkstichs sidn noch nicht perfekt
private static final int MAX_RECORDINGS = 5;
private static final Level LEVEL = Level.INFO;
private static final int TNT_INCREASE = 10;
private static final int MIN_BLOCK_TO_COUNT_AS_DEPTH = 20;
private final Map<Integer, Set<Location>> destroyedBlocksPerSlice = new HashMap<>();
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
if (direction == null) return;
if (Region.getRegion(event.getEntity().getLocation()) == region) {
event.blockList().forEach(block -> {
if (!region.inRegion(block.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) return;
int component = direction.component.apply(block.getLocation().toVector());
destroyedBlocksPerSlice.computeIfAbsent(component, __ -> new HashSet<>())
.add(block.getLocation());
});
}
}
private final Region region;
private final Simulator simulator;
private final TNTElement tntElement;
private final List<TNTPhase> phases;
private final int depthLimit;
private Clipboard clipboard;
private boolean cancel = false;
private Direction direction = null;
public SimulatorStabGenerator(Region region, Simulator simulator, TNTElement tntElement, int depthLimit) {
this.region = region;
this.simulator = simulator;
this.tntElement = tntElement;
this.phases = tntElement.getPhases();
this.depthLimit = depthLimit;
setup();
}
private void setup() {
TNTPhase tntPhase = simulator.getGroups().stream()
.map(SimulatorGroup::getElements)
.flatMap(List::stream)
.filter(TNTElement.class::isInstance)
.map(TNTElement.class::cast)
.filter(tntElement -> this.tntElement != tntElement)
.map(tntElement -> tntElement.getPhases().stream().max(Comparator.comparingInt(TNTPhase::getTickOffset)))
.filter(Optional::isPresent)
.map(Optional::get)
.filter(phase -> phase != phases.get(0))
.max(Comparator.comparingInt(TNTPhase::getTickOffset))
.orElse(null);
if (tntPhase == null) {
throw new SecurityException("");
}
TNTPhase phase = phases.get(0);
phases.clear();
phases.add(phase);
phase.setCount(1);
phase.setTickOffset(tntPhase.getTickOffset());
phase.setOrder(100);
TraceRecorder.instance.stopRecording(region);
if (TraceRecorder.instance.isAutoTraceEnabledInRegion(region)) {
TraceRecorder.instance.removeAutoTraceRegion(region);
}
clipboard = FlatteningWrapper.impl.copy(region.getMinPointTestblockExtension(), region.getMaxPointTestblockExtension(), region.getTestBlockPoint());
getDirection();
}
private BlockVector3 toBlockVector3(Point point) {
return BlockVector3.at(point.getX(), point.getY(), point.getZ());
}
private void getDirection() {
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) {
e.setBlocks((com.sk89q.worldedit.regions.Region) new CuboidRegion(toBlockVector3(region.getMinPointTestblockExtension()), toBlockVector3(region.getMaxPointTestblockExtension())), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
}
showBossbar(false);
Trace trace = TraceRecorder.instance.startRecording(region);
SimulatorExecutor.run(simulator, () -> {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
TraceRecorder.instance.stopRecording(region);
calculateDirection(trace);
}, 20);
});
}
private void calculateDirection(Trace trace) {
long tickSinceStart = -1;
List<TNTPoint> points = null;
for (List<TNTPoint> current : trace.getHistories()) {
long ticks = current.get(0).getTicksSinceStart();
if (points == null || ticks > tickSinceStart) {
tickSinceStart = ticks;
points = current;
} else if (ticks == tickSinceStart && points.get(0).getTntId() < current.get(0).getTntId()) {
points = current;
}
}
TraceManager.instance.remove(trace);
if (points == null) {
stop();
return;
}
TNTPoint current = points.getLast();
Vector velocity = current.getVelocity();
if (velocity.getX() < 0) velocity.setX(-velocity.getX());
if (velocity.getY() < 0) velocity.setY(-velocity.getY());
if (velocity.getZ() < 0) velocity.setZ(-velocity.getZ());
if (velocity.getX() > velocity.getY() && velocity.getX() > velocity.getZ()) {
direction = Direction.X;
} else if (velocity.getY() > velocity.getX() && velocity.getY() > velocity.getZ()) {
direction = Direction.Y;
} else if (velocity.getZ() > velocity.getX() && velocity.getZ() > velocity.getY()) {
direction = Direction.Z;
} else {
stop();
return;
}
Bukkit.getLogger().log(LEVEL, "Direction: {0}", direction);
phases.getFirst().setOrder(SimulatorPhase.ORDER_LIMIT);
phases.getFirst().setCount(TNT_INCREASE);
destroyedBlocksPerSlice.clear();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
getStab();
}, 20);
}
private void getStab() {
try {
PasteBuilder.ClipboardProvider clipboardProvider = new PasteBuilder.ClipboardProviderImpl(clipboard);
PasteBuilder pasteBuilder = new PasteBuilder(clipboardProvider)
.color(region.getPlain(Flag.COLOR, ColorMode.class).getColor());
region.reset(pasteBuilder, RegionType.TESTBLOCK, RegionExtensionType.EXTENSION);
} catch (SecurityException e) {
stop();
throw e;
}
if (cancel) return;
showBossbar(false);
SimulatorExecutor.run(simulator, () -> {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::calculateStep, 20);
});
}
private int recordings = 0;
private List<Integer> currentDepths = new ArrayList<>();
private int lastDepth = 0;
private int currentDepth = 0;
private void calculateStep() {
List<Map.Entry<Integer, Set<Location>>> locations = destroyedBlocksPerSlice.entrySet()
.stream()
.sorted(Comparator.comparingInt(Map.Entry::getKey))
.collect(Collectors.toList());
int depth = 0;
for (int i = 0; i < locations.size(); i++) {
if (i == 0 || i == locations.size() - 1) {
if (locations.get(i).getValue().size() > MIN_BLOCK_TO_COUNT_AS_DEPTH) {
depth++;
}
} else {
depth++;
}
}
if (depth > 0) {
Bukkit.getLogger().log(LEVEL, "{0} {1} {2}", new Object[]{depth, destroyedBlocksPerSlice.size(), destroyedBlocksPerSlice.values().stream().map(Set::size).collect(Collectors.toList())});
currentDepths.add(depth);
}
destroyedBlocksPerSlice.clear();
int maxDepth = currentDepths.stream().max(Integer::compareTo).orElse(0);
currentDepth = maxDepth;
int countWithoutLast = 0;
for (int i = 0; i < phases.size() - 1; i++) {
countWithoutLast += phases.get(i).getCount();
}
TNTPhase lastPhase = phases.getLast();
boolean moreTNTNeeded = maxDepth - countWithoutLast >= lastPhase.getCount() - 5;
if (!currentDepths.isEmpty() && moreTNTNeeded) {
Bukkit.getLogger().log(LEVEL, "Increasing tnt count by {0}", TNT_INCREASE);
lastPhase.setCount(lastPhase.getCount() + TNT_INCREASE);
recordings = 0;
currentDepths.clear();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
return;
}
if (recordings++ < MAX_RECORDINGS) {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
return;
}
recordings = 0;
if (currentDepths.isEmpty()) {
Bukkit.getLogger().log(LEVEL, "No dimension - Increasing tickOffset to: {0}", phases.getFirst().getTickOffset() + 1);
phases.getFirst().setTickOffset(phases.getFirst().getTickOffset() + 1);
phases.getFirst().setOrder(0);
if (phases.getFirst().getTickOffset() > 80) {
stop();
} else {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
}
return;
}
currentDepths.clear();
Bukkit.getLogger().log(LEVEL, "No more TNT needed on phase adjusting - {0} new depth; {1} current count", new Object[]{maxDepth - countWithoutLast, lastPhase.getCount()});
lastPhase.setCount(maxDepth - countWithoutLast);
if (lastPhase.getCount() <= 0) {
Bukkit.getLogger().log(LEVEL, "Count was 0 or negative - removing last phase");
phases.removeLast();
}
if (maxDepth > depthLimit) {
Bukkit.getLogger().log(LEVEL, "Depth is greater than {0} - finished", depthLimit);
stop();
return;
}
if (maxDepth <= lastDepth) {
Bukkit.getLogger().log(LEVEL, "Depth is equal to last depth recorded {0} - finished", maxDepth);
stop();
return;
}
lastDepth = maxDepth;
Bukkit.getLogger().log(LEVEL, "Adding new phase in next tick");
TNTPhase nextPhase = new TNTPhase();
nextPhase.setCount(TNT_INCREASE);
nextPhase.setTickOffset(lastPhase.getTickOffset() + 1);
nextPhase.setXJump(lastPhase.isXJump());
nextPhase.setYJump(lastPhase.isYJump());
nextPhase.setZJump(lastPhase.isZJump());
phases.add(nextPhase);
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), this::getStab, 20);
}
@AllArgsConstructor
private enum Direction {
X(Vector::getBlockX),
Y(Vector::getBlockY),
Z(Vector::getBlockZ);
private final Function<Vector, Integer> component;
}
private void showBossbar(boolean finished) {
for (Player player : Bukkit.getOnlinePlayers()) {
BauSystemBossbar bossbar = BossBarService.instance.get(player, region, "simulator_stab_generator");
bossbar.setColor(BarColor.GREEN);
bossbar.setStyle(BarStyle.SEGMENTED_10);
bossbar.setProgress(Math.min(currentDepth / (double) depthLimit, 1.0));
StringBuilder st = new StringBuilder();
if (finished) {
st.append("§eFinished ").append(currentDepth).append("§8/§7").append(depthLimit);
} else if (direction == null) {
st.append("§eCalculating Stab Direction");
} else {
st.append("§7Direction§7 §e" + direction);
st.append(" §e").append(currentDepth).append("§8/§7").append(depthLimit);
if (recordings > 0) {
st.append(" §7Retries§8:§e ").append(recordings).append("§8/§7").append(MAX_RECORDINGS);
}
}
bossbar.setTitle(st.toString());
}
}
private void stop() {
simulator.setStabGenerator(null);
SimulatorWatcher.update(simulator);
HandlerList.unregisterAll(this);
showBossbar(true);
new Thread(() -> {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
for (Player player : Bukkit.getOnlinePlayers()) {
BossBarService.instance.remove(player, region, "simulator_stab_generator");
}
}
}).start();
}
public void cancel() {
cancel = true;
simulator.setStabGenerator(null);
for (Player player : Bukkit.getOnlinePlayers()) {
BossBarService.instance.remove(player, region, "simulator_stab_generator");
}
HandlerList.unregisterAll(this);
}
}
@@ -24,8 +24,11 @@ import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup; import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement; import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase; import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
import de.steamwar.bausystem.features.simulator.execute.SimulatorStabGenerator;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui; import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui;
import de.steamwar.bausystem.region.Region;
import de.steamwar.inventory.SWItem; import de.steamwar.inventory.SWItem;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@@ -97,6 +100,14 @@ public class SimulatorTNTGui extends SimulatorScrollGui<TNTPhase> {
tnt.setDisabled(!tnt.isDisabled()); tnt.setDisabled(!tnt.isDisabled());
SimulatorWatcher.update(simulator); SimulatorWatcher.update(simulator);
})); }));
inventory.setItem(49, new SWItem(Material.CALIBRATED_SCULK_SENSOR, "§eCreate Stab", click -> {
new SimulatorAnvilGui<>(player, "Depth Limit", "", Integer::parseInt, depthLimit -> {
if (depthLimit <= 0) return false;
simulator.setStabGenerator(new SimulatorStabGenerator(Region.getRegion(player.getLocation()), simulator, tnt, depthLimit));
SimulatorWatcher.update(simulator);
return true;
}, null).open();
}));
inventory.setItem(50, new SWItem(Material.CHEST, parent.getElements().size() == 1 ? "§eMake Group" : "§eAdd another TNT to Group", clickType -> { inventory.setItem(50, new SWItem(Material.CHEST, parent.getElements().size() == 1 ? "§eMake Group" : "§eAdd another TNT to Group", clickType -> {
TNTElement tntElement = new TNTElement(tnt.getPosition().clone()); TNTElement tntElement = new TNTElement(tnt.getPosition().clone());
tntElement.add(new TNTPhase()); tntElement.add(new TNTPhase());
@@ -44,7 +44,7 @@ public class SimulatorAnvilGui<T extends Number> {
if (error.get()) { if (error.get()) {
anvilInv.open(); anvilInv.open();
} else { } else {
back.open(); if (back != null) back.open();
} }
error.set(false); error.set(false);
}, 0); }, 0);
@@ -22,7 +22,6 @@ package de.steamwar.bausystem.features.simulator.gui.base;
import de.steamwar.bausystem.features.simulator.SimulatorWatcher; import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
import de.steamwar.bausystem.features.simulator.data.Simulator; import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.core.Core; import de.steamwar.core.Core;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWInventory;
import de.steamwar.inventory.SWItem; import de.steamwar.inventory.SWItem;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -64,7 +63,11 @@ public abstract class SimulatorBaseGui {
if (Core.getVersion() > 19) { if (Core.getVersion() > 19) {
player.getOpenInventory().setTitle(title()); player.getOpenInventory().setTitle(title());
} }
populate(); if (simulator != null && simulator.getStabGenerator() != null) {
populateStabGenerator();
} else {
populate();
}
if (player.getOpenInventory().getTopInventory() == inv) { if (player.getOpenInventory().getTopInventory() == inv) {
inventory.open(); inventory.open();
SimulatorWatcher.watch(player, simulator, this::open); SimulatorWatcher.watch(player, simulator, this::open);
@@ -84,10 +87,21 @@ public abstract class SimulatorBaseGui {
}); });
SimulatorWatcher.watch(player, simulator, this::open); SimulatorWatcher.watch(player, simulator, this::open);
populate(); if (simulator != null && simulator.getStabGenerator() != null) {
populateStabGenerator();
} else {
populate();
}
inventory.open(); inventory.open();
} }
private void populateStabGenerator() {
inventory.setItem(22, new SWItem(Material.BARRIER, "§cCancel Stab Generator", click -> {
simulator.getStabGenerator().cancel();
SimulatorWatcher.update(simulator);
}));
}
public boolean shouldOpen() { public boolean shouldOpen() {
return true; return true;
} }
@@ -102,11 +102,14 @@ public class TraceRecorder implements Listener {
* *
* @param region region to be recorded * @param region region to be recorded
*/ */
public void startRecording(Region region) { public Trace startRecording(Region region) {
if (activeTraces.containsKey(region)) return; if (activeTraces.containsKey(region)) {
return activeTraces.get(region).getTrace();
}
TraceRecordingWrapper wrappedTrace = new TraceRecordingWrapper(region); TraceRecordingWrapper wrappedTrace = new TraceRecordingWrapper(region);
activeTraces.put(region, wrappedTrace); activeTraces.put(region, wrappedTrace);
return wrappedTrace.getTrace();
} }
/** /**