forked from SteamWar/SteamWar
Merge branch 'main' into dc-5
This commit is contained in:
@@ -11,5 +11,9 @@ steamwar.properties
|
|||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
|
# VSCode
|
||||||
|
bin/
|
||||||
|
.vscode
|
||||||
|
|
||||||
# Other
|
# Other
|
||||||
lib
|
lib
|
||||||
@@ -38,6 +38,7 @@ dependencies {
|
|||||||
compileOnly(libs.spigotapi)
|
compileOnly(libs.spigotapi)
|
||||||
compileOnly(libs.axiom)
|
compileOnly(libs.axiom)
|
||||||
compileOnly(libs.authlib)
|
compileOnly(libs.authlib)
|
||||||
|
compileOnly(libs.viaapi)
|
||||||
|
|
||||||
compileOnly(libs.nms20)
|
compileOnly(libs.nms20)
|
||||||
compileOnly(libs.fawe18)
|
compileOnly(libs.fawe18)
|
||||||
|
|||||||
@@ -1012,3 +1012,5 @@ COLORREPLACE_HELP=§8//§ecolorreplace §8[§7color§8] §8[§7color§8] §8- §
|
|||||||
TYPEREPLACE_HELP=§8//§etypereplace §8[§7type§8] §8[§7type§8] §8- §7Replace all blocks of one type with another
|
TYPEREPLACE_HELP=§8//§etypereplace §8[§7type§8] §8[§7type§8] §8- §7Replace all blocks of one type with another
|
||||||
# Schematic
|
# Schematic
|
||||||
SCHEMATIC_GUI_ITEM=§eSchematics
|
SCHEMATIC_GUI_ITEM=§eSchematics
|
||||||
|
#VersionAnnouncer
|
||||||
|
SERVER_VERSION=§7This server runs on Minecraft version §e{0}
|
||||||
@@ -953,3 +953,5 @@ COLORREPLACE_HELP=§8//§ecolorreplace §8[§7color§8] §8[§7color§8] §8- §
|
|||||||
TYPEREPLACE_HELP=§8//§etyreplace §8[§7type§8] §8[§7type§8] §8- §7Ersetzt einen Blockgruppe mit einer anderen
|
TYPEREPLACE_HELP=§8//§etyreplace §8[§7type§8] §8[§7type§8] §8- §7Ersetzt einen Blockgruppe mit einer anderen
|
||||||
# Schematics
|
# Schematics
|
||||||
SCHEMATIC_GUI_ITEM=§eSchematics
|
SCHEMATIC_GUI_ITEM=§eSchematics
|
||||||
|
#VersionAnnouncer
|
||||||
|
SERVER_VERSION=§7Dieser Server läuft auf Minecraft-Version §e{0}
|
||||||
@@ -28,6 +28,8 @@ import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
|
|||||||
import de.steamwar.bausystem.features.slaves.panzern.Panzern;
|
import de.steamwar.bausystem.features.slaves.panzern.Panzern;
|
||||||
import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm;
|
import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm;
|
||||||
import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils;
|
import de.steamwar.bausystem.features.tpslimit.TPSFreezeUtils;
|
||||||
|
import de.steamwar.bausystem.features.tracer.TraceManager;
|
||||||
|
import de.steamwar.bausystem.features.tracer.TraceRecorder;
|
||||||
import de.steamwar.bausystem.features.world.BauScoreboard;
|
import de.steamwar.bausystem.features.world.BauScoreboard;
|
||||||
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
import de.steamwar.bausystem.linkage.specific.BauGuiItem;
|
||||||
import de.steamwar.bausystem.region.loader.PrototypeLoader;
|
import de.steamwar.bausystem.region.loader.PrototypeLoader;
|
||||||
@@ -70,7 +72,7 @@ import java.util.function.Consumer;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class BauSystem extends JavaPlugin implements Listener {
|
public class BauSystem extends JavaPlugin {
|
||||||
|
|
||||||
// This should be treated as final!
|
// This should be treated as final!
|
||||||
public static Message MESSAGE;
|
public static Message MESSAGE;
|
||||||
@@ -197,6 +199,9 @@ public class BauSystem extends JavaPlugin implements Listener {
|
|||||||
});
|
});
|
||||||
|
|
||||||
TickListener.impl.init();
|
TickListener.impl.init();
|
||||||
|
|
||||||
|
TraceManager.instance.init();
|
||||||
|
TraceRecorder.instance.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ public class ResetCommand extends SWCommand {
|
|||||||
PasteBuilder pasteBuilder = new PasteBuilder(new PasteBuilder.FileProvider(region.getResetFile(RegionType.NORMAL)))
|
PasteBuilder pasteBuilder = new PasteBuilder(new PasteBuilder.FileProvider(region.getResetFile(RegionType.NORMAL)))
|
||||||
.color(region.getPlain(Flag.COLOR, ColorMode.class).getColor());
|
.color(region.getPlain(Flag.COLOR, ColorMode.class).getColor());
|
||||||
region.reset(pasteBuilder, RegionType.NORMAL, RegionExtensionType.NORMAL);
|
region.reset(pasteBuilder, RegionType.NORMAL, RegionExtensionType.NORMAL);
|
||||||
|
for (Flag value : Flag.values()) {
|
||||||
|
region.set(value, value.getDefaultValue());
|
||||||
|
}
|
||||||
RegionUtils.message(region, "REGION_RESET_RESETED");
|
RegionUtils.message(region, "REGION_RESET_RESETED");
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
BauSystem.MESSAGE.send("REGION_RESET_ERROR", p);
|
BauSystem.MESSAGE.send("REGION_RESET_ERROR", p);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ package de.steamwar.bausystem.features.tracer;
|
|||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
import de.steamwar.bausystem.region.utils.RegionExtensionType;
|
||||||
import de.steamwar.bausystem.region.utils.RegionType;
|
import de.steamwar.bausystem.region.utils.RegionType;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
@@ -39,8 +41,9 @@ import java.util.Optional;
|
|||||||
/**
|
/**
|
||||||
* Recording of a tnt at a specific tick
|
* Recording of a tnt at a specific tick
|
||||||
*/
|
*/
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
@Getter
|
@Getter
|
||||||
public class TNTPoint implements Externalizable {
|
public class TNTPoint{
|
||||||
/**
|
/**
|
||||||
* Unique number to identify records being of the same tnt
|
* Unique number to identify records being of the same tnt
|
||||||
*/
|
*/
|
||||||
@@ -97,12 +100,9 @@ public class TNTPoint implements Externalizable {
|
|||||||
private List<TNTPoint> history;
|
private List<TNTPoint> history;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for deserialization only !! Do not Call !!
|
* Constructor for object creation in trace recording
|
||||||
*/
|
*/
|
||||||
public TNTPoint() {
|
protected TNTPoint(int tntId, TNTPrimed tnt, boolean explosion, boolean afterFirstExplosion, long ticksSinceStart,
|
||||||
}
|
|
||||||
|
|
||||||
public TNTPoint(int tntId, TNTPrimed tnt, boolean explosion, boolean afterFirstExplosion, long ticksSinceStart,
|
|
||||||
List<TNTPoint> history, List<Block> destroyedBlocks) {
|
List<TNTPoint> history, List<Block> destroyedBlocks) {
|
||||||
this.tntId = tntId;
|
this.tntId = tntId;
|
||||||
this.explosion = explosion;
|
this.explosion = explosion;
|
||||||
@@ -161,44 +161,6 @@ public class TNTPoint implements Externalizable {
|
|||||||
this.history = 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
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "TNTPoint{" +
|
return "TNTPoint{" +
|
||||||
|
|||||||
@@ -26,20 +26,16 @@ import de.steamwar.bausystem.features.tracer.rendering.ViewFlag;
|
|||||||
import de.steamwar.bausystem.region.Region;
|
import de.steamwar.bausystem.region.Region;
|
||||||
import de.steamwar.entity.REntity;
|
import de.steamwar.entity.REntity;
|
||||||
import de.steamwar.entity.REntityServer;
|
import de.steamwar.entity.REntityServer;
|
||||||
import lombok.Cleanup;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.zip.GZIPInputStream;
|
|
||||||
|
|
||||||
public class Trace {
|
public class Trace {
|
||||||
/**
|
/**
|
||||||
@@ -77,6 +73,10 @@ public class Trace {
|
|||||||
*/
|
*/
|
||||||
private SoftReference<List<TNTPoint>> records;
|
private SoftReference<List<TNTPoint>> records;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
private int recordsCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of all REntityServers rendering this trace
|
* A map of all REntityServers rendering this trace
|
||||||
*/
|
*/
|
||||||
@@ -91,46 +91,25 @@ public class Trace {
|
|||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public Trace(Region region, List<TNTPoint> recordList) {
|
public Trace(Region region, List<TNTPoint> recordList) {
|
||||||
this.uuid = UUID.randomUUID();
|
this.uuid = UUID.randomUUID();
|
||||||
recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records");
|
|
||||||
this.region = region;
|
this.region = region;
|
||||||
this.date = new Date();
|
this.date = new Date();
|
||||||
records = new SoftReference<>(recordList);
|
records = new SoftReference<>(recordList);
|
||||||
metadataSaveFile = new File(TraceManager.tracesFolder, uuid + ".meta");
|
recordsSaveFile = new File(TraceRepository.tracesFolder, uuid + ".records");
|
||||||
|
metadataSaveFile = new File(TraceRepository.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
|
* Constructor for deserialising a trace from the file system
|
||||||
*
|
|
||||||
* @param metadataSaveFile the file for this traces metadata
|
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public Trace(File metadataSaveFile) {
|
protected Trace(UUID uuid, Region region, Date date, File metadataFile, File recordsFile, int recordsCount) {
|
||||||
String uuid = null;
|
this.metadataSaveFile = metadataFile;
|
||||||
Region region = null;
|
recordsSaveFile = recordsFile;
|
||||||
Date date = null;
|
this.uuid = uuid;
|
||||||
|
|
||||||
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.region = region;
|
||||||
this.date = date;
|
this.date = date;
|
||||||
recordsSaveFile = new File(TraceManager.tracesFolder, uuid + ".records");
|
|
||||||
this.records = new SoftReference<>(null);
|
this.records = new SoftReference<>(null);
|
||||||
}
|
this.recordsCount = recordsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,7 +152,8 @@ public class Trace {
|
|||||||
entityServer = new REntityServer();
|
entityServer = new REntityServer();
|
||||||
entityServer.addPlayer(player);
|
entityServer.addPlayer(player);
|
||||||
entityServer.setCallback((p, rEntity, entityAction) -> {
|
entityServer.setCallback((p, rEntity, entityAction) -> {
|
||||||
if (entityAction != REntityServer.EntityAction.INTERACT) return;
|
if (entityAction != REntityServer.EntityAction.INTERACT)
|
||||||
|
return;
|
||||||
if (rEntity instanceof TraceEntity) {
|
if (rEntity instanceof TraceEntity) {
|
||||||
((TraceEntity) rEntity).printIntoChat(p);
|
((TraceEntity) rEntity).printIntoChat(p);
|
||||||
}
|
}
|
||||||
@@ -195,7 +175,8 @@ public class Trace {
|
|||||||
REntityServer newEntityServer = new REntityServer();
|
REntityServer newEntityServer = new REntityServer();
|
||||||
newEntityServer.addPlayer(k);
|
newEntityServer.addPlayer(k);
|
||||||
newEntityServer.setCallback((p, rEntity, entityAction) -> {
|
newEntityServer.setCallback((p, rEntity, entityAction) -> {
|
||||||
if (entityAction != REntityServer.EntityAction.INTERACT) return;
|
if (entityAction != REntityServer.EntityAction.INTERACT)
|
||||||
|
return;
|
||||||
if (rEntity instanceof TraceEntity) {
|
if (rEntity instanceof TraceEntity) {
|
||||||
((TraceEntity) rEntity).printIntoChat(p);
|
((TraceEntity) rEntity).printIntoChat(p);
|
||||||
}
|
}
|
||||||
@@ -234,7 +215,8 @@ public class Trace {
|
|||||||
List<TraceEntity> entities = new LinkedList<>();
|
List<TraceEntity> entities = new LinkedList<>();
|
||||||
|
|
||||||
for (List<TNTPoint> bundle : bundles) {
|
for (List<TNTPoint> bundle : bundles) {
|
||||||
entities.add(new TraceEntity(entityServer, bundle.get(0).getLocation(), bundle.get(0).isExplosion(), bundle, this));
|
entities.add(new TraceEntity(entityServer, bundle.get(0).getLocation(), bundle.get(0).isExplosion(), bundle,
|
||||||
|
this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply modifiers
|
// Apply modifiers
|
||||||
@@ -312,38 +294,7 @@ public class Trace {
|
|||||||
* Loads the records of this trace from storage to memory
|
* Loads the records of this trace from storage to memory
|
||||||
*/
|
*/
|
||||||
private void loadRecords() {
|
private void loadRecords() {
|
||||||
List<TNTPoint> records = new ArrayList<>();
|
records = new SoftReference<>(TraceRepository.readTraceRecords(this));
|
||||||
long readBytes = 0;
|
|
||||||
try {
|
|
||||||
FileInputStream fileInputStream = new FileInputStream(recordsSaveFile);
|
|
||||||
|
|
||||||
@Cleanup
|
|
||||||
ObjectInputStream inputStream = new ObjectInputStream(new GZIPInputStream(fileInputStream));
|
|
||||||
long fileLenght = recordsSaveFile.length();
|
|
||||||
while (fileInputStream.getChannel().position() < fileLenght) {
|
|
||||||
records.add((TNTPoint) inputStream.readObject());
|
|
||||||
readBytes = fileInputStream.getChannel().position();
|
|
||||||
}
|
|
||||||
} catch (EOFException e) {
|
|
||||||
Logger logger = Bukkit.getLogger();
|
|
||||||
logger.log(Level.WARNING, "EOF in trace read detected in " + uuid);
|
|
||||||
logger.log(Level.WARNING, "Read " + readBytes + "/" + recordsSaveFile.length() + " Bytes");
|
|
||||||
logger.log(Level.WARNING, "Read so far: " + records);
|
|
||||||
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 synchronized List<TNTPoint> getRecords() {
|
public synchronized List<TNTPoint> getRecords() {
|
||||||
@@ -360,6 +311,7 @@ public class Trace {
|
|||||||
", region=" + region +
|
", region=" + region +
|
||||||
", creationTime=" + date +
|
", creationTime=" + date +
|
||||||
", recordsSaveFile=" + recordsSaveFile.getName() +
|
", recordsSaveFile=" + recordsSaveFile.getName() +
|
||||||
|
", recordCount=" + recordsCount +
|
||||||
", records=" + getRecords() +
|
", records=" + getRecords() +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-5
@@ -30,11 +30,14 @@ import org.bukkit.entity.Player;
|
|||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.event.server.PluginEnableEvent;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static de.steamwar.bausystem.features.tracer.TraceRepository.tracesFolder;
|
||||||
|
|
||||||
@Linked
|
@Linked
|
||||||
public class TraceManager implements Listener {
|
public class TraceManager implements Listener {
|
||||||
|
|
||||||
@@ -44,9 +47,9 @@ public class TraceManager implements Listener {
|
|||||||
instance = this;
|
instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File tracesFolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "traces");
|
|
||||||
|
|
||||||
public TraceManager() {
|
|
||||||
|
public void init() {
|
||||||
if (!tracesFolder.exists())
|
if (!tracesFolder.exists())
|
||||||
tracesFolder.mkdir();
|
tracesFolder.mkdir();
|
||||||
|
|
||||||
@@ -58,7 +61,15 @@ public class TraceManager implements Listener {
|
|||||||
if (traceFile.getName().contains(".records"))
|
if (traceFile.getName().contains(".records"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
add(new Trace(traceFile));
|
if (TraceRepository.getVersion(traceFile) == TraceRepository.SERIALISATION_VERSION) {
|
||||||
|
add(TraceRepository.readTrace(traceFile));
|
||||||
|
} else {
|
||||||
|
String uuid = traceFile.getName().replace(".meta", "");
|
||||||
|
|
||||||
|
new File(tracesFolder, uuid + ".records").deleteOnExit();
|
||||||
|
new File(tracesFolder, uuid + ".meta").deleteOnExit();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,8 +171,8 @@ public class TraceManager implements Listener {
|
|||||||
tracesByRegion.getOrDefault(region, new HashMap<>())
|
tracesByRegion.getOrDefault(region, new HashMap<>())
|
||||||
.forEach((i, trace) -> {
|
.forEach((i, trace) -> {
|
||||||
if (trace.getRegion() != region) return;
|
if (trace.getRegion() != region) return;
|
||||||
trace.getMetadataSaveFile().delete();
|
trace.getMetadataSaveFile().deleteOnExit();
|
||||||
trace.getRecordsSaveFile().delete();
|
trace.getRecordsSaveFile().deleteOnExit();
|
||||||
});
|
});
|
||||||
tracesByRegion.getOrDefault(region, new HashMap<>()).clear();
|
tracesByRegion.getOrDefault(region, new HashMap<>()).clear();
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -31,6 +31,7 @@ import org.bukkit.event.EventPriority;
|
|||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
import org.bukkit.event.entity.EntitySpawnEvent;
|
||||||
|
import org.bukkit.event.server.PluginEnableEvent;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@@ -70,7 +71,7 @@ public class TraceRecorder implements Listener {
|
|||||||
*/
|
*/
|
||||||
private final Set<Region> autoTraceRegions = new HashSet<>();
|
private final Set<Region> autoTraceRegions = new HashSet<>();
|
||||||
|
|
||||||
public TraceRecorder() {
|
public void init() {
|
||||||
BauSystem.runTaskTimer(BauSystem.getInstance(), () -> {
|
BauSystem.runTaskTimer(BauSystem.getInstance(), () -> {
|
||||||
record();
|
record();
|
||||||
checkForAutoTraceFinish();
|
checkForAutoTraceFinish();
|
||||||
@@ -170,8 +171,7 @@ public class TraceRecorder implements Listener {
|
|||||||
if (history.size() == 0) {
|
if (history.size() == 0) {
|
||||||
try {
|
try {
|
||||||
historyMap.put(tntPrimed, history);
|
historyMap.put(tntPrimed, history);
|
||||||
}
|
} catch (NullPointerException e) {
|
||||||
catch (NullPointerException e) {
|
|
||||||
Logger logger = Bukkit.getLogger();
|
Logger logger = Bukkit.getLogger();
|
||||||
//TODO remove when no longer neccecary
|
//TODO remove when no longer neccecary
|
||||||
logger.log(Level.WARNING, "Nullpointer thrown by historyMap");
|
logger.log(Level.WARNING, "Nullpointer thrown by historyMap");
|
||||||
|
|||||||
+5
-22
@@ -24,28 +24,22 @@ import de.steamwar.bausystem.region.Region;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.SneakyThrows;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.zip.GZIPOutputStream;
|
|
||||||
|
|
||||||
public class TraceRecordingWrapper {
|
public class TraceRecordingWrapper {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final Trace trace;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final long startTick;
|
private final long startTick;
|
||||||
private final List<TNTPoint> recordsToAdd;
|
private final List<TNTPoint> recordsToAdd;
|
||||||
private final List<TNTPoint> recordList;
|
private final List<TNTPoint> recordList;
|
||||||
private final ObjectOutputStream recordsOutputStream;
|
|
||||||
private int nextOpenRecordId = 0;
|
private int nextOpenRecordId = 0;
|
||||||
@Getter
|
@Getter
|
||||||
private boolean explosionRecorded = false;
|
private boolean explosionRecorded = false;
|
||||||
|
|
||||||
@Getter
|
|
||||||
private final Trace trace;
|
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public TraceRecordingWrapper(Region region) {
|
public TraceRecordingWrapper(Region region) {
|
||||||
startTick = TPSUtils.currentRealTick.get();
|
startTick = TPSUtils.currentRealTick.get();
|
||||||
@@ -53,8 +47,6 @@ public class TraceRecordingWrapper {
|
|||||||
recordList = new ArrayList<>();
|
recordList = new ArrayList<>();
|
||||||
|
|
||||||
trace = new Trace(region, recordList);
|
trace = new Trace(region, recordList);
|
||||||
File recordsSaveFile = new File(TraceManager.tracesFolder, trace.getUuid() + ".records");
|
|
||||||
recordsOutputStream = new ObjectOutputStream(new GZIPOutputStream(new FileOutputStream(recordsSaveFile)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNextOpenRecordIdAndIncrement() {
|
public int getNextOpenRecordIdAndIncrement() {
|
||||||
@@ -72,23 +64,14 @@ public class TraceRecordingWrapper {
|
|||||||
public void commitRecorded() {
|
public void commitRecorded() {
|
||||||
TraceManager.instance.showPartial(trace, recordsToAdd);
|
TraceManager.instance.showPartial(trace, recordsToAdd);
|
||||||
|
|
||||||
recordsToAdd.forEach(record -> {
|
|
||||||
try {
|
|
||||||
recordsOutputStream.writeObject(record);
|
|
||||||
recordsOutputStream.flush();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
recordList.addAll(recordsToAdd);
|
recordList.addAll(recordsToAdd);
|
||||||
|
trace.setRecordsCount(recordList.size());
|
||||||
recordsToAdd.clear();
|
recordsToAdd.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
protected void finalizeRecording() {
|
protected void finalizeRecording() {
|
||||||
recordsOutputStream.flush();
|
TraceRepository.writeTrace(trace, recordList);
|
||||||
recordsOutputStream.close();
|
|
||||||
TraceManager.instance.add(trace);
|
TraceManager.instance.add(trace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
package de.steamwar.bausystem.features.tracer;
|
||||||
|
|
||||||
|
import de.steamwar.bausystem.region.Region;
|
||||||
|
import lombok.Cleanup;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TraceRepository {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment this when changing serialisation format
|
||||||
|
*/
|
||||||
|
public static final int SERIALISATION_VERSION = 1;
|
||||||
|
public static File tracesFolder = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "traces");
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
protected static int getVersion(File metadataFile) {
|
||||||
|
@Cleanup
|
||||||
|
ObjectInputStream reader = new ObjectInputStream(new FileInputStream(metadataFile));
|
||||||
|
reader.readUTF();
|
||||||
|
reader.readUTF();
|
||||||
|
reader.readObject();
|
||||||
|
try {
|
||||||
|
int version = reader.readInt();
|
||||||
|
return version;
|
||||||
|
} catch (EOFException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public static Trace readTrace(File metadataFile) {
|
||||||
|
@Cleanup
|
||||||
|
ObjectInputStream reader = new ObjectInputStream(new FileInputStream(metadataFile));
|
||||||
|
UUID uuid = UUID.fromString(reader.readUTF());
|
||||||
|
Region region = Region.getREGION_MAP().get(reader.readUTF());
|
||||||
|
Date date = (Date) reader.readObject();
|
||||||
|
File recordsFile = new File(tracesFolder,uuid + ".records");
|
||||||
|
int serialisationVersion = reader.readInt();
|
||||||
|
int recordsCount = reader.readInt();
|
||||||
|
|
||||||
|
return new Trace(uuid, region, date, metadataFile, recordsFile, recordsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
protected static void writeTrace(Trace trace, List<TNTPoint> records) {
|
||||||
|
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(trace.getMetadataSaveFile()));
|
||||||
|
outputStream.writeUTF(trace.getUuid().toString());
|
||||||
|
outputStream.writeUTF(trace.getRegion().getName());
|
||||||
|
outputStream.writeObject(trace.getDate());
|
||||||
|
outputStream.writeInt(SERIALISATION_VERSION);
|
||||||
|
outputStream.writeInt(records.size());
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
|
||||||
|
writeTraceRecords(trace.getRecordsSaveFile(), records);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
protected static void writeTraceRecords(File recordsFile, List<TNTPoint> records) {
|
||||||
|
DataOutputStream outputStream = new DataOutputStream(new FileOutputStream(recordsFile));
|
||||||
|
for (TNTPoint record : records) {
|
||||||
|
outputStream.writeInt(record.getTntId());
|
||||||
|
outputStream.writeBoolean(record.isExplosion());
|
||||||
|
outputStream.writeBoolean(record.isInWater());
|
||||||
|
outputStream.writeBoolean(record.isAfterFirstExplosion());
|
||||||
|
outputStream.writeBoolean(record.isDestroyedBuildArea());
|
||||||
|
outputStream.writeBoolean(record.isDestroyedTestBlock());
|
||||||
|
outputStream.writeLong(record.getTicksSinceStart());
|
||||||
|
outputStream.writeInt(record.getFuse());
|
||||||
|
Location location = record.getLocation();
|
||||||
|
outputStream.writeDouble(location.getX());
|
||||||
|
outputStream.writeDouble(location.getY());
|
||||||
|
outputStream.writeDouble(location.getZ());
|
||||||
|
Vector velocity = record.getVelocity();
|
||||||
|
outputStream.writeDouble(velocity.getX());
|
||||||
|
outputStream.writeDouble(velocity.getY());
|
||||||
|
outputStream.writeDouble(velocity.getZ());
|
||||||
|
}
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
protected static TNTPoint readTraceRecord(DataInputStream objectInput) {
|
||||||
|
|
||||||
|
int tntId = objectInput.readInt();
|
||||||
|
boolean explosion = objectInput.readBoolean();
|
||||||
|
boolean inWater = objectInput.readBoolean();
|
||||||
|
boolean afterFirstExplosion = objectInput.readBoolean();
|
||||||
|
boolean destroyedBuildArea = objectInput.readBoolean();
|
||||||
|
boolean destroyedTestBlock = objectInput.readBoolean();
|
||||||
|
long ticksSinceStart = objectInput.readLong();
|
||||||
|
int fuse = objectInput.readInt();
|
||||||
|
|
||||||
|
double locX = objectInput.readDouble();
|
||||||
|
double locY = objectInput.readDouble();
|
||||||
|
double locZ = objectInput.readDouble();
|
||||||
|
Location location = new Location(Bukkit.getWorlds().get(0), locX, locY, locZ);
|
||||||
|
|
||||||
|
double velX = objectInput.readDouble();
|
||||||
|
double velY = objectInput.readDouble();
|
||||||
|
double velZ = objectInput.readDouble();
|
||||||
|
Vector velocity = new Vector(velX, velY, velZ);
|
||||||
|
|
||||||
|
return new TNTPoint(tntId, explosion, inWater, afterFirstExplosion, destroyedBuildArea, destroyedTestBlock, ticksSinceStart, fuse, location, velocity, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
protected static List<TNTPoint> readTraceRecords(Trace trace) {
|
||||||
|
File recordsFile = trace.getRecordsSaveFile();
|
||||||
|
@Cleanup
|
||||||
|
DataInputStream inputStream = new DataInputStream(new FileInputStream(recordsFile));
|
||||||
|
|
||||||
|
List<TNTPoint> records = new ArrayList<>();
|
||||||
|
for (int i = 0; i < trace.getRecordsCount(); i++) {
|
||||||
|
records.add(readTraceRecord(inputStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-10
@@ -20,6 +20,7 @@
|
|||||||
package de.steamwar.bausystem.features.world;
|
package de.steamwar.bausystem.features.world;
|
||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.core.CRIUWakeupEvent;
|
||||||
import de.steamwar.core.CheckpointUtils;
|
import de.steamwar.core.CheckpointUtils;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@@ -35,20 +36,16 @@ import org.bukkit.event.player.PlayerQuitEvent;
|
|||||||
@Linked
|
@Linked
|
||||||
public class AFKStopperListener implements Listener {
|
public class AFKStopperListener implements Listener {
|
||||||
|
|
||||||
private int afkTicks = 0;
|
private long lastMovementTime = System.currentTimeMillis();
|
||||||
|
|
||||||
public AFKStopperListener() {
|
public AFKStopperListener() {
|
||||||
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
|
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
|
||||||
switch (afkTicks) {
|
long currentTime = System.currentTimeMillis();
|
||||||
case 15:
|
if(currentTime - lastMovementTime > 10*60000) { // 10 Minutes
|
||||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
for (Player p : Bukkit.getOnlinePlayers())
|
||||||
p.kickPlayer(BauSystem.MESSAGE.parse("AFK_KICK_MESSAGE", p));
|
p.kickPlayer(BauSystem.MESSAGE.parse("AFK_KICK_MESSAGE", p));
|
||||||
}
|
} else if(currentTime - lastMovementTime > 9*60000)
|
||||||
case 14:
|
|
||||||
BauSystem.MESSAGE.broadcast("AFK_WARNING_MESSAGE");
|
BauSystem.MESSAGE.broadcast("AFK_WARNING_MESSAGE");
|
||||||
default:
|
|
||||||
afkTicks++;
|
|
||||||
}
|
|
||||||
}, 1200, 1200); //every minute
|
}, 1200, 1200); //every minute
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +57,7 @@ public class AFKStopperListener implements Listener {
|
|||||||
|
|
||||||
Location from = event.getFrom();
|
Location from = event.getFrom();
|
||||||
if (from.getPitch() != to.getPitch() || from.getYaw() != to.getYaw())
|
if (from.getPitch() != to.getPitch() || from.getYaw() != to.getYaw())
|
||||||
afkTicks = 0;
|
lastMovementTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOWEST) //Potential fix for potential race condition with WE axe spontaneously not working
|
@EventHandler(priority = EventPriority.LOWEST) //Potential fix for potential race condition with WE axe spontaneously not working
|
||||||
@@ -73,4 +70,9 @@ public class AFKStopperListener implements Listener {
|
|||||||
if(Bukkit.getOnlinePlayers().isEmpty() || (Bukkit.getOnlinePlayers().size() == 1 && Bukkit.getOnlinePlayers().contains(event.getPlayer())))
|
if(Bukkit.getOnlinePlayers().isEmpty() || (Bukkit.getOnlinePlayers().size() == 1 && Bukkit.getOnlinePlayers().contains(event.getPlayer())))
|
||||||
CheckpointUtils.freeze();
|
CheckpointUtils.freeze();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onCRIUWakeup(CRIUWakeupEvent event) {
|
||||||
|
lastMovementTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.world;
|
|||||||
|
|
||||||
import de.steamwar.bausystem.BauSystem;
|
import de.steamwar.bausystem.BauSystem;
|
||||||
import de.steamwar.bausystem.config.BauServer;
|
import de.steamwar.bausystem.config.BauServer;
|
||||||
|
import de.steamwar.core.CRIUWakeupEvent;
|
||||||
import de.steamwar.linkage.Linked;
|
import de.steamwar.linkage.Linked;
|
||||||
import de.steamwar.sql.BauweltMember;
|
import de.steamwar.sql.BauweltMember;
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
@@ -32,7 +33,6 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
|||||||
@Linked
|
@Linked
|
||||||
public class AntiBauAddMemberFix implements Listener {
|
public class AntiBauAddMemberFix implements Listener {
|
||||||
|
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.LOW)
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
if (BauSystem.DEV_SERVER) return;
|
if (BauSystem.DEV_SERVER) return;
|
||||||
@@ -44,4 +44,9 @@ public class AntiBauAddMemberFix implements Listener {
|
|||||||
throw new SecurityException("The player " + event.getPlayer().getName() + " joined on the server of " + SteamwarUser.get(BauServer.getInstance().getOwnerID()).getUserName() + " without being added!");
|
throw new SecurityException("The player " + event.getPlayer().getName() + " joined on the server of " + SteamwarUser.get(BauServer.getInstance().getOwnerID()).getUserName() + " without being added!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onCRIUWakeup(CRIUWakeupEvent event) {
|
||||||
|
BauweltMember.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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.world;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.regions.RegionSelector;
|
||||||
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.bausystem.shared.Pair;
|
||||||
|
import de.steamwar.bausystem.utils.WorldEditUtils;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
|
import de.steamwar.sql.SteamwarUser;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Linked
|
||||||
|
public class WorldEditSelectionSaver implements Listener {
|
||||||
|
|
||||||
|
private File WORLD_EDIT_SELECTIONS = new File(Bukkit.getWorlds().get(0).getWorldFolder(), "world_edit_selections");
|
||||||
|
|
||||||
|
{
|
||||||
|
WORLD_EDIT_SELECTIONS.mkdir();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
|
SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId());
|
||||||
|
File file = new File(WORLD_EDIT_SELECTIONS, Integer.toString(steamwarUser.getId()));
|
||||||
|
if (!file.exists()) return;
|
||||||
|
try {
|
||||||
|
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
|
||||||
|
Class<? extends RegionSelector> clazz = (Class<? extends RegionSelector>) Class.forName(bufferedReader.readLine());
|
||||||
|
List<Location> locations = bufferedReader.lines()
|
||||||
|
.map(s -> s.split(" "))
|
||||||
|
.map(strings -> strings.length != 3 ? null : new Location(event.getPlayer().getWorld(), Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), Integer.parseInt(strings[2])))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
WorldEditUtils.setVertices(event.getPlayer(), clazz, locations);
|
||||||
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
|
BauSystem.getInstance().getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
|
SteamwarUser steamwarUser = SteamwarUser.get(event.getPlayer().getUniqueId());
|
||||||
|
Pair<Class<? extends RegionSelector>, List<Location>> data = WorldEditUtils.getVertices(event.getPlayer());
|
||||||
|
File file = new File(WORLD_EDIT_SELECTIONS, Integer.toString(steamwarUser.getId()));
|
||||||
|
try {
|
||||||
|
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
|
||||||
|
bufferedWriter.write(data.getKey().getTypeName());
|
||||||
|
for (Location location : data.getValue()) {
|
||||||
|
if (location == null) {
|
||||||
|
bufferedWriter.write("\n");
|
||||||
|
} else {
|
||||||
|
bufferedWriter.write("\n" + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bufferedWriter.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
BauSystem.getInstance().getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.utils;
|
||||||
|
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
|
import com.viaversion.viaversion.api.ViaAPI;
|
||||||
|
import de.steamwar.bausystem.BauSystem;
|
||||||
|
import de.steamwar.linkage.Linked;
|
||||||
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
|
@Linked
|
||||||
|
public class VersionAnnouncer implements Listener {
|
||||||
|
|
||||||
|
private final String versionString = Bukkit.getBukkitVersion().split("-", 2)[0];
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private final ViaAPI<Player> via = Via.getAPI();
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if(via.getServerVersion().supportedVersions().contains(via.getPlayerVersion(player)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
BauSystem.MESSAGE.sendPrefixless("SERVER_VERSION", player, ChatMessageType.ACTION_BAR, versionString);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,17 +19,21 @@
|
|||||||
|
|
||||||
package de.steamwar.bausystem.utils;
|
package de.steamwar.bausystem.utils;
|
||||||
|
|
||||||
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.IncompleteRegionException;
|
import com.sk89q.worldedit.IncompleteRegionException;
|
||||||
|
import com.sk89q.worldedit.LocalSession;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.extension.factory.PatternFactory;
|
import com.sk89q.worldedit.extension.factory.PatternFactory;
|
||||||
|
import com.sk89q.worldedit.extension.platform.permission.ActorSelectorLimits;
|
||||||
import com.sk89q.worldedit.function.mask.Mask;
|
import com.sk89q.worldedit.function.mask.Mask;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.internal.registry.InputParser;
|
import com.sk89q.worldedit.internal.registry.InputParser;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.regions.RegionSelector;
|
import com.sk89q.worldedit.regions.RegionSelector;
|
||||||
|
import com.sk89q.worldedit.regions.selector.limit.SelectorLimits;
|
||||||
import de.steamwar.bausystem.shared.Pair;
|
import de.steamwar.bausystem.shared.Pair;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
@@ -37,6 +41,9 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class WorldEditUtils {
|
public class WorldEditUtils {
|
||||||
|
|
||||||
@@ -77,6 +84,40 @@ public class WorldEditUtils {
|
|||||||
return WorldEdit.getInstance().getPatternFactory();
|
return WorldEdit.getInstance().getPatternFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Pair<Class<? extends RegionSelector>, List<Location>> getVertices(Player player) {
|
||||||
|
RegionSelector regionSelector = WorldEdit.getInstance()
|
||||||
|
.getSessionManager()
|
||||||
|
.get(BukkitAdapter.adapt(player))
|
||||||
|
.getRegionSelector(BukkitAdapter.adapt(player.getWorld()));
|
||||||
|
return new Pair<>(regionSelector.getClass(), regionSelector.getVertices()
|
||||||
|
.stream()
|
||||||
|
.map(blockVector3 -> blockVector3 == null ? null : adapt(player.getWorld(), blockVector3))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVertices(Player player, Class<? extends RegionSelector> clazz, List<Location> vertices) {
|
||||||
|
LocalSession localSession = WorldEdit.getInstance()
|
||||||
|
.getSessionManager()
|
||||||
|
.get(BukkitAdapter.adapt(player));
|
||||||
|
|
||||||
|
Reflection.ConstructorInvoker constructorInvoker = Reflection.getConstructor(clazz, com.sk89q.worldedit.world.World.class);
|
||||||
|
RegionSelector regionSelector = (RegionSelector) constructorInvoker.invoke(BukkitAdapter.adapt(player.getWorld()));
|
||||||
|
localSession.setRegionSelector(BukkitAdapter.adapt(player.getWorld()), regionSelector);
|
||||||
|
|
||||||
|
if (vertices.isEmpty()) return;
|
||||||
|
|
||||||
|
SelectorLimits selectorLimits = ActorSelectorLimits.forActor(BukkitAdapter.adapt(player));
|
||||||
|
for (int i = 0; i < vertices.size(); i++) {
|
||||||
|
Location location = vertices.get(i);
|
||||||
|
if (location == null) continue;
|
||||||
|
if (i == 0) {
|
||||||
|
regionSelector.selectPrimary(BukkitAdapter.adapt(location).toBlockPoint(), selectorLimits);
|
||||||
|
} else {
|
||||||
|
regionSelector.selectSecondary(BukkitAdapter.adapt(location).toBlockPoint(), selectorLimits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Pair<Location, Location> getSelection(Player player) {
|
public Pair<Location, Location> getSelection(Player player) {
|
||||||
RegionSelector regionSelector = WorldEdit.getInstance()
|
RegionSelector regionSelector = WorldEdit.getInstance()
|
||||||
.getSessionManager()
|
.getSessionManager()
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ name: BauSystem
|
|||||||
authors: [ Lixfel, YoyoNow, Chaoscaot, Zeanon, D4rkr34lm ]
|
authors: [ Lixfel, YoyoNow, Chaoscaot, Zeanon, D4rkr34lm ]
|
||||||
version: "2.0"
|
version: "2.0"
|
||||||
depend: [ WorldEdit, SpigotCore ]
|
depend: [ WorldEdit, SpigotCore ]
|
||||||
|
softdepend:
|
||||||
|
- ViaVersion
|
||||||
load: POSTWORLD
|
load: POSTWORLD
|
||||||
main: de.steamwar.bausystem.BauSystem
|
main: de.steamwar.bausystem.BauSystem
|
||||||
api-version: "1.13"
|
api-version: "1.13"
|
||||||
|
|||||||
@@ -18,17 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("java")
|
steamwar.kotlin
|
||||||
kotlin("jvm") version "2.0.0"
|
alias(libs.plugins.shadow)
|
||||||
|
|
||||||
id("com.github.johnrengelman.shadow")
|
|
||||||
}
|
|
||||||
|
|
||||||
group = "de.steamwar"
|
|
||||||
version = ""
|
|
||||||
|
|
||||||
tasks.compileJava {
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.build {
|
tasks.build {
|
||||||
@@ -39,29 +30,6 @@ tasks.shadowJar {
|
|||||||
exclude("org/**")
|
exclude("org/**")
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_21
|
|
||||||
targetCompatibility = JavaVersion.VERSION_21
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
java {
|
|
||||||
srcDirs("src/")
|
|
||||||
}
|
|
||||||
resources {
|
|
||||||
srcDirs("src/")
|
|
||||||
exclude("**/*.java", "**/*.kt")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("reflect"))
|
compileOnly(libs.paperapi21)
|
||||||
|
|
||||||
compileOnly("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
jvmToolchain(21)
|
|
||||||
}
|
}
|
||||||
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
* 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.core
|
package de.steamwar.kotlin
|
||||||
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
name: KotlinCore
|
name: KotlinCore
|
||||||
version: '2.0.0'
|
version: '2.0.0'
|
||||||
main: de.steamwar.core.KotlinCore
|
main: de.steamwar.kotlin.KotlinCore
|
||||||
load: POSTWORLD
|
load: POSTWORLD
|
||||||
api-version: '1.21'
|
api-version: '1.21'
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ public abstract class SpecialItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ItemStack getRandomItem() {
|
public static ItemStack getRandomItem() {
|
||||||
if (Config.MissileChance == 0 || consecutiveSupportItems > 1) {
|
if (Config.MissileChance == 0) {
|
||||||
consecutiveSupportItems = 0;
|
|
||||||
return supportItems.get(random.nextInt(supportItems.size())).getItem();
|
return supportItems.get(random.nextInt(supportItems.size())).getItem();
|
||||||
}
|
}
|
||||||
if (Config.MissileChance == 1) {
|
if (Config.MissileChance == 1 || consecutiveSupportItems > 1) {
|
||||||
|
consecutiveSupportItems = 0;
|
||||||
return missileItems.get(random.nextInt(missileItems.size())).getItem();
|
return missileItems.get(random.nextInt(missileItems.size())).getItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.core;
|
||||||
|
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class CRIUSleepEvent extends Event {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.core;
|
||||||
|
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
|
||||||
|
public class CRIUWakeupEvent extends Event {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,6 @@ package de.steamwar.core;
|
|||||||
import com.comphenix.tinyprotocol.Reflection;
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
import com.viaversion.viaversion.api.Via;
|
import com.viaversion.viaversion.api.Via;
|
||||||
import de.steamwar.sql.BauweltMember;
|
|
||||||
import de.steamwar.sql.internal.Statement;
|
import de.steamwar.sql.internal.Statement;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@@ -94,6 +93,7 @@ public class CheckpointUtils {
|
|||||||
private static final Reflection.FieldAccessor<List> channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class);
|
private static final Reflection.FieldAccessor<List> channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class);
|
||||||
private static final Reflection.MethodInvoker bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class);
|
private static final Reflection.MethodInvoker bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class);
|
||||||
private static void freezeInternal(Path path) throws Exception {
|
private static void freezeInternal(Path path) throws Exception {
|
||||||
|
Bukkit.getPluginManager().callEvent(new CRIUSleepEvent());
|
||||||
Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave);
|
Bukkit.getWorlds().forEach(FlatteningWrapper.impl::syncSave);
|
||||||
Statement.closeAll();
|
Statement.closeAll();
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ public class CheckpointUtils {
|
|||||||
}
|
}
|
||||||
Via.getManager().getInjector().inject();
|
Via.getManager().getInjector().inject();
|
||||||
|
|
||||||
BauweltMember.clear();
|
Bukkit.getPluginManager().callEvent(new CRIUWakeupEvent());
|
||||||
Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored");
|
Core.getInstance().getLogger().log(Level.INFO, "Checkpoint restored");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
plugins {
|
||||||
|
steamwar.kotlin
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(libs.paperapi21)
|
||||||
|
compileOnly(project(":SpigotCore"))
|
||||||
|
compileOnly(project(":KotlinCore"))
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
startDelay: 10
|
||||||
|
gameTime: 1200
|
||||||
|
|
||||||
|
prices:
|
||||||
|
TNT:
|
||||||
|
price: 4
|
||||||
|
amount: 4
|
||||||
|
REDSTONE:
|
||||||
|
price: 4
|
||||||
|
amount: 4
|
||||||
|
REPEATER:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
COMPARATOR:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
REDSTONE_BLOCK:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
REDSTONE_TORCH:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
END_STONE:
|
||||||
|
price: 4
|
||||||
|
amount: 8
|
||||||
|
ICE:
|
||||||
|
price: 8
|
||||||
|
amount: 1
|
||||||
|
LEVER:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
OAK_BUTTON:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
STONE_BUTTON:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
OAK_TRAPDOOR:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
IRON_TRAPDOOR:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
PISTON:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
STICKY_PISTON:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
GLASS:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
OAK_FENCE:
|
||||||
|
price: 4
|
||||||
|
amount: 4
|
||||||
|
LADDER:
|
||||||
|
price: 6
|
||||||
|
amount: 2
|
||||||
|
WHITE_GLAZED_TERRACOTTA:
|
||||||
|
price: 4
|
||||||
|
amount: 3
|
||||||
|
JUKEBOX:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
OBSERVER:
|
||||||
|
price: 10
|
||||||
|
amount: 4
|
||||||
|
BREWING_STAND:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
STRING:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
END_STONE_BRICK_SLAB:
|
||||||
|
price: 4
|
||||||
|
amount: 2
|
||||||
|
TARGET:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
COPPER_BULB:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
SLIME_BLOCK:
|
||||||
|
price: 6
|
||||||
|
amount: 2
|
||||||
|
HONEY_BLOCK:
|
||||||
|
price: 6
|
||||||
|
amount: 2
|
||||||
|
STONE_PRESSURE_PLATE:
|
||||||
|
price: 4
|
||||||
|
amount: 1
|
||||||
|
NOTE_BLOCK:
|
||||||
|
price: 3
|
||||||
|
amount: 1
|
||||||
|
HOPPER:
|
||||||
|
price: 3
|
||||||
|
amount: 1
|
||||||
|
GRAVEL:
|
||||||
|
price: 4
|
||||||
|
amount: 3
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package de.steamwar.tntleague
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.command.AcceptCommand
|
||||||
|
import de.steamwar.tntleague.command.InviteCommand
|
||||||
|
import de.steamwar.tntleague.command.LeaveCommand
|
||||||
|
import de.steamwar.tntleague.command.RemoveCommand
|
||||||
|
import de.steamwar.tntleague.events.GlobalListener
|
||||||
|
import de.steamwar.tntleague.events.LobbyListener
|
||||||
|
import net.kyori.adventure.key.Key
|
||||||
|
import net.kyori.adventure.translation.GlobalTranslator
|
||||||
|
import net.kyori.adventure.translation.TranslationRegistry
|
||||||
|
import net.kyori.adventure.util.UTF8ResourceBundleControl
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
lateinit var plugin: TNTLeague
|
||||||
|
|
||||||
|
class TNTLeague : JavaPlugin() {
|
||||||
|
init {
|
||||||
|
plugin = this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEnable() {
|
||||||
|
saveResource("config.yml", false)
|
||||||
|
saveDefaultConfig()
|
||||||
|
|
||||||
|
val registry = TranslationRegistry.create(Key.key("steamwar:tntleague"))
|
||||||
|
|
||||||
|
val bundleDe = ResourceBundle.getBundle("de.steamwar.tntleague.TNTLeague", Locale.GERMAN, UTF8ResourceBundleControl())
|
||||||
|
val bundleEn = ResourceBundle.getBundle("de.steamwar.tntleague.TNTLeague", Locale.US, UTF8ResourceBundleControl())
|
||||||
|
registry.defaultLocale(Locale.US)
|
||||||
|
|
||||||
|
registry.registerAll(Locale.GERMAN, bundleDe, true)
|
||||||
|
registry.registerAll(Locale.US, bundleEn, true)
|
||||||
|
|
||||||
|
GlobalTranslator.translator().addSource(registry)
|
||||||
|
|
||||||
|
server.pluginManager.registerEvents(LobbyListener, this)
|
||||||
|
server.pluginManager.registerEvents(GlobalListener, this)
|
||||||
|
|
||||||
|
logger.info("TNTLeague enabled")
|
||||||
|
|
||||||
|
InviteCommand.register()
|
||||||
|
AcceptCommand.register()
|
||||||
|
RemoveCommand.register()
|
||||||
|
LeaveCommand.register()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
join={0} ist dem Spiel beigetreten!
|
||||||
|
joinTeam={0} ist dem {1} team begetreten!
|
||||||
|
quit={0} hat das Spiel verlassen!
|
||||||
|
blue=Blau
|
||||||
|
red=Rot
|
||||||
|
shutdown=Der Server fährt in {0} sekunden herunter!
|
||||||
|
teamWin=Team {0} gewinnt!
|
||||||
|
notEnoughCoins=Du hast nicht genug Coins um dir das zu kaufen!
|
||||||
|
gameStarting=Das Spiel beginnt in {0} Sekunden!
|
||||||
|
gameStart=Start in {0}
|
||||||
|
gameStarted=Das Spiel beginnt!
|
||||||
|
gameEnded=Das Spiel ist aus!
|
||||||
|
dealer=Händler
|
||||||
|
dealerItem=
|
||||||
|
dealerPrice=Kosten: {0} Coins
|
||||||
|
scoreboardTarget=Ziel: {0}
|
||||||
|
scoreboardTime=Zeit: {0}:{1}
|
||||||
|
scoreboardTeam=
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
join={0} joined the game!
|
||||||
|
joinTeam={0} joined the {1} team!
|
||||||
|
quit={0} left the game!
|
||||||
|
quitTeam={0} left the {1} team!
|
||||||
|
blue=Blue
|
||||||
|
red=Red
|
||||||
|
shutdown=The server stops in {0} seconds!
|
||||||
|
teamWin=Team {0} wins!
|
||||||
|
|
||||||
|
notEnoughCoins=You don't have enough coins to buy this item!
|
||||||
|
|
||||||
|
gameStarting=The game starts in {0} seconds!
|
||||||
|
gameStart=Starting in {0}
|
||||||
|
gameStarted=The game has started!
|
||||||
|
|
||||||
|
timeRemaining={0} minutes remaining!
|
||||||
|
|
||||||
|
gameEnded=The game has ended!
|
||||||
|
draw=The game ended in a draw!
|
||||||
|
chat={0}» {1}
|
||||||
|
|
||||||
|
dealer=Shopkeeper
|
||||||
|
dealerItem={0} {1}
|
||||||
|
dealerPrice=Price: {0} Coins
|
||||||
|
|
||||||
|
scoreboardTarget=Target: {0}
|
||||||
|
scoreboardTime=Time: {0}:{1}
|
||||||
|
scoreboardTeam=Team {0}: {1}
|
||||||
|
|
||||||
|
ready=Ready
|
||||||
|
notReady=Not ready
|
||||||
|
isReady=Team {0} is ready!
|
||||||
|
isNotReady=Team {0} is not ready!
|
||||||
|
|
||||||
|
invited={0} invited you to join the {1} team! *Click*
|
||||||
|
invitedHover=Click to join the {0} team!
|
||||||
|
invitedPlayer=Invited {0} to join your team!
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* 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.tntleague.command
|
||||||
|
|
||||||
|
import de.steamwar.command.SWCommand
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
object AcceptCommand: SWCommand("accept") {
|
||||||
|
|
||||||
|
@Register
|
||||||
|
fun acceptInvite(sender: Player, @Validator("isLeader") target: Player) {
|
||||||
|
if (TNTLeagueGame.state != TNTLeagueGame.GameState.LOBBY) return
|
||||||
|
|
||||||
|
val team = TNTLeagueGame.getTeam(target) ?: return
|
||||||
|
if (team.leader != target) return
|
||||||
|
if (sender !in team.invites) return
|
||||||
|
|
||||||
|
team.invites.remove(target)
|
||||||
|
team.opposite.invites.remove(target)
|
||||||
|
team.join(sender)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.tntleague.command
|
||||||
|
|
||||||
|
import de.steamwar.command.SWCommand
|
||||||
|
import de.steamwar.command.TypeValidator
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import de.steamwar.tntleague.util.*
|
||||||
|
import net.kyori.adventure.text.event.ClickEvent
|
||||||
|
import net.kyori.adventure.text.event.HoverEvent
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
object InviteCommand: SWCommand("invite") {
|
||||||
|
|
||||||
|
@Register
|
||||||
|
fun invitePlayer(@Validator("isLeader") sender: Player, target: Player) {
|
||||||
|
if (TNTLeagueGame.state != TNTLeagueGame.GameState.LOBBY) return
|
||||||
|
if (TNTLeagueGame.getTeam(target) != null) return
|
||||||
|
|
||||||
|
val team = TNTLeagueGame.getTeam(sender)!!
|
||||||
|
team.invites.add(target)
|
||||||
|
|
||||||
|
target.sendMessage(translate("invited", sender.name.yellow(), translate(team.name).colorByTeam(team)).basic().clickEvent(
|
||||||
|
ClickEvent.callback {
|
||||||
|
if (target !in team.invites) return@callback
|
||||||
|
|
||||||
|
team.invites.remove(target)
|
||||||
|
team.opposite.invites.remove(target)
|
||||||
|
team.join(target)
|
||||||
|
})
|
||||||
|
.hoverEvent(HoverEvent.showText(translate("invitedHover", translate(team.name).colorByTeam(team)).green())))
|
||||||
|
sender.sendMessage(translate("invitedPlayer", target.name.yellow()).basic())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validator("isLeader", local = false)
|
||||||
|
fun isLeader(): TypeValidator<Player> {
|
||||||
|
return TypeValidator<Player> { _, player, _ -> TNTLeagueGame.getTeam(player)?.leader == player}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.tntleague.command
|
||||||
|
|
||||||
|
import de.steamwar.command.SWCommand
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
object LeaveCommand: SWCommand("leave", "l") {
|
||||||
|
|
||||||
|
@Register
|
||||||
|
fun leave(player: Player) = TNTLeagueGame.getTeam(player)?.remove(player)
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.tntleague.command
|
||||||
|
|
||||||
|
import de.steamwar.command.SWCommand
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
object RemoveCommand: SWCommand("remove") {
|
||||||
|
|
||||||
|
@Register
|
||||||
|
fun removePlayer(@Validator("isLeader") sender: Player, target: Player) {
|
||||||
|
if (TNTLeagueGame.state != TNTLeagueGame.GameState.LOBBY) return
|
||||||
|
|
||||||
|
if (sender == target) return
|
||||||
|
val team = TNTLeagueGame.getTeam(sender) ?: return
|
||||||
|
if (team.leader != sender) return
|
||||||
|
if (target !in team.members) return
|
||||||
|
|
||||||
|
team.remove(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package de.steamwar.tntleague.config
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.plugin
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.configuration.ConfigurationSection
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration
|
||||||
|
|
||||||
|
data class TNTLeagueConfig(
|
||||||
|
val startDelay: Int = 10,
|
||||||
|
val gameTime: Int = 60 * 20,
|
||||||
|
|
||||||
|
val prices: Map<Material, Price>
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val config: TNTLeagueConfig by lazy { loadConfig(plugin.config) }
|
||||||
|
|
||||||
|
private fun loadConfig(config: FileConfiguration): TNTLeagueConfig {
|
||||||
|
return TNTLeagueConfig(config.getInt("startDelay"), config.getInt("gameTime"), loadPrices(config.getConfigurationSection("prices")!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadPrices(config: ConfigurationSection): Map<Material, Price> {
|
||||||
|
return config.getKeys(false).associateWith {
|
||||||
|
Price(
|
||||||
|
config.getInt("$it.amount"),
|
||||||
|
config.getInt("$it.price")
|
||||||
|
)
|
||||||
|
}.mapKeys { Material.getMaterial(it.key)!! }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Price(
|
||||||
|
val amount: Int,
|
||||||
|
val price: Int,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package de.steamwar.tntleague.config
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.plugin
|
||||||
|
import de.steamwar.tntleague.util.Area
|
||||||
|
import de.steamwar.tntleague.util.translate
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.configuration.ConfigurationSection
|
||||||
|
import org.bukkit.configuration.file.YamlConfiguration
|
||||||
|
import org.bukkit.entity.Villager
|
||||||
|
import org.bukkit.entity.WanderingTrader
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
val world by lazy { plugin.server.worlds.first()!! }
|
||||||
|
|
||||||
|
private val targetedBlocksRed by lazy { TNTLeagueWorldConfig.redTeam.target.blocks.count { block -> block.type == TNTLeagueWorldConfig.targetMaterial } }
|
||||||
|
|
||||||
|
private val targetedBlocksBlue by lazy { TNTLeagueWorldConfig.blueTeam.target.blocks.count { block -> block.type == TNTLeagueWorldConfig.targetMaterial } }
|
||||||
|
|
||||||
|
private val targetedBlocksAll: Int
|
||||||
|
get() = if (targetedBlocksBlue == targetedBlocksRed) targetedBlocksBlue else error("Targeted blocks are not equal")
|
||||||
|
|
||||||
|
val targetedBlocks: Int
|
||||||
|
get() = if (TNTLeagueWorldConfig.target != -1) TNTLeagueWorldConfig.target else targetedBlocksAll
|
||||||
|
|
||||||
|
object TNTLeagueWorldConfig {
|
||||||
|
private val config: YamlConfiguration by lazy {
|
||||||
|
YamlConfiguration.loadConfiguration(
|
||||||
|
File(
|
||||||
|
plugin.server.worlds.first().worldFolder,
|
||||||
|
"tntleague.yml"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val blueTeam: TeamConfig = TeamConfig.fromConfig(config.getConfigurationSection("blueTeam")!!)
|
||||||
|
val redTeam: TeamConfig = TeamConfig.fromConfig(config.getConfigurationSection("redTeam")!!)
|
||||||
|
val lobby: Location = config.getLocation("lobby", blueTeam.spawnLocation.clone().add(redTeam.spawnLocation).multiply(0.5))!!
|
||||||
|
val targetMaterial: Material = Material.matchMaterial(config.getString("targetMaterial", "IRON_BLOCK")!!)!!
|
||||||
|
val minHeight: Int = config.getInt("minHeight", 0)
|
||||||
|
val target: Int = config.getInt("target", -1)
|
||||||
|
|
||||||
|
@JvmRecord
|
||||||
|
data class TeamConfig(
|
||||||
|
val spawnLocation: Location,
|
||||||
|
val dealerSpawn: Location,
|
||||||
|
val itemSpawn: Location,
|
||||||
|
val target: Area
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun fromConfig(config: ConfigurationSection): TeamConfig {
|
||||||
|
val spawnLocation = config.getLocation("spawn")!!
|
||||||
|
val dealerSpawn = config.getLocation("dealerSpawn")!!
|
||||||
|
val itemSpawn = config.getLocation("itemSpawn")!!
|
||||||
|
val targetPos1 = config.getLocation("targetMin")!!
|
||||||
|
val targetPos2 = config.getLocation("targetMax")!!
|
||||||
|
|
||||||
|
spawnDealer(dealerSpawn)
|
||||||
|
|
||||||
|
return TeamConfig(spawnLocation, dealerSpawn, itemSpawn, Area(targetPos1, targetPos2))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun spawnDealer(loc: Location) = world.spawn(loc, WanderingTrader::class.java)
|
||||||
|
.apply {
|
||||||
|
customName(translate("dealer"))
|
||||||
|
isCustomNameVisible = false
|
||||||
|
isInvulnerable = true
|
||||||
|
isSilent = true
|
||||||
|
isCollidable = false
|
||||||
|
isAware = false
|
||||||
|
setAI(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.tntleague.events
|
||||||
|
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
|
||||||
|
object DummyListener: Listener {
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
package de.steamwar.tntleague.events
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.config.TNTLeagueWorldConfig
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueTeam
|
||||||
|
import de.steamwar.tntleague.inventory.SWInventoryHolder
|
||||||
|
import de.steamwar.tntleague.plugin
|
||||||
|
import de.steamwar.tntleague.util.*
|
||||||
|
import io.papermc.paper.event.player.AsyncChatEvent
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.EventPriority
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
import org.bukkit.event.player.PlayerRespawnEvent
|
||||||
|
|
||||||
|
object GlobalListener: Listener {
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
fun onPlayerJoin(e: PlayerJoinEvent) {
|
||||||
|
e.joinMessage(null)
|
||||||
|
with(e.player) {
|
||||||
|
teleport(TNTLeagueWorldConfig.lobby)
|
||||||
|
inventory.clear()
|
||||||
|
plugin.server.broadcast(translate("join", name.bold()).basic())
|
||||||
|
isOp = false
|
||||||
|
gameMode = GameMode.SPECTATOR
|
||||||
|
respawnLocation = TNTLeagueWorldConfig.lobby
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
fun onPlayerQuit(e: PlayerQuitEvent) {
|
||||||
|
e.quitMessage(null)
|
||||||
|
plugin.server.broadcast(translate("quit", e.player.name.bold().colorByTeam(TNTLeagueGame.getTeam(e.player))).basic())
|
||||||
|
TNTLeagueGame.playerLeave(e.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
fun onPlayerClick(e: InventoryClickEvent) {
|
||||||
|
val holder = e.inventory.getHolder(false)
|
||||||
|
if (holder is SWInventoryHolder && e.clickedInventory == holder._inventory) {
|
||||||
|
e.isCancelled = true
|
||||||
|
holder.handleInventoryClick(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
fun onPlayerMove(e: PlayerMoveEvent) {
|
||||||
|
if (e.to.blockY < TNTLeagueWorldConfig.minHeight) {
|
||||||
|
when (val team = TNTLeagueGame.getTeam(e.player)) {
|
||||||
|
is TNTLeagueTeam -> e.player.teleport(team.config.spawnLocation)
|
||||||
|
null -> e.player.teleport(TNTLeagueWorldConfig.blueTeam.spawnLocation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.player.foodLevel = 20
|
||||||
|
e.player.saturation = 20f
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerDeath(e: PlayerDeathEvent) {
|
||||||
|
e.deathMessage(null)
|
||||||
|
e.drops.clear()
|
||||||
|
|
||||||
|
e.itemsToKeep.removeIf { it.type != Material.DIAMOND_PICKAXE }
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerRespawn(e: PlayerRespawnEvent) {
|
||||||
|
when (val team = TNTLeagueGame.getTeam(e.player)) {
|
||||||
|
is TNTLeagueTeam -> e.respawnLocation = team.config.spawnLocation
|
||||||
|
null -> e.respawnLocation = TNTLeagueWorldConfig.lobby
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onChat(e: AsyncChatEvent) {
|
||||||
|
e.renderer { source, sourceDisplayName, message, _ ->
|
||||||
|
translate("chat", sourceDisplayName.colorByTeam(TNTLeagueGame.getTeam(source)), message).basic()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package de.steamwar.tntleague.events
|
||||||
|
|
||||||
|
import de.steamwar.scoreboard.SWScoreboard
|
||||||
|
import de.steamwar.tntleague.config.TNTLeagueWorldConfig
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueTeam
|
||||||
|
import de.steamwar.tntleague.inventory.DealerInventory
|
||||||
|
import de.steamwar.tntleague.util.TNTLeagueScoreboard
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.entity.EntityType
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.entity.EntityExplodeEvent
|
||||||
|
import org.bukkit.event.entity.PlayerDeathEvent
|
||||||
|
import org.bukkit.event.player.PlayerDropItemEvent
|
||||||
|
import org.bukkit.event.player.PlayerInteractEntityEvent
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
|
||||||
|
object IngameListener: Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onEntityInteract(e: PlayerInteractEntityEvent) {
|
||||||
|
if (e.player.gameMode == GameMode.SPECTATOR) return
|
||||||
|
|
||||||
|
if(e.rightClicked.type == EntityType.VILLAGER) {
|
||||||
|
e.isCancelled = true
|
||||||
|
e.player.openInventory(DealerInventory(e.player).getInventory())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onExplode(e: EntityExplodeEvent) {
|
||||||
|
e.blockList().filter { it.type == TNTLeagueWorldConfig.targetMaterial }
|
||||||
|
.groupBy { getTeamByTargetLocation(it.location) }
|
||||||
|
.filterKeysNotNull()
|
||||||
|
.mapValues { it.value.size }
|
||||||
|
.forEach { it.key.damagedBlocks += it.value }
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onJoin(e: PlayerJoinEvent) {
|
||||||
|
SWScoreboard.createScoreboard(e.player, TNTLeagueScoreboard(e.player))
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onMove(e: PlayerMoveEvent) {
|
||||||
|
if (TNTLeagueGame.getTeam(e.player) != null) {
|
||||||
|
if (e.to.blockX >= TNTLeagueWorldConfig.lobby.blockX && e.to.blockX <= TNTLeagueWorldConfig.lobby.blockX + 1 ||
|
||||||
|
e.to.blockZ >= TNTLeagueWorldConfig.lobby.blockZ && e.to.blockZ <= TNTLeagueWorldConfig.lobby.blockZ + 1) {
|
||||||
|
e.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onDropPickaxe(e: PlayerDropItemEvent) {
|
||||||
|
if (e.itemDrop.itemStack.type == Material.DIAMOND_PICKAXE) {
|
||||||
|
e.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTeamByTargetLocation(location: Location): TNTLeagueTeam? =
|
||||||
|
when (location) {
|
||||||
|
in TNTLeagueWorldConfig.redTeam.target -> TNTLeagueGame.redTeam
|
||||||
|
in TNTLeagueWorldConfig.blueTeam.target -> TNTLeagueGame.blueTeam
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <K, T> Map<K?, T>.filterKeysNotNull(destination: MutableMap<K, T> = mutableMapOf()): Map<K, T> {
|
||||||
|
this.forEach { (t, u) -> if(t != null) destination[t] = u }
|
||||||
|
return destination
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package de.steamwar.tntleague.events
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import de.steamwar.tntleague.plugin
|
||||||
|
import de.steamwar.tntleague.util.basic
|
||||||
|
import de.steamwar.tntleague.util.colorByTeam
|
||||||
|
import de.steamwar.tntleague.util.translate
|
||||||
|
import de.steamwar.tntleague.util.yellow
|
||||||
|
import io.papermc.paper.util.Tick
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.EventPriority
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.event.block.Action
|
||||||
|
import org.bukkit.event.entity.EntityDamageEvent
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
|
import org.bukkit.event.player.PlayerDropItemEvent
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent
|
||||||
|
import org.bukkit.event.player.PlayerJoinEvent
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent
|
||||||
|
|
||||||
|
object LobbyListener: Listener {
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerJoin(e: PlayerJoinEvent) {
|
||||||
|
TNTLeagueGame.getFreeTeam()?.run {
|
||||||
|
join(e.player)
|
||||||
|
TNTLeagueGame.checkStart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
fun onPlayerQuit(e: PlayerQuitEvent) {
|
||||||
|
val team = TNTLeagueGame.getTeam(e.player) ?: return
|
||||||
|
team.leave(e.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onPlayerDamage(e: EntityDamageEvent) {
|
||||||
|
e.isCancelled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun onDropEvent(e: PlayerDropItemEvent) {
|
||||||
|
e.isCancelled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun interactEvent(e: PlayerInteractEvent) {
|
||||||
|
val team = TNTLeagueGame.getTeam(e.player)
|
||||||
|
if (e.action.isRightClick && team != null && e.item?.isSimilar(team.readyItem()) == true && team.opposite.leader != null) {
|
||||||
|
team.isReady = !team.isReady
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
fun inventoryClick(e: InventoryClickEvent) {
|
||||||
|
if (e.clickedInventory == e.whoClicked.inventory) {
|
||||||
|
e.isCancelled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
package de.steamwar.tntleague.game
|
||||||
|
|
||||||
|
import de.steamwar.scoreboard.SWScoreboard
|
||||||
|
import de.steamwar.sql.Fight
|
||||||
|
import de.steamwar.sql.FightPlayer
|
||||||
|
import de.steamwar.sql.SteamwarUser
|
||||||
|
import de.steamwar.tntleague.config.TNTLeagueConfig
|
||||||
|
import de.steamwar.tntleague.config.TNTLeagueWorldConfig
|
||||||
|
import de.steamwar.tntleague.config.world
|
||||||
|
import de.steamwar.tntleague.events.DummyListener
|
||||||
|
import de.steamwar.tntleague.events.IngameListener
|
||||||
|
import de.steamwar.tntleague.events.LobbyListener
|
||||||
|
import de.steamwar.tntleague.inventory.DealerInventory
|
||||||
|
import de.steamwar.tntleague.plugin
|
||||||
|
import de.steamwar.tntleague.util.*
|
||||||
|
import net.kyori.adventure.bossbar.BossBar
|
||||||
|
import net.kyori.adventure.sound.Sound
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.block.data.type.TNT
|
||||||
|
import org.bukkit.entity.Entity
|
||||||
|
import org.bukkit.entity.Item
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.entity.TNTPrimed
|
||||||
|
import org.bukkit.entity.Villager
|
||||||
|
import org.bukkit.event.HandlerList
|
||||||
|
import org.bukkit.event.Listener
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.scheduler.BukkitTask
|
||||||
|
import java.sql.Timestamp
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
object TNTLeagueGame {
|
||||||
|
var state: GameState = GameState.LOBBY
|
||||||
|
set(value) {
|
||||||
|
if (field.listener != value.listener) {
|
||||||
|
HandlerList.unregisterAll(field.listener)
|
||||||
|
plugin.server.pluginManager.registerEvents(value.listener, plugin)
|
||||||
|
}
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
var gameTimeRemaining: Int = TNTLeagueConfig.config.gameTime
|
||||||
|
|
||||||
|
val blueTeam = TNTLeagueTeam(TNTLeagueWorldConfig.blueTeam, TNTLeagueTeam.Team.BLUE)
|
||||||
|
val redTeam = TNTLeagueTeam(TNTLeagueWorldConfig.redTeam, TNTLeagueTeam.Team.RED)
|
||||||
|
|
||||||
|
private lateinit var start: Timestamp
|
||||||
|
|
||||||
|
private var task: Int? = null
|
||||||
|
private lateinit var spawnerTask: BukkitTask
|
||||||
|
private lateinit var timerTask: BukkitTask
|
||||||
|
|
||||||
|
private fun setup() {
|
||||||
|
assert(state == GameState.STARTING) { "Game is already running" }
|
||||||
|
|
||||||
|
state = GameState.RUNNING
|
||||||
|
|
||||||
|
plugin.server.onlinePlayers.forEach { SWScoreboard.createScoreboard(it, TNTLeagueScoreboard(it)) }
|
||||||
|
|
||||||
|
blueTeam.start()
|
||||||
|
redTeam.start()
|
||||||
|
|
||||||
|
plugin.server.broadcast(translate("gameStarted").success())
|
||||||
|
|
||||||
|
val tnt = ItemStack(Material.TNT)
|
||||||
|
|
||||||
|
start = Timestamp.from(Instant.now())
|
||||||
|
|
||||||
|
spawnerTask = plugin.server.scheduler.runTaskTimer(plugin, bukkit {
|
||||||
|
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.blueTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
|
||||||
|
spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, tnt)
|
||||||
|
spawnItems(TNTLeagueWorldConfig.blueTeam.itemSpawn, DealerInventory.coins)
|
||||||
|
}
|
||||||
|
if (world.getNearbyEntitiesByType(Item::class.java, TNTLeagueWorldConfig.redTeam.itemSpawn, 3.0).sumOf { it.itemStack.amount } <= 256) {
|
||||||
|
spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, tnt)
|
||||||
|
spawnItems(TNTLeagueWorldConfig.redTeam.itemSpawn, DealerInventory.coins)
|
||||||
|
}
|
||||||
|
}, 5, 10)
|
||||||
|
|
||||||
|
timerTask = plugin.server.scheduler.runTaskTimer(plugin, bukkit {
|
||||||
|
gameTimeRemaining--
|
||||||
|
if (gameTimeRemaining == 0) {
|
||||||
|
draw(WinReason.TIMEOUT)
|
||||||
|
return@bukkit
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gameTimeRemaining % 300 == 0) {
|
||||||
|
plugin.server.broadcast(translate("timeRemaining", (gameTimeRemaining / 60).toString().yellow()).basic())
|
||||||
|
plugin.server.onlinePlayers.forEach { it.playSound(Sound.sound(org.bukkit.Sound.BLOCK_NOTE_BLOCK_PLING.key, Sound.Source.MASTER, 1f, 1f)) }
|
||||||
|
}
|
||||||
|
}, 20, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bukkit(f: () -> Unit): () -> Unit = f
|
||||||
|
|
||||||
|
private fun end() {
|
||||||
|
if(state != GameState.RUNNING) return
|
||||||
|
state = GameState.END
|
||||||
|
|
||||||
|
plugin.server.onlinePlayers.forEach {
|
||||||
|
it.gameMode = GameMode.SPECTATOR
|
||||||
|
SWScoreboard.removeScoreboard(it)
|
||||||
|
it.playSound(Sound.sound(org.bukkit.Sound.ENTITY_ENDER_DRAGON_DEATH.key, Sound.Source.MASTER, 1f, 1f))
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.server.broadcast(translate("gameEnded").success())
|
||||||
|
|
||||||
|
spawnerTask.cancel()
|
||||||
|
|
||||||
|
var shutdown = 10
|
||||||
|
|
||||||
|
plugin.server.scheduler.runTaskTimer(plugin, bukkit {
|
||||||
|
if (shutdown == 0) {
|
||||||
|
plugin.server.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.server.broadcast(translate("shutdown", shutdown.toString().yellow()).basic())
|
||||||
|
|
||||||
|
shutdown--
|
||||||
|
}, 20, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun spawnItems(loc: Location, item: ItemStack) = plugin.server.worlds.first().dropItem(loc, item)
|
||||||
|
|
||||||
|
fun getTeam(player: Player) = if (player in blueTeam.members) blueTeam else if (player in redTeam.members) redTeam else null
|
||||||
|
|
||||||
|
fun getFreeTeam() = if (blueTeam.leader == null) blueTeam else if (redTeam.leader == null) redTeam else null
|
||||||
|
|
||||||
|
fun checkStart() {
|
||||||
|
if (blueTeam.isReady && redTeam.isReady) {
|
||||||
|
blueTeam.leader?.inventory?.clear()
|
||||||
|
redTeam.leader?.inventory?.clear()
|
||||||
|
state = GameState.STARTING
|
||||||
|
|
||||||
|
var countdown = TNTLeagueConfig.config.startDelay
|
||||||
|
plugin.server.broadcast(translate("gameStarting", countdown.toString().yellow()).basic())
|
||||||
|
val bar = BossBar.bossBar(translate("gameStart", countdown.toString().yellow()).gray(), (TNTLeagueConfig.config.startDelay - countdown) / TNTLeagueConfig.config.startDelay.toFloat(), BossBar.Color.GREEN, BossBar.Overlay.NOTCHED_10)
|
||||||
|
plugin.server.onlinePlayers.forEach { bar.addViewer(it) }
|
||||||
|
task = plugin.server.scheduler.scheduleSyncRepeatingTask(plugin, {
|
||||||
|
plugin.server.onlinePlayers.forEach { it.playSound(Sound.sound(org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP.key, Sound.Source.MASTER, 1f, 1f)) }
|
||||||
|
if (countdown-- == 0) {
|
||||||
|
plugin.server.onlinePlayers.forEach { it.hideBossBar(bar) }
|
||||||
|
task = task?.also { plugin.server.scheduler.cancelTask(it) }.let { null }
|
||||||
|
setup()
|
||||||
|
} else {
|
||||||
|
bar.name(translate("gameStart", countdown.toString().yellow()).gray())
|
||||||
|
bar.progress((TNTLeagueConfig.config.startDelay - countdown) / TNTLeagueConfig.config.startDelay.toFloat())
|
||||||
|
plugin.server.onlinePlayers.filter { !it.activeBossBars().contains(bar) }.forEach { bar.addViewer(it) }
|
||||||
|
}
|
||||||
|
}, 20, 20)
|
||||||
|
|
||||||
|
if (task == -1) {
|
||||||
|
error("Failed to start countdown task")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playerLeave(player: Player) {
|
||||||
|
blueTeam.invites.remove(player)
|
||||||
|
redTeam.invites.remove(player)
|
||||||
|
getTeam(player)?.apply {
|
||||||
|
members.remove(player)
|
||||||
|
if (leader == player) {
|
||||||
|
win(this.opposite, WinReason.LEAVE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
assert(state == GameState.LOBBY || state == GameState.STARTING) { "Game is not in lobby or starting state" }
|
||||||
|
|
||||||
|
if (state == GameState.STARTING) {
|
||||||
|
task = task?.also { plugin.server.scheduler.cancelTask(it) }.let { null }
|
||||||
|
plugin.server.onlinePlayers.forEach { p -> p.activeBossBars().forEach { it.removeViewer(p) } }
|
||||||
|
state = GameState.LOBBY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun win(tntLeagueTeam: TNTLeagueTeam, reason: WinReason) {
|
||||||
|
if (state != GameState.RUNNING) return
|
||||||
|
end()
|
||||||
|
plugin.server.broadcast(translate("teamWin", translate(tntLeagueTeam.name).color(tntLeagueTeam.color)).success())
|
||||||
|
statistic(tntLeagueTeam, reason)
|
||||||
|
explode(tntLeagueTeam.opposite)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun draw(reason: WinReason) {
|
||||||
|
if (state != GameState.RUNNING) return
|
||||||
|
end()
|
||||||
|
plugin.server.broadcast(translate("draw").success())
|
||||||
|
statistic(null, reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun explode(team: TNTLeagueTeam) {
|
||||||
|
Area(team.config.spawnLocation.clone().add(20.0, 30.0, 20.0), team.config.spawnLocation.clone().subtract(20.0, 0.0, 20.0).add(0.0, 30.0, 0.0))
|
||||||
|
.locations
|
||||||
|
.filterIndexed { index, _ -> index % 7 == 0 }
|
||||||
|
.forEachIndexed { index, location ->
|
||||||
|
world.spawn(location, TNTPrimed::class.java).apply {
|
||||||
|
fuseTicks = index + 40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun statistic(winTeam: TNTLeagueTeam?, reason: WinReason) {
|
||||||
|
val fightId = Fight.create(
|
||||||
|
"TNTLeague",
|
||||||
|
world.name,
|
||||||
|
start,
|
||||||
|
TNTLeagueConfig.config.gameTime - gameTimeRemaining,
|
||||||
|
SteamwarUser.get(blueTeam.leader!!.uniqueId).id,
|
||||||
|
SteamwarUser.get(redTeam.leader!!.uniqueId).id,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
when (winTeam) {
|
||||||
|
blueTeam -> 1
|
||||||
|
redTeam -> 2
|
||||||
|
else -> 0
|
||||||
|
},
|
||||||
|
when (reason) {
|
||||||
|
WinReason.TIMEOUT -> "TIMEOUT"
|
||||||
|
WinReason.DESTROYED -> "DESTROYED"
|
||||||
|
WinReason.LEAVE -> "LEAVE"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
addTeamMember(blueTeam, fightId)
|
||||||
|
addTeamMember(redTeam, fightId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addTeamMember(team: TNTLeagueTeam, fightId: Int) {
|
||||||
|
team.members.filter { team.leader != it }
|
||||||
|
.forEach {
|
||||||
|
FightPlayer.create(
|
||||||
|
fightId,
|
||||||
|
SteamwarUser.get(it.uniqueId).id,
|
||||||
|
team == blueTeam,
|
||||||
|
"TNTLeague",
|
||||||
|
0,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class GameState(val listener: Listener) {
|
||||||
|
LOBBY(LobbyListener),
|
||||||
|
STARTING(LobbyListener),
|
||||||
|
RUNNING(IngameListener),
|
||||||
|
END(DummyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class WinReason {
|
||||||
|
TIMEOUT,
|
||||||
|
DESTROYED,
|
||||||
|
LEAVE
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
package de.steamwar.tntleague.game
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.config.TNTLeagueWorldConfig
|
||||||
|
import de.steamwar.tntleague.config.targetedBlocks
|
||||||
|
import de.steamwar.tntleague.plugin
|
||||||
|
import de.steamwar.tntleague.util.*
|
||||||
|
import net.kyori.adventure.sound.Sound
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import net.kyori.adventure.text.format.TextColor
|
||||||
|
import org.bukkit.GameMode
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.enchantments.Enchantment
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import java.awt.Color.green
|
||||||
|
|
||||||
|
data class TNTLeagueTeam(val config: TNTLeagueWorldConfig.TeamConfig, private val team: Team) {
|
||||||
|
|
||||||
|
var leader: Player? = null
|
||||||
|
set(player) {
|
||||||
|
field = player
|
||||||
|
if (player != null) {
|
||||||
|
with(player.inventory) {
|
||||||
|
clear()
|
||||||
|
setItem(4, readyItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val members = mutableListOf<Player>()
|
||||||
|
val invites = mutableListOf<Player>()
|
||||||
|
|
||||||
|
val name: String
|
||||||
|
get() = team.name.lowercase()
|
||||||
|
|
||||||
|
val color: TextColor
|
||||||
|
get() = team.color
|
||||||
|
|
||||||
|
var isReady: Boolean = false
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
leader?.inventory?.setItem(4, readyItem())
|
||||||
|
leader?.playSound(Sound.sound(org.bukkit.Sound.BLOCK_NOTE_BLOCK_PLING.key, Sound.Source.MASTER, 1f, 1f))
|
||||||
|
|
||||||
|
plugin.server.onlinePlayers.forEach { it.sendActionBar(translate(if (value) "isReady" else "isNotReady", translate(this.name).colorByTeam(this)).let { cmp ->
|
||||||
|
if (value) {
|
||||||
|
cmp.green()
|
||||||
|
} else {
|
||||||
|
cmp.red()
|
||||||
|
}
|
||||||
|
}) }
|
||||||
|
|
||||||
|
if (value && opposite.isReady) {
|
||||||
|
TNTLeagueGame.checkStart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var damagedBlocks: Int = 0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
if (value >= targetedBlocks) {
|
||||||
|
TNTLeagueGame.win(this, TNTLeagueGame.WinReason.DESTROYED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val opposite: TNTLeagueTeam
|
||||||
|
get() = when (team) {
|
||||||
|
Team.BLUE -> TNTLeagueGame.redTeam
|
||||||
|
Team.RED -> TNTLeagueGame.blueTeam
|
||||||
|
}
|
||||||
|
|
||||||
|
fun join(player: Player): Boolean {
|
||||||
|
members.add(player)
|
||||||
|
|
||||||
|
with(player) {
|
||||||
|
teleport(config.spawnLocation)
|
||||||
|
gameMode = GameMode.ADVENTURE
|
||||||
|
inventory.clear()
|
||||||
|
plugin.server.broadcast(translate("joinTeam", name().colorByTeam(this@TNTLeagueTeam), translate(this@TNTLeagueTeam.name).colorByTeam(this@TNTLeagueTeam)).basic())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leader == null) {
|
||||||
|
leader = player
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readyItem() = if (isReady) {
|
||||||
|
ItemStack.of(Material.LIME_DYE).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
displayName(translate("ready").green().translate(leader!!))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ItemStack.of(Material.RED_DYE).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
displayName(translate("notReady").red().translate(leader!!))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun start() = members.forEach {
|
||||||
|
with(it) {
|
||||||
|
gameMode = GameMode.SURVIVAL
|
||||||
|
inventory.addItem(ItemStack.of(Material.DIAMOND_PICKAXE).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
isUnbreakable = true
|
||||||
|
addEnchant(Enchantment.EFFICIENCY, 1, false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun leave(player: Player) {
|
||||||
|
if (TNTLeagueGame.state == TNTLeagueGame.GameState.RUNNING) {
|
||||||
|
TNTLeagueGame.playerLeave(player)
|
||||||
|
} else {
|
||||||
|
members.remove(player)
|
||||||
|
|
||||||
|
if (members.isEmpty()) {
|
||||||
|
plugin.server.onlinePlayers.firstOrNull { it != player && TNTLeagueGame.getTeam(it) == null }?.run {
|
||||||
|
members.add(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (leader == player) {
|
||||||
|
leader = members.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remove(player: Player) {
|
||||||
|
leave(player)
|
||||||
|
with(player) {
|
||||||
|
teleport(TNTLeagueWorldConfig.lobby)
|
||||||
|
gameMode = GameMode.SPECTATOR
|
||||||
|
inventory.clear()
|
||||||
|
plugin.server.broadcast(translate("quitTeam", name().colorByTeam(this@TNTLeagueTeam), translate(this@TNTLeagueTeam.name).colorByTeam(this@TNTLeagueTeam)).basic())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class Team(val color: TextColor) {
|
||||||
|
BLUE(NamedTextColor.BLUE),
|
||||||
|
RED(NamedTextColor.RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package de.steamwar.tntleague.inventory
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.config.TNTLeagueConfig
|
||||||
|
import de.steamwar.tntleague.plugin
|
||||||
|
import de.steamwar.tntleague.util.*
|
||||||
|
import net.kyori.adventure.sound.Sound
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.format.Style
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration
|
||||||
|
import org.bukkit.Material
|
||||||
|
import org.bukkit.NamespacedKey
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import org.bukkit.inventory.Inventory
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
import org.bukkit.persistence.PersistentDataType
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.math.ceil
|
||||||
|
|
||||||
|
class DealerInventory(player: Player): SWInventoryHolder() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
items.forEachIndexed { index, item ->
|
||||||
|
this[index] = item.first to {
|
||||||
|
val price = item.second.price * if (it.isShiftClick) 5 else 1
|
||||||
|
val amount = item.second.amount * if (it.isShiftClick) 5 else 1
|
||||||
|
|
||||||
|
if (!player.inventory.containsAtLeast(coins, price)) {
|
||||||
|
player.sendMessage(translate("notEnoughCoins").error())
|
||||||
|
player.playSound(Sound.sound(org.bukkit.Sound.ENTITY_VILLAGER_HURT.key, net.kyori.adventure.sound.Sound.Source.MASTER, 1f, 1f))
|
||||||
|
return@to
|
||||||
|
}
|
||||||
|
|
||||||
|
player.inventory.removeItem(coins.asQuantity(price))
|
||||||
|
player.inventory.addItem(ItemStack.of(item.first.type, amount))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createInventory(): Inventory = plugin.server.createInventory(this, ceil(TNTLeagueConfig.config.prices.size / 9f).toInt() * 9, translate("dealer").reset())
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val priceKey = NamespacedKey(plugin, "price")
|
||||||
|
private val amountKey = NamespacedKey(plugin, "amount")
|
||||||
|
private val coinKey = NamespacedKey(plugin, "coin")
|
||||||
|
|
||||||
|
val coins = ItemStack(Material.RAW_GOLD).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
displayName(Component.text("Coins").bold().gold())
|
||||||
|
persistentDataContainer.apply {
|
||||||
|
set(coinKey, PersistentDataType.BOOLEAN, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val items by lazy {
|
||||||
|
val prices = TNTLeagueConfig.config.prices
|
||||||
|
|
||||||
|
prices.map { (material, price) ->
|
||||||
|
ItemStack(material).apply {
|
||||||
|
itemMeta = itemMeta.apply {
|
||||||
|
displayName(material.name.lowercase().replace("_", " ")
|
||||||
|
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
|
||||||
|
.component().gray().appendSpace().append(price.amount.toString().component().yellow()))
|
||||||
|
amount = price.amount
|
||||||
|
lore(listOf(price.price.toString().component().yellow().bold().appendSpace().append(Component.text("Coins").yellow())))
|
||||||
|
persistentDataContainer.apply {
|
||||||
|
set(priceKey, PersistentDataType.INTEGER, price.price)
|
||||||
|
set(amountKey, PersistentDataType.INTEGER, price.amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} to price
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package de.steamwar.tntleague.inventory
|
||||||
|
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent
|
||||||
|
import org.bukkit.event.inventory.InventoryCloseEvent
|
||||||
|
import org.bukkit.inventory.Inventory
|
||||||
|
import org.bukkit.inventory.InventoryHolder
|
||||||
|
import org.bukkit.inventory.ItemStack
|
||||||
|
|
||||||
|
abstract class SWInventoryHolder: InventoryHolder {
|
||||||
|
|
||||||
|
val _inventory: Inventory by lazy { createInventory() }
|
||||||
|
|
||||||
|
private val callbacks = mutableMapOf<Int, (event: InventoryClickEvent) -> Unit>()
|
||||||
|
|
||||||
|
override fun getInventory(): Inventory = _inventory
|
||||||
|
|
||||||
|
abstract fun createInventory(): Inventory
|
||||||
|
|
||||||
|
open fun handleInventoryClick(event: InventoryClickEvent) {
|
||||||
|
callbacks[event.slot]?.invoke(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addItem(item: ItemStack, slot: Int, callback: (event: InventoryClickEvent) -> Unit) {
|
||||||
|
_inventory.setItem(slot, item)
|
||||||
|
addCallback(slot, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addCallback(slot: Int, callback: (event: InventoryClickEvent) -> Unit) {
|
||||||
|
callbacks[slot] = callback
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun handleClose(event: InventoryCloseEvent) { }
|
||||||
|
|
||||||
|
operator fun set(slot: Int, item: Pair<ItemStack, (event: InventoryClickEvent) -> Unit>) {
|
||||||
|
addItem(item.first, slot, item.second)
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun set(slot: Int, item: ItemStack) {
|
||||||
|
addItem(item, slot) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package de.steamwar.tntleague.util
|
||||||
|
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.block.Block
|
||||||
|
|
||||||
|
class Area(loc1: Location, loc2: Location) {
|
||||||
|
|
||||||
|
val min: Location
|
||||||
|
val max: Location
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(loc1.world == loc2.world) { "Locations must be in the same world" }
|
||||||
|
this.min = loc1 min loc2
|
||||||
|
this.max = loc1 max loc2
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun contains(loc: Location): Boolean {
|
||||||
|
return loc.world == min.world && loc.x >= min.x && loc.x <= max.x && loc.y >= min.y && loc.y <= max.y && loc.z >= min.z && loc.z <= max.z
|
||||||
|
}
|
||||||
|
|
||||||
|
val blocks: Sequence<Block>
|
||||||
|
inline get() = sequence {
|
||||||
|
for (x in locations) {
|
||||||
|
yield(x.block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val locations: Sequence<Location>
|
||||||
|
inline get() = sequence {
|
||||||
|
for (x in min.blockX..max.blockX) {
|
||||||
|
for (y in min.blockY..max.blockY) {
|
||||||
|
for (z in min.blockZ..max.blockZ) {
|
||||||
|
yield(Location(min.world, x.toDouble(), y.toDouble(), z.toDouble()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
infix fun Location.max(other: Location): Location {
|
||||||
|
return Location(world, x.coerceAtLeast(other.x), y.coerceAtLeast(other.y), z.coerceAtLeast(other.z))
|
||||||
|
}
|
||||||
|
|
||||||
|
infix fun Location.min(other: Location): Location {
|
||||||
|
return Location(world, x.coerceAtMost(other.x), y.coerceAtMost(other.y), z.coerceAtMost(other.z))
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package de.steamwar.tntleague.util
|
||||||
|
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueTeam
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.ComponentLike
|
||||||
|
import net.kyori.adventure.text.TranslatableComponent
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor
|
||||||
|
import net.kyori.adventure.text.format.Style
|
||||||
|
import net.kyori.adventure.text.format.TextDecoration
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer
|
||||||
|
import net.kyori.adventure.translation.GlobalTranslator
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
val prefix = Component.text("Steam").yellow()
|
||||||
|
.append(Component.text("War").darkGray())
|
||||||
|
.appendSpace()
|
||||||
|
|
||||||
|
val tntLeaguePrefix = Component.text("TNT").color(NamedTextColor.DARK_RED)
|
||||||
|
.append(Component.text("League").color(NamedTextColor.GOLD))
|
||||||
|
|
||||||
|
val tntLeagueChatPrefix: Component = tntLeaguePrefix
|
||||||
|
.append(Component.text("»").darkGray())
|
||||||
|
.appendSpace()
|
||||||
|
|
||||||
|
fun TranslatableComponent.basic(): Component = tntLeagueChatPrefix.append(this.gray())
|
||||||
|
|
||||||
|
fun TranslatableComponent.error(): Component = tntLeagueChatPrefix.append(this.red())
|
||||||
|
|
||||||
|
fun TranslatableComponent.success(): Component = tntLeagueChatPrefix.append(this.green())
|
||||||
|
|
||||||
|
fun String.component(): Component = Component.text(this)
|
||||||
|
|
||||||
|
fun Component.bold(): Component = this.decorate(TextDecoration.BOLD)
|
||||||
|
|
||||||
|
fun String.bold(): Component = this.component().bold()
|
||||||
|
|
||||||
|
fun Component.yellow(): Component = this.color(NamedTextColor.YELLOW)
|
||||||
|
|
||||||
|
fun String.yellow(): Component = this.component().yellow()
|
||||||
|
|
||||||
|
fun Component.red(): Component = this.color(NamedTextColor.RED)
|
||||||
|
|
||||||
|
fun String.red(): Component = this.component().red()
|
||||||
|
|
||||||
|
fun Component.green(): Component = this.color(NamedTextColor.GREEN)
|
||||||
|
|
||||||
|
fun String.green(): Component = this.component().green()
|
||||||
|
|
||||||
|
fun Component.gray(): Component = this.color(NamedTextColor.GRAY)
|
||||||
|
|
||||||
|
fun String.gray(): Component = this.component().gray()
|
||||||
|
|
||||||
|
fun Component.darkGray(): Component = this.color(NamedTextColor.DARK_GRAY)
|
||||||
|
|
||||||
|
fun String.darkGray(): Component = this.component().darkGray()
|
||||||
|
|
||||||
|
fun Component.gold(): Component = this.color(NamedTextColor.GOLD)
|
||||||
|
|
||||||
|
fun translate(key: String, vararg args: ComponentLike): TranslatableComponent = Component.translatable(key, *args).decoration(TextDecoration.ITALIC, false)
|
||||||
|
|
||||||
|
fun Component.reset(): Component = this.style(Style.empty())
|
||||||
|
|
||||||
|
fun Component.colorByTeam(team: TNTLeagueTeam?) = when (team) {
|
||||||
|
null -> this.gray()
|
||||||
|
else -> this.color(team.color)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Component.translate(locale: Locale): Component = GlobalTranslator.render(this, locale)
|
||||||
|
|
||||||
|
fun Component.translate(p: Player): Component = this.translate(p.locale())
|
||||||
|
|
||||||
|
fun Component.toLegacy(): String = LegacyComponentSerializer.legacySection().serialize(this)
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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.tntleague.util
|
||||||
|
|
||||||
|
import de.steamwar.scoreboard.ScoreboardCallback
|
||||||
|
import de.steamwar.tntleague.config.targetedBlocks
|
||||||
|
import de.steamwar.tntleague.game.TNTLeagueGame
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
|
private val scoreboardTitle by lazy { tntLeaguePrefix.toLegacy() }
|
||||||
|
|
||||||
|
data class TNTLeagueScoreboard(val p: Player): ScoreboardCallback {
|
||||||
|
override fun getData(): HashMap<String, Int> {
|
||||||
|
val lines = mutableListOf<Component>()
|
||||||
|
|
||||||
|
lines.add(Component.space().green())
|
||||||
|
|
||||||
|
val minutes = TNTLeagueGame.gameTimeRemaining.floorDiv(60)
|
||||||
|
val seconds = TNTLeagueGame.gameTimeRemaining.rem(60).toString().padStart(2, '0')
|
||||||
|
lines.add(translate("scoreboardTime", minutes.toString().yellow(), seconds.yellow()).gray())
|
||||||
|
|
||||||
|
lines.add(Component.space().yellow())
|
||||||
|
|
||||||
|
with(TNTLeagueGame.blueTeam) {
|
||||||
|
lines.add(translate("scoreboardTeam", translate(name).colorByTeam(this), (targetedBlocks - damagedBlocks).toString().yellow()).gray())
|
||||||
|
}
|
||||||
|
with(TNTLeagueGame.redTeam) {
|
||||||
|
lines.add(translate("scoreboardTeam", translate(name).colorByTeam(this), (targetedBlocks - damagedBlocks).toString().yellow()).gray())
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.add(Component.space().gray())
|
||||||
|
|
||||||
|
return lines
|
||||||
|
.foldIndexed(HashMap()) { index, acc, component -> acc.also { it[component.translate(p).toLegacy()] = index } }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTitle(): String = scoreboardTitle
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
name: TNTLeague
|
||||||
|
version: '1.0.0'
|
||||||
|
main: de.steamwar.tntleague.TNTLeague
|
||||||
|
load: POSTWORLD
|
||||||
|
api-version: '1.21'
|
||||||
|
dependencies:
|
||||||
|
- name: SpigotCore
|
||||||
|
required: true
|
||||||
|
- name: KotlinCore
|
||||||
|
required: true
|
||||||
@@ -292,7 +292,7 @@ FIGHT_UNKNOWN_GAMEMODE=§cUnknown gamemode: {0}
|
|||||||
FIGHT_UNKNOWN_ARENA=§cThe desired arena does not exist.
|
FIGHT_UNKNOWN_ARENA=§cThe desired arena does not exist.
|
||||||
FIGHT_IN_ARENA=§cYou are already in an arena.
|
FIGHT_IN_ARENA=§cYou are already in an arena.
|
||||||
FIGHT_BROADCAST=§7Click §ehere§7 to fight §e{0} §7against §e{1}!
|
FIGHT_BROADCAST=§7Click §ehere§7 to fight §e{0} §7against §e{1}!
|
||||||
FIGHT_BROADCAST_HOVER=§aFight §eagainst §7{1}
|
FIGHT_BROADCAST_HOVER=§aFight §eagainst §7{0}
|
||||||
|
|
||||||
#CheckCommand
|
#CheckCommand
|
||||||
CHECK_REMINDER=§7There are §e{0} §7schematics left for review§8!
|
CHECK_REMINDER=§7There are §e{0} §7schematics left for review§8!
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ FIGHT_UNKNOWN_GAMEMODE=§cUnbekannter Spielmodus: {0}
|
|||||||
FIGHT_UNKNOWN_ARENA=§cDie gewünschte Arena gibt es nicht.
|
FIGHT_UNKNOWN_ARENA=§cDie gewünschte Arena gibt es nicht.
|
||||||
FIGHT_IN_ARENA=§cDu befindest dich bereits in einer Arena.
|
FIGHT_IN_ARENA=§cDu befindest dich bereits in einer Arena.
|
||||||
FIGHT_BROADCAST=§7Klicke §ehier§7, um §e{0} §7gegen §e{1} §7zu §7kämpfen!
|
FIGHT_BROADCAST=§7Klicke §ehier§7, um §e{0} §7gegen §e{1} §7zu §7kämpfen!
|
||||||
FIGHT_BROADCAST_HOVER=§aGegen §7{1} §ekämpfen
|
FIGHT_BROADCAST_HOVER=§aGegen §7{0} §ekämpfen
|
||||||
|
|
||||||
#CheckCommand
|
#CheckCommand
|
||||||
CHECK_REMINDER=§7Es sind §e{0} §7Schematics zu prüfen§8!
|
CHECK_REMINDER=§7Es sind §e{0} §7Schematics zu prüfen§8!
|
||||||
@@ -642,7 +642,6 @@ RANK_PLAYER_FOUND=§eRang §7von §e{0}
|
|||||||
RANK_HEADER={0} §e{1} {2}
|
RANK_HEADER={0} §e{1} {2}
|
||||||
RANK_UNPLACED=§7unplatziert
|
RANK_UNPLACED=§7unplatziert
|
||||||
RANK_PLACED=§e{0}§8. §7mit §e{1} §7Elo§8.
|
RANK_PLACED=§e{0}§8. §7mit §e{1} §7Elo§8.
|
||||||
RANK_EMBLEM=§7Emblem§8: {0}
|
|
||||||
|
|
||||||
#Fabric Mod Sender
|
#Fabric Mod Sender
|
||||||
MODIFICATION_BAN_MESSAGE=Du hast probiert den FabricModSender zu umgehen / zu modifizieren!
|
MODIFICATION_BAN_MESSAGE=Du hast probiert den FabricModSender zu umgehen / zu modifizieren!
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
package de.steamwar.velocitycore;
|
package de.steamwar.velocitycore;
|
||||||
|
|
||||||
import de.steamwar.messages.Chatter;
|
import de.steamwar.messages.Chatter;
|
||||||
|
import de.steamwar.messages.Message;
|
||||||
import de.steamwar.persistent.Subserver;
|
import de.steamwar.persistent.Subserver;
|
||||||
import de.steamwar.sql.EventFight;
|
import de.steamwar.sql.EventFight;
|
||||||
import de.steamwar.sql.Team;
|
import de.steamwar.sql.Team;
|
||||||
@@ -43,7 +44,7 @@ public class EventStarter {
|
|||||||
|
|
||||||
public EventStarter() {
|
public EventStarter() {
|
||||||
EventFight.loadAllComingFights();
|
EventFight.loadAllComingFights();
|
||||||
VelocityCore.schedule(this::run).delay(10, TimeUnit.SECONDS).schedule();
|
VelocityCore.schedule(this::run).repeat(10, TimeUnit.SECONDS).schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Integer, Subserver> getEventServer() {
|
public static Map<Integer, Subserver> getEventServer() {
|
||||||
@@ -73,7 +74,7 @@ public class EventStarter {
|
|||||||
} else {
|
} else {
|
||||||
command = "/" + spectatePorts.get(next.getSpectatePort());
|
command = "/" + spectatePorts.get(next.getSpectatePort());
|
||||||
}
|
}
|
||||||
Chatter.broadcast().system("EVENT_FIGHT_BROADCAST", "EVENT_FIGHT_BROADCAST_HOVER", ClickEvent.runCommand(command), blue.getTeamColor(), blue.getTeamName(), red.getTeamColor(), red.getTeamName());
|
Chatter.broadcast().system("EVENT_FIGHT_BROADCAST", new Message("EVENT_FIGHT_BROADCAST_HOVER"), ClickEvent.runCommand(command), blue.getTeamColor(), blue.getTeamName(), red.getTeamColor(), red.getTeamName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ public class FightCommand extends SWCommand {
|
|||||||
public void fight(@Validator("arenaPlayer") PlayerChatter sender, @Mapper("nonHistoricArenaMode") @OptionalValue("") @AllowNull ArenaMode arenaMode, @Mapper("arenaMap") @OptionalValue("") @AllowNull String map) {
|
public void fight(@Validator("arenaPlayer") PlayerChatter sender, @Mapper("nonHistoricArenaMode") @OptionalValue("") @AllowNull ArenaMode arenaMode, @Mapper("arenaMap") @OptionalValue("") @AllowNull String map) {
|
||||||
createArena(sender, "/fight ", true, arenaMode, map, false,
|
createArena(sender, "/fight ", true, arenaMode, map, false,
|
||||||
(p, mode, m) -> new ServerStarter().arena(mode, m).blueLeader(p.getPlayer()).callback(
|
(p, mode, m) -> new ServerStarter().arena(mode, m).blueLeader(p.getPlayer()).callback(
|
||||||
arena -> Chatter.broadcast().system("FIGHT_BROADCAST", new Message("FIGHT_BROADCAST_HOVER"), ClickEvent.runCommand("/arena " + arena.getServer().getName()), mode.getGameName(), p.getPlayer().getUsername())
|
arena -> Chatter.broadcast().system("FIGHT_BROADCAST", new Message("FIGHT_BROADCAST_HOVER", p.getPlayer().getUsername()), ClickEvent.runCommand("/arena " + arena.getServer().getName()), mode.getGameName(), p.getPlayer().getUsername())
|
||||||
).start()
|
).start()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ public class ChannelListener extends ListenerAdapter {
|
|||||||
if(permission != null && !sender.user().perms().contains(permission))
|
if(permission != null && !sender.user().perms().contains(permission))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
command.execute(sender, args.split(" "));
|
command.execute(sender, args.isEmpty() ? new String[0] : args.split(" "));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,12 @@ package de.steamwar.velocitycore.listeners;
|
|||||||
import com.lunarclient.apollo.ApolloManager;
|
import com.lunarclient.apollo.ApolloManager;
|
||||||
import com.velocitypowered.api.event.Subscribe;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||||
|
import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent;
|
||||||
|
import com.velocitypowered.api.event.player.PlayerClientBrandEvent;
|
||||||
import com.velocitypowered.api.network.ProtocolVersion;
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import com.velocitypowered.api.proxy.ServerConnection;
|
import com.velocitypowered.api.proxy.ServerConnection;
|
||||||
|
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
|
||||||
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
|
import com.velocitypowered.api.proxy.messages.ChannelMessageSource;
|
||||||
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
|
||||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||||
@@ -373,11 +376,11 @@ public class PluginMessage extends BasicListener {
|
|||||||
))
|
))
|
||||||
register(channel, false, directional(UNKNOWN, DROP));
|
register(channel, false, directional(UNKNOWN, DROP));
|
||||||
|
|
||||||
register("REGISTER", false, directional(this::serverRegistersChannel, this::clientRegistersChannel));
|
register("REGISTER", false, directional(this::serverRegistersChannel, UNKNOWN));
|
||||||
register("minecraft:register", false, directional(this::serverRegistersChannel, this::clientRegistersChannel));
|
register("minecraft:register", false, directional(this::serverRegistersChannel, UNKNOWN));
|
||||||
|
|
||||||
register("MC|Brand", false, directional(this::steamWarBrand, this::userBrand));
|
register("MC|Brand", false, directional(this::steamWarBrand, UNKNOWN));
|
||||||
register("minecraft:brand", false, directional(this::steamWarBrand, this::userBrand));
|
register("minecraft:brand", false, directional(this::steamWarBrand, UNKNOWN));
|
||||||
|
|
||||||
//Needs to be registered cause paper refuses to send PluginMessages on unregistered channels...
|
//Needs to be registered cause paper refuses to send PluginMessages on unregistered channels...
|
||||||
register("sw:bridge", true, directional(onlySWSource(async(event -> NetworkPacket.handle(new ServerMetaInfo((ServerConnection) event.getSource()), event.getData()))), UNKNOWN));
|
register("sw:bridge", true, directional(onlySWSource(async(event -> NetworkPacket.handle(new ServerMetaInfo((ServerConnection) event.getSource()), event.getData()))), UNKNOWN));
|
||||||
@@ -401,6 +404,15 @@ public class PluginMessage extends BasicListener {
|
|||||||
// Hackclientlike modsuppressor for labymod: https://github.com/Neocraftr/LabyMod-NeoEssentials (Potentially recognizable from NO Addons/NO Mods?) https://github.com/Neocraftr/LabyMod-NeoEssentials/blob/master/src/main/java/de/neocraftr/neoessentials/utils/BytecodeMethods.java
|
// Hackclientlike modsuppressor for labymod: https://github.com/Neocraftr/LabyMod-NeoEssentials (Potentially recognizable from NO Addons/NO Mods?) https://github.com/Neocraftr/LabyMod-NeoEssentials/blob/master/src/main/java/de/neocraftr/neoessentials/utils/BytecodeMethods.java
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onClientChannelRegister(PlayerChannelRegisterEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
for(ChannelIdentifier channel : event.getChannels()) {
|
||||||
|
channelRegisterHandlers.getOrDefault(channel.getId(), p -> VelocityCore.getLogger().log(Level.WARNING, () -> p.getUsername() + " registered unknown channel " + channel)).accept(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onPluginMessage(PluginMessageEvent event) {
|
public void onPluginMessage(PluginMessageEvent event) {
|
||||||
event.setResult(PluginMessageEvent.ForwardResult.handled());
|
event.setResult(PluginMessageEvent.ForwardResult.handled());
|
||||||
@@ -412,6 +424,20 @@ public class PluginMessage extends BasicListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onClientBrand(PlayerClientBrandEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
String brand = event.getBrand();
|
||||||
|
boolean lunarclient = brand.startsWith("lunarclient:");
|
||||||
|
|
||||||
|
VelocityCore.getLogger().log(knownBrands.contains(brand) || lunarclient ? Level.INFO : Level.WARNING, () -> player.getUsername() + " joins with brand: " + brand);
|
||||||
|
if(lunarclient)
|
||||||
|
lunar.sendRestrictions(player);
|
||||||
|
if(brand.equals("badlion"))
|
||||||
|
badlion.sendRestrictions(player);
|
||||||
|
}
|
||||||
|
|
||||||
private void registerPassthroughToClient(String... channels) {
|
private void registerPassthroughToClient(String... channels) {
|
||||||
for(String channel : channels) {
|
for(String channel : channels) {
|
||||||
channelRegisterHandlers.put(channel, player -> {});
|
channelRegisterHandlers.put(channel, player -> {});
|
||||||
@@ -437,16 +463,6 @@ public class PluginMessage extends BasicListener {
|
|||||||
VelocityCore.getProxy().getChannelRegistrar().register(channel.indexOf(':') != -1 ? MinecraftChannelIdentifier.from(channel) : new LegacyChannelIdentifier(channel));
|
VelocityCore.getProxy().getChannelRegistrar().register(channel.indexOf(':') != -1 ? MinecraftChannelIdentifier.from(channel) : new LegacyChannelIdentifier(channel));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clientRegistersChannel(PluginMessageEvent event) {
|
|
||||||
Player player = (Player) event.getSource();
|
|
||||||
|
|
||||||
for(String channel : new String(event.getData()).split("\0")) {
|
|
||||||
channelRegisterHandlers.getOrDefault(channel, p -> VelocityCore.getLogger().log(Level.WARNING, () -> p.getUsername() + " registered unknown channel " + channel)).accept(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
PASS_THROUGH.handle(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void serverRegistersChannel(PluginMessageEvent event) {
|
private void serverRegistersChannel(PluginMessageEvent event) {
|
||||||
Player player = (Player) event.getTarget();
|
Player player = (Player) event.getTarget();
|
||||||
|
|
||||||
@@ -455,22 +471,6 @@ public class PluginMessage extends BasicListener {
|
|||||||
send(player, "REGISTER", "minecraft:register", String.join("\0", channels).getBytes());
|
send(player, "REGISTER", "minecraft:register", String.join("\0", channels).getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void userBrand(PluginMessageEvent event) {
|
|
||||||
Player player = (Player) event.getSource();
|
|
||||||
|
|
||||||
ByteBuf buf = Unpooled.wrappedBuffer(event.getData());
|
|
||||||
String brand = ProtocolUtils.readString(buf);
|
|
||||||
boolean lunarclient = brand.startsWith("lunarclient:");
|
|
||||||
|
|
||||||
VelocityCore.getLogger().log(knownBrands.contains(brand) || lunarclient ? Level.INFO : Level.WARNING, () -> player.getUsername() + " joins with brand: " + brand);
|
|
||||||
if(lunarclient)
|
|
||||||
lunar.sendRestrictions(player);
|
|
||||||
if(brand.equals("badlion"))
|
|
||||||
badlion.sendRestrictions(player);
|
|
||||||
|
|
||||||
PASS_THROUGH.handle(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void steamWarBrand(PluginMessageEvent event) {
|
private void steamWarBrand(PluginMessageEvent event) {
|
||||||
Player player = (Player) event.getTarget();
|
Player player = (Player) event.getTarget();
|
||||||
String brand = Chatter.of(player).parseToLegacy("STEAMWAR_BRAND", "Velocity", player.getCurrentServer().map(serverConnection -> serverConnection.getServerInfo().getName()).orElse(""), new String(event.getData(), 1, event.getData().length - 1));
|
String brand = Chatter.of(player).parseToLegacy("STEAMWAR_BRAND", "Velocity", player.getCurrentServer().map(serverConnection -> serverConnection.getServerInfo().getName()).orElse(""), new String(event.getData(), 1, event.getData().length - 1));
|
||||||
|
|||||||
@@ -28,25 +28,25 @@ public class Badlion {
|
|||||||
|
|
||||||
private final byte[] packet;
|
private final byte[] packet;
|
||||||
|
|
||||||
public Badlion() { //TODO check if working or (json) modsDisallowed wrapper necessary
|
public Badlion() {
|
||||||
JsonObject disabled = new JsonObject();
|
JsonObject disabled = new JsonObject();
|
||||||
disabled.addProperty("disabled", true);
|
disabled.addProperty("disabled", true);
|
||||||
|
|
||||||
JsonObject json = new JsonObject();
|
JsonObject modsDisallowed = new JsonObject();
|
||||||
json.add("Clear Glass", disabled);
|
modsDisallowed.add("Clear Glass", disabled);
|
||||||
json.add("ClearWater", disabled);
|
modsDisallowed.add("ClearWater", disabled);
|
||||||
json.add("FOV Changer", disabled);
|
modsDisallowed.add("FOV Changer", disabled);
|
||||||
json.add("Hitboxes", disabled);
|
modsDisallowed.add("Hitboxes", disabled);
|
||||||
json.add("LevelHead", disabled);
|
modsDisallowed.add("LevelHead", disabled);
|
||||||
json.add("MiniMap", disabled);
|
modsDisallowed.add("MiniMap", disabled);
|
||||||
json.add("MLG Cobweb", disabled);
|
modsDisallowed.add("MLG Cobweb", disabled);
|
||||||
json.add("Replay", disabled); //TODO check if ReplayMod restrictions work
|
modsDisallowed.add("Replay", disabled);
|
||||||
json.add("Schematica", disabled);
|
modsDisallowed.add("Schematica", disabled);
|
||||||
json.add("ToggleSneak", disabled);
|
modsDisallowed.add("ToggleSneak", disabled);
|
||||||
json.add("ToggleSprint", disabled);
|
modsDisallowed.add("ToggleSprint", disabled);
|
||||||
json.add("TNT Time", disabled);
|
modsDisallowed.add("TNT Time", disabled);
|
||||||
|
|
||||||
packet = json.toString().getBytes();
|
packet = modsDisallowed.toString().getBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendRestrictions(Player player) {
|
public void sendRestrictions(Player player) {
|
||||||
|
|||||||
@@ -20,13 +20,13 @@
|
|||||||
package de.steamwar.velocitycore.network.handlers;
|
package de.steamwar.velocitycore.network.handlers;
|
||||||
|
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import de.steamwar.velocitycore.ArenaMode;
|
|
||||||
import de.steamwar.velocitycore.VelocityCore;
|
|
||||||
import de.steamwar.network.packets.PacketHandler;
|
import de.steamwar.network.packets.PacketHandler;
|
||||||
import de.steamwar.network.packets.common.FightEndsPacket;
|
import de.steamwar.network.packets.common.FightEndsPacket;
|
||||||
import de.steamwar.sql.SchematicType;
|
import de.steamwar.sql.SchematicType;
|
||||||
import de.steamwar.sql.SteamwarUser;
|
import de.steamwar.sql.SteamwarUser;
|
||||||
import de.steamwar.sql.UserElo;
|
import de.steamwar.sql.UserElo;
|
||||||
|
import de.steamwar.velocitycore.ArenaMode;
|
||||||
|
import de.steamwar.velocitycore.VelocityCore;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
@@ -52,8 +52,15 @@ public class EloPlayerHandler extends PacketHandler {
|
|||||||
*/
|
*/
|
||||||
@Handler
|
@Handler
|
||||||
public void handle(FightEndsPacket fightEndsPacket) {
|
public void handle(FightEndsPacket fightEndsPacket) {
|
||||||
if (!ArenaMode.getBySchemType(SchematicType.fromDB(fightEndsPacket.getGameMode())).isRanked())
|
SchematicType schematicType = SchematicType.fromDB(fightEndsPacket.getGameMode());
|
||||||
return;
|
ArenaMode arenaMode;
|
||||||
|
if (schematicType == null) {
|
||||||
|
arenaMode = ArenaMode.getByInternal(fightEndsPacket.getGameMode());
|
||||||
|
} else {
|
||||||
|
arenaMode = ArenaMode.getBySchemType(schematicType);
|
||||||
|
}
|
||||||
|
if (arenaMode == null) return;
|
||||||
|
if (!arenaMode.isRanked()) return;
|
||||||
|
|
||||||
if (EloSchemHandler.publicVsPrivate(fightEndsPacket))
|
if (EloSchemHandler.publicVsPrivate(fightEndsPacket))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -19,18 +19,21 @@
|
|||||||
|
|
||||||
package de.steamwar.velocitycore.network.handlers;
|
package de.steamwar.velocitycore.network.handlers;
|
||||||
|
|
||||||
import de.steamwar.velocitycore.ArenaMode;
|
|
||||||
import de.steamwar.network.packets.PacketHandler;
|
import de.steamwar.network.packets.PacketHandler;
|
||||||
import de.steamwar.network.packets.common.FightEndsPacket;
|
import de.steamwar.network.packets.common.FightEndsPacket;
|
||||||
import de.steamwar.sql.SchemElo;
|
import de.steamwar.sql.SchemElo;
|
||||||
import de.steamwar.sql.SchematicNode;
|
import de.steamwar.sql.SchematicNode;
|
||||||
import de.steamwar.sql.SchematicType;
|
import de.steamwar.sql.SchematicType;
|
||||||
|
import de.steamwar.velocitycore.ArenaMode;
|
||||||
|
|
||||||
public class EloSchemHandler extends PacketHandler {
|
public class EloSchemHandler extends PacketHandler {
|
||||||
|
|
||||||
private static final int K = 20;
|
private static final int K = 20;
|
||||||
|
|
||||||
public static boolean publicVsPrivate(FightEndsPacket packet) {
|
public static boolean publicVsPrivate(FightEndsPacket packet) {
|
||||||
|
if (packet.getRedSchem() == -1 && packet.getBlueSchem() == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
SchematicNode blueSchem = SchematicNode.getSchematicNode(packet.getBlueSchem());
|
SchematicNode blueSchem = SchematicNode.getSchematicNode(packet.getBlueSchem());
|
||||||
SchematicNode redSchem = SchematicNode.getSchematicNode(packet.getRedSchem());
|
SchematicNode redSchem = SchematicNode.getSchematicNode(packet.getRedSchem());
|
||||||
return (blueSchem.getOwner() == 0) != (redSchem.getOwner() == 0);
|
return (blueSchem.getOwner() == 0) != (redSchem.getOwner() == 0);
|
||||||
@@ -38,9 +41,10 @@ public class EloSchemHandler extends PacketHandler {
|
|||||||
|
|
||||||
@Handler
|
@Handler
|
||||||
public void handle(FightEndsPacket fightEndsPacket) {
|
public void handle(FightEndsPacket fightEndsPacket) {
|
||||||
if (!ArenaMode.getBySchemType(SchematicType.fromDB(fightEndsPacket.getGameMode())).isRanked()) {
|
SchematicType type = SchematicType.fromDB(fightEndsPacket.getGameMode());
|
||||||
return;
|
if (type == null) return;
|
||||||
}
|
ArenaMode arenaMode = ArenaMode.getBySchemType(type);
|
||||||
|
if (!arenaMode.isRanked()) return;
|
||||||
|
|
||||||
if (publicVsPrivate(fightEndsPacket))
|
if (publicVsPrivate(fightEndsPacket))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import net.kyori.adventure.text.Component;
|
|||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
@ChannelHandler.Sharable
|
@ChannelHandler.Sharable
|
||||||
@@ -63,7 +64,6 @@ public class Tablist extends ChannelInboundHandlerAdapter {
|
|||||||
this.player = player;
|
this.player = player;
|
||||||
this.viewer = Chatter.of(player);
|
this.viewer = Chatter.of(player);
|
||||||
this.directTabItems = Storage.directTabItems.computeIfAbsent(player, p -> new HashMap<>());
|
this.directTabItems = Storage.directTabItems.computeIfAbsent(player, p -> new HashMap<>());
|
||||||
injection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(TablistPart global, int seconds) {
|
public void update(TablistPart global, int seconds) {
|
||||||
@@ -139,7 +139,9 @@ public class Tablist extends ChannelInboundHandlerAdapter {
|
|||||||
synchronized (directTabItems) {
|
synchronized (directTabItems) {
|
||||||
directTabItems.clear();
|
directTabItems.clear();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServerPostSwitch() {
|
||||||
if(player.getProtocolVersion().greaterThan(ProtocolVersion.MINECRAFT_1_20)) {
|
if(player.getProtocolVersion().greaterThan(ProtocolVersion.MINECRAFT_1_20)) {
|
||||||
current.clear();
|
current.clear();
|
||||||
sendPacket(player, createTeamPacket);
|
sendPacket(player, createTeamPacket);
|
||||||
@@ -148,8 +150,14 @@ public class Tablist extends ChannelInboundHandlerAdapter {
|
|||||||
|
|
||||||
private void injection() {
|
private void injection() {
|
||||||
connection = (VelocityServerConnection) player.getCurrentServer().orElse(null);
|
connection = (VelocityServerConnection) player.getCurrentServer().orElse(null);
|
||||||
if(connection == null)
|
if(connection == null) {
|
||||||
|
connection = ((ConnectedPlayer) player).getConnectionInFlight();
|
||||||
|
|
||||||
|
if(connection == null) {
|
||||||
|
VelocityCore.getLogger().log(Level.WARNING, "Could not inject Tablist: %s".formatted(player));
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ChannelPipeline pipeline = connection.getConnection().getChannel().pipeline();
|
ChannelPipeline pipeline = connection.getConnection().getChannel().pipeline();
|
||||||
if(pipeline.get("steamwar-tablist") != null) //Catch unclean exit
|
if(pipeline.get("steamwar-tablist") != null) //Catch unclean exit
|
||||||
|
|||||||
@@ -21,8 +21,9 @@ package de.steamwar.velocitycore.tablist;
|
|||||||
|
|
||||||
import com.velocitypowered.api.event.Subscribe;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
import com.velocitypowered.api.event.connection.DisconnectEvent;
|
||||||
import com.velocitypowered.api.event.connection.PostLoginEvent;
|
import com.velocitypowered.api.event.player.ServerConnectedEvent;
|
||||||
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
|
import com.velocitypowered.api.event.player.ServerPostConnectEvent;
|
||||||
|
import com.velocitypowered.api.network.ProtocolVersion;
|
||||||
import com.velocitypowered.api.proxy.Player;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
import de.steamwar.network.packets.common.FightInfoPacket;
|
import de.steamwar.network.packets.common.FightInfoPacket;
|
||||||
@@ -59,17 +60,19 @@ public class TablistManager extends BasicListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onJoin(PostLoginEvent event) {
|
public void onServerConnection(ServerConnectedEvent event) {
|
||||||
synchronized (tablists) {
|
synchronized (tablists) {
|
||||||
tablists.put(event.getPlayer(), new Tablist(event.getPlayer()));
|
tablists.computeIfAbsent(event.getPlayer(), Tablist::new).onServerSwitch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(event.getPlayer().getProtocolVersion().noGreaterThan(ProtocolVersion.MINECRAFT_1_20))
|
||||||
Tablist.sendPacket(event.getPlayer(), Tablist.createTeamPacket);
|
Tablist.sendPacket(event.getPlayer(), Tablist.createTeamPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onServerConnection(ServerPostConnectEvent event) {
|
public void onServerPostConnection(ServerPostConnectEvent event) {
|
||||||
synchronized (tablists) {
|
synchronized (tablists) {
|
||||||
tablists.get(event.getPlayer()).onServerSwitch();
|
tablists.get(event.getPlayer()).onServerPostSwitch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,3 +28,11 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:2.0.10")
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id "org.jetbrains.kotlin.jvm"
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain(21)
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_21
|
||||||
|
targetCompatibility = JavaVersion.VERSION_21
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.compileJava {
|
||||||
|
options.encoding "UTF-8"
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
java {
|
||||||
|
srcDirs("src/")
|
||||||
|
}
|
||||||
|
resources {
|
||||||
|
srcDirs("src/")
|
||||||
|
exclude("**/*.java", "**/*.kt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
java {
|
||||||
|
srcDirs("testsrc/")
|
||||||
|
}
|
||||||
|
resources {
|
||||||
|
srcDirs("testsrc/")
|
||||||
|
exclude("**/*.java", "**/*.kt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-1
@@ -89,6 +89,7 @@ dependencyResolutionManagement {
|
|||||||
includeGroup("org.spigotmc")
|
includeGroup("org.spigotmc")
|
||||||
includeGroup("io.papermc.paper")
|
includeGroup("io.papermc.paper")
|
||||||
includeGroup("com.velocitypowered")
|
includeGroup("com.velocitypowered")
|
||||||
|
includeGroup("net.md-5")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -113,6 +114,7 @@ dependencyResolutionManagement {
|
|||||||
library("spigotapi", "org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT")
|
library("spigotapi", "org.spigotmc:spigot-api:1.20-R0.1-SNAPSHOT")
|
||||||
library("spigotannotations", "org.spigotmc:plugin-annotations:1.2.3-SNAPSHOT")
|
library("spigotannotations", "org.spigotmc:plugin-annotations:1.2.3-SNAPSHOT")
|
||||||
library("paperapi", "io.papermc.paper:paper-api:1.19.2-R0.1-SNAPSHOT")
|
library("paperapi", "io.papermc.paper:paper-api:1.19.2-R0.1-SNAPSHOT")
|
||||||
|
library("paperapi21", "io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
|
||||||
library("authlib", "com.mojang:authlib:1.5.25")
|
library("authlib", "com.mojang:authlib:1.5.25")
|
||||||
library("datafixer", "com.mojang:datafixerupper:4.0.26")
|
library("datafixer", "com.mojang:datafixerupper:4.0.26")
|
||||||
library("brigadier", "com.mojang:brigadier:1.0.18")
|
library("brigadier", "com.mojang:brigadier:1.0.18")
|
||||||
@@ -174,7 +176,7 @@ include(
|
|||||||
"FightSystem:FightSystem_Standalone"
|
"FightSystem:FightSystem_Standalone"
|
||||||
)
|
)
|
||||||
|
|
||||||
// include("KotlinCore")
|
include("KotlinCore")
|
||||||
|
|
||||||
include("LobbySystem")
|
include("LobbySystem")
|
||||||
|
|
||||||
@@ -214,3 +216,5 @@ include(
|
|||||||
"VelocityCore",
|
"VelocityCore",
|
||||||
"VelocityCore:Persistent"
|
"VelocityCore:Persistent"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
include("TNTLeague")
|
||||||
|
|||||||
Reference in New Issue
Block a user