/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 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 .
*/
package de.steamwar.bausystem.world;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.FlatteningWrapper;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
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 extends AbstractAutoLoader implements Listener {
private static final Map 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 actions = new LinkedList<>();
private int ticksBetweenShots = 80;
private int ticksBetweenBlocks = 1;
private int lastActivation;
private int waitTicks;
private ListIterator lastAction;
private boolean setup;
private Location lastLocation;
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 < 1){
print("§cDie Wartezeit ist zu klein", false);
return;
}
print("§aSchusswartezeit §e" + time + " §aTicks§8, zuvor " + ticksBetweenShots, false);
ticksBetweenShots = time;
}
public void blockWait(int time){
if(time < 1){
print("§cDie Wartezeit ist zu klein", false);
return;
}
print("§aSetzwartezeit §e" + time + " §aTicks§8, zuvor " + ticksBetweenBlocks, false);
ticksBetweenBlocks = time;
}
public int getTicksBetweenShots() {
return ticksBetweenShots;
}
public int getTicksBetweenBlocks() {
return ticksBetweenBlocks;
}
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(this, event.getBlock().getLocation());
print("§eTNT platziert", true);
}
//BlockRedstoneEvent?
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event){
if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.PHYSICAL)
return;
if (event.getClickedBlock().getType() == Material.OBSERVER)
return;
if (event.getPlayer().isSneaking())
return;
if (!setup || !event.getPlayer().equals(player))
return;
Detoloader detoloader = FlatteningWrapper.impl.onPlayerInteractLoader(event);
if (detoloader == null || detoloader.getActivation() < 0) return;
if (lastLocation != null && lastLocation.distance(event.getClickedBlock().getLocation()) <= 1) return;
if (detoloader.useActive) {
new AbstractAutoLoader.RedstoneActivation(this, event.getClickedBlock().getLocation()
, detoloader.getActivation() == 0 ? getLastActivation() : detoloader.getActivation()
, detoloader.isActive());
} else {
new AbstractAutoLoader.TemporaryActivation(this, event.getClickedBlock().getLocation()
, detoloader.getActivation());
}
print(detoloader.addBack ? "§e" + detoloader.getBlock() + " betätigt" :
detoloader.getBlock(), detoloader.addBack);
lastLocation = event.getClickedBlock().getLocation();
}
@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;
}
}
}
@Override
Player getPlayer() {
return player;
}
@Override
boolean setRedstone(Location location, boolean active){
return FlatteningWrapper.impl.setRedstone(location, active);
}
@Override
LinkedList getActions() {
return actions;
}
@Override
void resetLastActivation() {
lastActivation = 0;
}
@Override
int getLastActivation() {
return lastActivation;
}
class TNTPlaceAction extends AbstractAutoLoader.LoaderAction {
TNTPlaceAction(AbstractAutoLoader loader, Location location){
super(loader, location);
}
@Override
public boolean perform() {
return FlatteningWrapper.impl.tntPlaceActionPerform(location);
}
@Override
int ticks(){
return ticksBetweenBlocks;
}
}
}