Great rework, AutoLoader & TNTTracer
Dieser Commit ist enthalten in:
Ursprung
7a3f8cb8f2
Commit
0046a84cde
4
pom.xml
4
pom.xml
@ -35,8 +35,8 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>7</source>
|
||||
<target>7</target>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
@ -4,7 +4,7 @@ import de.steamwar.bausystem.commands.*;
|
||||
import de.steamwar.bausystem.sql.Bauwelt;
|
||||
import de.steamwar.bausystem.world.ArenaSection;
|
||||
import de.steamwar.bausystem.world.RegionListener;
|
||||
import de.steamwar.bausystem.world.TNTTracer;
|
||||
import de.steamwar.bausystem.world.TNTListener;
|
||||
import de.warking.hunjy.MySQL.WarkingUser;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
@ -21,12 +21,12 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BauSystem extends JavaPlugin implements Listener {
|
||||
private static BauSystem plugin;
|
||||
private static UUID owner;
|
||||
private static Bauwelt welt;
|
||||
private static TNTTracer tracer;
|
||||
private static List<ArenaSection> sections;
|
||||
public static final String PREFIX = "§eBauSystem§8» §7";
|
||||
public static final String SECTION_PATH = "/home/minecraft/backbone/server/UserBau/";
|
||||
@ -38,12 +38,11 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
try{
|
||||
owner = UUID.fromString(Bukkit.getWorlds().get(0).getName());
|
||||
}catch(IllegalArgumentException e){
|
||||
e.printStackTrace();
|
||||
getLogger().log(Level.SEVERE, "owner is no UUID", e);
|
||||
Bukkit.shutdown();
|
||||
return;
|
||||
}
|
||||
welt = Bauwelt.getBauwelt(owner);
|
||||
tracer = new TNTTracer();
|
||||
|
||||
try {
|
||||
CommandRemover.removeCommand("tp");
|
||||
@ -53,7 +52,7 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
CommandRemover.removeCommand("time");
|
||||
CommandRemover.injectCommand(new CommandTime());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
getLogger().log(Level.SEVERE, "Failed to replace commands", e);
|
||||
Bukkit.shutdown();
|
||||
return;
|
||||
}
|
||||
@ -61,7 +60,7 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
try {
|
||||
sections = ArenaSection.loadFromFile(new File(Bukkit.getWorldContainer().getPath() + '/' + owner.toString() + "/sections.yml"));
|
||||
} catch (IOException | InvalidConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
getLogger().log(Level.SEVERE, "Failed to load sections.yml", e);
|
||||
Bukkit.shutdown();
|
||||
return;
|
||||
}
|
||||
@ -78,9 +77,11 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
getCommand("protect").setExecutor(new CommandProtect());
|
||||
getCommand("skull").setExecutor(new CommandSkull());
|
||||
getCommand("freeze").setExecutor(new CommandFreeze());
|
||||
getCommand("loader").setExecutor(new CommandLoader());
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
Bukkit.getPluginManager().registerEvents(new RegionListener(), this);
|
||||
Bukkit.getPluginManager().registerEvents(new TNTListener(), this);
|
||||
}
|
||||
|
||||
public static BauSystem getPlugin(){
|
||||
@ -92,9 +93,6 @@ public class BauSystem extends JavaPlugin implements Listener {
|
||||
public static Bauwelt getWelt(){
|
||||
return welt;
|
||||
}
|
||||
public static TNTTracer getTracer(){
|
||||
return tracer;
|
||||
}
|
||||
public static List<ArenaSection> getSections(){
|
||||
return sections;
|
||||
}
|
||||
|
@ -4,6 +4,5 @@ public enum Permission {
|
||||
world,
|
||||
worldedit,
|
||||
build,
|
||||
member,
|
||||
owner
|
||||
member
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public class CommandBau implements CommandExecutor {
|
||||
|
||||
private void onToggleBD(Player p, String arg) {
|
||||
UUID id = WarkingUser.get(arg).getUUID();
|
||||
if(!toggleCheck(p, id)){
|
||||
if(negativeToggleCheck(p, id)){
|
||||
return;
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ public class CommandBau implements CommandExecutor {
|
||||
|
||||
private void onToggleWE(Player p, String arg) {
|
||||
UUID id = WarkingUser.get(arg).getUUID();
|
||||
if(!toggleCheck(p, id)){
|
||||
if(negativeToggleCheck(p, id)){
|
||||
return;
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ public class CommandBau implements CommandExecutor {
|
||||
|
||||
private void onToggleWorld(Player p, String arg) {
|
||||
UUID id = WarkingUser.get(arg).getUUID();
|
||||
if(!toggleCheck(p, id)){
|
||||
if(negativeToggleCheck(p, id)){
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,18 +43,18 @@ public class CommandBau implements CommandExecutor {
|
||||
Welt.toggleTestblock(p, target);
|
||||
}
|
||||
|
||||
private boolean toggleCheck(Player p, UUID id){
|
||||
private boolean negativeToggleCheck(Player p, UUID id){
|
||||
if (id == null) {
|
||||
p.sendMessage(BauSystem.PREFIX + "§cUnbekannter Spieler");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
BauweltMember target = BauweltMember.getBauMember(id);
|
||||
if (target == null) {
|
||||
p.sendMessage(BauSystem.PREFIX + "§cDer Spieler ist kein Mitglied deiner Welt!");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,7 +23,7 @@ public class CommandFreeze implements CommandExecutor, Listener {
|
||||
return false;
|
||||
Player player = (Player) sender;
|
||||
|
||||
if (!Welt.hasPermission(player, Permission.world)){
|
||||
if (Welt.noPermission(player, Permission.world)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu darfst diese Welt nicht einfrieren");
|
||||
return false;
|
||||
}
|
||||
|
140
src/de/steamwar/bausystem/commands/CommandLoader.java
Normale Datei
140
src/de/steamwar/bausystem/commands/CommandLoader.java
Normale Datei
@ -0,0 +1,140 @@
|
||||
package de.steamwar.bausystem.commands;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.world.AutoLoader;
|
||||
import de.steamwar.bausystem.world.Welt;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CommandLoader implements CommandExecutor {
|
||||
|
||||
private void help(Player player){
|
||||
player.sendMessage("§8/§eloader setup §8- §7Startet die Aufnahme der Aktionen");
|
||||
player.sendMessage("§8/§7loader undo §8- §7Entfernt die zuletzt aufgenommene Aktion");
|
||||
player.sendMessage("§8/§eloader start §8- §7Spielt die zuvor aufgenommenen Aktionen ab");
|
||||
player.sendMessage("§8/§7loader wait §8[§7Ticks§8] - §7Setzt die Wartezeit zwischen Schüssen");
|
||||
player.sendMessage("§8/§7loader speed §8[§7Ticks§8] - §7Setzt die Wartezeit zwischen Aktionen");
|
||||
player.sendMessage("§8/§eloader stop §8- §7Stoppt die Aufnahme bzw. das Abspielen");
|
||||
player.sendMessage("§7Der AutoLader arbeitet mit §eIngame§8-§eTicks §8(20 Ticks pro Sekunde)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if(!(sender instanceof Player))
|
||||
return false;
|
||||
Player player = (Player) sender;
|
||||
|
||||
if(Welt.noPermission(player, Permission.build)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht den AutoLader verwenden");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(args.length == 0){
|
||||
help(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(args[0].toLowerCase()){
|
||||
case "setup":
|
||||
setup(player);
|
||||
break;
|
||||
case "undo":
|
||||
undo(player);
|
||||
break;
|
||||
case "start":
|
||||
start(player);
|
||||
break;
|
||||
case "stop":
|
||||
stop(player);
|
||||
break;
|
||||
case "wait":
|
||||
wait(player, args);
|
||||
break;
|
||||
case "speed":
|
||||
speed(player, args);
|
||||
break;
|
||||
default:
|
||||
help(player);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setup(Player player){
|
||||
AutoLoader.getLoader(player).setup();
|
||||
}
|
||||
|
||||
private void undo(Player player){
|
||||
AutoLoader loader = loader(player);
|
||||
if(loader == null)
|
||||
return;
|
||||
|
||||
if(!loader.isSetup()){
|
||||
player.sendMessage("§cDer AutoLader wird in den Setup-Zustand versetzt");
|
||||
setup(player);
|
||||
}
|
||||
|
||||
loader.undo();
|
||||
}
|
||||
|
||||
private void start(Player player){
|
||||
AutoLoader loader = loader(player);
|
||||
if(loader == null)
|
||||
return;
|
||||
|
||||
loader.start();
|
||||
}
|
||||
|
||||
private void stop(Player player){
|
||||
if(!AutoLoader.hasLoader(player)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu hast keinen aktiven AutoLader");
|
||||
return;
|
||||
}
|
||||
AutoLoader.getLoader(player).stop();
|
||||
}
|
||||
|
||||
private void wait(Player player, String[] args){
|
||||
if(args.length != 2){
|
||||
help(player);
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLoader loader = loader(player);
|
||||
if(loader == null)
|
||||
loader = AutoLoader.getLoader(player);
|
||||
|
||||
try {
|
||||
loader.wait(Integer.parseInt(args[1]));
|
||||
}catch (NumberFormatException e){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cBitte gib eine Ganzzahl an");
|
||||
}
|
||||
}
|
||||
|
||||
private void speed(Player player, String[] args){
|
||||
if(args.length != 2){
|
||||
help(player);
|
||||
return;
|
||||
}
|
||||
|
||||
AutoLoader loader = loader(player);
|
||||
if(loader == null)
|
||||
loader = AutoLoader.getLoader(player);
|
||||
|
||||
try {
|
||||
loader.blockWait(Integer.parseInt(args[1]));
|
||||
}catch (NumberFormatException e){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cBitte gib eine Ganzzahl an");
|
||||
}
|
||||
}
|
||||
|
||||
private AutoLoader loader(Player player){
|
||||
if(AutoLoader.hasLoader(player))
|
||||
return AutoLoader.getLoader(player);
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu hast keinen aktiven AutoLader");
|
||||
player.sendMessage(BauSystem.PREFIX + "§7Es wird ein neuer AutoLader gestartet");
|
||||
setup(player);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ public class CommandProtect implements CommandExecutor {
|
||||
return false;
|
||||
Player player = (Player) sender;
|
||||
|
||||
if(!Welt.hasPermission(player, Permission.worldedit)){
|
||||
if(Welt.noPermission(player, Permission.worldedit)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht den Boden schützen");
|
||||
return false;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ public class CommandReset implements CommandExecutor {
|
||||
return false;
|
||||
Player player = (Player) sender;
|
||||
|
||||
if(!Welt.hasPermission(player, Permission.world)){
|
||||
if(Welt.noPermission(player, Permission.world)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht die Region zurücksetzen");
|
||||
return false;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ public class CommandTestblock implements CommandExecutor {
|
||||
return false;
|
||||
Player player = (Player) sender;
|
||||
|
||||
if(!Welt.hasPermission(player, Permission.worldedit)){
|
||||
if(Welt.noPermission(player, Permission.worldedit)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht den Testblock zurücksetzen");
|
||||
return false;
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class CommandTime extends BukkitCommand {
|
||||
}
|
||||
Player player = (Player) sender;
|
||||
|
||||
if (!Welt.hasPermission(player, Permission.world)){
|
||||
if (Welt.noPermission(player, Permission.world)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht die Zeit ändern");
|
||||
return false;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package de.steamwar.bausystem.commands;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import de.steamwar.bausystem.Permission;
|
||||
import de.steamwar.bausystem.world.TNTTracer;
|
||||
import de.steamwar.bausystem.world.Welt;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
@ -10,68 +11,10 @@ import org.bukkit.entity.Player;
|
||||
|
||||
public class CommandTrace implements CommandExecutor {
|
||||
|
||||
private static final String DENY_MESSAGE = "§cDu darfst hier nicht den TNT-Tracer nutzen";
|
||||
|
||||
private void help(Player player){
|
||||
player.sendMessage("§8/§etrace start §7- Startet die Aufnahme aller TNT-Positionen");
|
||||
player.sendMessage("§8/§etrace show §7- Zeigt alle TNT-Positionen");
|
||||
player.sendMessage("§8/§etrace hide §7- Versteckt die TNT-Positionen wieder");
|
||||
player.sendMessage("§8/§etrace stop §7- Bricht die Aufnahme ab");
|
||||
}
|
||||
|
||||
private void start(Player p){
|
||||
if(!Welt.hasPermission(p, Permission.world)){
|
||||
p.sendMessage(BauSystem.PREFIX + DENY_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
BauSystem.getTracer().start();
|
||||
p.sendMessage(BauSystem.PREFIX + "§aAufnahme gestartet");
|
||||
}
|
||||
|
||||
private void stop(Player p){
|
||||
if(!Welt.hasPermission(p, Permission.world)){
|
||||
p.sendMessage(BauSystem.PREFIX + DENY_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!BauSystem.getTracer().isActive()){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cKein laufender TNT-Tracer");
|
||||
return;
|
||||
}
|
||||
|
||||
BauSystem.getTracer().stop();
|
||||
p.sendMessage(BauSystem.PREFIX + "§aAufnahme abgebrochen");
|
||||
}
|
||||
|
||||
private void show(Player p){
|
||||
if(!Welt.hasPermission(p, Permission.world)){
|
||||
p.sendMessage(BauSystem.PREFIX + DENY_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!BauSystem.getTracer().isActive()){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cKein laufender TNT-Tracer");
|
||||
return;
|
||||
}
|
||||
|
||||
BauSystem.getTracer().show();
|
||||
p.sendMessage(BauSystem.PREFIX + "§aTNT-Positionen angezeigt");
|
||||
}
|
||||
|
||||
private void hide(Player p){
|
||||
if(!Welt.hasPermission(p, Permission.world)){
|
||||
p.sendMessage(BauSystem.PREFIX + DENY_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!BauSystem.getTracer().isPrinted()){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cDerzeit werden keine Blöcke angezeigt");
|
||||
return;
|
||||
}
|
||||
|
||||
BauSystem.getTracer().hide();
|
||||
p.sendMessage(BauSystem.PREFIX + "§aTNT-Positionen versteckt");
|
||||
player.sendMessage("§8/§etrace start §8- §7Startet die Aufnahme aller TNT-Positionen");
|
||||
player.sendMessage("§8/§etrace show §8- §7Zeigt alle TNT-Positionen");
|
||||
player.sendMessage("§8/§etrace stop §8- §7Stoppt den TNT-Tracer");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -80,19 +23,28 @@ public class CommandTrace implements CommandExecutor {
|
||||
return false;
|
||||
Player player = (Player) sender;
|
||||
|
||||
switch(args.length){
|
||||
case 1:
|
||||
if(args[0].equalsIgnoreCase("start")){
|
||||
start(player);
|
||||
}else if(args[0].equalsIgnoreCase("stop")){
|
||||
stop(player);
|
||||
}else if(args[0].equalsIgnoreCase("show")){
|
||||
show(player);
|
||||
}else if(args[0].equalsIgnoreCase("hide")){
|
||||
hide(player);
|
||||
}else{
|
||||
help(player);
|
||||
}
|
||||
if(args.length == 0){
|
||||
help(player);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(Welt.noPermission(player, Permission.world)){
|
||||
player.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht den TNT-Tracer nutzen");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(args[0].toLowerCase()){
|
||||
case "start":
|
||||
TNTTracer.start();
|
||||
player.sendMessage(BauSystem.PREFIX + "§aAufnahme gestartet");
|
||||
break;
|
||||
case "show":
|
||||
int blocks = TNTTracer.show();
|
||||
player.sendMessage(BauSystem.PREFIX + "§a" + blocks + " TNT-Positionen angezeigt");
|
||||
break;
|
||||
case "stop":
|
||||
TNTTracer.stop();
|
||||
player.sendMessage(BauSystem.PREFIX + "§cTNT-Tracer gestoppt");
|
||||
break;
|
||||
default:
|
||||
help(player);
|
||||
|
319
src/de/steamwar/bausystem/world/AutoLoader.java
Normale Datei
319
src/de/steamwar/bausystem/world/AutoLoader.java
Normale Datei
@ -0,0 +1,319 @@
|
||||
package de.steamwar.bausystem.world;
|
||||
|
||||
import de.steamwar.bausystem.BauSystem;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class AutoLoader implements Listener {
|
||||
|
||||
private static final Map<Player, AutoLoader> players = new HashMap<>();
|
||||
|
||||
public static AutoLoader getLoader(Player player){
|
||||
if(!players.containsKey(player))
|
||||
return new AutoLoader(player);
|
||||
return players.get(player);
|
||||
}
|
||||
|
||||
public static boolean hasLoader(Player player){
|
||||
return players.containsKey(player);
|
||||
}
|
||||
|
||||
private final Player player;
|
||||
private final BukkitTask task;
|
||||
|
||||
private final LinkedList<LoaderAction> actions = new LinkedList<>();
|
||||
private int ticksBetweenShots = 80;
|
||||
private int ticksBetweenBlocks = 1;
|
||||
|
||||
private int lastActivation;
|
||||
private int waitTicks;
|
||||
private ListIterator<LoaderAction> lastAction;
|
||||
private boolean setup;
|
||||
|
||||
private AutoLoader(Player player){
|
||||
this.player = player;
|
||||
Bukkit.getPluginManager().registerEvents(this, BauSystem.getPlugin());
|
||||
task = Bukkit.getScheduler().runTaskTimer(BauSystem.getPlugin(), this::run, 1, 1);
|
||||
players.put(player, this);
|
||||
player.sendMessage(BauSystem.PREFIX + "§7Schieße bitte einmal die Kanone ab");
|
||||
player.sendMessage(BauSystem.PREFIX + "§7Und starte anschließend den AutoLader mit §8/§eloader start");
|
||||
setup();
|
||||
}
|
||||
|
||||
public void setup(){
|
||||
print("§aAutoLader im Setup-Modus", false);
|
||||
setup = true;
|
||||
waitTicks = 0;
|
||||
lastActivation = 0;
|
||||
}
|
||||
|
||||
public void start(){
|
||||
if(actions.isEmpty()){
|
||||
print("§cKeine Aktion vorhanden", false);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!setup){
|
||||
print("§cAutoLader läuft bereits", false);
|
||||
return;
|
||||
}
|
||||
|
||||
setup = false;
|
||||
waitTicks = 0;
|
||||
lastActivation = 0;
|
||||
lastAction = actions.listIterator();
|
||||
print("§aAutoLader gestartet", false);
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
print("§cAutoLader gestoppt", false);
|
||||
players.remove(player);
|
||||
HandlerList.unregisterAll(this);
|
||||
if(task != null)
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
public void undo(){
|
||||
if(actions.isEmpty()){
|
||||
print("§cKeine Aktion vorhanden", false);
|
||||
return;
|
||||
}
|
||||
|
||||
actions.removeLast();
|
||||
print("§aUndo erfolgreich", true);
|
||||
}
|
||||
|
||||
public void wait(int time){
|
||||
if(time < 0){
|
||||
print("§cNegative Wartezeit", false);
|
||||
return;
|
||||
}
|
||||
|
||||
print("§aSchusswartezeit §e" + time + " §aTicks§8, zuvor " + ticksBetweenShots, false);
|
||||
ticksBetweenShots = time;
|
||||
}
|
||||
|
||||
public void blockWait(int time){
|
||||
if(time < 0){
|
||||
print("§cNegative Wartezeit", false);
|
||||
return;
|
||||
}
|
||||
|
||||
print("§aSetzwartezeit §e" + time + " §aTicks§8, zuvor " + ticksBetweenBlocks, false);
|
||||
ticksBetweenBlocks = time;
|
||||
}
|
||||
|
||||
public boolean isSetup() {
|
||||
return setup;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPlace(BlockPlaceEvent event){
|
||||
if(!setup || !event.getPlayer().equals(player))
|
||||
return;
|
||||
if(event.getBlock().getType() != Material.TNT)
|
||||
return;
|
||||
|
||||
new TNTPlaceAction(event.getBlock().getLocation());
|
||||
print("§eTNT platziert", true);
|
||||
}
|
||||
|
||||
//BlockRedstoneEvent?
|
||||
@EventHandler
|
||||
public void onPlayerInteract(PlayerInteractEvent event){
|
||||
if(!setup || !event.getPlayer().equals(player))
|
||||
return;
|
||||
|
||||
if(event.getAction() == Action.RIGHT_CLICK_BLOCK){
|
||||
Block block = event.getClickedBlock();
|
||||
Material material = block.getType();
|
||||
if(material == Material.LEVER){
|
||||
if((block.getData() & 8) == 8) {
|
||||
new RedstoneActivation(block.getLocation(), lastActivation, false);
|
||||
print("§eHebel zurückgesetzt", true);
|
||||
}else{
|
||||
new RedstoneActivation(block.getLocation(), 1, true);
|
||||
print("§eHebel betätigt", true);
|
||||
}
|
||||
}else if(material == Material.STONE_BUTTON){
|
||||
new TemporaryActivation(block.getLocation(), 20);
|
||||
print("§eKnopf betätigt", true);
|
||||
}else if(material == Material.WOOD_BUTTON){
|
||||
new TemporaryActivation(block.getLocation(), 30);
|
||||
print("§eKnopf betätigt", true);
|
||||
}
|
||||
}else if(event.getAction() == Action.PHYSICAL){
|
||||
Block block = event.getClickedBlock();
|
||||
System.out.println(block);
|
||||
Material material = block.getType();
|
||||
if(material == Material.STONE_PLATE || material == Material.WOOD_PLATE){
|
||||
new TemporaryActivation(block.getLocation(), 20);
|
||||
print("§eDruckplatte betätigt", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onLeave(PlayerQuitEvent event){
|
||||
if(!event.getPlayer().equals(player))
|
||||
return;
|
||||
stop();
|
||||
}
|
||||
|
||||
private void run(){
|
||||
lastActivation++;
|
||||
if(setup)
|
||||
return;
|
||||
while(lastActivation >= waitTicks){
|
||||
lastActivation = 0;
|
||||
|
||||
LoaderAction action = lastAction.next();
|
||||
if(action.perform()){
|
||||
waitTicks = action.ticks();
|
||||
}else{
|
||||
waitTicks = 1;
|
||||
lastAction.previous();
|
||||
}
|
||||
|
||||
if(!lastAction.hasNext()){
|
||||
lastAction = actions.listIterator();
|
||||
waitTicks = ticksBetweenShots;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void print(String message, boolean withSize){
|
||||
if(withSize)
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message + " §8" + actions.size()));
|
||||
else
|
||||
player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
|
||||
}
|
||||
|
||||
private boolean setRedstone(Location location, boolean active){
|
||||
Block block = location.getBlock();
|
||||
Material material = block.getType();
|
||||
if(material == Material.LEVER || material == Material.STONE_BUTTON || material == Material.WOOD_BUTTON){
|
||||
if(active)
|
||||
block.setData((byte)(block.getData() | 8));
|
||||
else
|
||||
block.setData((byte)(block.getData() & -9));
|
||||
}else if(material == Material.STONE_PLATE || material == Material.WOOD_PLATE){
|
||||
if(active)
|
||||
block.setData((byte)1);
|
||||
else
|
||||
block.setData((byte)0);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
block.getState().update(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private abstract class LoaderAction {
|
||||
|
||||
final Location location;
|
||||
|
||||
LoaderAction(Location location){
|
||||
this.location = location;
|
||||
actions.add(this);
|
||||
lastActivation = 0;
|
||||
}
|
||||
|
||||
abstract boolean perform();
|
||||
abstract int ticks();
|
||||
}
|
||||
|
||||
private class TNTPlaceAction extends LoaderAction{
|
||||
|
||||
TNTPlaceAction(Location location){
|
||||
super(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean perform() {
|
||||
Material m = location.getBlock().getType();
|
||||
if(m != Material.AIR && m != Material.STATIONARY_WATER)
|
||||
return false;
|
||||
|
||||
location.getBlock().setType(Material.TNT);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
int ticks(){
|
||||
return ticksBetweenBlocks;
|
||||
}
|
||||
}
|
||||
|
||||
private class RedstoneActivation extends LoaderAction{
|
||||
|
||||
final boolean active;
|
||||
final int length;
|
||||
|
||||
RedstoneActivation(Location location, int ticks, boolean active){
|
||||
super(location);
|
||||
this.length = ticks;
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean perform() {
|
||||
return setRedstone(location, active);
|
||||
}
|
||||
|
||||
@Override
|
||||
int ticks() {
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
private class TemporaryActivation extends LoaderAction{
|
||||
|
||||
final int length;
|
||||
int status;
|
||||
|
||||
TemporaryActivation(Location location, int ticks){
|
||||
super(location);
|
||||
this.length = ticks;
|
||||
status = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean perform() {
|
||||
if(status == 0){
|
||||
if(!setRedstone(location, true))
|
||||
return false;
|
||||
}else if(status == length){
|
||||
if(!setRedstone(location, false))
|
||||
return false;
|
||||
status = 0;
|
||||
return true;
|
||||
}
|
||||
status++;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
int ticks() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,34 +16,34 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent;
|
||||
|
||||
public class RegionListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void playerCommandHandler(PlayerCommandPreprocessEvent e) {
|
||||
if (!isWorldEditCommand(e.getMessage().split(" ")[0]))
|
||||
return;
|
||||
|
||||
Player p = e.getPlayer();
|
||||
|
||||
if (!Welt.hasPermission(p, Permission.worldedit)){
|
||||
if (Welt.noPermission(p, Permission.worldedit)){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cDu darfst hier kein WorldEdit benutzen");
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onBlockBreak(BlockBreakEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
|
||||
if (!Welt.hasPermission(p, Permission.build)){
|
||||
if (Welt.noPermission(p, Permission.build)){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cDu darfst hier keine Blöcke abbauen");
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onBlockPlace(BlockPlaceEvent e) {
|
||||
Player p = e.getPlayer();
|
||||
|
||||
if (!Welt.hasPermission(p, Permission.build)){
|
||||
if (Welt.noPermission(p, Permission.build)){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cDu darfst hier keine Blöcke platzieren");
|
||||
e.setCancelled(true);
|
||||
}
|
||||
|
20
src/de/steamwar/bausystem/world/TNTListener.java
Normale Datei
20
src/de/steamwar/bausystem/world/TNTListener.java
Normale Datei
@ -0,0 +1,20 @@
|
||||
package de.steamwar.bausystem.world;
|
||||
|
||||
import org.bukkit.entity.TNTPrimed;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityExplodeEvent;
|
||||
|
||||
public class TNTListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onEntityExplode(EntityExplodeEvent event){
|
||||
if(TNTTracer.getStatus() != TNTTracer.Status.RECORD)
|
||||
return;
|
||||
if(!(event.getEntity() instanceof TNTPrimed))
|
||||
return;
|
||||
TNTPrimed entity = (TNTPrimed) event.getEntity();
|
||||
|
||||
TNTTracer.remove(entity);
|
||||
}
|
||||
}
|
@ -6,93 +6,240 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.TNTPrimed;
|
||||
import org.bukkit.material.Step;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class TNTTracer implements Runnable {
|
||||
public class TNTTracer {
|
||||
|
||||
private BukkitTask task;
|
||||
private final Set<Location> locations;
|
||||
private boolean printed;
|
||||
private boolean active;
|
||||
private static final byte BRICK_STEP = new Step(Material.BRICK).getData();
|
||||
private static final byte INVERTED_BRICK_STEP = (byte)(BRICK_STEP + 8);
|
||||
|
||||
public TNTTracer(){
|
||||
this.locations = new HashSet<Location>();
|
||||
this.printed = false;
|
||||
this.active = false;
|
||||
private static BukkitTask task;
|
||||
private static final Set<Location> printedLocs = new HashSet<>();
|
||||
private static final Map<TNTPrimed, LinkedList<Location>> locations = new HashMap<>();
|
||||
private static World world;
|
||||
|
||||
static Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void start(){
|
||||
active = true;
|
||||
this.task = Bukkit.getScheduler().runTaskTimer(BauSystem.getPlugin(), this, 1, 1);
|
||||
private static Status status = Status.IDLE;
|
||||
|
||||
static void remove(TNTPrimed tnt){
|
||||
Material material = tnt.getLocation().getBlock().getType();
|
||||
if(material == Material.WATER || material == Material.STATIONARY_WATER)
|
||||
locations.remove(tnt);
|
||||
}
|
||||
|
||||
private void end(){
|
||||
active = false;
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
public boolean isActive(){
|
||||
return active;
|
||||
}
|
||||
public boolean isPrinted(){
|
||||
return printed;
|
||||
}
|
||||
|
||||
public void stop(){
|
||||
end();
|
||||
if(!printed){
|
||||
locations.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void show(){
|
||||
end();
|
||||
printed = true;
|
||||
Set<Location> unsetLoc = new HashSet<Location>();
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
for(Location l : locations){
|
||||
Block b = world.getBlockAt(l);
|
||||
if(b.getType() != Material.AIR){
|
||||
unsetLoc.add(l);
|
||||
continue;
|
||||
}
|
||||
b.setType(Material.STAINED_GLASS);
|
||||
b.setData((byte) 1);
|
||||
}
|
||||
locations.removeAll(unsetLoc);
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
if(!printed)
|
||||
public static void start(){
|
||||
if(status == Status.RECORD)
|
||||
return;
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
for(Location l : locations){
|
||||
Block b = world.getBlockAt(l);
|
||||
if(b.getType() != Material.STAINED_GLASS || b.getData() != 1)
|
||||
continue;
|
||||
b.setType(Material.AIR);
|
||||
}
|
||||
printed = false;
|
||||
stop();
|
||||
locations.clear();
|
||||
world = Bukkit.getWorlds().get(0);
|
||||
|
||||
status = Status.RECORD;
|
||||
task = Bukkit.getScheduler().runTaskTimer(BauSystem.getPlugin(), TNTTracer::run, 1, 1);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if(locations.size() < 20000){
|
||||
World world = Bukkit.getWorlds().get(0);
|
||||
for(Entity e : world.getEntitiesByClass(TNTPrimed.class)){
|
||||
locations.add(e.getLocation());
|
||||
public static int show(){
|
||||
if(status == Status.SHOW)
|
||||
return printedLocs.size();
|
||||
stop();
|
||||
status = Status.SHOW;
|
||||
|
||||
for(LinkedList<Location> tntTrace : locations.values()){
|
||||
if(tntTrace.size() == 1)
|
||||
printLocation(tntTrace.getFirst());
|
||||
else if(tntTrace.size() > 1)
|
||||
interpolate(tntTrace);
|
||||
}
|
||||
locations.clear();
|
||||
return printedLocs.size();
|
||||
}
|
||||
|
||||
public static void stop(){
|
||||
status = Status.IDLE;
|
||||
if(task != null)
|
||||
task.cancel();
|
||||
|
||||
for(Location l : printedLocs){
|
||||
Block b = world.getBlockAt(l);
|
||||
if(airOrBrick(b))
|
||||
b.setType(Material.AIR);
|
||||
}
|
||||
printedLocs.clear();
|
||||
}
|
||||
|
||||
private static void interpolate(LinkedList<Location> trace){
|
||||
ListIterator<Location> it = trace.listIterator();
|
||||
Location previous = it.next();
|
||||
printLocation(previous);
|
||||
while(it.hasNext()){
|
||||
Location actual = it.next();
|
||||
Set<Double> xSteps = getSteps(previous.getX(), actual.getX());
|
||||
Set<Double> ySteps = getSteps(previous.getY(), actual.getY());
|
||||
Set<Double> zSteps = getSteps(previous.getZ(), actual.getZ());
|
||||
for(double y : ySteps)
|
||||
printLocation(new Location(world, previous.getX(), y, previous.getZ()));
|
||||
for(double x : xSteps)
|
||||
printLocation(new Location(world, x, actual.getY(), previous.getZ()));
|
||||
for(double z : zSteps)
|
||||
printLocation(new Location(world, actual.getX(), actual.getY(), z));
|
||||
previous = actual;
|
||||
}
|
||||
}
|
||||
private static Set<Double> getSteps(double previous, double actual){
|
||||
Set<Double> steps = new HashSet<>();
|
||||
if(actual < previous){
|
||||
double temp = previous;
|
||||
previous = actual;
|
||||
actual = temp;
|
||||
}
|
||||
|
||||
steps.add(actual);
|
||||
steps.add(previous);
|
||||
double iterator = previous;
|
||||
while(actual - iterator > 1){
|
||||
iterator++;
|
||||
steps.add(iterator);
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
private static void printLocation(Location l){
|
||||
Block block = l.getBlock();
|
||||
double rx = l.getX() - Math.abs(l.getX());
|
||||
double ry = l.getY() - Math.abs(l.getY());
|
||||
double rz = l.getZ() - Math.abs(l.getZ());
|
||||
BlockStatus main;
|
||||
BlockStatus upper;
|
||||
if(ry <= 0.02){
|
||||
main = BlockStatus.BLOCK;
|
||||
upper = BlockStatus.NONE;
|
||||
}else if(ry <= 0.5){
|
||||
main = BlockStatus.BLOCK;
|
||||
upper = BlockStatus.SLAB;
|
||||
}else if(ry <= 0.52){
|
||||
main = BlockStatus.INVERTED_SLAB;
|
||||
upper = BlockStatus.SLAB;
|
||||
}else{
|
||||
main = BlockStatus.INVERTED_SLAB;
|
||||
upper = BlockStatus.BLOCK;
|
||||
}
|
||||
|
||||
Block nearX = null;
|
||||
Block nearZ = null;
|
||||
Block nearCross = null;
|
||||
if(rx < 0.48){
|
||||
nearX = block.getRelative(BlockFace.WEST);
|
||||
if(rz < 0.48){
|
||||
nearZ = block.getRelative(BlockFace.NORTH);
|
||||
nearCross = block.getRelative(BlockFace.NORTH_WEST);
|
||||
}else if(rz > 0.52){
|
||||
nearZ = block.getRelative(BlockFace.SOUTH);
|
||||
nearCross = block.getRelative(BlockFace.SOUTH_WEST);
|
||||
}
|
||||
if(locations.size() >= 20000){
|
||||
for(Player p : world.getPlayers()){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cEs werden keine weiteren Positionen mehr erfasst (20.000 Block Limit)");
|
||||
}
|
||||
}else if(rx > 0.52){
|
||||
nearX = block.getRelative(BlockFace.EAST);
|
||||
if(rz < 0.48){
|
||||
nearZ = block.getRelative(BlockFace.NORTH);
|
||||
nearCross = block.getRelative(BlockFace.NORTH_EAST);
|
||||
}else if(rz > 0.52){
|
||||
nearZ = block.getRelative(BlockFace.SOUTH);
|
||||
nearCross = block.getRelative(BlockFace.SOUTH_EAST);
|
||||
}
|
||||
}else{
|
||||
if(rz < 0.48){
|
||||
nearZ = block.getRelative(BlockFace.NORTH);
|
||||
}else if(rz > 0.52){
|
||||
nearZ = block.getRelative(BlockFace.SOUTH);
|
||||
}
|
||||
}
|
||||
|
||||
setBlock(block, main);
|
||||
setBlock(block.getRelative(BlockFace.UP), upper);
|
||||
if(nearX != null){
|
||||
setBlock(nearX, main);
|
||||
setBlock(nearX.getRelative(BlockFace.UP), upper);
|
||||
}
|
||||
if(nearZ != null){
|
||||
setBlock(nearZ, main);
|
||||
setBlock(nearZ.getRelative(BlockFace.UP), upper);
|
||||
}
|
||||
if(nearCross != null){
|
||||
setBlock(nearCross, main);
|
||||
setBlock(nearCross.getRelative(BlockFace.UP), upper);
|
||||
}
|
||||
}
|
||||
private static void setBlock(Block block, BlockStatus status){
|
||||
if(status == BlockStatus.NONE)
|
||||
return;
|
||||
|
||||
Material material = block.getType();
|
||||
if(material == Material.AIR){
|
||||
status.setBlock(block);
|
||||
printedLocs.add(block.getLocation());
|
||||
}else if(material == Material.STEP){
|
||||
byte data = block.getData();
|
||||
if(data == BRICK_STEP){
|
||||
if(status == BlockStatus.BLOCK)
|
||||
status.setBlock(block);
|
||||
else if(status == BlockStatus.INVERTED_SLAB)
|
||||
BlockStatus.BLOCK.setBlock(block);
|
||||
}else if(data == INVERTED_BRICK_STEP){
|
||||
if(status == BlockStatus.BLOCK)
|
||||
status.setBlock(block);
|
||||
else if(status == BlockStatus.SLAB)
|
||||
BlockStatus.BLOCK.setBlock(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static boolean airOrBrick(Block block){
|
||||
Material material = block.getType();
|
||||
if(material == Material.AIR || material == Material.BRICK)
|
||||
return true;
|
||||
if(material != Material.STEP)
|
||||
return false;
|
||||
|
||||
byte data = block.getData();
|
||||
return data == BRICK_STEP || data == INVERTED_BRICK_STEP;
|
||||
}
|
||||
|
||||
private static void run() {
|
||||
for(TNTPrimed tnt : world.getEntitiesByClass(TNTPrimed.class)){
|
||||
locations.computeIfAbsent(tnt, k -> new LinkedList<>()).add(tnt.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
enum Status{
|
||||
RECORD,
|
||||
SHOW,
|
||||
IDLE
|
||||
}
|
||||
|
||||
enum BlockStatus{
|
||||
NONE(Material.AIR, 0),
|
||||
BLOCK(Material.BRICK, 0),
|
||||
SLAB(Material.STEP, BRICK_STEP),
|
||||
INVERTED_SLAB(Material.STEP, INVERTED_BRICK_STEP);
|
||||
|
||||
|
||||
private final Material material;
|
||||
private final byte data;
|
||||
|
||||
BlockStatus(Material material, int data){
|
||||
this.material = material;
|
||||
this.data = (byte)data;
|
||||
}
|
||||
|
||||
void setBlock(Block b){
|
||||
b.setType(material);
|
||||
b.setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,30 +12,30 @@ public class Welt {
|
||||
|
||||
private Welt(){}
|
||||
|
||||
public static boolean hasPermission(Player member, Permission perm){
|
||||
public static boolean noPermission(Player member, Permission perm){
|
||||
if(member.getUniqueId().equals(BauSystem.getOwner()))
|
||||
return true;
|
||||
return false;
|
||||
|
||||
BauweltMember member1 = BauweltMember.getBauMember(member.getUniqueId());
|
||||
if(member1 == null)
|
||||
return false;
|
||||
return true;
|
||||
|
||||
switch(perm){
|
||||
case build:
|
||||
return member1.isBuild();
|
||||
return !member1.isBuild();
|
||||
case worldedit:
|
||||
return member1.isWorldEdit();
|
||||
return !member1.isWorldEdit();
|
||||
case world:
|
||||
return member1.isWorld();
|
||||
return !member1.isWorld();
|
||||
case member:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void switchTNT(Player p){
|
||||
if (!hasPermission(p, Permission.world)){
|
||||
if (noPermission(p, Permission.world)){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht TNT-Schaden (de)aktivieren");
|
||||
return;
|
||||
}
|
||||
@ -49,7 +49,7 @@ public class Welt {
|
||||
}
|
||||
|
||||
public static void switchFire(Player p){
|
||||
if (!hasPermission(p, Permission.world)){
|
||||
if (noPermission(p, Permission.world)){
|
||||
p.sendMessage(BauSystem.PREFIX + "§cDu darfst hier nicht Feuerschaden (de)aktivieren");
|
||||
return;
|
||||
}
|
||||
|
@ -16,5 +16,6 @@ commands:
|
||||
speed:
|
||||
skull:
|
||||
freeze:
|
||||
loader:
|
||||
nightvision:
|
||||
aliases: nv
|
In neuem Issue referenzieren
Einen Benutzer sperren