Merge pull request 'Trace Refactor' (#233) from TracerGUI into master
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Reviewed-on: #233 Reviewed-by: YoyoNow <jwsteam@nidido.de>
Dieser Commit ist enthalten in:
Commit
aeb5ebfc12
10
.gitignore
vendored
10
.gitignore
vendored
@ -1,5 +1,7 @@
|
|||||||
# Package Files
|
# Build files
|
||||||
*.jar
|
*.jar
|
||||||
|
**/bin
|
||||||
|
**/build
|
||||||
|
|
||||||
# Gradle
|
# Gradle
|
||||||
.gradle
|
.gradle
|
||||||
@ -10,6 +12,10 @@ steamwar.properties
|
|||||||
# IntelliJ IDEA
|
# IntelliJ IDEA
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
plugin.yml
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
lib
|
lib
|
||||||
|
|
||||||
|
#linkage
|
||||||
|
LinkageUtils.java
|
@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import net.minecraft.server.v1_15_R1.EntityTNTPrimed;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.craftbukkit.v1_15_R1.CraftWorld;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class TNTPrimedIterator15 implements TNTPrimedIterator {
|
|
||||||
|
|
||||||
private static final CraftWorld WORLD = (CraftWorld) Bukkit.getWorlds().get(0);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<TNTPrimed> iterator() {
|
|
||||||
return WORLD.getHandle().entitiesById.values().stream()
|
|
||||||
.filter(EntityTNTPrimed.class::isInstance)
|
|
||||||
.map(entity -> (TNTPrimed) entity.getBukkitEntity());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import com.comphenix.tinyprotocol.Reflection;
|
|
||||||
import net.minecraft.server.level.WorldServer;
|
|
||||||
import net.minecraft.world.level.entity.LevelEntityGetter;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import java.util.stream.StreamSupport;
|
|
||||||
|
|
||||||
public class TNTPrimedIterator18 implements TNTPrimedIterator {
|
|
||||||
|
|
||||||
private static final Reflection.MethodInvoker getWorld = Reflection.getMethod(Reflection.getClass("{obc}.CraftWorld"), "getHandle");
|
|
||||||
private static final Reflection.MethodInvoker getWorldEntities = Reflection.getTypedMethod(WorldServer.class, null, LevelEntityGetter.class);
|
|
||||||
private static final Reflection.MethodInvoker getIterable = Reflection.getTypedMethod(LevelEntityGetter.class, null, Iterable.class);
|
|
||||||
private static final Reflection.MethodInvoker getBukkitEntity = Reflection.getTypedMethod(Reflection.getClass("{nms.world.entity}.Entity"), "getBukkitEntity", null);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<TNTPrimed> iterator() {
|
|
||||||
return StreamSupport.stream(((Iterable<?>) getIterable.invoke(getWorldEntities.invoke(getWorld.invoke(Bukkit.getWorlds().get(0))))).spliterator(), false)
|
|
||||||
.map(getBukkitEntity::invoke)
|
|
||||||
.filter(TNTPrimed.class::isInstance)
|
|
||||||
.map(TNTPrimed.class::cast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
@ -39,7 +39,10 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.inventory.ClickType;
|
import org.bukkit.event.inventory.ClickType;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class Loader implements Listener {
|
public class Loader implements Listener {
|
||||||
@ -78,6 +81,10 @@ public class Loader implements Listener {
|
|||||||
}
|
}
|
||||||
if (currentElement >= elements.size()) {
|
if (currentElement >= elements.size()) {
|
||||||
currentElement = 0;
|
currentElement = 0;
|
||||||
|
if (stage == Stage.SINGLE) {
|
||||||
|
stage = Stage.PAUSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (currentElement < elements.size()) {
|
while (currentElement < elements.size()) {
|
||||||
@ -92,6 +99,20 @@ public class Loader implements Listener {
|
|||||||
}, 0, 1);
|
}, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void single() {
|
||||||
|
if (stage == Stage.END) return;
|
||||||
|
if (stage == Stage.RUNNING) return;
|
||||||
|
stage = Stage.SINGLE;
|
||||||
|
if (recorder != null) {
|
||||||
|
recorder.stop();
|
||||||
|
recorder = null;
|
||||||
|
}
|
||||||
|
if (elements.isEmpty()) {
|
||||||
|
BauSystem.MESSAGE.send("LOADER_NOTHING_RECORDED", p);
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
if (stage == Stage.END) return;
|
if (stage == Stage.END) return;
|
||||||
if (stage == Stage.RUNNING) return;
|
if (stage == Stage.RUNNING) return;
|
||||||
@ -349,6 +370,7 @@ public class Loader implements Listener {
|
|||||||
public enum Stage implements EnumDisplay {
|
public enum Stage implements EnumDisplay {
|
||||||
SETUP("LOADER_SETUP"),
|
SETUP("LOADER_SETUP"),
|
||||||
RUNNING("LOADER_RUNNING"),
|
RUNNING("LOADER_RUNNING"),
|
||||||
|
SINGLE("LOADER_SINGLE"),
|
||||||
PAUSE("LOADER_PAUSE"),
|
PAUSE("LOADER_PAUSE"),
|
||||||
END("LOADER_END");
|
END("LOADER_END");
|
||||||
|
|
||||||
|
@ -20,10 +20,8 @@
|
|||||||
package de.steamwar.bausystem.features.loader;
|
package de.steamwar.bausystem.features.loader;
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.Permission;
|
|
||||||
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
||||||
import de.steamwar.command.SWCommand;
|
import de.steamwar.command.SWCommand;
|
||||||
import de.steamwar.command.TypeValidator;
|
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -105,6 +103,14 @@ public class LoaderCommand extends SWCommand implements Listener {
|
|||||||
loader.setTicksBetweenBlocks(delay);
|
loader.setTicksBetweenBlocks(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Register(value = "single", description = "LOADER_HELP_SINGLE")
|
||||||
|
public void singleLoader(@Validator Player p) {
|
||||||
|
Loader loader = Loader.getLoader(p);
|
||||||
|
if (loaderNullCheck(loader, p)) return;
|
||||||
|
loader.single();
|
||||||
|
BauSystem.MESSAGE.send("LOADER_SINGLE_CMD", p);
|
||||||
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBauMemberUpdate(BauMemberUpdateEvent event) {
|
public void onBauMemberUpdate(BauMemberUpdateEvent event) {
|
||||||
event.getNewSpectator().forEach(player -> {
|
event.getNewSpectator().forEach(player -> {
|
||||||
|
@ -20,9 +20,6 @@
|
|||||||
package de.steamwar.bausystem.features.script.lua.libs;
|
package de.steamwar.bausystem.features.script.lua.libs;
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.loader.Loader;
|
import de.steamwar.bausystem.features.loader.Loader;
|
||||||
import de.steamwar.bausystem.features.tracer.record.ActiveTracer;
|
|
||||||
import de.steamwar.bausystem.features.tracer.record.AutoTraceRecorder;
|
|
||||||
import de.steamwar.bausystem.features.tracer.record.Recorder;
|
|
||||||
import de.steamwar.bausystem.region.GlobalRegion;
|
import de.steamwar.bausystem.region.GlobalRegion;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.flags.Flag;
|
import de.steamwar.bausystem.region.flags.Flag;
|
||||||
@ -71,13 +68,13 @@ public class RegionLib implements LuaLib {
|
|||||||
table.set("freeze", getter(() -> region.get().getPlain(Flag.FREEZE, FreezeMode.class) == FreezeMode.ACTIVE));
|
table.set("freeze", getter(() -> region.get().getPlain(Flag.FREEZE, FreezeMode.class) == FreezeMode.ACTIVE));
|
||||||
table.set("protect", getter(() -> region.get().getPlain(Flag.PROTECT, ProtectMode.class) == ProtectMode.ACTIVE));
|
table.set("protect", getter(() -> region.get().getPlain(Flag.PROTECT, ProtectMode.class) == ProtectMode.ACTIVE));
|
||||||
|
|
||||||
LuaValue traceLib = LuaValue.tableOf();
|
//LuaValue traceLib = LuaValue.tableOf();
|
||||||
traceLib.set("active", getter(() -> !region.get().isGlobal() && Recorder.INSTANCE.get(region.get()) instanceof ActiveTracer));
|
//traceLib.set("active", getter(() -> !region.get().isGlobal() && Recorder.INSTANCE.get(region.get()) instanceof ActiveTracer));
|
||||||
traceLib.set("auto", getter(() -> !region.get().isGlobal() && Recorder.INSTANCE.get(region.get()) instanceof AutoTraceRecorder));
|
//traceLib.set("auto", getter(() -> !region.get().isGlobal() && Recorder.INSTANCE.get(region.get()) instanceof AutoTraceRecorder));
|
||||||
traceLib.set("status", getter(() -> Recorder.INSTANCE.get(region.get()).scriptState()));
|
//traceLib.set("status", getter(() -> Recorder.INSTANCE.get(region.get()).scriptState()));
|
||||||
traceLib.set("time", getter(() -> Recorder.INSTANCE.get(region.get()).scriptTime()));
|
//traceLib.set("time", getter(() -> Recorder.INSTANCE.get(region.get()).scriptTime()));
|
||||||
|
|
||||||
table.set("trace", traceLib);
|
//table.set("trace", traceLib);
|
||||||
|
|
||||||
Loader loader = Loader.getLoader(player);
|
Loader loader = Loader.getLoader(player);
|
||||||
table.set("loader", getter(() -> loader == null ? "OFF" : loader.getStage().name()));
|
table.set("loader", getter(() -> loader == null ? "OFF" : loader.getStage().name()));
|
||||||
|
@ -23,8 +23,7 @@ import de.steamwar.bausystem.features.simulator.data.Simulator;
|
|||||||
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
|
||||||
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
|
||||||
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
||||||
import de.steamwar.bausystem.features.tracer.record.Recorder;
|
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
||||||
import de.steamwar.bausystem.features.tracer.record.SingleTraceRecorder;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.utils.TickEndEvent;
|
import de.steamwar.bausystem.utils.TickEndEvent;
|
||||||
import de.steamwar.bausystem.utils.TickStartEvent;
|
import de.steamwar.bausystem.utils.TickStartEvent;
|
||||||
@ -69,6 +68,20 @@ public class SimulatorExecutor implements Listener {
|
|||||||
@Override
|
@Override
|
||||||
public void accept(World world) {
|
public void accept(World world) {
|
||||||
currentlyRunning.remove(simulator);
|
currentlyRunning.remove(simulator);
|
||||||
|
|
||||||
|
if (simulator.isAutoTrace()) {
|
||||||
|
simulator.getGroups()
|
||||||
|
.stream()
|
||||||
|
.map(SimulatorGroup::getElements)
|
||||||
|
.flatMap(List::stream)
|
||||||
|
.map(SimulatorElement::getPosition)
|
||||||
|
.map(pos -> pos.toLocation(WORLD))
|
||||||
|
.map(Region::getRegion)
|
||||||
|
.distinct()
|
||||||
|
.forEach(region -> {
|
||||||
|
TraceRecorder.instance.stopRecording(region);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,9 +95,7 @@ public class SimulatorExecutor implements Listener {
|
|||||||
.map(Region::getRegion)
|
.map(Region::getRegion)
|
||||||
.distinct()
|
.distinct()
|
||||||
.forEach(region -> {
|
.forEach(region -> {
|
||||||
if (Recorder.INSTANCE.isDisabled(region)) {
|
TraceRecorder.instance.startRecording(region);
|
||||||
Recorder.INSTANCE.set(region, new SingleTraceRecorder(region));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -20,9 +20,7 @@
|
|||||||
package de.steamwar.bausystem.features.slaves.laufbau;
|
package de.steamwar.bausystem.features.slaves.laufbau;
|
||||||
|
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import de.steamwar.bausystem.features.slaves.laufbau.states.FilteringTracesState;
|
|
||||||
import de.steamwar.bausystem.features.slaves.laufbau.states.LaufbauState;
|
import de.steamwar.bausystem.features.slaves.laufbau.states.LaufbauState;
|
||||||
import de.steamwar.bausystem.features.slaves.laufbau.states.CreatingLaufState;
|
|
||||||
import de.steamwar.bausystem.features.slaves.laufbau.states.ProcessingTracesState;
|
import de.steamwar.bausystem.features.slaves.laufbau.states.ProcessingTracesState;
|
||||||
import de.steamwar.bausystem.utils.WorldEditUtils;
|
import de.steamwar.bausystem.utils.WorldEditUtils;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -40,9 +38,7 @@ public class Laufbau {
|
|||||||
private Location pos1;
|
private Location pos1;
|
||||||
private Location pos2;
|
private Location pos2;
|
||||||
|
|
||||||
private FilteringTracesState filteringTracesState = null;
|
private LaufbauState active;
|
||||||
private ProcessingTracesState processingTracesState = null;
|
|
||||||
private CreatingLaufState creatingLaufState = null;
|
|
||||||
|
|
||||||
private List<BlockBoundingBox> elements;
|
private List<BlockBoundingBox> elements;
|
||||||
|
|
||||||
@ -62,8 +58,6 @@ public class Laufbau {
|
|||||||
int zFactor = (int) (Math.abs(selectionSize.getZ()) / 9.875);
|
int zFactor = (int) (Math.abs(selectionSize.getZ()) / 9.875);
|
||||||
factor = Math.max(Math.max(xFactor, Math.max(yFactor, zFactor)), 8);
|
factor = Math.max(Math.max(xFactor, Math.max(yFactor, zFactor)), 8);
|
||||||
|
|
||||||
filteringTracesState = new FilteringTracesState(world, this::inRegion);
|
|
||||||
|
|
||||||
editSession = WorldEditUtils.getEditSession(player);
|
editSession = WorldEditUtils.getEditSession(player);
|
||||||
|
|
||||||
elements = BlockBoundingBox.elements.stream().filter(blockBoundingBox -> {
|
elements = BlockBoundingBox.elements.stream().filter(blockBoundingBox -> {
|
||||||
@ -86,49 +80,32 @@ public class Laufbau {
|
|||||||
return -Double.compare(o1.blockData.getMaterial().getBlastResistance(), o2.blockData.getMaterial().getBlastResistance());
|
return -Double.compare(o1.blockData.getMaterial().getBlastResistance(), o2.blockData.getMaterial().getBlastResistance());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private LaufbauState getActive() {
|
active = new ProcessingTracesState(world, this::inRegion, editSession, elements, factor);
|
||||||
if (creatingLaufState != null) {
|
|
||||||
return creatingLaufState;
|
|
||||||
}
|
|
||||||
if (processingTracesState != null) {
|
|
||||||
return processingTracesState;
|
|
||||||
}
|
|
||||||
return filteringTracesState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createNextState() {
|
private void createNextState() {
|
||||||
if (creatingLaufState != null) {
|
if (active == null) return;
|
||||||
return;
|
active = active.getNextState();
|
||||||
}
|
|
||||||
if (processingTracesState != null) {
|
|
||||||
creatingLaufState = new CreatingLaufState(processingTracesState.getBlocks(), processingTracesState.getCuboidIntersectionCache(), world, editSession, elements, factor);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
processingTracesState = new ProcessingTracesState(filteringTracesState.getTntPositions(), this::inRegion, factor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String actionBarMessage(Player p) {
|
public String actionBarMessage(Player p) {
|
||||||
return getActive().actionBarMessage(p);
|
return active.actionBarMessage(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return getActive().hasNext();
|
if (active == null) return false;
|
||||||
|
return active.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void next() {
|
public void next() {
|
||||||
LaufbauState state = getActive();
|
LaufbauState state = active;
|
||||||
state.next();
|
state.next();
|
||||||
if (!state.hasNext()) {
|
if (!state.hasNext()) {
|
||||||
createNextState();
|
createNextState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean inRegion(Location location, int expansion) {
|
|
||||||
return inRegion(location.toVector(), expansion);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean inRegion(Vector location, int expansion) {
|
private boolean inRegion(Vector location, int expansion) {
|
||||||
if (location.getBlockX() >= pos1.getBlockX() - expansion) {
|
if (location.getBlockX() >= pos1.getBlockX() - expansion) {
|
||||||
if (location.getBlockY() >= pos1.getBlockY() - expansion) {
|
if (location.getBlockY() >= pos1.getBlockY() - expansion) {
|
||||||
|
@ -196,4 +196,9 @@ public class CreatingLaufState implements LaufbauState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LaufbauState getNextState() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.slaves.laufbau.states;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.bausystem.features.tracer.TNTPosition;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.StoredRecords;
|
|
||||||
import de.steamwar.bausystem.utils.FlatteningWrapper;
|
|
||||||
import lombok.Getter;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.BiPredicate;
|
|
||||||
|
|
||||||
public class FilteringTracesState implements LaufbauState {
|
|
||||||
|
|
||||||
private long start = System.currentTimeMillis();
|
|
||||||
|
|
||||||
private World world;
|
|
||||||
private BiPredicate<Location, Integer> inRegionCheck;
|
|
||||||
|
|
||||||
private int totalRecord;
|
|
||||||
private List<Record> recordList;
|
|
||||||
private List<Record.TNTRecord> tntRecords = new ArrayList<>();
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private List<TNTPosition> tntPositions = new ArrayList<>();
|
|
||||||
|
|
||||||
public FilteringTracesState(World world, BiPredicate<Location, Integer> inRegionCheck) {
|
|
||||||
recordList = new ArrayList<>(StoredRecords.getRecords());
|
|
||||||
totalRecord = recordList.size();
|
|
||||||
|
|
||||||
this.world = world;
|
|
||||||
this.inRegionCheck = inRegionCheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String actionBarMessage(Player p) {
|
|
||||||
return BauSystem.MESSAGE.parse("LAUFBAU_SIMPLE_PROGRESS", p, BauSystem.MESSAGE.parse("LAUFBAU_STATE_FILTERING_TRACES", p), totalRecord - recordList.size(), totalRecord, eta(p, start, totalRecord - recordList.size(), totalRecord));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return !recordList.isEmpty() || !tntRecords.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void next() {
|
|
||||||
if (tntRecords.isEmpty()) {
|
|
||||||
Record record = recordList.remove(0);
|
|
||||||
tntRecords.addAll(record.getTnt());
|
|
||||||
}
|
|
||||||
if (tntRecords.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Record.TNTRecord tntRecord = tntRecords.remove(0);
|
|
||||||
tntRecord.getPositions().forEach(tntPosition -> {
|
|
||||||
if (FlatteningWrapper.impl.inWater(world, tntPosition.getLocation())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (inRegionCheck.test(tntPosition.getLocation().toLocation(world), 1)) {
|
|
||||||
tntPositions.add(tntPosition);
|
|
||||||
}
|
|
||||||
if (tntPosition.getPreviousLocation() != null && inRegionCheck.test(tntPosition.getPreviousLocation().toLocation(world), 1)) {
|
|
||||||
tntPositions.add(tntPosition);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -45,4 +45,6 @@ public interface LaufbauState {
|
|||||||
}
|
}
|
||||||
return LocalTime.ofNanoOfDay(eta).format(DateTimeFormatter.ofPattern(BauSystem.MESSAGE.parse("TIME", p)));
|
return LocalTime.ofNanoOfDay(eta).format(DateTimeFormatter.ofPattern(BauSystem.MESSAGE.parse("TIME", p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaufbauState getNextState();
|
||||||
}
|
}
|
||||||
|
@ -1,115 +1,128 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* 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/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.bausystem.features.slaves.laufbau.states;
|
package de.steamwar.bausystem.features.slaves.laufbau.states;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
|
||||||
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
|
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
|
||||||
import de.steamwar.bausystem.features.tracer.TNTPosition;
|
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||||
|
import de.steamwar.bausystem.features.tracer.TraceManager;
|
||||||
import de.steamwar.bausystem.region.Point;
|
import de.steamwar.bausystem.region.Point;
|
||||||
import lombok.Getter;
|
import de.steamwar.bausystem.utils.FlatteningWrapper;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ProcessingTracesState implements LaufbauState {
|
public class ProcessingTracesState implements LaufbauState {
|
||||||
|
|
||||||
private long start = System.currentTimeMillis();
|
private final long start = System.currentTimeMillis();
|
||||||
|
private final World world;
|
||||||
|
private final BiPredicate<Vector, Integer> inRegionCheck;
|
||||||
|
private final EditSession editSession;
|
||||||
|
private final List<BlockBoundingBox> elements;
|
||||||
|
private final int factor;
|
||||||
|
|
||||||
private int totalCuboids;
|
private final List<TNTPoint> TNTPoints;
|
||||||
private List<TNTPosition> tntPositionList;
|
private final int totalTntRecords;
|
||||||
private BiPredicate<Vector, Integer> inRegionCheck;
|
|
||||||
private int factor;
|
|
||||||
|
|
||||||
private List<Cuboid> toExpand = new ArrayList<>();
|
private final Set<Point> affectedBlocks = new HashSet<>();
|
||||||
|
private final Map<Point, Set<Cuboid>> cuboidsPerChunk = new HashMap<>();
|
||||||
|
|
||||||
private int cuboidsDone = 0;
|
public ProcessingTracesState(World world, BiPredicate<Vector, Integer> inRegionCheck, EditSession editSession, List<BlockBoundingBox> elements, int factor) {
|
||||||
|
this.world = world;
|
||||||
@Getter
|
|
||||||
private Set<Point> blocks = new HashSet<>();
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private Map<Point, Set<Cuboid>> cuboidIntersectionCache = new HashMap<>();
|
|
||||||
|
|
||||||
public ProcessingTracesState(List<TNTPosition> tntPositionList, BiPredicate<Vector, Integer> inRegionCheck, int factor) {
|
|
||||||
this.tntPositionList = tntPositionList;
|
|
||||||
this.totalCuboids = tntPositionList.stream().mapToInt(tntPosition -> tntPosition.getPreviousLocation() == null ? 1 : 3).sum();
|
|
||||||
this.inRegionCheck = inRegionCheck;
|
this.inRegionCheck = inRegionCheck;
|
||||||
|
this.editSession = editSession;
|
||||||
|
this.elements = elements;
|
||||||
this.factor = factor;
|
this.factor = factor;
|
||||||
|
|
||||||
|
// TODO: Optimize only retrieving traces inside of the affected regions!
|
||||||
|
TNTPoints = TraceManager.instance.getAll()
|
||||||
|
.stream()
|
||||||
|
.flatMap(trace -> trace.getHistories().stream())
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
totalTntRecords = TNTPoints.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String actionBarMessage(Player p) {
|
public String actionBarMessage(Player p) {
|
||||||
return BauSystem.MESSAGE.parse("LAUFBAU_SIMPLE_PROGRESS", p, BauSystem.MESSAGE.parse("LAUFBAU_STATE_PROCESSING_TRACES", p), cuboidsDone, totalCuboids, eta(p, start, cuboidsDone, totalCuboids));
|
return BauSystem.MESSAGE.parse("LAUFBAU_SIMPLE_PROGRESS", p, BauSystem.MESSAGE.parse("LAUFBAU_STATE_PROCESSING_TRACES", p), totalTntRecords - TNTPoints.size(), totalTntRecords, eta(p, start, totalTntRecords - TNTPoints.size(), totalTntRecords));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean inRegion(Vector location, int expansion) {
|
||||||
|
return inRegionCheck.test(location, expansion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return !tntPositionList.isEmpty() || !toExpand.isEmpty();
|
return !TNTPoints.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void next() {
|
public void next() {
|
||||||
if (!toExpand.isEmpty()) {
|
TNTPoint current = TNTPoints.remove(0);
|
||||||
Cuboid cuboid = toExpand.remove(0);
|
if (FlatteningWrapper.impl.inWater(world, current.getLocation().toVector())) return;
|
||||||
expandCuboid(cuboid);
|
if (!(inRegion(current.getLocation().toVector(), 1) || (current.getPrevious().isPresent() && inRegion(current.getPrevious().get().getLocation().toVector(), 1))))
|
||||||
} else {
|
return;
|
||||||
TNTPosition tntPosition = tntPositionList.remove(0);
|
|
||||||
createCuboid(tntPosition);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createCuboid(TNTPosition tntPosition) {
|
Location location = current.getLocation();
|
||||||
Vector location = tntPosition.getLocation();
|
if (current.getPrevious().isPresent()) {
|
||||||
Vector previousLocation = tntPosition.getPreviousLocation();
|
Vector velocity = current.getPrevious().get().getVelocity();
|
||||||
|
Location previousLocation = current.getPrevious().get().getLocation();
|
||||||
if (previousLocation == null) {
|
Location movement = location.clone().subtract(previousLocation);
|
||||||
toExpand.add(new Cuboid(location.getX() - 0.49, location.getY(), location.getZ() - 0.49, 0.98, 0.98, 0.98));
|
calculateCuboid(new Cuboid(previousLocation.getX() - 0.49, Math.min(previousLocation.getY(), location.getY()), previousLocation.getZ() - 0.49, 0.98, Math.abs(movement.getY()) + 0.98, 0.98));
|
||||||
} else {
|
if (velocity.getX() >= velocity.getZ()) {
|
||||||
Vector movement = location.clone().subtract(previousLocation);
|
calculateCuboid(new Cuboid(Math.min(previousLocation.getX(), location.getX()) - 0.49, location.getY(), previousLocation.getZ() - 0.49, Math.abs(movement.getX()) + 0.98, 0.98, 0.98));
|
||||||
toExpand.add(new Cuboid(previousLocation.getX() - 0.49, Math.min(previousLocation.getY(), location.getY()), previousLocation.getZ() - 0.49, 0.98, Math.abs(movement.getY()) + 0.98, 0.98));
|
calculateCuboid(new Cuboid(location.getX() - 0.49, location.getY(), Math.min(previousLocation.getZ(), location.getZ()) - 0.49, 0.98, 0.98, Math.abs(movement.getZ()) + 0.98));
|
||||||
if (Math.abs(tntPosition.getUpdateVelocity().getX()) >= Math.abs(tntPosition.getUpdateVelocity().getZ())) {
|
|
||||||
toExpand.add(new Cuboid(Math.min(previousLocation.getX(), location.getX()) - 0.49, location.getY(), previousLocation.getZ() - 0.49, Math.abs(movement.getX()) + 0.98, 0.98, 0.98));
|
|
||||||
toExpand.add(new Cuboid(location.getX() - 0.49, location.getY(), Math.min(previousLocation.getZ(), location.getZ()) - 0.49, 0.98, 0.98, Math.abs(movement.getZ()) + 0.98));
|
|
||||||
} else {
|
} else {
|
||||||
toExpand.add(new Cuboid(previousLocation.getX() - 0.49, location.getY(), Math.min(previousLocation.getZ(), location.getZ()) - 0.49, 0.98, 0.98, Math.abs(movement.getZ()) + 0.98));
|
calculateCuboid(new Cuboid(previousLocation.getX() - 0.49, location.getY(), Math.min(previousLocation.getZ(), location.getZ()) - 0.49, 0.98, 0.98, Math.abs(movement.getZ()) + 0.98));
|
||||||
toExpand.add(new Cuboid(Math.min(previousLocation.getX(), location.getX()) - 0.49, location.getY(), location.getZ() - 0.49, Math.abs(movement.getX()) + 0.98, 0.98, 0.98));
|
calculateCuboid(new Cuboid(Math.min(previousLocation.getX(), location.getX()) - 0.49, location.getY(), location.getZ() - 0.49, Math.abs(movement.getX()) + 0.98, 0.98, 0.98));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
calculateCuboid(new Cuboid(location.getX() - 0.49, location.getY(), location.getZ() - 0.49, 0.98, 0.98, 0.98));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expandCuboid(Cuboid cuboid) {
|
private void calculateCuboid(Cuboid cuboid) {
|
||||||
cuboidsDone++;
|
|
||||||
for (double x = cuboid.getX() - 2; x < cuboid.getX() + cuboid.getDx() + 2; x++) {
|
for (double x = cuboid.getX() - 2; x < cuboid.getX() + cuboid.getDx() + 2; x++) {
|
||||||
for (double y = cuboid.getY() - 2; y < cuboid.getY() + cuboid.getDy() + 2; y++) {
|
for (double y = cuboid.getY() - 2; y < cuboid.getY() + cuboid.getDy() + 2; y++) {
|
||||||
for (double z = cuboid.getZ() - 2; z < cuboid.getZ() + cuboid.getDz() + 2; z++) {
|
for (double z = cuboid.getZ() - 2; z < cuboid.getZ() + cuboid.getDz() + 2; z++) {
|
||||||
Vector location = new Vector(x, y, z);
|
Vector location = new Vector(x, y, z);
|
||||||
if (inRegionCheck.test(location, 0)) {
|
if (inRegion(location, 0)) {
|
||||||
Point point = new Point(location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
affectedBlocks.add(new Point(location.getBlockX(), location.getBlockY(), location.getBlockZ()));
|
||||||
blocks.add(point);
|
cuboidsPerChunk.computeIfAbsent(new Point(location.getBlockX() / factor, location.getBlockY() / factor, location.getBlockZ() / factor), __ -> new HashSet<>())
|
||||||
cuboidIntersectionCache.computeIfAbsent(point.divide(factor), __ -> new HashSet<>())
|
|
||||||
.add(cuboid);
|
.add(cuboid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LaufbauState getNextState() {
|
||||||
|
return new CreatingLaufState(affectedBlocks, cuboidsPerChunk, world, editSession, elements, factor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
227
BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java
Normale Datei
227
BauSystem_Main/src/de/steamwar/bausystem/features/tracer/TNTPoint.java
Normale Datei
@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 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.tracer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
||||||
|
import de.steamwar.bausystem.region.utils.RegionType;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.TNTPrimed;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.io.Externalizable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInput;
|
||||||
|
import java.io.ObjectOutput;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recording of a tnt at a specific tick
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class TNTPoint implements Externalizable {
|
||||||
|
/**
|
||||||
|
* Unique number to identify records being of the same tnt
|
||||||
|
*/
|
||||||
|
private int tntId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this is a record of a tnt explosion or an entity
|
||||||
|
*/
|
||||||
|
private boolean explosion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this is a record of a tnt that was in water
|
||||||
|
*/
|
||||||
|
private boolean inWater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this record was taken after the first tnt exploded
|
||||||
|
*/
|
||||||
|
private boolean afterFirstExplosion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this record has destroyed blocks in build area
|
||||||
|
*/
|
||||||
|
private boolean destroyedBuildArea;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this record has destroyed blocks in testblock area
|
||||||
|
*/
|
||||||
|
private boolean destroyedTestBlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tick offset, from this record being taken to the start of the trace
|
||||||
|
*/
|
||||||
|
private long ticksSinceStart;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fuse ticks of the recorded tnt (0 if this is an explosion)
|
||||||
|
*/
|
||||||
|
private int fuse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Location of the recorded tnt
|
||||||
|
*/
|
||||||
|
private Location location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Velocity of the recorded tnt
|
||||||
|
*/
|
||||||
|
private Vector velocity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all tnt records, that are represent the same tnt
|
||||||
|
*/
|
||||||
|
private List<TNTPoint> history;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for deserialization only !! Do not Call !!
|
||||||
|
*/
|
||||||
|
public TNTPoint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TNTPoint(int tntId, TNTPrimed tnt, boolean explosion, boolean afterFirstExplosion, long ticksSinceStart,
|
||||||
|
List<TNTPoint> history, List<Block> destroyedBlocks) {
|
||||||
|
this.tntId = tntId;
|
||||||
|
this.explosion = explosion;
|
||||||
|
this.inWater = tnt.isInWater();
|
||||||
|
this.afterFirstExplosion = afterFirstExplosion;
|
||||||
|
this.ticksSinceStart = ticksSinceStart;
|
||||||
|
fuse = tnt.getFuseTicks();
|
||||||
|
location = tnt.getLocation();
|
||||||
|
velocity = tnt.getVelocity();
|
||||||
|
this.history = history;
|
||||||
|
|
||||||
|
boolean buildDestroy = false;
|
||||||
|
boolean testblockDestroy = false;
|
||||||
|
for (Block destroyedBlock : destroyedBlocks) {
|
||||||
|
if (Region.getRegion(destroyedBlock.getLocation()).inRegion(destroyedBlock.getLocation(), RegionType.BUILD,
|
||||||
|
RegionExtensionType.EXTENSION)) {
|
||||||
|
buildDestroy = true;
|
||||||
|
}
|
||||||
|
if (Region.getRegion(destroyedBlock.getLocation()).inRegion(destroyedBlock.getLocation(),
|
||||||
|
RegionType.TESTBLOCK, RegionExtensionType.EXTENSION)) {
|
||||||
|
testblockDestroy = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destroyedBuildArea = buildDestroy;
|
||||||
|
destroyedTestBlock = testblockDestroy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for getting the next record of the tnt represented by this record
|
||||||
|
*
|
||||||
|
* @return the next record
|
||||||
|
*/
|
||||||
|
public Optional<TNTPoint> getNext() {
|
||||||
|
int index = history.indexOf(this);
|
||||||
|
return index == history.size() - 1 ? Optional.empty() : Optional.of(history.get(index + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method for getting the previous record of the tnt represented by this record
|
||||||
|
*
|
||||||
|
* @return the previous record
|
||||||
|
*/
|
||||||
|
public Optional<TNTPoint> getPrevious() {
|
||||||
|
int index = history.indexOf(this);
|
||||||
|
return index == 0 ? Optional.empty() : Optional.of(history.get(index - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal methode for setting the history of this record
|
||||||
|
* during deserialization.
|
||||||
|
*
|
||||||
|
* @param history
|
||||||
|
*/
|
||||||
|
void setHistory(List<TNTPoint> history) {
|
||||||
|
this.history = history;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeExternal(ObjectOutput objectOutput) throws IOException {
|
||||||
|
objectOutput.writeInt(tntId);
|
||||||
|
objectOutput.writeBoolean(explosion);
|
||||||
|
objectOutput.writeBoolean(inWater);
|
||||||
|
objectOutput.writeBoolean(afterFirstExplosion);
|
||||||
|
objectOutput.writeBoolean(destroyedBuildArea);
|
||||||
|
objectOutput.writeBoolean(destroyedTestBlock);
|
||||||
|
objectOutput.writeLong(ticksSinceStart);
|
||||||
|
objectOutput.writeInt(fuse);
|
||||||
|
objectOutput.writeDouble(location.getX());
|
||||||
|
objectOutput.writeDouble(location.getY());
|
||||||
|
objectOutput.writeDouble(location.getZ());
|
||||||
|
objectOutput.writeDouble(velocity.getX());
|
||||||
|
objectOutput.writeDouble(velocity.getY());
|
||||||
|
objectOutput.writeDouble(velocity.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readExternal(ObjectInput objectInput) throws IOException {
|
||||||
|
tntId = objectInput.readInt();
|
||||||
|
explosion = objectInput.readBoolean();
|
||||||
|
inWater = objectInput.readBoolean();
|
||||||
|
afterFirstExplosion = objectInput.readBoolean();
|
||||||
|
destroyedBuildArea = objectInput.readBoolean();
|
||||||
|
destroyedTestBlock = objectInput.readBoolean();
|
||||||
|
ticksSinceStart = objectInput.readLong();
|
||||||
|
fuse = objectInput.readInt();
|
||||||
|
double locX = objectInput.readDouble();
|
||||||
|
double locY = objectInput.readDouble();
|
||||||
|
double locZ = objectInput.readDouble();
|
||||||
|
location = new Location(Bukkit.getWorlds().get(0), locX, locY, locZ);
|
||||||
|
double velX = objectInput.readDouble();
|
||||||
|
double velY = objectInput.readDouble();
|
||||||
|
double velZ = objectInput.readDouble();
|
||||||
|
velocity = new Vector(velX, velY, velZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TNTPoint{" +
|
||||||
|
"tntId=" + tntId +
|
||||||
|
", explosion=" + explosion +
|
||||||
|
", inWater=" + inWater +
|
||||||
|
", afterFirstExplosion=" + afterFirstExplosion +
|
||||||
|
", destroyedBuildArea=" + destroyedBuildArea +
|
||||||
|
", destroyedTestBlock=" + destroyedTestBlock +
|
||||||
|
", ticksSinceStart=" + ticksSinceStart +
|
||||||
|
", fuse=" + fuse +
|
||||||
|
", location=" + location +
|
||||||
|
", velocity=" + velocity +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof TNTPoint)) return false;
|
||||||
|
TNTPoint record = (TNTPoint) obj;
|
||||||
|
if (record.isExplosion() != explosion) return false;
|
||||||
|
if (!record.getLocation().equals(location)) return false;
|
||||||
|
if (!record.getVelocity().equals(velocity)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
|
||||||
import de.steamwar.bausystem.shared.Position;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class TNTPosition extends Position {
|
|
||||||
|
|
||||||
private final Record.TNTRecord record;
|
|
||||||
private final int fuseTicks;
|
|
||||||
private final long timeTicks;
|
|
||||||
private final Vector previousLocation;
|
|
||||||
private final Vector velocity;
|
|
||||||
private final Vector updateVelocity;
|
|
||||||
private final boolean source;
|
|
||||||
private final boolean exploded;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private boolean microMotion;
|
|
||||||
|
|
||||||
public TNTPosition(Record.TNTRecord record, TNTPrimed entity, long timeTicks, Vector previousLocation, Vector velocity, Vector updateVelocity, boolean source, boolean exploded) {
|
|
||||||
super(entity.getLocation().toVector());
|
|
||||||
this.record = record;
|
|
||||||
this.fuseTicks = entity.getFuseTicks();
|
|
||||||
this.timeTicks = timeTicks;
|
|
||||||
this.previousLocation = previousLocation;
|
|
||||||
this.velocity = velocity;
|
|
||||||
this.updateVelocity = updateVelocity;
|
|
||||||
this.source = source;
|
|
||||||
this.exploded = exploded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Position{" +
|
|
||||||
"location=" + super.getLocation() +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
339
BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java
Normale Datei
339
BauSystem_Main/src/de/steamwar/bausystem/features/tracer/Trace.java
Normale Datei
@ -0,0 +1,339 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 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.tracer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.PlayerTraceShowData;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.TraceEntity;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.ViewFlag;
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import de.steamwar.entity.REntity;
|
||||||
|
import de.steamwar.entity.REntityServer;
|
||||||
|
import lombok.Cleanup;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
public class Trace {
|
||||||
|
/**
|
||||||
|
* UUID of the trace used for
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final UUID uuid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File the records are saved in
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final File recordsSaveFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File the metadata are saved in
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final File metadataSaveFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Region the trace was recorded in
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final Region region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date the trace was recorded at
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final Date date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records of TNTs, making up the trace
|
||||||
|
*/
|
||||||
|
private SoftReference<List<TNTPoint>> records;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map of all REntityServers rendering this trace
|
||||||
|
*/
|
||||||
|
private final Map<Player, REntityServer> entityServerMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for the creation of a new trace
|
||||||
|
*
|
||||||
|
* @param region the region the trace is created at
|
||||||
|
* @param recordList the list for the records making up this trace
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public Trace(Region region, List<TNTPoint> recordList) {
|
||||||
|
this.uuid = UUID.randomUUID();
|
||||||
|
recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records");
|
||||||
|
this.region = region;
|
||||||
|
this.date = new Date();
|
||||||
|
records = new SoftReference<>(recordList);
|
||||||
|
metadataSaveFile = new File(TraceManager.tracesFolder, uuid + ".meta");
|
||||||
|
|
||||||
|
@Cleanup
|
||||||
|
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(metadataSaveFile));
|
||||||
|
outputStream.writeUTF(uuid.toString());
|
||||||
|
outputStream.writeUTF(region.getName());
|
||||||
|
outputStream.writeObject(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for serialising a trace from the file system
|
||||||
|
*
|
||||||
|
* @param metadataSaveFile the file for this traces metadata
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
public Trace(File metadataSaveFile) {
|
||||||
|
String uuid = null;
|
||||||
|
Region region = null;
|
||||||
|
Date date = null;
|
||||||
|
|
||||||
|
this.metadataSaveFile = metadataSaveFile;
|
||||||
|
|
||||||
|
try {
|
||||||
|
@Cleanup
|
||||||
|
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(metadataSaveFile));
|
||||||
|
uuid = inputStream.readUTF();
|
||||||
|
region = Region.getREGION_MAP().get(inputStream.readUTF());
|
||||||
|
date = (Date) inputStream.readObject();
|
||||||
|
inputStream.close();
|
||||||
|
} finally {
|
||||||
|
this.uuid = UUID.fromString(uuid);
|
||||||
|
this.region = region;
|
||||||
|
this.date = date;
|
||||||
|
recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records");
|
||||||
|
this.records = new SoftReference<>(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the histories of all tnts in this trace
|
||||||
|
*
|
||||||
|
* @return the histories of this trace
|
||||||
|
*/
|
||||||
|
public Set<List<TNTPoint>> getHistories() {
|
||||||
|
Set<List<TNTPoint>> histories = new HashSet<>();
|
||||||
|
|
||||||
|
for (TNTPoint record : getRecords()) {
|
||||||
|
histories.add(record.getHistory());
|
||||||
|
}
|
||||||
|
|
||||||
|
return histories;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all used ids
|
||||||
|
*/
|
||||||
|
public List<String> getUsedIds() {
|
||||||
|
return getRecords()
|
||||||
|
.stream()
|
||||||
|
.map(TNTPoint::getTntId)
|
||||||
|
.map(i -> i + "")
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders this traces
|
||||||
|
*
|
||||||
|
* @param player The player the trace is rendered to
|
||||||
|
* @param playerTraceShowData The showData for modifying the rendering
|
||||||
|
*/
|
||||||
|
public void render(Player player, PlayerTraceShowData playerTraceShowData) {
|
||||||
|
REntityServer entityServer = entityServerMap.get(player);
|
||||||
|
if (entityServer != null) {
|
||||||
|
entityServer.getEntities().forEach(REntity::die);
|
||||||
|
} else {
|
||||||
|
entityServer = new REntityServer();
|
||||||
|
entityServer.addPlayer(player);
|
||||||
|
entityServer.setCallback((p, rEntity, entityAction) -> {
|
||||||
|
if (entityAction != REntityServer.EntityAction.INTERACT) return;
|
||||||
|
if (rEntity instanceof TraceEntity) {
|
||||||
|
((TraceEntity) rEntity).printIntoChat(p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
entityServerMap.put(player, entityServer);
|
||||||
|
}
|
||||||
|
render(getRecords(), entityServer, playerTraceShowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders specific records to this trace rendering
|
||||||
|
*
|
||||||
|
* @param records The records to be rendered
|
||||||
|
* @param player The player the records are rendered to
|
||||||
|
* @param playerTraceShowData The showData for modifying the rendering
|
||||||
|
*/
|
||||||
|
protected void render(List<TNTPoint> records, Player player, PlayerTraceShowData playerTraceShowData) {
|
||||||
|
render(records, entityServerMap.get(player), playerTraceShowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal methode to render records to a REntityServer
|
||||||
|
*
|
||||||
|
* @param records Records to render
|
||||||
|
* @param entityServer The show server the trace will be renderd to
|
||||||
|
* @param playerTraceShowData The showData for modifying the rendering
|
||||||
|
*/
|
||||||
|
private void render(List<TNTPoint> records, REntityServer entityServer, PlayerTraceShowData playerTraceShowData) {
|
||||||
|
if (records.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<ViewFlag> flagList = playerTraceShowData.getEffectiveViewFlags();
|
||||||
|
|
||||||
|
// Apply filters
|
||||||
|
Stream<TNTPoint> workingRecordsStream = records.stream();
|
||||||
|
for (ViewFlag flag : flagList) {
|
||||||
|
workingRecordsStream = flag.filter(workingRecordsStream);
|
||||||
|
}
|
||||||
|
List<TNTPoint> workingRecords = workingRecordsStream.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// Bundle records at unique positions
|
||||||
|
List<List<TNTPoint>> bundles = bundleRecords(workingRecords, playerTraceShowData.getBundleFilter());
|
||||||
|
|
||||||
|
// Render bundled records
|
||||||
|
List<TraceEntity> entities = new LinkedList<>();
|
||||||
|
|
||||||
|
for (List<TNTPoint> bundle : bundles) {
|
||||||
|
entities.add(new TraceEntity(entityServer, bundle.get(0).getLocation(), bundle.get(0).isExplosion(), bundle, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply modifiers
|
||||||
|
for (ViewFlag flag : flagList) {
|
||||||
|
flag.modify(entityServer, entities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundles the passed TNTRecords based on whether they are at the same location
|
||||||
|
*
|
||||||
|
* @param records The TNTRecords that are supposed to be bundled
|
||||||
|
* @param filter A filter specefieng whether records can be bundled
|
||||||
|
* @return A list of bundles
|
||||||
|
*/
|
||||||
|
private List<List<TNTPoint>> bundleRecords(List<TNTPoint> records, BundleFilter filter) {
|
||||||
|
if (filter == BundleFilter.NONE) {
|
||||||
|
return records.stream().map(List::of).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<List<TNTPoint>> bundles = new ArrayList<>();
|
||||||
|
|
||||||
|
recordsLoop:
|
||||||
|
for (TNTPoint record : records) {
|
||||||
|
for (int i = bundles.size() - 1; i >= 0; i--) {
|
||||||
|
List<TNTPoint> bundle = bundles.get(i);
|
||||||
|
|
||||||
|
Boolean filterResult = filter.function.apply(record, bundle.get(0));
|
||||||
|
if (filterResult == null) {
|
||||||
|
ArrayList<TNTPoint> newBundle = new ArrayList<>();
|
||||||
|
newBundle.add(record);
|
||||||
|
bundles.add(newBundle);
|
||||||
|
continue recordsLoop;
|
||||||
|
} else if (filterResult) {
|
||||||
|
bundle.add(record);
|
||||||
|
continue recordsLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<TNTPoint> newBundle = new ArrayList<>();
|
||||||
|
newBundle.add(record);
|
||||||
|
bundles.add(newBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bundles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides this trail for the given player
|
||||||
|
*
|
||||||
|
* @param player
|
||||||
|
*/
|
||||||
|
public void hide(Player player) {
|
||||||
|
REntityServer entityServer = entityServerMap.remove(player);
|
||||||
|
if (entityServer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entityServer.removePlayer(player);
|
||||||
|
if (entityServer.getPlayers().isEmpty()) {
|
||||||
|
entityServer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides this trace for all players
|
||||||
|
*/
|
||||||
|
public void hide() {
|
||||||
|
entityServerMap.forEach((player, entityServer) -> {
|
||||||
|
entityServer.close();
|
||||||
|
});
|
||||||
|
entityServerMap.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the records of this trace from storage to memory
|
||||||
|
*/
|
||||||
|
@SneakyThrows
|
||||||
|
private void loadRecords() {
|
||||||
|
List<TNTPoint> records = new ArrayList<>();
|
||||||
|
|
||||||
|
FileInputStream fileInputStream = new FileInputStream(recordsSaveFile);
|
||||||
|
|
||||||
|
@Cleanup
|
||||||
|
ObjectInputStream inputStream = new ObjectInputStream(new GZIPInputStream(fileInputStream));
|
||||||
|
while (fileInputStream.getChannel().position() < recordsSaveFile.length()) {
|
||||||
|
records.add((TNTPoint) inputStream.readObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, List<TNTPoint>> histories = new HashMap<>();
|
||||||
|
for (TNTPoint record : records) {
|
||||||
|
int tntId = record.getTntId();
|
||||||
|
List<TNTPoint> history = histories.computeIfAbsent(tntId, id -> new ArrayList<>());
|
||||||
|
history.add(record);
|
||||||
|
record.setHistory(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.records = new SoftReference<>(records);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TNTPoint> getRecords() {
|
||||||
|
if (records.get() == null) {
|
||||||
|
loadRecords();
|
||||||
|
}
|
||||||
|
return records.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Trace{" +
|
||||||
|
"uuid=" + uuid +
|
||||||
|
", region=" + region +
|
||||||
|
", creationTime=" + date +
|
||||||
|
", recordsSaveFile=" + recordsSaveFile.getName() +
|
||||||
|
", records=" + getRecords() +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -1,44 +1,43 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* 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/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.bausystem.features.tracer;
|
package de.steamwar.bausystem.features.tracer;
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.Permission;
|
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
|
||||||
import de.steamwar.bausystem.features.tracer.record.*;
|
import de.steamwar.bausystem.features.tracer.rendering.PlayerTraceShowData;
|
||||||
import de.steamwar.bausystem.features.tracer.show.*;
|
import de.steamwar.bausystem.features.tracer.rendering.ViewFlag;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.dynamicflags.AtFlag;
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.shared.ShowMode;
|
|
||||||
import de.steamwar.command.PreviousArguments;
|
import de.steamwar.command.PreviousArguments;
|
||||||
import de.steamwar.command.SWCommand;
|
import de.steamwar.command.SWCommand;
|
||||||
import de.steamwar.command.TypeMapper;
|
import de.steamwar.command.TypeMapper;
|
||||||
import de.steamwar.command.TypeValidator;
|
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import de.steamwar.linkage.LinkedInstance;
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
import java.util.function.BiFunction;
|
import java.util.Arrays;
|
||||||
import java.util.function.Supplier;
|
import java.util.Collection;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
public class TraceCommand extends SWCommand {
|
public class TraceCommand extends SWCommand {
|
||||||
@ -47,199 +46,226 @@ public class TraceCommand extends SWCommand {
|
|||||||
super("trace", "trail");
|
super("trace", "trail");
|
||||||
}
|
}
|
||||||
|
|
||||||
@LinkedInstance
|
@Register(value = "start", description = "TRACE_COMMAND_HELP_START")
|
||||||
public Recorder recorder;
|
public void start(@Validator Player player) {
|
||||||
|
Region region = Region.getRegion(player.getLocation());
|
||||||
@Register(value = {"start"}, description = "TRACE_COMMAND_HELP_START")
|
TraceRecorder.instance.startRecording(region);
|
||||||
public void startCommand(@Validator Player p) {
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_START", player);
|
||||||
Region region = Region.getRegion(p.getLocation());
|
|
||||||
recorder.set(region, new SimpleTraceRecorder());
|
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_START", p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"single"}, description = "TRACE_COMMAND_HELP_SINGLE")
|
@Register(value = "stop", description = "TRACE_COMMAND_HELP_STOP")
|
||||||
public void singleCommand(@Validator Player p) {
|
public void stop(@Validator Player player) {
|
||||||
Region region = Region.getRegion(p.getLocation());
|
Region region = Region.getRegion(player.getLocation());
|
||||||
recorder.set(region, new SingleTraceRecorder(region));
|
TraceRecorder.instance.stopRecording(region);
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_SINGLE", p);
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_STOP", player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"stop"}, description = "TRACE_COMMAND_HELP_STOP")
|
@Register(value = "auto", description = "TRACE_COMMAND_HELP_AUTO")
|
||||||
public void stopCommand(@Validator Player p) {
|
public void auto(@Validator Player player) {
|
||||||
Region region = Region.getRegion(p.getLocation());
|
Region region = Region.getRegion(player.getLocation());
|
||||||
recorder.remove(region);
|
if (TraceRecorder.instance.toggleAutoTrace(region)) {
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_STOP", p);
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_AUTO_START", player);
|
||||||
}
|
} else {
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_AUTO_STOP", player);
|
||||||
@Register(value = {"auto"}, description = "TRACE_COMMAND_HELP_AUTO")
|
|
||||||
@Register({"toggleauto"})
|
|
||||||
public void autoCommand(@Validator Player p, @OptionalValue("-explode") @StaticValue({"-explode", "-ignite"}) String type) {
|
|
||||||
Region region = Region.getRegion(p.getLocation());
|
|
||||||
switch (type) {
|
|
||||||
case "-explode":
|
|
||||||
recorder.set(region, new AutoExplodeTraceRecorder());
|
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_AUTO_IDLE_EXPLODE", p);
|
|
||||||
break;
|
|
||||||
case "-ignite":
|
|
||||||
recorder.set(region, new AutoIgniteTraceRecorder());
|
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_AUTO_IDLE_IGNITE", p);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"autoremove"}, description = "TRACE_COMMAND_HELP_AUTO_REMOVE")
|
@Register(value = "show", description = "TRACE_COMMAND_HELP_SHOW")
|
||||||
@Register(value = {"autodelete"})
|
public void show(@Validator Player player, @OptionalValue("DEFAULT") BundleFilter bundleFilter, ViewFlag... flags) {
|
||||||
public void setAutoDeleteMode(@Validator Player p, @StaticValue({"-always", "-never", "-no_build_destroy", "-build_destroy", "-no_testblock_destroy", "-testblock_destroy"}) String destroyMode) {
|
showInternal(player, bundleFilter, flags);
|
||||||
Region region = Region.getRegion(p.getLocation());
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW", player);
|
||||||
TraceRecorder recorder = this.recorder.get(region);
|
|
||||||
if (!(recorder instanceof AutoTraceRecorder) || recorder instanceof SingleTraceRecorder) {
|
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_AUTO_DELETE_INVALID", p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AutoTraceRecorder autoTraceRecorder = (AutoTraceRecorder) recorder;
|
|
||||||
switch (destroyMode) {
|
|
||||||
case "-always":
|
|
||||||
autoTraceRecorder.setTraceRecordAutoDeletion(TraceRecordAutoDeletion.ALWAYS);
|
|
||||||
break;
|
|
||||||
case "-never":
|
|
||||||
autoTraceRecorder.setTraceRecordAutoDeletion(TraceRecordAutoDeletion.NEVER);
|
|
||||||
break;
|
|
||||||
case "-no_build_destroy":
|
|
||||||
autoTraceRecorder.setTraceRecordAutoDeletion(TraceRecordAutoDeletion.NO_BUILD_DESTROY);
|
|
||||||
break;
|
|
||||||
case "-build_destroy":
|
|
||||||
autoTraceRecorder.setTraceRecordAutoDeletion(TraceRecordAutoDeletion.BUILD_DESTROY);
|
|
||||||
break;
|
|
||||||
case "-no_testblock_destroy":
|
|
||||||
autoTraceRecorder.setTraceRecordAutoDeletion(TraceRecordAutoDeletion.NO_TESTBLOCK_DESTROY);
|
|
||||||
break;
|
|
||||||
case "-testblock_destroy":
|
|
||||||
autoTraceRecorder.setTraceRecordAutoDeletion(TraceRecordAutoDeletion.TESTBLOCK_DESTROY);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_AUTO_DELETE_" + autoTraceRecorder.getTraceRecordAutoDeletion().name(), p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"show"}, description = "TRACE_COMMAND_HELP_SHOW_AT")
|
@Register(value = {"show", "at"}, description = "TRACE_COMMAND_HELP_SHOW_AT_WITH")
|
||||||
public void showAtCommand(@Validator Player p, @OptionalValue("time") @StaticValue({"time", "fuse"}) String type, @StaticValue("at") String __, @Min(intValue = 0) int at) {
|
public void showAt(@Validator Player player, @Min(intValue = 0) int time, @StaticValue("with") String with, @OptionalValue("DEFAULT") BundleFilter bundleFilter, ViewFlag... flags) {
|
||||||
internalSetShowFilter(p, "TRACE_MESSAGE_SHOW_AT", type, at, at);
|
showInternal(player, time, time, bundleFilter, flags);
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_AT", player, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"show"}, description = "TRACE_COMMAND_HELP_SHOW_FROM")
|
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM_WITH")
|
||||||
public void showFromCommand(@Validator Player p, @OptionalValue("time") @StaticValue({"time", "fuse"}) String type, @StaticValue("from") String __, @Min(intValue = 0) int from) {
|
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("with") String with, @OptionalValue("DEFAULT") BundleFilter bundleFilter, ViewFlag... flags) {
|
||||||
if (from == 0) {
|
showInternal(player, from, Integer.MAX_VALUE, bundleFilter, flags);
|
||||||
TraceShowManager.setShowFilter(p, null);
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_FROM", player, from);
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW", p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
internalSetShowFilter(p, "TRACE_MESSAGE_SHOW_FROM", type, from, Integer.MAX_VALUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"show"}, description = "TRACE_COMMAND_HELP_SHOW_FROM_TO")
|
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM_TO_WITH")
|
||||||
public void showFromToCommand(@Validator Player p, @OptionalValue("time") @StaticValue({"time", "fuse"}) String type, @StaticValue("from") String __, @Min(intValue = 0) int from, @StaticValue("to") String ___, @Min(intValue = 0) int to) {
|
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("to") String toString, int to, @StaticValue("with") String with, @OptionalValue("DEFAULT") BundleFilter bundleFilter, ViewFlag... flags) {
|
||||||
internalSetShowFilter(p, "TRACE_MESSAGE_SHOW_FROM_TO", type, from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void internalSetShowFilter(Player p, String message, String type, int from, int to) {
|
|
||||||
if (to < from) {
|
if (to < from) {
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_TO_SMALLER", p);
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_TO_SMALLER", player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TraceShowManager.setShowFilter(p, tntPosition -> {
|
showInternal(player, from, to, bundleFilter, flags);
|
||||||
switch (type) {
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_FROM_TO", player, from, to);
|
||||||
case "time":
|
|
||||||
return tntPosition.getTimeTicks() >= from && tntPosition.getTimeTicks() <= to;
|
|
||||||
case "fuse":
|
|
||||||
return tntPosition.getFuseTicks() >= from && tntPosition.getFuseTicks() <= to;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
BauSystem.MESSAGE.send(message, p, type, from, to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /trace show at 0
|
|
||||||
// /trace show raw -auto at 0
|
@Register(value = {"show", "at"}, description = "TRACE_COMMAND_HELP_SHOW_AT")
|
||||||
@Register(value = {"show"}, description = "TRACE_COMMAND_HELP_SHOW")
|
public void showAt(@Validator Player player, @Min(intValue = 0) int time) {
|
||||||
public void showCommand(@Validator Player p, @OptionalValue("entity") ShowModeType showModeType, ShowModeParameterType... showModeParameterTypes) {
|
TraceManager.instance.renderAt(player, time, time);
|
||||||
Region region = Region.getRegion(p.getLocation());
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_AT", player, time);
|
||||||
ShowModeParameter showModeParameter = new ShowModeParameter();
|
}
|
||||||
if (region.getWaterLevel() != 0) { // Enable Water by default for regions with WaterLevel e.g. WarShip
|
|
||||||
showModeParameter.enableWater();
|
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM")
|
||||||
|
public void showFrom(@Validator Player player, @Min(intValue = 0) int from) {
|
||||||
|
TraceManager.instance.renderAt(player, from, Integer.MAX_VALUE);
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_FROM", player, from);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register(value = {"show", "from"}, description = "TRACE_COMMAND_HELP_SHOW_FROM_TO")
|
||||||
|
public void showFromTo(@Validator Player player, @Min(intValue = 0) int from, @StaticValue("to") String toString, int to) {
|
||||||
|
TraceManager.instance.renderAt(player, from, to);
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW_FROM_TO", player, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showInternal(Player player, BundleFilter bundleFilter, ViewFlag... flags) {
|
||||||
|
PlayerTraceShowData playerTraceShowData = new PlayerTraceShowData(bundleFilter, flags);
|
||||||
|
TraceManager.instance.show(player, playerTraceShowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showInternal(Player player, int from, int to, BundleFilter bundleFilter, ViewFlag... flags) {
|
||||||
|
PlayerTraceShowData playerTraceShowData = new PlayerTraceShowData(bundleFilter, flags);
|
||||||
|
playerTraceShowData.addViewFlag(new AtFlag(from, to));
|
||||||
|
TraceManager.instance.show(player, playerTraceShowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register(value = "hide", description = "TRACE_COMMAND_HELP_HIDE")
|
||||||
|
public void hide(@Validator Player player) {
|
||||||
|
TraceManager.instance.hide(player);
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_HIDE", player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register(value = "clear")
|
||||||
|
public void clear(@Validator Player player) {
|
||||||
|
TraceManager.instance.clear(Region.getRegion(player.getLocation()));
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_CLEAR", player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register(value = "delete", description = "TRACE_COMMAND_HELP_DELETE")
|
||||||
|
public void delete(@Validator Player player, Trace trace) {
|
||||||
|
TraceManager.instance.remove(trace);
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_DELETE", player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register(value = "isolate", description = "TRACE_COMMAND_HELP_ISOLATE")
|
||||||
|
public void isolate(@Validator Player player, Trace trace, @ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) {
|
||||||
|
TraceManager.instance.isolate(player, records);
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_ISOLATE", player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register(value = "share", description = "TRACE_COMMAND_HELP_SHARE")
|
||||||
|
public void share(@Validator Player player) {
|
||||||
|
BauSystem.MESSAGE.broadcast("TRACE_MESSAGE_SHARE", "TRACE_MESSAGE_SHARE_HOVER", new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/trace follow " + player.getName()), player.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Register(value = "follow", description = "TRACE_COMMAND_HELP_FOLLOW")
|
||||||
|
public void follow(@Validator Player player, Player toFollow) {
|
||||||
|
if (player == toFollow) {
|
||||||
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_FOLLOW_SELF", player);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
for (ShowModeParameterType showModeParameterType : showModeParameterTypes) {
|
TraceManager.instance.follow(player, toFollow);
|
||||||
if (showModeParameterType == ShowModeParameterType.WATER && region.getWaterLevel() != 0) {
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_FOLLOW", player, toFollow.getName());
|
||||||
showModeParameter.disableWater();
|
|
||||||
} else {
|
|
||||||
showModeParameterType.getShowModeParameterConsumer().accept(showModeParameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TraceShowManager.show(p, showModeType.showModeBiFunction.apply(p, showModeParameter));
|
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_SHOW", p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"hide"}, description = "TRACE_COMMAND_HELP_HIDE")
|
@Register(value = "unfollow", description = "TRACE_COMMAND_HELP_UNFOLLOW")
|
||||||
public void hideCommand(@Validator Player p) {
|
public void unfollow(@Validator Player player) {
|
||||||
TraceShowManager.hide(p);
|
TraceManager.instance.unfollow(player);
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_HIDE", p);
|
BauSystem.MESSAGE.send("TRACE_MESSAGE_UNFOLLOW", player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Register(value = {"delete"}, description = "TRACE_COMMAND_HELP_DELETE")
|
@ClassMapper(value = Trace.class, local = true)
|
||||||
@Register({"clear"})
|
public TypeMapper<Trace> traceClassMapper() {
|
||||||
public void deleteCommand(@Validator Player p) {
|
return new TypeMapper<>() {
|
||||||
Region region = Region.getRegion(p.getLocation());
|
|
||||||
StoredRecords.clear(region);
|
|
||||||
BauSystem.MESSAGE.send("TRACE_MESSAGE_DELETE", p);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
private enum ShowModeType {
|
|
||||||
ENTITY((player, showModeParameter) -> new EntityShowMode(player, showModeParameter, 16)),
|
|
||||||
RAW((player, showModeParameter) -> new EntityShowMode(player, showModeParameter, -1));
|
|
||||||
|
|
||||||
private BiFunction<Player, ShowModeParameter, ShowMode<TNTPosition>> showModeBiFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ClassMapper(value = ShowModeParameterType.class, local = true)
|
|
||||||
public TypeMapper<ShowModeParameterType> showModeParameterTypesTypeMapper() {
|
|
||||||
Map<ShowModeParameterType, List<String>> showModeParameterTypeListMap = new EnumMap<>(ShowModeParameterType.class);
|
|
||||||
for (ShowModeParameterType value : ShowModeParameterType.values()) {
|
|
||||||
showModeParameterTypeListMap.put(value, value.getTabCompletes());
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, ShowModeParameterType> showModeParameterTypesMap = new HashMap<>();
|
|
||||||
showModeParameterTypeListMap.forEach((k, v) -> v.forEach(s -> showModeParameterTypesMap.put(s, k)));
|
|
||||||
|
|
||||||
return new TypeMapper<ShowModeParameterType>() {
|
|
||||||
@Override
|
@Override
|
||||||
public ShowModeParameterType map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
|
public Trace map(CommandSender commandSender, String[] previousArguments, String s) {
|
||||||
return showModeParameterTypesMap.get(s);
|
return TraceManager.instance.get(Integer.parseInt(s)).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
|
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
|
||||||
Set<ShowModeParameterType> showModeParameterTypeSet = new HashSet<>();
|
return TraceManager.instance.getAllIds().stream()
|
||||||
Arrays.stream(previousArguments.userArgs).map(showModeParameterTypesMap::get).forEach(showModeParameterTypeSet::add);
|
.map(Object::toString)
|
||||||
showModeParameterTypeSet.remove(null);
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Set<ShowModeParameterType> removed = showModeParameterTypeSet.stream()
|
@ClassMapper(value = TNTPoint.class, local = true)
|
||||||
.map(ShowModeParameterType::getRemoved)
|
public TypeMapper<TNTPoint> recordMapper() {
|
||||||
.map(Supplier::get)
|
return new TypeMapper<>() {
|
||||||
.flatMap(Arrays::stream)
|
@Override
|
||||||
.collect(Collectors.toSet());
|
public TNTPoint map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
|
||||||
|
Trace trace = previousArguments.getFirst(Trace.class).orElse(null);
|
||||||
|
if (trace == null) return null;
|
||||||
|
|
||||||
List<String> tabCompletes = new ArrayList<>();
|
int id = Integer.parseInt(s);
|
||||||
for (Map.Entry<ShowModeParameterType, List<String>> entry : showModeParameterTypeListMap.entrySet()) {
|
return trace.getRecords().stream()
|
||||||
if (removed.contains(entry.getKey()) || showModeParameterTypeSet.contains(entry.getKey())) {
|
.filter(record -> record.getTntId() == id)
|
||||||
continue;
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO change when new command framework update
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
|
||||||
|
Trace trace = previousArguments.getFirst(Trace.class).orElse(null);
|
||||||
|
if (trace == null) return null;
|
||||||
|
return trace.getUsedIds();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@ClassMapper(value = BundleFilter.class, local = true)
|
||||||
|
public TypeMapper<BundleFilter> bundleFilterClassMapper() {
|
||||||
|
return new TypeMapper<>() {
|
||||||
|
@Override
|
||||||
|
public BundleFilter map(CommandSender commandSender, String[] previousArguments, String s) {
|
||||||
|
for (BundleFilter filter : BundleFilter.values()) {
|
||||||
|
if (s.equals(filter.toString())) {
|
||||||
|
return filter;
|
||||||
}
|
}
|
||||||
tabCompletes.addAll(entry.getValue());
|
|
||||||
}
|
}
|
||||||
return tabCompletes;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
|
||||||
|
if (s.length() == 0) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Arrays.stream(BundleFilter.values())
|
||||||
|
.map(Enum::toString)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@ClassMapper(value = ViewFlag.class, local = true)
|
||||||
|
public TypeMapper<ViewFlag> viewFlagClassMapper() {
|
||||||
|
return new TypeMapper<ViewFlag>() {
|
||||||
|
@Override
|
||||||
|
public ViewFlag map(CommandSender commandSender, String[] previousArguments, String s) {
|
||||||
|
for (ViewFlag flag : ViewFlag.flags) {
|
||||||
|
if (s.equals("--" + flag.name)) {
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String alias : flag.aliases) {
|
||||||
|
if (s.equals("-" + alias)) {
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
|
||||||
|
return ViewFlag.flags.stream()
|
||||||
|
.flatMap(viewFlag -> Stream.concat(Stream.of("--" + viewFlag.name),
|
||||||
|
Arrays.stream(viewFlag.aliases).map(name -> "-" + name)))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,388 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 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.tracer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.BundleFilter;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.PlayerTraceShowData;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.dynamicflags.AtFlag;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.dynamicflags.IsolateFlag;
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Linked
|
||||||
|
public class TraceManager implements Listener {
|
||||||
|
|
||||||
|
public static TraceManager instance;
|
||||||
|
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File tracesFolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "traces");
|
||||||
|
|
||||||
|
public TraceManager() {
|
||||||
|
if (!tracesFolder.exists())
|
||||||
|
tracesFolder.mkdir();
|
||||||
|
|
||||||
|
File[] traceFiles = tracesFolder.listFiles();
|
||||||
|
if (traceFiles == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (File traceFile : traceFiles) {
|
||||||
|
if (traceFile.getName().contains(".records"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
add(new Trace(traceFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all current traces
|
||||||
|
*/
|
||||||
|
private final Map<Region, Map<Integer, Trace>> tracesByRegion = new HashMap<>();
|
||||||
|
|
||||||
|
private final Map<Region, Map<Player, PlayerTraceShowData>> showDataPerRegionPerPlayer = new HashMap<>();
|
||||||
|
|
||||||
|
private final Map<Player, Set<Player>> followerMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility variable to keep track of the next open trace id;
|
||||||
|
*/
|
||||||
|
private int nextOpenId = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new trace to the global record
|
||||||
|
*
|
||||||
|
* @param trace Trace to be added
|
||||||
|
* @return id of the created trace
|
||||||
|
*/
|
||||||
|
protected int add(Trace trace) {
|
||||||
|
showDataPerRegionPerPlayer.getOrDefault(trace.getRegion(), Collections.emptyMap()).forEach((player, playerTraceShowData) -> {
|
||||||
|
trace.render(player, playerTraceShowData);
|
||||||
|
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
|
||||||
|
trace.render(follower, playerTraceShowData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tracesByRegion.computeIfAbsent(trace.getRegion(), region -> new HashMap<>()).put(nextOpenId, trace);
|
||||||
|
nextOpenId++;
|
||||||
|
return nextOpenId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the id of the given trace
|
||||||
|
*
|
||||||
|
* @param trace
|
||||||
|
*/
|
||||||
|
public int getId(Trace trace) {
|
||||||
|
for (Map.Entry<Integer, Trace> entry : tracesByRegion.getOrDefault(trace.getRegion(), Collections.emptyMap()).entrySet()) {
|
||||||
|
if (entry.getValue() == trace) return entry.getKey();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders only the given records to the specified trace
|
||||||
|
*
|
||||||
|
* @param trace
|
||||||
|
* @param recordsToAdd
|
||||||
|
*/
|
||||||
|
protected void showPartial(Trace trace, List<TNTPoint> recordsToAdd) {
|
||||||
|
showDataPerRegionPerPlayer.getOrDefault(trace.getRegion(), Collections.emptyMap()).forEach((player, playerTraceShowData) -> {
|
||||||
|
trace.render(recordsToAdd, player, playerTraceShowData);
|
||||||
|
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
|
||||||
|
trace.render(recordsToAdd, follower, playerTraceShowData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Map<Player, PlayerTraceShowData> getTraceShowDataPlayerMapping(Region region) {
|
||||||
|
return showDataPerRegionPerPlayer.getOrDefault(region, new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the trace with the given id
|
||||||
|
*
|
||||||
|
* @param trace the trace to be removed
|
||||||
|
*/
|
||||||
|
public boolean remove(Trace trace) {
|
||||||
|
Map<Integer, Trace> traces = tracesByRegion.getOrDefault(trace.getRegion(), Collections.emptyMap());
|
||||||
|
Integer traceId = traces.entrySet().stream()
|
||||||
|
.filter(entry -> entry.getValue() == trace)
|
||||||
|
.map(Map.Entry::getKey)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (traceId == null) return false;
|
||||||
|
traces.remove(traceId);
|
||||||
|
trace.hide();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all traces
|
||||||
|
*/
|
||||||
|
public void clear(Region region) {
|
||||||
|
showDataPerRegionPerPlayer.getOrDefault(region, new HashMap<>())
|
||||||
|
.keySet()
|
||||||
|
.forEach(player -> {
|
||||||
|
Set<Player> players = followerMap.getOrDefault(player, Collections.emptySet());
|
||||||
|
tracesByRegion.get(region).values().forEach(trace -> {
|
||||||
|
trace.hide(player);
|
||||||
|
players.forEach(trace::hide);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
tracesByRegion.getOrDefault(region, new HashMap<>())
|
||||||
|
.forEach((i, trace) -> {
|
||||||
|
if (trace.getRegion() != region) return;
|
||||||
|
trace.getMetadataSaveFile().delete();
|
||||||
|
trace.getRecordsSaveFile().delete();
|
||||||
|
});
|
||||||
|
tracesByRegion.getOrDefault(region, new HashMap<>()).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode to get all traces in a certain region
|
||||||
|
*
|
||||||
|
* @param region Region to look for traces in
|
||||||
|
* @return All traces recorded in the given Region
|
||||||
|
*/
|
||||||
|
public Collection<Trace> get(Region region) {
|
||||||
|
return tracesByRegion.getOrDefault(region, Collections.emptyMap()).values();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode to get the trace with specific id
|
||||||
|
*
|
||||||
|
* @param index index of the trace
|
||||||
|
* @return the trace with given id
|
||||||
|
*/
|
||||||
|
public Optional<Trace> get(int index) {
|
||||||
|
for (Map.Entry<Region, Map<Integer, Trace>> intermediate : tracesByRegion.entrySet()) {
|
||||||
|
if (intermediate.getValue().containsKey(index)) {
|
||||||
|
return Optional.ofNullable(intermediate.getValue().get(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methode to get all traces
|
||||||
|
*
|
||||||
|
* @return internal list of all current traces
|
||||||
|
*/
|
||||||
|
public Collection<Trace> getAll() {
|
||||||
|
return tracesByRegion.values().stream().map(Map::values).flatMap(Collection::stream).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return all ids of active traces
|
||||||
|
*/
|
||||||
|
public Set<Integer> getAllIds() {
|
||||||
|
return tracesByRegion.values().stream().map(Map::keySet).flatMap(Collection::stream).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows traces for the player of the current Region
|
||||||
|
*
|
||||||
|
* @param player
|
||||||
|
* @param playerTraceShowData
|
||||||
|
*/
|
||||||
|
public void show(Player player, PlayerTraceShowData playerTraceShowData) {
|
||||||
|
unfollow(player);
|
||||||
|
|
||||||
|
Region region = Region.getRegion(player.getLocation());
|
||||||
|
showDataPerRegionPerPlayer.computeIfAbsent(region, ignored -> new HashMap<>()).put(player, playerTraceShowData);
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||||
|
trace.render(player, playerTraceShowData);
|
||||||
|
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
|
||||||
|
trace.render(follower, playerTraceShowData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hides traces for the player of the current Region
|
||||||
|
*
|
||||||
|
* @param player
|
||||||
|
*/
|
||||||
|
public void hide(Player player) {
|
||||||
|
unfollow(player);
|
||||||
|
|
||||||
|
Region region = Region.getRegion(player.getLocation());
|
||||||
|
PlayerTraceShowData previous = showDataPerRegionPerPlayer.getOrDefault(region, Collections.emptyMap()).remove(player);
|
||||||
|
if (previous == null) return;
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||||
|
trace.hide(player);
|
||||||
|
followerMap.getOrDefault(player, Collections.emptySet()).forEach(trace::hide);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the given player
|
||||||
|
*
|
||||||
|
* @param follower
|
||||||
|
* @param following
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean follow(Player follower, Player following) {
|
||||||
|
if (followerMap.containsKey(follower)) return false;
|
||||||
|
if (followerMap.entrySet().stream().anyMatch(playerSetEntry -> playerSetEntry.getValue().contains(follower))) {
|
||||||
|
unfollow(follower);
|
||||||
|
}
|
||||||
|
|
||||||
|
followerMap.computeIfAbsent(following, ignored -> new HashSet<>()).add(follower);
|
||||||
|
|
||||||
|
showDataPerRegionPerPlayer.forEach((region, playerPlayerTraceShowDataMap) -> {
|
||||||
|
if (playerPlayerTraceShowDataMap.containsKey(follower)) {
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> trace.hide(follower));
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerTraceShowData playerTraceShowData = playerPlayerTraceShowDataMap.get(following);
|
||||||
|
if (playerTraceShowData == null) return;
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||||
|
trace.render(follower, playerTraceShowData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unfollow(Player follower) {
|
||||||
|
if (followerMap.containsKey(follower)) return;
|
||||||
|
List<Player> toRemove = new ArrayList<>();
|
||||||
|
Set<Player> toHide = new HashSet<>();
|
||||||
|
followerMap.forEach((player, players) -> {
|
||||||
|
if (players.remove(follower)) toHide.add(follower);
|
||||||
|
if (players.isEmpty()) toRemove.add(player);
|
||||||
|
});
|
||||||
|
toRemove.forEach(followerMap::remove);
|
||||||
|
|
||||||
|
showDataPerRegionPerPlayer.forEach((region, playerPlayerTraceShowDataMap) -> {
|
||||||
|
toHide.forEach(player -> {
|
||||||
|
if (!playerPlayerTraceShowDataMap.containsKey(player)) return;
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||||
|
trace.hide(follower);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
PlayerTraceShowData playerTraceShowData = playerPlayerTraceShowDataMap.get(follower);
|
||||||
|
if (playerTraceShowData == null) return;
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||||
|
trace.render(follower, playerTraceShowData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies the render for the given player, to only show tnts at the given time
|
||||||
|
* interval
|
||||||
|
*
|
||||||
|
* @param player
|
||||||
|
* @param from start of time interval
|
||||||
|
* @param to end of time interval
|
||||||
|
*/
|
||||||
|
public void renderAt(Player player, int from, int to) {
|
||||||
|
unfollow(player);
|
||||||
|
|
||||||
|
Region region = Region.getRegion(player.getLocation());
|
||||||
|
PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer
|
||||||
|
.computeIfAbsent(region, ignored -> new HashMap<>())
|
||||||
|
.computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.DEFAULT));
|
||||||
|
|
||||||
|
AtFlag atFlag = playerTraceShowData.getViewFlag(AtFlag.class);
|
||||||
|
if (atFlag == null) {
|
||||||
|
atFlag = new AtFlag(from, to);
|
||||||
|
playerTraceShowData.addViewFlag(atFlag);
|
||||||
|
} else {
|
||||||
|
atFlag.update(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||||
|
trace.render(player, playerTraceShowData);
|
||||||
|
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
|
||||||
|
trace.render(follower, playerTraceShowData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the isolated render for the given records and player
|
||||||
|
*
|
||||||
|
* @param player the player the trace is shown to
|
||||||
|
* @param records the record for which isolation is toggled
|
||||||
|
*/
|
||||||
|
public void isolate(Player player, TNTPoint... records) {
|
||||||
|
unfollow(player);
|
||||||
|
|
||||||
|
Region region = Region.getRegion(player.getLocation());
|
||||||
|
PlayerTraceShowData playerTraceShowData = showDataPerRegionPerPlayer
|
||||||
|
.computeIfAbsent(region, ignored -> new HashMap<>())
|
||||||
|
.computeIfAbsent(player, ignored -> new PlayerTraceShowData(BundleFilter.DEFAULT));
|
||||||
|
|
||||||
|
IsolateFlag isolateFlag;
|
||||||
|
if (playerTraceShowData.hasViewFlagOnly(IsolateFlag.class)) {
|
||||||
|
isolateFlag = playerTraceShowData.getViewFlag(IsolateFlag.class);
|
||||||
|
} else if (playerTraceShowData.hasNoViewFlags()) {
|
||||||
|
isolateFlag = new IsolateFlag();
|
||||||
|
playerTraceShowData.addViewFlag(isolateFlag);
|
||||||
|
} else {
|
||||||
|
playerTraceShowData = new PlayerTraceShowData(BundleFilter.DEFAULT);
|
||||||
|
isolateFlag = new IsolateFlag();
|
||||||
|
playerTraceShowData.addViewFlag(isolateFlag);
|
||||||
|
showDataPerRegionPerPlayer.get(region).put(player, playerTraceShowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TNTPoint record : records) {
|
||||||
|
isolateFlag.toggleId(record.getTntId());
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerTraceShowData finalPlayerTraceShowData = playerTraceShowData;
|
||||||
|
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
|
||||||
|
trace.render(player, finalPlayerTraceShowData);
|
||||||
|
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
|
||||||
|
trace.render(follower, finalPlayerTraceShowData);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
unfollow(event.getPlayer());
|
||||||
|
new ArrayList<>(followerMap.getOrDefault(event.getPlayer(), Collections.emptySet())).forEach(this::unfollow);
|
||||||
|
|
||||||
|
showDataPerRegionPerPlayer.forEach((region, playerPlayerTraceShowDataMap) -> {
|
||||||
|
playerPlayerTraceShowDataMap.remove(event.getPlayer());
|
||||||
|
});
|
||||||
|
|
||||||
|
tracesByRegion.forEach((region, integerTraceMap) -> {
|
||||||
|
integerTraceMap.forEach((integer, trace) -> {
|
||||||
|
trace.hide(event.getPlayer());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 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.tracer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.TNTPrimed;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||||
|
import org.bukkit.event.entity.EntitySpawnEvent;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@Linked
|
||||||
|
public class TraceRecorder implements Listener {
|
||||||
|
|
||||||
|
public static TraceRecorder instance;
|
||||||
|
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map for all traces being actively recorded
|
||||||
|
*/
|
||||||
|
private final Map<Region, TraceRecordingWrapper> activeTraces = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map for all TNTs being traced, by region
|
||||||
|
*/
|
||||||
|
private final Map<Region, List<TNTPrimed>> trackedTNT = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from TNT to Region the TNT spawned in
|
||||||
|
*/
|
||||||
|
private final Map<TNTPrimed, Region> tntSpawnRegion = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a tracked tnt entity to its entire recording history
|
||||||
|
*/
|
||||||
|
private final Map<TNTPrimed, List<TNTPoint>> historyMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regions where auto-trace is enabled
|
||||||
|
*/
|
||||||
|
private final Set<Region> autoTraceRegions = new HashSet<>();
|
||||||
|
|
||||||
|
public TraceRecorder() {
|
||||||
|
BauSystem.runTaskTimer(BauSystem.getInstance(), () -> {
|
||||||
|
record();
|
||||||
|
checkForAutoTraceFinish();
|
||||||
|
}, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles auto trace for the given region
|
||||||
|
*
|
||||||
|
* @param region
|
||||||
|
*/
|
||||||
|
public boolean toggleAutoTrace(Region region) {
|
||||||
|
if (!autoTraceRegions.remove(region)) {
|
||||||
|
autoTraceRegions.add(region);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes checks for whether auto traces finished
|
||||||
|
*/
|
||||||
|
public void checkForAutoTraceFinish() {
|
||||||
|
for (Region region : autoTraceRegions) {
|
||||||
|
if (autoTraceRegions.contains(region) && trackedTNT.getOrDefault(region, Collections.emptyList()).size() == 0) {
|
||||||
|
stopRecording(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a recording at the given region
|
||||||
|
*
|
||||||
|
* @param region region to be recorded
|
||||||
|
*/
|
||||||
|
public int startRecording(Region region) {
|
||||||
|
if (activeTraces.containsKey(region)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceRecordingWrapper wrappedTrace = new TraceRecordingWrapper(region);
|
||||||
|
activeTraces.put(region, wrappedTrace);
|
||||||
|
return TraceManager.instance.add(wrappedTrace.getTrace());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the recording at the given region
|
||||||
|
*
|
||||||
|
* @param region region to stop recording
|
||||||
|
*/
|
||||||
|
public void stopRecording(Region region) {
|
||||||
|
TraceRecordingWrapper wrappedTrace = activeTraces.getOrDefault(region, null);
|
||||||
|
if (wrappedTrace == null) return;
|
||||||
|
|
||||||
|
wrappedTrace.finalizeRecording();
|
||||||
|
|
||||||
|
activeTraces.remove(region);
|
||||||
|
for (TNTPrimed tnt : trackedTNT.getOrDefault(region, Collections.emptyList())) {
|
||||||
|
historyMap.remove(tnt);
|
||||||
|
}
|
||||||
|
trackedTNT.put(region, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal methode to record all tracked TNT Entities
|
||||||
|
*/
|
||||||
|
private void record() {
|
||||||
|
for (Region region : activeTraces.keySet()) {
|
||||||
|
TraceRecordingWrapper wrappedTrace = activeTraces.get(region);
|
||||||
|
for (TNTPrimed tnt : trackedTNT.getOrDefault(region, Collections.emptyList())) {
|
||||||
|
TNTPoint record = record(tnt, wrappedTrace, Collections.emptyList());
|
||||||
|
wrappedTrace.addRecord(record);
|
||||||
|
}
|
||||||
|
wrappedTrace.commitRecorded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal methode to record exploded tnt
|
||||||
|
*
|
||||||
|
* @param tntPrimed tnt exploding
|
||||||
|
* @param wrappedTrace the trace to record the tnt for wrapped with metadata
|
||||||
|
* @param destroyedBlocks the blocks destoryed by the passed tnt
|
||||||
|
* @return the record creaded of the passed tnt
|
||||||
|
*/
|
||||||
|
private TNTPoint record(TNTPrimed tntPrimed, TraceRecordingWrapper wrappedTrace, List<Block> destroyedBlocks) {
|
||||||
|
List<TNTPoint> history = historyMap.getOrDefault(tntPrimed, new ArrayList<>());
|
||||||
|
int tntID;
|
||||||
|
|
||||||
|
if (history.size() == 0) {
|
||||||
|
historyMap.put(tntPrimed, history);
|
||||||
|
tntID = wrappedTrace.getNextOpenRecordIdAndIncrement();
|
||||||
|
} else {
|
||||||
|
tntID = history.get(0).getTntId();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isExplosion = tntPrimed.getFuseTicks() == 0;
|
||||||
|
if (isExplosion) {
|
||||||
|
wrappedTrace.activateExplosionRecorded();
|
||||||
|
}
|
||||||
|
boolean afterFirstExplosion = wrappedTrace.isExplosionRecorded();
|
||||||
|
|
||||||
|
TNTPoint record = new TNTPoint(tntID, tntPrimed, isExplosion, afterFirstExplosion, TPSUtils.currentTick.get() - wrappedTrace.getStartTick(), history, destroyedBlocks);
|
||||||
|
history.add(record);
|
||||||
|
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutoTraceEnabledInRegion(Region region) {
|
||||||
|
return autoTraceRegions.contains(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTraceActiveInRegion(Region region) {
|
||||||
|
return activeTraces.containsKey(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartTimeOfTraceInRegion(Region region) {
|
||||||
|
TraceRecordingWrapper wrapper = activeTraces.get(region);
|
||||||
|
if (wrapper == null) return 0;
|
||||||
|
return wrapper.getStartTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event for TNTs beeing spawn.
|
||||||
|
* Registers newly spawned TNT to be traced if reqired
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||||
|
public void onTNTSpawn(EntitySpawnEvent event) {
|
||||||
|
if (!(event.getEntity() instanceof TNTPrimed)) return;
|
||||||
|
|
||||||
|
Region region = Region.getRegion(event.getLocation());
|
||||||
|
|
||||||
|
if (autoTraceRegions.contains(region) && !activeTraces.containsKey(region)) {
|
||||||
|
startRecording(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeTraces.containsKey(region)) {
|
||||||
|
// Check whether set for tracking already exists. Creating it if necessary
|
||||||
|
if (!trackedTNT.containsKey(region)) {
|
||||||
|
trackedTNT.put(region, new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
trackedTNT.get(region).add((TNTPrimed) event.getEntity());
|
||||||
|
tntSpawnRegion.put((TNTPrimed) event.getEntity(), region);
|
||||||
|
activeTraces.get(region).addRecord(record((TNTPrimed) event.getEntity(), activeTraces.get(region), Collections.emptyList()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event for TNTs exploding
|
||||||
|
* Unregisters TNTs from beeing traced on explode
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
||||||
|
public void onTNTExplode(EntityExplodeEvent event) {
|
||||||
|
if (!(event.getEntity() instanceof TNTPrimed)) return;
|
||||||
|
|
||||||
|
Region region = tntSpawnRegion.getOrDefault((TNTPrimed) event.getEntity(), null);
|
||||||
|
if (region == null) return;
|
||||||
|
trackedTNT.get(region).remove((TNTPrimed) event.getEntity());
|
||||||
|
tntSpawnRegion.remove((TNTPrimed) event.getEntity());
|
||||||
|
|
||||||
|
activeTraces.get(region).addRecord(record((TNTPrimed) event.getEntity(), activeTraces.get(region), event.blockList()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.tracer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
public class TraceRecordingWrapper {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final long startTick;
|
||||||
|
private final List<TNTPoint> recordsToAdd;
|
||||||
|
private final List<TNTPoint> recordList;
|
||||||
|
private final ObjectOutputStream recordsOutputStream;
|
||||||
|
private int nextOpenRecordId = 0;
|
||||||
|
@Getter
|
||||||
|
private boolean explosionRecorded = false;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final Trace trace;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public TraceRecordingWrapper(Region region) {
|
||||||
|
startTick = TPSUtils.currentRealTick.get();
|
||||||
|
recordsToAdd = new ArrayList<>();
|
||||||
|
recordList = new ArrayList<>();
|
||||||
|
|
||||||
|
trace = new Trace(region, recordList);
|
||||||
|
TraceManager.instance.add(trace);
|
||||||
|
File recordsSaveFile = new File(TraceManager.tracesFolder, trace.getUuid() + ".records");
|
||||||
|
recordsOutputStream = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(recordsSaveFile)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNextOpenRecordIdAndIncrement() {
|
||||||
|
return nextOpenRecordId++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activateExplosionRecorded() {
|
||||||
|
explosionRecorded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRecord(TNTPoint record) {
|
||||||
|
recordsToAdd.add(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commitRecorded() {
|
||||||
|
TraceManager.instance.showPartial(trace, recordsToAdd);
|
||||||
|
|
||||||
|
recordsToAdd.forEach(record -> {
|
||||||
|
try {
|
||||||
|
recordsOutputStream.writeObject(record);
|
||||||
|
recordsOutputStream.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
recordList.addAll(recordsToAdd);
|
||||||
|
recordsToAdd.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
protected void finalizeRecording() {
|
||||||
|
recordsOutputStream.flush();
|
||||||
|
recordsOutputStream.close();
|
||||||
|
|
||||||
|
if (trace.getRecords().isEmpty()) {
|
||||||
|
TraceManager.instance.remove(trace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,34 +1,33 @@
|
|||||||
/*
|
/*
|
||||||
* This file is a part of the SteamWar software.
|
* This file is a part of the SteamWar software.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* 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
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* 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/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.steamwar.bausystem.features.tracer;
|
package de.steamwar.bausystem.features.tracer;
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.features.tracer.record.Recorder;
|
import de.steamwar.bausystem.Permission;
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
||||||
import de.steamwar.bausystem.features.tracer.show.StoredRecords;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.utils.ScoreboardElement;
|
import de.steamwar.bausystem.utils.ScoreboardElement;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.Collection;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
public class TraceScoreboardElement implements ScoreboardElement {
|
public class TraceScoreboardElement implements ScoreboardElement {
|
||||||
@ -45,17 +44,18 @@ public class TraceScoreboardElement implements ScoreboardElement {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String get(Region region, Player p) {
|
public String get(Region region, Player p) {
|
||||||
String traceScore = Recorder.INSTANCE.get(region).scoreboard(p);
|
if (!Permission.BUILD.hasPermission(p)) return null;
|
||||||
if (traceScore != null) {
|
if (TraceRecorder.instance.isTraceActiveInRegion(region)) {
|
||||||
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE", p) + "§8: " + traceScore;
|
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE", p) + "§8: " + BauSystem.MESSAGE.parse("TRACE_RECORD", p) + " §8| §e" + (TPSUtils.currentRealTick.get() - TraceRecorder.instance.getStartTimeOfTraceInRegion(region)) + " §7" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE_TICKS", p);
|
||||||
|
} else if (TraceRecorder.instance.isAutoTraceEnabledInRegion(region)) {
|
||||||
|
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE", p) + "§8: " + BauSystem.MESSAGE.parse("TRACE_IDLE_AUTO", p);
|
||||||
}
|
}
|
||||||
List<Record> records = StoredRecords.getRecords(region);
|
|
||||||
if (records.isEmpty()) {
|
Collection<Trace> traces = TraceManager.instance.get(region);
|
||||||
|
if (traces.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
|
} else {
|
||||||
|
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE", p) + "§8: " + BauSystem.MESSAGE.parse("TRACE_HAS_TRACES", p);
|
||||||
}
|
}
|
||||||
if (records.stream().allMatch(record -> record.getTnt().isEmpty())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return "§e" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE", p) + "§8: " + BauSystem.MESSAGE.parse("TRACE_HAS_TRACES", p);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.bausystem.Permission;
|
|
||||||
import de.steamwar.bausystem.SWUtils;
|
|
||||||
import de.steamwar.bausystem.features.tracer.record.*;
|
|
||||||
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import de.steamwar.inventory.SWInventory;
|
|
||||||
import de.steamwar.inventory.SWItem;
|
|
||||||
import de.steamwar.linkage.Linked;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.inventory.ClickType;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
@Linked
|
|
||||||
public class TracerBauGuiItem extends BauGuiItem {
|
|
||||||
|
|
||||||
public TracerBauGuiItem() {
|
|
||||||
super(21);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack getItem(Player player) {
|
|
||||||
Region region = Region.getRegion(player.getLocation());
|
|
||||||
return SWUtils.setCustomModelData(new SWItem(Material.OBSERVER, BauSystem.MESSAGE.parse("TRACE_GUI_ITEM_NAME", player), Arrays.asList(BauSystem.MESSAGE.parse("TRACE_GUI_ITEM_LORE", player, Recorder.INSTANCE.get(region).scoreboard(player))), false, clickType -> {
|
|
||||||
}), 1).getItemStack();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void open(Player p) {
|
|
||||||
Region region = Region.getRegion(p.getLocation());
|
|
||||||
TraceRecorder traceRecorder = Recorder.INSTANCE.get(region);
|
|
||||||
SWInventory inv = new SWInventory(p, 9, BauSystem.MESSAGE.parse("TRACE_GUI_NAME", p));
|
|
||||||
if (traceRecorder instanceof ActiveTracer) {
|
|
||||||
if (traceRecorder instanceof AutoTraceRecorder) {
|
|
||||||
inv.setItem(1, new SWItem(Material.GRAY_DYE, BauSystem.MESSAGE.parse("TRACE_GUI_TRACE_ACTIVE_AUTO", p)));
|
|
||||||
} else {
|
|
||||||
inv.setItem(1, new SWItem(Material.GREEN_DYE, BauSystem.MESSAGE.parse("TRACE_GUI_TRACE_ACTIVE", p), clickType -> {
|
|
||||||
p.performCommand("trace stop");
|
|
||||||
open(p);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
inv.setItem(1, new SWItem(Material.RED_DYE, BauSystem.MESSAGE.parse("TRACE_GUI_TRACE_INACTIVE", p), clickType -> {
|
|
||||||
p.performCommand("trace start");
|
|
||||||
open(p);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
if (traceRecorder instanceof AutoTraceRecorder) {
|
|
||||||
inv.setItem(3, new SWItem(Material.ENDER_EYE, BauSystem.MESSAGE.parse("TRACE_GUI_AUTO_TRACE_ACTIVE", p), clickType -> {
|
|
||||||
p.performCommand("trace auto");
|
|
||||||
open(p);
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
inv.setItem(3, new SWItem(Material.FIREWORK_STAR, BauSystem.MESSAGE.parse("TRACE_GUI_AUTO_TRACE_INACTIVE", p), clickType -> {
|
|
||||||
p.performCommand("trace auto");
|
|
||||||
open(p);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
inv.setItem(7, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("TRACE_GUI_DELETE", p), clickType -> {
|
|
||||||
p.performCommand("trace delete");
|
|
||||||
open(p);
|
|
||||||
}));
|
|
||||||
|
|
||||||
inv.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean click(ClickType click, Player p) {
|
|
||||||
open(p);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Permission permission() {
|
|
||||||
return Permission.BUILD;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
public interface ActiveTracer {
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
public class AutoExplodeTraceRecorder extends AutoTraceRecorder {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getInactivityMessage() {
|
|
||||||
return "TRACE_IDLE_AUTO_EXPLODE";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldStartRecording(StartType startType) {
|
|
||||||
return startType == StartType.EXPLODE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getScriptState() {
|
|
||||||
return "IDLE_AUTO_EXPLODE";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
public class AutoIgniteTraceRecorder extends AutoTraceRecorder implements ActiveTracer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getInactivityMessage() {
|
|
||||||
return "TRACE_IDLE_AUTO_IGNITE";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldStartRecording(StartType startType) {
|
|
||||||
return startType == StartType.IGNITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getScriptState() {
|
|
||||||
return "IDLE_AUTO_IGNITE";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.StoredRecords;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.TraceShowManager;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public abstract class AutoTraceRecorder implements TraceRecorder {
|
|
||||||
|
|
||||||
protected boolean recording = false;
|
|
||||||
private long startTime = TPSUtils.currentRealTick.get();
|
|
||||||
private long lastExplosion = 0;
|
|
||||||
|
|
||||||
private final Map<TNTPrimed, Record.TNTRecord> recordMap = new HashMap<>();
|
|
||||||
private Record record;
|
|
||||||
|
|
||||||
private Region region;
|
|
||||||
private Supplier<Record> recordSupplier;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
private TraceRecordAutoDeletion traceRecordAutoDeletion = TraceRecordAutoDeletion.NEVER;
|
|
||||||
private Record lastRecord;
|
|
||||||
|
|
||||||
private Record.TNTRecord getRecord(TNTPrimed tntPrimed) {
|
|
||||||
return recordMap.computeIfAbsent(tntPrimed, __ -> record.spawn());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract String getInactivityMessage();
|
|
||||||
protected abstract boolean shouldStartRecording(StartType startType);
|
|
||||||
protected void stoppedRecording() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final String scoreboard(Player player) {
|
|
||||||
if (recording) {
|
|
||||||
return BauSystem.MESSAGE.parse("TRACE_RECORD", player) + " §8| §e" + (TPSUtils.currentRealTick.get() - startTime) + " §7" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE_TICKS", player);
|
|
||||||
} else {
|
|
||||||
return BauSystem.MESSAGE.parse(getInactivityMessage(), player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startRecording() {
|
|
||||||
if (lastRecord != null && traceRecordAutoDeletion.test(lastRecord)) {
|
|
||||||
StoredRecords.remove(region, lastRecord);
|
|
||||||
TraceShowManager.reshow(region);
|
|
||||||
}
|
|
||||||
lastExplosion = 0;
|
|
||||||
startTime = TPSUtils.currentRealTick.get();
|
|
||||||
record = recordSupplier.get();
|
|
||||||
recording = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Region region, Supplier<Record> recordSupplier) {
|
|
||||||
this.region = region;
|
|
||||||
this.recordSupplier = recordSupplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postClear() {
|
|
||||||
recordMap.clear();
|
|
||||||
record = recordSupplier.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void spawn(TNTPrimed tntPrimed) {
|
|
||||||
if (!recording && shouldStartRecording(StartType.IGNITE)) {
|
|
||||||
startRecording();
|
|
||||||
}
|
|
||||||
if (recording) {
|
|
||||||
getRecord(tntPrimed).source(tntPrimed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void tick(TNTPrimed tntPrimed) {
|
|
||||||
if (recording) {
|
|
||||||
getRecord(tntPrimed).location(tntPrimed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void explode(TNTPrimed tntPrimed, boolean inBuildRegion, boolean inTestblockRegion) {
|
|
||||||
if (!recording && shouldStartRecording(StartType.EXPLODE)) {
|
|
||||||
startRecording();
|
|
||||||
}
|
|
||||||
if (recording) {
|
|
||||||
Record.TNTRecord tntRecord = getRecord(tntPrimed);
|
|
||||||
if (inBuildRegion) tntRecord.setInBuildArea(true);
|
|
||||||
if (inTestblockRegion) tntRecord.setInTestblockArea(true);
|
|
||||||
tntRecord.explode(tntPrimed);
|
|
||||||
}
|
|
||||||
lastExplosion = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void tick() {
|
|
||||||
lastExplosion++;
|
|
||||||
if (recording && lastExplosion > 80) {
|
|
||||||
recording = false;
|
|
||||||
recordMap.clear();
|
|
||||||
lastRecord = record;
|
|
||||||
record = null;
|
|
||||||
stoppedRecording();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected enum StartType {
|
|
||||||
IGNITE,
|
|
||||||
EXPLODE
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract String getScriptState();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String scriptState() {
|
|
||||||
return recording ? "RECORDING" : getScriptState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long scriptTime() {
|
|
||||||
return TPSUtils.currentRealTick.get() - startTime;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,160 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.StoredRecords;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
|
||||||
import de.steamwar.bausystem.region.utils.RegionType;
|
|
||||||
import de.steamwar.linkage.Linked;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
|
||||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Linked
|
|
||||||
public class Recorder implements Listener {
|
|
||||||
|
|
||||||
public static Recorder INSTANCE;
|
|
||||||
|
|
||||||
{
|
|
||||||
INSTANCE = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class DisabledTracerRecorder implements TraceRecorder {
|
|
||||||
@Override
|
|
||||||
public String scoreboard(Player player) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void spawn(TNTPrimed tntPrimed) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick(TNTPrimed tntPrimed) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void explode(TNTPrimed tntPrimed, boolean inBuildArea, boolean inTestblockRegion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String scriptState() {
|
|
||||||
return "IDLE";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long scriptTime() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private static final DisabledTracerRecorder DISABLED = new DisabledTracerRecorder();
|
|
||||||
|
|
||||||
private Map<Region, TraceRecorder> regionTraceRecorderMap = new HashMap<>();
|
|
||||||
private Map<TNTPrimed, Region> tntTraceRecorderMap = new HashMap<>();
|
|
||||||
|
|
||||||
private TraceRecorder get(TNTPrimed tntPrimed) {
|
|
||||||
return get(tntTraceRecorderMap.computeIfAbsent(tntPrimed, e -> Region.getRegion(e.getLocation())));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDisabled(Region region) {
|
|
||||||
return !regionTraceRecorderMap.containsKey(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TraceRecorder get(Region region) {
|
|
||||||
return regionTraceRecorderMap.getOrDefault(region, DISABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void set(Region region, TraceRecorder traceRecorder) {
|
|
||||||
regionTraceRecorderMap.put(region, traceRecorder);
|
|
||||||
traceRecorder.init(region, () -> {
|
|
||||||
Record record = new Record(region);
|
|
||||||
StoredRecords.add(region, record);
|
|
||||||
return record;
|
|
||||||
});
|
|
||||||
tntTraceRecorderMap.forEach((tntPrimed, rg) -> {
|
|
||||||
if (rg == region) {
|
|
||||||
traceRecorder.spawn(tntPrimed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove(Region region) {
|
|
||||||
regionTraceRecorderMap.remove(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void postClear(Region region) {
|
|
||||||
get(region).postClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onEntitySpawn(EntitySpawnEvent event) {
|
|
||||||
Entity entity = event.getEntity();
|
|
||||||
if (!(entity instanceof TNTPrimed)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
get((TNTPrimed) entity).spawn((TNTPrimed) entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
BauSystem.runTaskTimer(BauSystem.getInstance(), () -> {
|
|
||||||
tick();
|
|
||||||
tntTraceRecorderMap.keySet()
|
|
||||||
.stream()
|
|
||||||
.filter(e -> !e.isValid())
|
|
||||||
.collect(Collectors.toList())
|
|
||||||
.forEach(tntTraceRecorderMap::remove);
|
|
||||||
new ArrayList<>(regionTraceRecorderMap.values()).forEach(TraceRecorder::tick);
|
|
||||||
}, 1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tick() {
|
|
||||||
TNTPrimedIterator.impl.iterator().forEach(tntPrimed -> {
|
|
||||||
get(tntPrimed).tick(tntPrimed);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
|
||||||
public void onEntityExplode(EntityExplodeEvent event) {
|
|
||||||
Entity entity = event.getEntity();
|
|
||||||
if (!(entity instanceof TNTPrimed)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TraceRecorder traceRecorder = get((TNTPrimed) entity);
|
|
||||||
Region region = tntTraceRecorderMap.get((TNTPrimed) entity);
|
|
||||||
boolean inBuildRegion = event.blockList().stream().anyMatch(block -> region.inRegion(block.getLocation(), RegionType.BUILD, RegionExtensionType.EXTENSION));
|
|
||||||
boolean inTestblockRegion = event.blockList().stream().anyMatch(block -> region.inRegion(block.getLocation(), RegionType.TESTBLOCK, RegionExtensionType.EXTENSION));
|
|
||||||
traceRecorder.explode((TNTPrimed) entity, inBuildRegion, inTestblockRegion);
|
|
||||||
tntTraceRecorderMap.remove(entity);
|
|
||||||
tick();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public class SimpleTraceRecorder implements TraceRecorder, ActiveTracer {
|
|
||||||
|
|
||||||
private final long startTime = TPSUtils.currentRealTick.get();
|
|
||||||
private final Map<TNTPrimed, Record.TNTRecord> recordMap = new HashMap<>();
|
|
||||||
private Record record;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String scoreboard(Player player) {
|
|
||||||
return BauSystem.MESSAGE.parse("TRACE_RECORD", player) + " §8| §e" + (TPSUtils.currentRealTick.get() - startTime) + " §7" + BauSystem.MESSAGE.parse("SCOREBOARD_TRACE_TICKS", player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(Region region, Supplier<Record> recordSupplier) {
|
|
||||||
record = recordSupplier.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postClear() {
|
|
||||||
recordMap.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Record.TNTRecord getRecord(TNTPrimed tntPrimed) {
|
|
||||||
return recordMap.computeIfAbsent(tntPrimed, __ -> record.spawn());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void spawn(TNTPrimed tntPrimed) {
|
|
||||||
getRecord(tntPrimed).source(tntPrimed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick(TNTPrimed tntPrimed) {
|
|
||||||
getRecord(tntPrimed).location(tntPrimed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void explode(TNTPrimed tntPrimed, boolean inBuildRegion, boolean inTestblockRegion) {
|
|
||||||
Record.TNTRecord tntRecord = getRecord(tntPrimed);
|
|
||||||
if (inBuildRegion) tntRecord.setInBuildArea(true);
|
|
||||||
if (inTestblockRegion) tntRecord.setInTestblockArea(true);
|
|
||||||
tntRecord.explode(tntPrimed);
|
|
||||||
recordMap.remove(tntPrimed);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String scriptState() {
|
|
||||||
return "RECORD";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long scriptTime() {
|
|
||||||
return TPSUtils.currentRealTick.get() - startTime;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
|
|
||||||
public class SingleTraceRecorder extends AutoTraceRecorder {
|
|
||||||
|
|
||||||
private Region region;
|
|
||||||
|
|
||||||
public SingleTraceRecorder(Region region) {
|
|
||||||
this.region = region;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getInactivityMessage() {
|
|
||||||
return "TRACE_IDLE_SINGLE";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldStartRecording(StartType startType) {
|
|
||||||
return startType == StartType.IGNITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void stoppedRecording() {
|
|
||||||
Recorder.INSTANCE.remove(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getScriptState() {
|
|
||||||
return "IDLE_SINGLE";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.core.VersionDependent;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public interface TNTPrimedIterator {
|
|
||||||
TNTPrimedIterator impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
|
|
||||||
|
|
||||||
Stream<TNTPrimed> iterator();
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2023 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.tracer.record;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
|
||||||
|
|
||||||
public enum TraceRecordAutoDeletion {
|
|
||||||
|
|
||||||
ALWAYS {
|
|
||||||
@Override
|
|
||||||
public boolean test(Record record) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NEVER {
|
|
||||||
@Override
|
|
||||||
public boolean test(Record record) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NO_BUILD_DESTROY {
|
|
||||||
@Override
|
|
||||||
public boolean test(Record record) {
|
|
||||||
return record.getTnt().stream().noneMatch(Record.TNTRecord::isInBuildArea);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
BUILD_DESTROY {
|
|
||||||
@Override
|
|
||||||
public boolean test(Record record) {
|
|
||||||
return record.getTnt().stream().anyMatch(Record.TNTRecord::isInBuildArea);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
NO_TESTBLOCK_DESTROY {
|
|
||||||
@Override
|
|
||||||
public boolean test(Record record) {
|
|
||||||
return record.getTnt().stream().noneMatch(Record.TNTRecord::isInTestblockArea);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TESTBLOCK_DESTROY {
|
|
||||||
@Override
|
|
||||||
public boolean test(Record record) {
|
|
||||||
return record.getTnt().stream().anyMatch(Record.TNTRecord::isInTestblockArea);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
;
|
|
||||||
|
|
||||||
public abstract boolean test(Record record);
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.record;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.tracer.show.Record;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public interface TraceRecorder {
|
|
||||||
|
|
||||||
String scoreboard(Player player);
|
|
||||||
default void init(Region region, Supplier<Record> recordSupplier) {
|
|
||||||
}
|
|
||||||
default void postClear() {
|
|
||||||
}
|
|
||||||
void spawn(TNTPrimed tntPrimed);
|
|
||||||
void tick(TNTPrimed tntPrimed);
|
|
||||||
void explode(TNTPrimed tntPrimed, boolean inBuildRegion, boolean inTestblockRegion);
|
|
||||||
default void tick() {
|
|
||||||
}
|
|
||||||
|
|
||||||
String scriptState();
|
|
||||||
long scriptTime();
|
|
||||||
}
|
|
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.tracer.rendering;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Comparator for determining whether two records should be bundled
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public enum BundleFilter {
|
||||||
|
|
||||||
|
LOOSE((TNTPoint a, TNTPoint b) -> {
|
||||||
|
if (a.isExplosion() != b.isExplosion()) return false;
|
||||||
|
if (a.getLocation().distanceSquared(b.getLocation()) > BundleFilter.pixelSizeSquared * 8) return false;
|
||||||
|
if (a.getVelocity().distanceSquared(b.getVelocity()) > BundleFilter.pixelSizeSquared * 8) return false;
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
|
|
||||||
|
DEFAULT((TNTPoint a, TNTPoint b) -> {
|
||||||
|
if (a.isExplosion() != b.isExplosion()) return false;
|
||||||
|
if (a.getTicksSinceStart() != b.getTicksSinceStart()) return null;
|
||||||
|
if (a.getLocation().distanceSquared(b.getLocation()) > BundleFilter.pixelSizeSquared) return false;
|
||||||
|
if (a.getVelocity().distanceSquared(b.getVelocity()) > BundleFilter.pixelSizeSquared) return false;
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
|
|
||||||
|
RAW((TNTPoint a, TNTPoint b) -> {
|
||||||
|
if (a.isExplosion() != b.isExplosion()) return false;
|
||||||
|
if (!a.getLocation().equals(b.getLocation())) return false;
|
||||||
|
if (!a.getVelocity().equals(b.getVelocity())) return false;
|
||||||
|
if (a.getTicksSinceStart() != b.getTicksSinceStart()) return null;
|
||||||
|
return true;
|
||||||
|
}),
|
||||||
|
|
||||||
|
NONE((TNTPoint a, TNTPoint b) -> {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@code null}: Bundling can be stopped from this point forward
|
||||||
|
* {@code false}: No bundling allowed
|
||||||
|
* {@code true}: Bundling should be applied
|
||||||
|
*/
|
||||||
|
public final BiFunction<TNTPoint, TNTPoint, Boolean> function;
|
||||||
|
|
||||||
|
private static final double pixelSize = 0.0625;
|
||||||
|
private static final double pixelSizeSquared = pixelSize * pixelSize;
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.tracer.rendering;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A holder for the view data of a player trace render
|
||||||
|
*/
|
||||||
|
public class PlayerTraceShowData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bundle filter applied by this class
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
private BundleFilter bundleFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A map for stating whether a flag is contained in this holder or not
|
||||||
|
*/
|
||||||
|
private final Map<Class<? extends ViewFlag>, ViewFlag> viewFlags = new HashMap<>();
|
||||||
|
|
||||||
|
public PlayerTraceShowData(BundleFilter bundleFilter, ViewFlag... viewFlags) {
|
||||||
|
this.bundleFilter = bundleFilter;
|
||||||
|
for (ViewFlag viewFlag : viewFlags) {
|
||||||
|
this.viewFlags.put(viewFlag.getClass(), viewFlag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A methode that returns the flags that should be used by renders according
|
||||||
|
* to this holder. Especially handles inverse and required flags
|
||||||
|
*
|
||||||
|
* @return the flags that should be used in a render according to this holder
|
||||||
|
*/
|
||||||
|
public Set<ViewFlag> getEffectiveViewFlags() {
|
||||||
|
// Manage flags and required flags
|
||||||
|
Set<ViewFlag> flagList = new HashSet<>();
|
||||||
|
for (ViewFlag flag : viewFlags.values()) {
|
||||||
|
flagList.add(flag);
|
||||||
|
if (flag.required != null) {
|
||||||
|
flagList.addAll(Arrays.asList(flag.required));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manage inverse flags
|
||||||
|
ViewFlag.inverseFlags.forEach(viewFlag -> {
|
||||||
|
if (!flagList.remove(viewFlag)) {
|
||||||
|
flagList.add(viewFlag);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return flagList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNoViewFlags() {
|
||||||
|
return viewFlags.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasViewFlag(Class<? extends ViewFlag> clazz) {
|
||||||
|
return viewFlags.containsKey(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasViewFlagOnly(Class<? extends ViewFlag> clazz) {
|
||||||
|
return viewFlags.containsKey(clazz) && viewFlags.size() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO ?
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends ViewFlag> T getViewFlag(Class<T> clazz) {
|
||||||
|
return (T) viewFlags.get(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addViewFlag(ViewFlag viewFlag) {
|
||||||
|
viewFlags.put(viewFlag.getClass(), viewFlag);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.tracer.rendering;
|
||||||
|
|
||||||
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||||
|
import de.steamwar.bausystem.features.tracer.Trace;
|
||||||
|
import de.steamwar.bausystem.features.tracer.TraceManager;
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import de.steamwar.entity.REntity;
|
||||||
|
import de.steamwar.entity.REntityServer;
|
||||||
|
import de.steamwar.techhider.BlockIds;
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.EntityType;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for the rendering of a record bundle
|
||||||
|
*/
|
||||||
|
public class TraceEntity extends REntity {
|
||||||
|
|
||||||
|
private static final Reflection.MethodInvoker addEntityMethod = Reflection.getMethod(REntityServer.class, "addEntity", REntity.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The records represented by this REntity
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private final List<TNTPoint> records;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A string of all unique tnt records
|
||||||
|
*/
|
||||||
|
private final String uniqueTntIdsString;
|
||||||
|
|
||||||
|
private final Trace trace;
|
||||||
|
|
||||||
|
public TraceEntity(REntityServer server, Location location, boolean isExplosion, List<TNTPoint> records, Trace trace) {
|
||||||
|
super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(isExplosion ? Material.RED_STAINED_GLASS : Material.TNT) >> (Core.getVersion() <= 12 ? 4 : 0));
|
||||||
|
setNoGravity(true);
|
||||||
|
this.records = records;
|
||||||
|
uniqueTntIdsString = records.stream().map(TNTPoint::getTntId).distinct().map(Object::toString).collect(Collectors.joining(" "));
|
||||||
|
this.trace = trace;
|
||||||
|
addEntityMethod.invoke(server, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message for printing the data contained in this wrapper into player chat
|
||||||
|
*
|
||||||
|
* @param player the player the message should be printed for
|
||||||
|
*/
|
||||||
|
public void printIntoChat(Player player) {
|
||||||
|
TNTPoint representative = records.get(0);
|
||||||
|
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_HEADER", player);
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_FUSE_TIME", player, representative.getFuse());
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_X", player, representative.getLocation().getX() + "");
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Y", player, representative.getLocation().getY() + "");
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Z", player, representative.getLocation().getZ() + "");
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_X", player, representative.getVelocity().getX() + "");
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Y", player, representative.getVelocity().getY() + "");
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Z", player, representative.getVelocity().getZ() + "");
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_ISOLATE", player, BauSystem.MESSAGE.parse("TRACE_MESSAGE_CLICK_ISOLATE", player), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/trace isolate " + TraceManager.instance.getId(trace) + " " + uniqueTntIdsString));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (!(object instanceof TraceEntity)) return false;
|
||||||
|
TraceEntity entity = (TraceEntity) object;
|
||||||
|
return records.get(0).equals(entity.getRecords().get(0));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.tracer.rendering;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||||
|
import de.steamwar.entity.REntityServer;
|
||||||
|
import de.steamwar.entity.RFallingBlockEntity;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A settable flag that changes how a trace is rendered
|
||||||
|
*/
|
||||||
|
public abstract class ViewFlag {
|
||||||
|
/**
|
||||||
|
* Static registry of static flags
|
||||||
|
*/
|
||||||
|
public static final List<ViewFlag> flags = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inverse flags are used by trace render by default, as long as they are not explicitly added as argument
|
||||||
|
*/
|
||||||
|
public static final List<ViewFlag> inverseFlags = new ArrayList<>();
|
||||||
|
|
||||||
|
public static ViewFlag EXPLOSION = new ViewFlag(true, false, "explosion", "e") {
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
return records.filter(TNTPoint::isExplosion);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag IGNITE = new ViewFlag(true, true, "ignite", "i") {
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
return records.filter(record -> record.isAfterFirstExplosion());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag SOURCE = new ViewFlag(true, false, IGNITE, "source", "s") {
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
return records.filter(record -> record.getFuse() == 80);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag BUILD_DESTROY_ONLY = new ViewFlag(true, false, "build-destroy-only") {
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
return records.filter(record -> record.getHistory().get(record.getHistory().size() - 1).isDestroyedBuildArea());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag TESTBLOCK_DESTROY_ONLY = new ViewFlag(true, false, "testblock-destroy-only") {
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
return records.filter(record -> record.getHistory().get(record.getHistory().size() - 1).isDestroyedTestBlock());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag MICROMOTION = new ViewFlag(true, false, "micromotion", "m") {
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> stream) {
|
||||||
|
List<TNTPoint> records = stream.collect(Collectors.toList());
|
||||||
|
;
|
||||||
|
Set<Integer> seen = new HashSet<>();
|
||||||
|
Set<TNTPoint> toRemove = new HashSet<>();
|
||||||
|
|
||||||
|
for (TNTPoint uniqueRecord : records) {
|
||||||
|
if (seen.contains(uniqueRecord.getTntId())) continue;
|
||||||
|
|
||||||
|
boolean hasMicromotion = false;
|
||||||
|
for (TNTPoint record : uniqueRecord.getHistory()) {
|
||||||
|
Vector velocity = record.getVelocity();
|
||||||
|
if (velocity.getY() == 0 && (Math.abs(velocity.getX()) < 0.001 || Math.abs(velocity.getZ()) < 0.001)) {
|
||||||
|
hasMicromotion = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasMicromotion)
|
||||||
|
toRemove.add(uniqueRecord);
|
||||||
|
|
||||||
|
seen.add(uniqueRecord.getTntId());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TNTPoint record : toRemove) {
|
||||||
|
records.removeAll(record.getHistory());
|
||||||
|
}
|
||||||
|
|
||||||
|
return records.stream();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag ADVANCED = new ViewFlag(true, false, "advanced", "a") {
|
||||||
|
@Override
|
||||||
|
public void modify(REntityServer server, List<TraceEntity> entities) {
|
||||||
|
for (TraceEntity entity : entities) {
|
||||||
|
TNTPoint current = entity.getRecords().get(0);
|
||||||
|
if (current.isExplosion()) continue;
|
||||||
|
TNTPoint next = current.getNext().orElse(null);
|
||||||
|
if (next == null) continue;
|
||||||
|
|
||||||
|
Location pos = current.getLocation().clone();
|
||||||
|
pos.setY(next.getLocation().getY());
|
||||||
|
|
||||||
|
if (pos.distanceSquared(current.getLocation()) >= 1.0 / 256.0) {
|
||||||
|
RFallingBlockEntity y = new RFallingBlockEntity(server, pos, Material.WHITE_STAINED_GLASS);
|
||||||
|
y.setNoGravity(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.getVelocity().getX() >= current.getVelocity().getZ()) {
|
||||||
|
pos.setX(next.getLocation().getX());
|
||||||
|
} else {
|
||||||
|
pos.setZ(next.getLocation().getZ());
|
||||||
|
}
|
||||||
|
if (pos.distanceSquared(next.getLocation()) >= 1.0 / 256.0) {
|
||||||
|
RFallingBlockEntity second = new RFallingBlockEntity(server, pos, Material.WHITE_STAINED_GLASS);
|
||||||
|
second.setNoGravity(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag COUNT = new ViewFlag(true, false, "count", "c") {
|
||||||
|
@Override
|
||||||
|
public void modify(REntityServer server, List<TraceEntity> entities) {
|
||||||
|
for (TraceEntity entity : entities) {
|
||||||
|
entity.setDisplayName(String.valueOf(entity.getRecords().size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag FUSE = new ViewFlag(true, false, "fuse", "f") {
|
||||||
|
@Override
|
||||||
|
public void modify(REntityServer server, List<TraceEntity> entities) {
|
||||||
|
for (TraceEntity entity : entities) {
|
||||||
|
List<String> fuses = entity.getRecords()
|
||||||
|
.stream()
|
||||||
|
.map(TNTPoint::getFuse)
|
||||||
|
.distinct()
|
||||||
|
.sorted()
|
||||||
|
.map(i -> i + "")
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (fuses.size() <= 5) {
|
||||||
|
entity.setDisplayName(String.join(",", fuses));
|
||||||
|
} else {
|
||||||
|
entity.setDisplayName(fuses.stream().limit(5).collect(Collectors.joining(",")) + ", +" + (fuses.size() - 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static ViewFlag TIME = new ViewFlag(true, false, "time", "t") {
|
||||||
|
@Override
|
||||||
|
public void modify(REntityServer server, List<TraceEntity> entities) {
|
||||||
|
for (TraceEntity entity : entities) {
|
||||||
|
List<String> time = entity.getRecords()
|
||||||
|
.stream()
|
||||||
|
.map(TNTPoint::getTicksSinceStart)
|
||||||
|
.distinct()
|
||||||
|
.sorted()
|
||||||
|
.map(i -> i + "")
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (time.size() <= 5) {
|
||||||
|
entity.setDisplayName(String.join(",", time));
|
||||||
|
} else {
|
||||||
|
entity.setDisplayName(time.stream().limit(5).collect(Collectors.joining(",")) + ", +" + (time.size() - 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the flag
|
||||||
|
*/
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aliases of the flag
|
||||||
|
*/
|
||||||
|
public final String[] aliases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag that is used whenever this flag is used
|
||||||
|
*/
|
||||||
|
public final ViewFlag[] required;
|
||||||
|
|
||||||
|
protected ViewFlag(boolean isStatic, boolean isInverse, String name, String... aliases) {
|
||||||
|
this(isStatic, isInverse, new ViewFlag[0], name, aliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ViewFlag(boolean isStatic, boolean isInverse, ViewFlag required, String name, String... aliases) {
|
||||||
|
this(isStatic, isInverse, new ViewFlag[]{required}, name, aliases);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ViewFlag(boolean isStatic, boolean isInverse, ViewFlag[] required, String name, String... aliases) {
|
||||||
|
this.name = name;
|
||||||
|
this.aliases = aliases;
|
||||||
|
if (isStatic) flags.add(this);
|
||||||
|
if (isInverse) inverseFlags.add(this);
|
||||||
|
this.required = required;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filters the given records for a given condition
|
||||||
|
*
|
||||||
|
* @param records Records to be filtered
|
||||||
|
* @return Filtered records
|
||||||
|
*/
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifies the trace rendering
|
||||||
|
*
|
||||||
|
* @param server the server the trace is rendered on
|
||||||
|
* @param entities the entities representing tnts
|
||||||
|
*/
|
||||||
|
public void modify(REntityServer server, List<TraceEntity> entities) {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.tracer.rendering.dynamicflags;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.ViewFlag;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A view flag for rendering a trace only in a given time intervall
|
||||||
|
*/
|
||||||
|
public class AtFlag extends ViewFlag {
|
||||||
|
/**
|
||||||
|
* Start of the time interval
|
||||||
|
*/
|
||||||
|
private int start;
|
||||||
|
/**
|
||||||
|
* End of the time interval
|
||||||
|
*/
|
||||||
|
private int end;
|
||||||
|
|
||||||
|
public AtFlag(int start, int end) {
|
||||||
|
super(false, false, ViewFlag.IGNITE, null);
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update this flag to represent another time interval
|
||||||
|
*
|
||||||
|
* @param start new interval start
|
||||||
|
* @param end new interval end
|
||||||
|
*/
|
||||||
|
public void update(int start, int end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
return records.filter(record -> record.getTicksSinceStart() >= start && record.getTicksSinceStart() <= end);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* This file is a part of the SteamWar software.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 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.tracer.rendering.dynamicflags;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.features.tracer.TNTPoint;
|
||||||
|
import de.steamwar.bausystem.features.tracer.rendering.ViewFlag;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A flag for rendering only the records of specific tnts
|
||||||
|
*/
|
||||||
|
public class IsolateFlag extends ViewFlag {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tnt ids that will be isolated
|
||||||
|
*/
|
||||||
|
private final Set<Integer> tntToIsolate = new HashSet<>();
|
||||||
|
|
||||||
|
public IsolateFlag() {
|
||||||
|
super(false, false, ViewFlag.IGNITE, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the given id to be or not to be rendered
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
public void toggleId(int id) {
|
||||||
|
if (!tntToIsolate.remove(id)) {
|
||||||
|
tntToIsolate.add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
|
||||||
|
if (tntToIsolate.isEmpty()) return records;
|
||||||
|
return records.filter(record -> tntToIsolate.contains(record.getTntId()));
|
||||||
|
}
|
||||||
|
}
|
@ -1,268 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2023 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.tracer.show;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.bausystem.features.tracer.TNTPosition;
|
|
||||||
import de.steamwar.bausystem.shared.RoundedPosition;
|
|
||||||
import de.steamwar.bausystem.shared.ShowMode;
|
|
||||||
import de.steamwar.bausystem.utils.FlatteningWrapper;
|
|
||||||
import de.steamwar.entity.REntity;
|
|
||||||
import de.steamwar.entity.REntityServer;
|
|
||||||
import de.steamwar.entity.RFallingBlockEntity;
|
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class EntityShowMode implements ShowMode<TNTPosition> {
|
|
||||||
|
|
||||||
private final int factor;
|
|
||||||
private final Player player;
|
|
||||||
private final ShowModeParameter showModeParameter;
|
|
||||||
|
|
||||||
private REntityServer entityServer;
|
|
||||||
|
|
||||||
private final Map<RoundedPosition, EntityStack> tntEntityMap = new HashMap<>();
|
|
||||||
private final Map<RoundedPosition, EntityStack> explodeEntityMap = new HashMap<>();
|
|
||||||
private final Map<RoundedPosition, EntityStack> updateEntityMap = new HashMap<>();
|
|
||||||
|
|
||||||
public EntityShowMode(Player player, ShowModeParameter showModeParameter, int factor) {
|
|
||||||
this.player = player;
|
|
||||||
this.showModeParameter = showModeParameter;
|
|
||||||
this.factor = factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void show(TNTPosition position) {
|
|
||||||
if (entityServer == null) {
|
|
||||||
entityServer = new REntityServer();
|
|
||||||
entityServer.setCallback((player, rEntity, entityAction) -> {
|
|
||||||
if (entityAction != REntityServer.EntityAction.INTERACT) return;
|
|
||||||
TNTPosition tntPosition = Stream.concat(tntEntityMap.values().stream(), explodeEntityMap.values().stream())
|
|
||||||
.filter(entityStack -> entityStack.entity == rEntity)
|
|
||||||
.findFirst()
|
|
||||||
.map(entityStack -> entityStack.tntPosition)
|
|
||||||
.orElse(null);
|
|
||||||
if (tntPosition == null) return;
|
|
||||||
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_HEADER", player);
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_FUSE_TIME", player, tntPosition.getFuseTicks());
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_X", player, tntPosition.getLocation().getX() + "");
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Y", player, tntPosition.getLocation().getY() + "");
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_POSITION_Z", player, tntPosition.getLocation().getZ() + "");
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_X", player, tntPosition.getVelocity().getX() + "");
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Y", player, tntPosition.getVelocity().getY() + "");
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_VELOCITY_Z", player, tntPosition.getVelocity().getZ() + "");
|
|
||||||
BauSystem.MESSAGE.sendPrefixless("TNT_CLICK_ISOLATE", player, BauSystem.MESSAGE.parse("TRACE_MESSAGE_CLICK_ISOLATE", player), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/trace isolate " + tntPosition.getRecord().getId()));
|
|
||||||
});
|
|
||||||
entityServer.addPlayer(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showModeParameter.isBuildDestroyOnly() && !position.getRecord().isInBuildArea()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showModeParameter.isTestblockDestroyOnly() && !position.getRecord().isInTestblockArea()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showModeParameter.isMicroMotion() && !position.getRecord().isHasMicroMotion()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean exploded = position.getRecord().getPositions().stream().anyMatch(TNTPosition::isExploded);
|
|
||||||
boolean hideWater = !showModeParameter.isWater() && exploded && checkWater(position.getLocation());
|
|
||||||
|
|
||||||
if (showModeParameter.isExplodeOnly()) {
|
|
||||||
if (position.isExploded()) {
|
|
||||||
generatePositions(position, false, false);
|
|
||||||
}
|
|
||||||
if (!showModeParameter.isSourceOnly() && !showModeParameter.isMicroMotionLocation() && !hideWater) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showModeParameter.isSourceOnly()) {
|
|
||||||
if (position.isSource()) {
|
|
||||||
generatePositions(position, false, false);
|
|
||||||
}
|
|
||||||
if (!showModeParameter.isMicroMotionLocation() && !hideWater) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showModeParameter.isMicroMotionLocation()) {
|
|
||||||
if (position.isMicroMotion()) {
|
|
||||||
generatePositions(position, false, false);
|
|
||||||
}
|
|
||||||
if (!hideWater) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (hideWater) {
|
|
||||||
if (position.isExploded()) {
|
|
||||||
for (TNTPosition pos : position.getRecord().getPositions()) {
|
|
||||||
generatePositions(pos, showModeParameter.isInterpolateY(), showModeParameter.isInterpolateXZ(), (positionType, vector) -> {
|
|
||||||
RoundedPosition roundedPosition = new RoundedPosition(vector, factor);
|
|
||||||
Map<RoundedPosition, EntityStack> map;
|
|
||||||
if (positionType == PositionType.TNT) {
|
|
||||||
map = tntEntityMap;
|
|
||||||
} else if (positionType == PositionType.EXPLODE) {
|
|
||||||
map = explodeEntityMap;
|
|
||||||
} else {
|
|
||||||
map = updateEntityMap;
|
|
||||||
}
|
|
||||||
map.computeIfPresent(roundedPosition, (roundedPosition1, entityStack) -> {
|
|
||||||
if (!entityStack.remove(pos.getRecord())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return entityStack;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
generatePositions(position, showModeParameter.isInterpolateY(), showModeParameter.isInterpolateXZ());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void hide() {
|
|
||||||
tntEntityMap.clear();
|
|
||||||
explodeEntityMap.clear();
|
|
||||||
updateEntityMap.clear();
|
|
||||||
if (entityServer != null) {
|
|
||||||
entityServer.close();
|
|
||||||
entityServer = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void generatePositions(TNTPosition position, boolean interpolateY, boolean interpolateXZ) {
|
|
||||||
generatePositions(position, interpolateY, interpolateXZ, (positionType, vector) -> {
|
|
||||||
RoundedPosition roundedPosition = new RoundedPosition(vector, factor);
|
|
||||||
EntityStack entityStack;
|
|
||||||
if (positionType == PositionType.TNT) {
|
|
||||||
entityStack = tntEntityMap.computeIfAbsent(roundedPosition, i -> new EntityStack(position, vector, positionType, position.getFuseTicks()));
|
|
||||||
} else if (positionType == PositionType.EXPLODE) {
|
|
||||||
entityStack = explodeEntityMap.computeIfAbsent(roundedPosition, i -> new EntityStack(position, vector, positionType, position.getFuseTicks()));
|
|
||||||
} else {
|
|
||||||
entityStack = updateEntityMap.computeIfAbsent(roundedPosition, i -> new EntityStack(position, vector, positionType, position.getFuseTicks()));
|
|
||||||
}
|
|
||||||
entityStack.add(position.getRecord());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkWater(Vector position) {
|
|
||||||
return FlatteningWrapper.impl.inWater(player.getWorld(), position);
|
|
||||||
}
|
|
||||||
|
|
||||||
private REntity createEntity(Vector position, PositionType positionType) {
|
|
||||||
Material material;
|
|
||||||
if (positionType == PositionType.TNT) {
|
|
||||||
material = Material.TNT;
|
|
||||||
} else if (positionType == PositionType.EXPLODE) {
|
|
||||||
material = Material.RED_STAINED_GLASS;
|
|
||||||
} else {
|
|
||||||
material = Material.WHITE_STAINED_GLASS;
|
|
||||||
}
|
|
||||||
RFallingBlockEntity entity = new RFallingBlockEntity(entityServer, position.toLocation(player.getWorld()), material);
|
|
||||||
entity.setNoGravity(true);
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class EntityStack {
|
|
||||||
|
|
||||||
private final TNTPosition tntPosition;
|
|
||||||
private final Vector position;
|
|
||||||
private final PositionType positionType;
|
|
||||||
private final int fuseTicks;
|
|
||||||
|
|
||||||
private REntity entity;
|
|
||||||
private int count;
|
|
||||||
private List<Record.TNTRecord> records = new ArrayList<>();
|
|
||||||
|
|
||||||
public EntityStack(TNTPosition tntPosition, Vector position, PositionType positionType, int fuseTicks) {
|
|
||||||
this.tntPosition = tntPosition;
|
|
||||||
this.position = position;
|
|
||||||
this.positionType = positionType;
|
|
||||||
this.fuseTicks = fuseTicks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(Record.TNTRecord record) {
|
|
||||||
records.add(record);
|
|
||||||
if (entity == null) {
|
|
||||||
entity = createEntity(position, positionType);
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
if (showModeParameter.isFuse()) {
|
|
||||||
entity.setDisplayName(fuseTicks + "");
|
|
||||||
} else if (showModeParameter.isCount()) {
|
|
||||||
entity.setDisplayName(new HashSet<>(records).size() + "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean remove(Record.TNTRecord record) {
|
|
||||||
if (entity == null) return false;
|
|
||||||
records.remove(record);
|
|
||||||
count--;
|
|
||||||
if (count == 0) {
|
|
||||||
entity.die();
|
|
||||||
entity = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void generatePositions(TNTPosition position, boolean interpolateY, boolean interpolateXZ, BiConsumer<PositionType, Vector> positionCallback) {
|
|
||||||
positionCallback.accept(position.isExploded() ? PositionType.EXPLODE : PositionType.TNT, position.getLocation());
|
|
||||||
if (position.getPreviousLocation() == null) return;
|
|
||||||
|
|
||||||
if (interpolateY) {
|
|
||||||
Vector updatePointY = position.getPreviousLocation().clone().setY(position.getLocation().getY());
|
|
||||||
if (!position.getLocation().equals(updatePointY)) {
|
|
||||||
positionCallback.accept(PositionType.UPDATE, updatePointY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interpolateXZ) {
|
|
||||||
Vector updatePointXZ = Math.abs(position.getUpdateVelocity().getX()) >= Math.abs(position.getUpdateVelocity().getZ())
|
|
||||||
? position.getLocation().clone().setZ(position.getPreviousLocation().getZ())
|
|
||||||
: position.getLocation().clone().setX(position.getPreviousLocation().getX());
|
|
||||||
if (!position.getLocation().equals(updatePointXZ)) {
|
|
||||||
positionCallback.accept(PositionType.UPDATE, updatePointXZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PositionType {
|
|
||||||
TNT,
|
|
||||||
EXPLODE,
|
|
||||||
UPDATE
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.show;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.tpslimit.TPSUtils;
|
|
||||||
import de.steamwar.bausystem.features.tracer.TNTPosition;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import de.steamwar.bausystem.shared.ShowMode;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class Record {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final List<TNTRecord> tnt = new ArrayList<>();
|
|
||||||
private final Region region;
|
|
||||||
private final long startTicks = TPSUtils.currentTick.get();
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return tnt.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showAll(ShowMode<TNTPosition> traceShowMode) {
|
|
||||||
tnt.forEach(tntRecord -> tntRecord.getPositions().forEach(traceShowMode::show));
|
|
||||||
}
|
|
||||||
|
|
||||||
public TNTRecord spawn() {
|
|
||||||
TNTRecord record = new TNTRecord(this, region);
|
|
||||||
tnt.add(record);
|
|
||||||
return record;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
tnt.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkMicroMotion(Vector explosionPosition) {
|
|
||||||
for (TNTRecord tntRecord : tnt) {
|
|
||||||
List<TNTPosition> positions = tntRecord.positions;
|
|
||||||
if (positions.isEmpty()) continue;
|
|
||||||
TNTPosition position = positions.get(positions.size() - 1);
|
|
||||||
if (position.isExploded()) continue;
|
|
||||||
if (position.getLocation().distanceSquared(explosionPosition) > 64) continue;
|
|
||||||
|
|
||||||
Vector velocity = position.getVelocity();
|
|
||||||
if (velocity.getY() == 0 && ((velocity.getX() != 0 && Math.abs(velocity.getX()) < 0.001) || (velocity.getZ() != 0 && Math.abs(velocity.getZ()) < 0.001))) {
|
|
||||||
if (!tntRecord.hasMicroMotion) {
|
|
||||||
positions.forEach(tntPosition -> TraceShowManager.show(region, tntPosition));
|
|
||||||
}
|
|
||||||
tntRecord.hasMicroMotion = true;
|
|
||||||
position.setMicroMotion(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TNTRecord {
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final UUID id = UUID.randomUUID();
|
|
||||||
|
|
||||||
private Record record;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final Region region;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final List<TNTPosition> positions = new ArrayList<>(82);
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private boolean inBuildArea = false;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private boolean inTestblockArea = false;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private boolean hasMicroMotion = false;
|
|
||||||
|
|
||||||
public TNTRecord(Record record, Region region) {
|
|
||||||
this.record = record;
|
|
||||||
this.region = region;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void source(TNTPrimed tntPrimed) {
|
|
||||||
add(tntPrimed, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void location(TNTPrimed tntPrimed) {
|
|
||||||
add(tntPrimed, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void explode(TNTPrimed tntPrimed) {
|
|
||||||
add(tntPrimed, false, true);
|
|
||||||
record.checkMicroMotion(tntPrimed.getLocation().toVector());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void add(TNTPrimed tntPrimed, boolean source, boolean exploded) {
|
|
||||||
TNTPosition position;
|
|
||||||
if (positions.isEmpty()) {
|
|
||||||
position = new TNTPosition(this, tntPrimed, TPSUtils.currentTick.get() - record.startTicks, null, tntPrimed.getVelocity(), null, source, exploded);
|
|
||||||
} else {
|
|
||||||
TNTPosition tntPosition = positions.get(positions.size() - 1);
|
|
||||||
Vector lastVelocity = tntPrimed.getLocation().toVector().clone().subtract(tntPosition.getLocation());
|
|
||||||
position = new TNTPosition(this, tntPrimed, TPSUtils.currentTick.get() - record.startTicks, positions.get(positions.size() - 1).getLocation(), tntPrimed.getVelocity(), lastVelocity, source, exploded);
|
|
||||||
}
|
|
||||||
positions.add(position);
|
|
||||||
TraceShowManager.show(region, position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.show;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class ShowModeParameter {
|
|
||||||
private boolean water = false;
|
|
||||||
private boolean interpolateY = false;
|
|
||||||
private boolean interpolateXZ = false;
|
|
||||||
private boolean sourceOnly = false;
|
|
||||||
private boolean explodeOnly = false;
|
|
||||||
private boolean fuse = false;
|
|
||||||
private boolean count = false;
|
|
||||||
private boolean buildDestroyOnly = false;
|
|
||||||
private boolean testblockDestroyOnly = false;
|
|
||||||
private boolean microMotion = false;
|
|
||||||
private boolean microMotionLocation = false;
|
|
||||||
|
|
||||||
public void enableWater() {
|
|
||||||
this.water = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disableWater() {
|
|
||||||
this.water = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableInterpolateY() {
|
|
||||||
this.interpolateY = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableInterpolateXZ() {
|
|
||||||
this.interpolateXZ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableSourceOnly() {
|
|
||||||
this.sourceOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableExplodeOnly() {
|
|
||||||
this.explodeOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableFuse() {
|
|
||||||
this.fuse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableCount() {
|
|
||||||
this.count = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableBuildDestroyOnly() {
|
|
||||||
this.buildDestroyOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableTestblockDestroyOnly() {
|
|
||||||
this.testblockDestroyOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableMicroMotion() {
|
|
||||||
this.microMotion = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void enableMicroMotionLocation() {
|
|
||||||
this.microMotionLocation = true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.show;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public enum ShowModeParameterType {
|
|
||||||
|
|
||||||
WATER(ShowModeParameter::enableWater, Arrays.asList("-water"), "EXPLODE", "SOURCE", "BUILD_DESTROY_ONLY"),
|
|
||||||
INTERPOLATE_Y(ShowModeParameter::enableInterpolateY, Arrays.asList("-interpolatey", "-interpolate-y", "-interpolate_y", "-y"), "ADVANCED"),
|
|
||||||
INTERPOLATE_XZ(ShowModeParameter::enableInterpolateXZ, Arrays.asList("-interpolatex", "-interpolate-x", "-interpolate_x", "-x", "-interpolatez", "-interpolate-z", "-interpolate_z", "-z", "-interpolatexz", "-interpolate-xz", "-interpolate_xz", "-xz"), "ADVANCED"),
|
|
||||||
ADVANCED(showModeParameter -> {
|
|
||||||
showModeParameter.enableInterpolateY();
|
|
||||||
showModeParameter.enableInterpolateXZ();
|
|
||||||
}, Arrays.asList("-advanced", "-a"), "INTERPOLATE_Y", "INTERPOLATE_XZ"),
|
|
||||||
SOURCE(ShowModeParameter::enableSourceOnly, Arrays.asList("-source", "-sourceonly", "-ignite"), "FUSE", "ADVANCED", "INTERPOLATE_Y", "INTERPOLATE_XZ", "WATER"),
|
|
||||||
EXPLODE(ShowModeParameter::enableExplodeOnly, Arrays.asList("-explode", "-explodeonly"), "FUSE", "ADVANCED", "INTERPOLATE_Y", "INTERPOLATE_XZ", "WATER"),
|
|
||||||
FUSE(ShowModeParameter::enableFuse, Arrays.asList("-fuse", "-f"), "EXPLODE", "SOURCE", "COUNT"),
|
|
||||||
COUNT(ShowModeParameter::enableCount, Arrays.asList("-count", "-c"), "FUSE"),
|
|
||||||
BUILD_DESTROY_ONLY(ShowModeParameter::enableBuildDestroyOnly, Arrays.asList("-builddestroy", "-builddestoryonly"), "WATER", "TESTBLOCK_DESTROY_ONLY"),
|
|
||||||
TESTBLOCK_DESTROY_ONLY(ShowModeParameter::enableTestblockDestroyOnly, Arrays.asList("-testblockdestroy", "-testblockdestroyonly"), "WATER", "BUILD_DESTROY_ONLY"),
|
|
||||||
MICROMOTION(ShowModeParameter::enableMicroMotion, Arrays.asList("-micromotion", "-micro", "-m")),
|
|
||||||
MICROMOTION_LOCATION(ShowModeParameter::enableMicroMotionLocation, Arrays.asList("-micromotionloc", "-microloc", "-mloc", "-micromotionlocation", "-microlocation", "-mlocation")),
|
|
||||||
;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final Consumer<ShowModeParameter> showModeParameterConsumer;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private List<String> tabCompletes;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final Supplier<ShowModeParameterType[]> removed;
|
|
||||||
private AtomicReference<ShowModeParameterType[]> cached = new AtomicReference<>();
|
|
||||||
|
|
||||||
ShowModeParameterType(Consumer<ShowModeParameter> showModeParameterConsumer, List<String> tabCompletes, String... removed) {
|
|
||||||
this.showModeParameterConsumer = showModeParameterConsumer;
|
|
||||||
this.tabCompletes = tabCompletes;
|
|
||||||
this.removed = () -> {
|
|
||||||
if (cached.get() == null) {
|
|
||||||
ShowModeParameterType[] showModeParameterTypes = new ShowModeParameterType[removed.length];
|
|
||||||
for (int i = 0; i < removed.length; i++) {
|
|
||||||
showModeParameterTypes[i] = ShowModeParameterType.valueOf(removed[i]);
|
|
||||||
}
|
|
||||||
cached.set(showModeParameterTypes);
|
|
||||||
return showModeParameterTypes;
|
|
||||||
}
|
|
||||||
return cached.get();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.show;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.features.tracer.TNTPosition;
|
|
||||||
import de.steamwar.bausystem.features.tracer.record.Recorder;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import de.steamwar.bausystem.shared.ShowMode;
|
|
||||||
import lombok.experimental.UtilityClass;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@UtilityClass
|
|
||||||
public class StoredRecords {
|
|
||||||
|
|
||||||
private static final Map<Region, List<Record>> records = new HashMap<>();
|
|
||||||
|
|
||||||
public static void add(Region region, Record record) {
|
|
||||||
records.computeIfAbsent(region, k -> new ArrayList<>()).add(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void remove(Region region, Record record) {
|
|
||||||
records.computeIfAbsent(region, k -> new ArrayList<>()).remove(record);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clear(Region region) {
|
|
||||||
records.remove(region);
|
|
||||||
TraceShowManager.clear(region);
|
|
||||||
Recorder.INSTANCE.postClear(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Record> getRecords() {
|
|
||||||
return records.values().stream()
|
|
||||||
.flatMap(Collection::stream)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Record> getRecords(Region region) {
|
|
||||||
return records.getOrDefault(region, Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void show(Region region, Predicate<TNTPosition> traceShowFilter, ShowMode<TNTPosition> traceShowMode) {
|
|
||||||
records.getOrDefault(region, new ArrayList<>()).forEach(record -> {
|
|
||||||
record.getTnt().forEach(tntRecord -> {
|
|
||||||
tntRecord.getPositions().stream()
|
|
||||||
.filter(traceShowFilter)
|
|
||||||
.forEach(traceShowMode::show);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 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.tracer.show;
|
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
|
||||||
import de.steamwar.bausystem.features.tracer.TNTPosition;
|
|
||||||
import de.steamwar.bausystem.region.Region;
|
|
||||||
import de.steamwar.bausystem.shared.ShowMode;
|
|
||||||
import de.steamwar.bausystem.utils.BauMemberUpdateEvent;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
public class TraceShowManager implements Listener {
|
|
||||||
private TraceShowManager() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Map<Region, Map<Player, ShowMode<TNTPosition>>> showModes = new HashMap<>();
|
|
||||||
private static final Map<Region, Map<Player, Predicate<TNTPosition>>> showFilters = new HashMap<>();
|
|
||||||
|
|
||||||
public static void show(Player player, ShowMode<TNTPosition> traceShowMode) {
|
|
||||||
Region region = Region.getRegion(player.getLocation());
|
|
||||||
_hide(region, player, true);
|
|
||||||
|
|
||||||
Map<Player, ShowMode<TNTPosition>> regionalShowModes = showModes.computeIfAbsent(region, __ -> new HashMap<>());
|
|
||||||
regionalShowModes.put(player, traceShowMode);
|
|
||||||
StoredRecords.show(region, getShowFilter(player, region), traceShowMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void hide(Player player) {
|
|
||||||
Region region = Region.getRegion(player.getLocation());
|
|
||||||
_hide(region, player, true);
|
|
||||||
|
|
||||||
showFilters.getOrDefault(region, new HashMap<>()).remove(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setShowFilter(Player player, Predicate<TNTPosition> showFilter) {
|
|
||||||
Region region = Region.getRegion(player.getLocation());
|
|
||||||
Map<Player, Predicate<TNTPosition>> regionShowFilters = showFilters.computeIfAbsent(region, __ -> new HashMap<>());
|
|
||||||
if (showFilter == null) {
|
|
||||||
regionShowFilters.remove(player);
|
|
||||||
} else {
|
|
||||||
regionShowFilters.put(player, showFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
_hide(region, player, false);
|
|
||||||
ShowMode<TNTPosition> showMode = showModes.computeIfAbsent(region, __ -> new HashMap<>()).computeIfAbsent(player, __ -> new EntityShowMode(player, new ShowModeParameter(), 16));
|
|
||||||
StoredRecords.show(region, getShowFilter(player, region), showMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void reshow(Region region) {
|
|
||||||
Map<Player, ShowMode<TNTPosition>> regionalShowModes = showModes.get(region);
|
|
||||||
if (regionalShowModes == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (Map.Entry<Player, ShowMode<TNTPosition>> entry : regionalShowModes.entrySet()) {
|
|
||||||
entry.getValue().hide();
|
|
||||||
StoredRecords.show(region, getShowFilter(entry.getKey(), region), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void _hide(Region region, Player player, boolean remove) {
|
|
||||||
Map<Player, ShowMode<TNTPosition>> regionalShowModes = showModes.get(region);
|
|
||||||
if (regionalShowModes == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ShowMode<TNTPosition> showMode;
|
|
||||||
if (remove) {
|
|
||||||
showMode = regionalShowModes.remove(player);
|
|
||||||
} else {
|
|
||||||
showMode = regionalShowModes.get(player);
|
|
||||||
}
|
|
||||||
if (showMode == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
showMode.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Predicate<TNTPosition> getShowFilter(Player player, Region region) {
|
|
||||||
return showFilters.getOrDefault(region, new HashMap<>()).getOrDefault(player, tntPosition -> true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only to be called by record */
|
|
||||||
static void show(Region region, TNTPosition tnt) {
|
|
||||||
Map<Player, ShowMode<TNTPosition>> regionalShowModes = showModes.get(region);
|
|
||||||
if (regionalShowModes == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
regionalShowModes.forEach((player, tntPositionShowMode) -> {
|
|
||||||
if (getShowFilter(player, region).test(tnt)) {
|
|
||||||
tntPositionShowMode.show(tnt);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only to be called by StoredRecords */
|
|
||||||
static void clear(Region region) {
|
|
||||||
Map<Player, ShowMode<TNTPosition>> regionalShowModes = showModes.get(region);
|
|
||||||
if (regionalShowModes == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
regionalShowModes.values().forEach(ShowMode::hide);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Internal if player leaves*/
|
|
||||||
static {
|
|
||||||
Bukkit.getPluginManager().registerEvents(new TraceShowManager(), BauSystem.getInstance());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onLeave(PlayerQuitEvent event) {
|
|
||||||
hideComplete(event.getPlayer());
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onBauMemberUpdate(BauMemberUpdateEvent event) {
|
|
||||||
event.getNewSpectator().forEach(this::hideComplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideComplete(Player player) {
|
|
||||||
showModes.forEach((region, playerShowModeMap) -> {
|
|
||||||
ShowMode<TNTPosition> showMode = playerShowModeMap.remove(player);
|
|
||||||
if (showMode != null) showMode.hide();
|
|
||||||
});
|
|
||||||
showFilters.forEach((region, playerPredicateMap) -> {
|
|
||||||
playerPredicateMap.remove(player);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
In neuem Issue referenzieren
Einen Benutzer sperren