diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
index 911872ba..83b373ce 100644
--- a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/SimulatorCursor.java
@@ -26,6 +26,8 @@ import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement;
import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
@@ -230,7 +232,7 @@ public class SimulatorCursor implements Listener {
}
}
- public static Vector getPosTNT(Player player, RayTraceUtils.RRayTraceResult result) {
+ public static Vector getPosFree(Player player, RayTraceUtils.RRayTraceResult result) {
Vector pos = result.getHitPosition();
BlockFace face = result.getHitBlockFace();
@@ -270,7 +272,7 @@ public class SimulatorCursor implements Listener {
return pos;
}
- private static Vector getPosRedstoneBlock(Player player, RayTraceUtils.RRayTraceResult result) {
+ private static Vector getPosBlockAligned(Player player, RayTraceUtils.RRayTraceResult result) {
Vector pos = result.getHitPosition();
BlockFace face = result.getHitBlockFace();
@@ -309,8 +311,9 @@ public class SimulatorCursor implements Listener {
@Getter
@AllArgsConstructor
public enum CursorType {
- TNT(Material.TNT, SimulatorCursor::getPosTNT, "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
- REDSTONE_BLOCK(Material.REDSTONE_BLOCK, SimulatorCursor::getPosRedstoneBlock, "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
+ TNT(Material.TNT, SimulatorCursor::getPosFree, "TNT", vector -> new TNTElement(vector).add(new TNTPhase())),
+ REDSTONE_BLOCK(Material.REDSTONE_BLOCK, SimulatorCursor::getPosBlockAligned, "Redstone Block", vector -> new RedstoneElement(vector).add(new RedstonePhase())),
+ OBSERVER(Material.OBSERVER, SimulatorCursor::getPosBlockAligned, "Observer", vector -> new ObserverElement(vector).add(new ObserverPhase())),
;
private Material material;
@@ -322,6 +325,9 @@ public class SimulatorCursor implements Listener {
if (this == TNT) {
return REDSTONE_BLOCK;
}
+ if (this == REDSTONE_BLOCK) {
+ return OBSERVER;
+ }
return TNT;
}
}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/SimulatorBlockAlignedElement.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/SimulatorBlockAlignedElement.java
new file mode 100644
index 00000000..de0d2b69
--- /dev/null
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/SimulatorBlockAlignedElement.java
@@ -0,0 +1,35 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.features.simulator.data;
+
+import org.bukkit.Material;
+import org.bukkit.util.Vector;
+
+public abstract class SimulatorBlockAlignedElement extends SimulatorElement {
+
+ protected SimulatorBlockAlignedElement(Material material, Vector position) {
+ super(material, position);
+ }
+
+ @Override
+ public final boolean canBeInGroup(SimulatorGroup simulatorGroup) {
+ return simulatorGroup.getElements().stream().allMatch(SimulatorBlockAlignedElement.class::isInstance);
+ }
+}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/observer/ObserverElement.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/observer/ObserverElement.java
new file mode 100644
index 00000000..9c7f36d5
--- /dev/null
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/observer/ObserverElement.java
@@ -0,0 +1,103 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.features.simulator.data.observer;
+
+import de.steamwar.bausystem.features.simulator.data.Simulator;
+import de.steamwar.bausystem.features.simulator.data.SimulatorBlockAlignedElement;
+import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
+import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
+import de.steamwar.bausystem.features.simulator.data.tnt.TNTPhase;
+import de.steamwar.bausystem.features.simulator.execute.SimulatorAction;
+import de.steamwar.bausystem.features.simulator.gui.SimulatorObserverGui;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
+import de.steamwar.inventory.InvCallback;
+import de.steamwar.inventory.SWItem;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.util.Vector;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiConsumer;
+
+public final class ObserverElement extends SimulatorBlockAlignedElement {
+
+ public ObserverElement(Vector position) {
+ super(Material.OBSERVER, position);
+ }
+
+ @Override
+ public String getName(Player player) {
+ return "Observer";
+ }
+
+ @Override
+ public Material getWorldMaterial() {
+ return Material.OBSERVER;
+ }
+
+ @Override
+ public Material getWorldDisabledMaterial() {
+ return Material.GRAY_STAINED_GLASS;
+ }
+
+ public void toSimulatorActions(BiConsumer tickStart, BiConsumer tickEnd) {
+ if (disabled) return;
+ phases.forEach(phase -> {
+ phase.toSimulatorActions(position.clone(), tickStart, tickEnd);
+ });
+
+ int end = phases.stream().mapToInt(SimulatorPhase::getTickOffset).max().orElse(0) + 4;
+ AtomicReference blockState = new AtomicReference<>();
+ tickStart.accept(0, new SimulatorAction(-100, 1) {
+ @Override
+ public void accept(World world) {
+ Block block = world.getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
+ blockState.set(block.getState());
+ block.setType(Material.OBSERVER, false);
+ }
+ });
+ tickEnd.accept(end, new SimulatorAction(0, 1) {
+ @Override
+ public void accept(World world) {
+ BlockState oldState = blockState.get();
+ if (oldState != null) {
+ oldState.update(true, true);
+ } else {
+ Block block = world.getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
+ block.setType(Material.AIR);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void open(Player player, Simulator simulator, SimulatorGroup group, SimulatorBaseGui back) {
+ new SimulatorObserverGui(player, simulator, group, this, back).open();
+ }
+
+ @Override
+ public String getType() {
+ return "Observer";
+ }
+}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/observer/ObserverPhase.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/observer/ObserverPhase.java
new file mode 100644
index 00000000..e3707c3e
--- /dev/null
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/observer/ObserverPhase.java
@@ -0,0 +1,81 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.features.simulator.data.observer;
+
+import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
+import de.steamwar.bausystem.features.simulator.execute.SimulatorAction;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.BlockState;
+import org.bukkit.block.data.type.Observer;
+import org.bukkit.util.Vector;
+import yapion.hierarchy.types.YAPIONObject;
+
+import java.util.function.BiConsumer;
+
+@NoArgsConstructor
+public final class ObserverPhase extends SimulatorPhase {
+
+ @Getter
+ @Setter
+ private BlockFace orientation = BlockFace.UP;
+
+ public ObserverPhase(int tickOffset) {
+ this.tickOffset = tickOffset;
+ }
+
+ {
+ this.lifetime = 0;
+ }
+
+ @Override
+ public void toSimulatorActions(Vector position, BiConsumer tickStart, BiConsumer tickEnd) {
+ Observer observer = (Observer) Material.OBSERVER.createBlockData();
+ observer.setFacing(orientation.getOppositeFace());
+ observer.setPowered(true);
+
+ tickStart.accept(tickOffset, new SimulatorAction(order, 1) {
+ @Override
+ public void accept(World world) {
+ Block block = world.getBlockAt(position.getBlockX(), position.getBlockY(), position.getBlockZ());
+ Block updateBlock = block.getRelative(orientation);
+ BlockState state = updateBlock.getState();
+ updateBlock.setType(Material.SPONGE, true);
+ block.setBlockData(observer, true);
+ state.update(true, true);
+ }
+ });
+ }
+
+ @Override
+ public void saveExtra(YAPIONObject phaseObject) {
+ phaseObject.add("orientation", orientation.name());
+ }
+
+ @Override
+ public void loadExtra(YAPIONObject phaseObject) {
+ orientation = BlockFace.valueOf(phaseObject.getPlainValue("orientation"));
+ }
+}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/redstone/RedstoneElement.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/redstone/RedstoneElement.java
index 2eb7aca2..9a970526 100644
--- a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/redstone/RedstoneElement.java
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/data/redstone/RedstoneElement.java
@@ -19,8 +19,8 @@
package de.steamwar.bausystem.features.simulator.data.redstone;
+import de.steamwar.bausystem.features.simulator.data.SimulatorBlockAlignedElement;
import de.steamwar.bausystem.features.simulator.data.Simulator;
-import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
import de.steamwar.bausystem.features.simulator.gui.SimulatorRedstoneGui;
import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
@@ -28,7 +28,7 @@ import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
-public final class RedstoneElement extends SimulatorElement {
+public final class RedstoneElement extends SimulatorBlockAlignedElement {
public RedstoneElement(Vector position) {
super(Material.REDSTONE_BLOCK, position);
@@ -49,11 +49,6 @@ public final class RedstoneElement extends SimulatorElement {
return Material.WHITE_STAINED_GLASS;
}
- @Override
- public boolean canBeInGroup(SimulatorGroup simulatorGroup) {
- return simulatorGroup.getElements().stream().allMatch(RedstoneElement.class::isInstance);
- }
-
@Override
public Vector getWorldPos() {
return position.clone().add(new Vector(0.5, 0, 0.5));
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverGui.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverGui.java
new file mode 100644
index 00000000..42669387
--- /dev/null
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverGui.java
@@ -0,0 +1,188 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.features.simulator.gui;
+
+import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
+import de.steamwar.bausystem.features.simulator.data.Simulator;
+import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorScrollGui;
+import de.steamwar.inventory.SWItem;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.ClickType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+public class SimulatorObserverGui extends SimulatorScrollGui {
+
+ private final SimulatorGroup parent;
+ private final ObserverElement observer;
+ private final SimulatorBaseGui back;
+
+ public SimulatorObserverGui(Player player, Simulator simulator, SimulatorGroup parent, ObserverElement observer, SimulatorBaseGui back) {
+ super(player, simulator, 6 * 9, observer.getPhases());
+ this.parent = parent;
+ this.observer = observer;
+ this.back = back;
+ }
+
+ @Override
+ public String baseTitle() {
+ return "Observer";
+ }
+
+ @Override
+ public void headerAndFooter() {
+ if (observer.getPhases().isEmpty()) {
+ back.open();
+ SimulatorWatcher.update(simulator);
+ return;
+ }
+
+ observer.sort();
+
+ // Back Arrow
+ inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> {
+ if (parent.getElements().contains(observer)) {
+ back.open();
+ } else {
+ SimulatorGroup newParent = observer.getGroup(simulator);
+ if (newParent == null) {
+ player.closeInventory();
+ return;
+ }
+ SimulatorGui simulatorGui = new SimulatorGui(player, simulator);
+ if (newParent.getElements().size() == 1) {
+ simulatorGui.open();
+ } else {
+ new SimulatorGroupGui(player, simulator, newParent, simulatorGui).open();
+ }
+ }
+ }));
+
+ inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
+ observer.getPhases().clear();
+ SimulatorWatcher.update(simulator);
+ }));
+
+ // Material Chooser
+ inventory.setItem(4, observer.toItem(player, clickType -> {
+ new SimulatorMaterialGui(player, simulator, observer::getMaterial, observer::setMaterial, this).open();
+ }));
+
+ // Settings
+ inventory.setItem(47, new SWItem(Material.REPEATER, "§eSettings", clickType -> {
+ new SimulatorObserverSettingsGui(player, simulator, observer, this).open();
+ }));
+
+ // Enable/Disable
+ inventory.setItem(48, new SWItem(observer.isDisabled() ? Material.ENDER_PEARL : Material.ENDER_EYE, observer.isDisabled() ? "§cDisabled" : "§aEnabled", clickType -> {
+ observer.setDisabled(!observer.isDisabled());
+ SimulatorWatcher.update(simulator);
+ }));
+
+ // Group chooser
+ inventory.setItem(51, new SWItem(Material.LEAD, "§eJoin Group", clickType -> {
+ new SimulatorGroupChooserGui(player, simulator, observer, observer.getGroup(simulator), this).open();
+ }));
+ }
+
+ @Override
+ public SWItem[] column(ObserverPhase observerPhase, int index) {
+ int min;
+ if (index > 0) {
+ min = data.get(index - 1).getTickOffset() + 4;
+ } else {
+ min = 0;
+ }
+
+ int max;
+ if (index < data.size() - 1) {
+ max = data.get(index + 1).getTickOffset() - 4;
+ } else {
+ max = Integer.MAX_VALUE - 4;
+ }
+
+ List lore = new ArrayList<>();
+ lore.add("§7Time§8:§e " + observerPhase.getTickOffset());
+ lore.add("§7Order§8:§e " + observerPhase.getOrder());
+ lore.add("");
+ lore.add("§7Orientation§8:§e " + observerPhase.getOrientation().name());
+ lore.add("");
+ lore.add("§7Click§8:§e Edit");
+ lore.add("§7Middle-Click§8:§e Remove");
+ SWItem observer = new SWItem(Material.OBSERVER, "§eObserver", lore, false, clickType -> {
+ if (clickType == ClickType.MIDDLE) {
+ this.observer.getPhases().remove(observerPhase);
+ SimulatorWatcher.update(simulator);
+ } else {
+ new SimulatorObserverPhaseSettingsGui(player, simulator, this.observer, observerPhase, this).open();
+ }
+ });
+ observer.getItemStack().setAmount(Math.min(Math.max(observerPhase.getTickOffset(), 1), 64));
+
+ Supplier getter = observerPhase::getTickOffset;
+ Consumer setter = observerPhase::setTickOffset;
+ return new SWItem[] {
+ new SWItem(SWItem.getDye(getter.get() < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
+ setter.accept(Math.min(max, getter.get() + (clickType.isShiftClick() ? 5 : 1)));
+ SimulatorWatcher.update(simulator);
+ }),
+ observer,
+ new SWItem(SWItem.getDye(getter.get() > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8:§e -5"), false, clickType -> {
+ setter.accept(Math.max(min, getter.get() - (clickType.isShiftClick() ? 5 : 1)));
+ SimulatorWatcher.update(simulator);
+ }),
+ new SWItem(Material.ANVIL, "§eEdit Activation", clickType -> {
+ new SimulatorObserverPhaseSettingsGui(player, simulator, this.observer, observerPhase, this).open();
+ }),
+ };
+ }
+
+ @Override
+ public SWItem[] lastColumn() {
+ return new SWItem[]{
+ new SWItem(SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8:§e +5"), false, clickType -> {
+ addNewPhase(clickType.isShiftClick());
+ }),
+ new SWItem(Material.QUARTZ, "§eObserver§8:§a New Phase", clickType -> {
+ addNewPhase(false);
+ }),
+ new SWItem(SWItem.getDye(8), "§7", clickType -> {
+ }),
+ };
+ }
+
+ private void addNewPhase(boolean shift) {
+ ObserverPhase lastElement = observer.getPhases().get(observer.getPhases().size() - 1);
+ ObserverPhase newPhase = new ObserverPhase(lastElement.getTickOffset() + 4);
+ if (shift) newPhase.setTickOffset(newPhase.getTickOffset() + 5);
+ scroll += 2;
+ observer.add(newPhase);
+ SimulatorWatcher.update(simulator);
+ }
+}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverPhaseSettingsGui.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverPhaseSettingsGui.java
new file mode 100644
index 00000000..f7925c34
--- /dev/null
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverPhaseSettingsGui.java
@@ -0,0 +1,172 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.features.simulator.gui;
+
+import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
+import de.steamwar.bausystem.features.simulator.data.Simulator;
+import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
+import de.steamwar.core.Core;
+import de.steamwar.inventory.SWItem;
+import org.bukkit.Material;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+
+import java.util.Arrays;
+
+public class SimulatorObserverPhaseSettingsGui extends SimulatorBaseGui {
+
+ private final ObserverElement observerElement;
+ private final ObserverPhase observer;
+ private final SimulatorBaseGui back;
+
+ public SimulatorObserverPhaseSettingsGui(Player player, Simulator simulator, ObserverElement observerElement, ObserverPhase observer, SimulatorBaseGui back) {
+ super(player, simulator, 5 * 9);
+ this.observerElement = observerElement;
+ this.observer = observer;
+ this.back = back;
+ }
+
+ @Override
+ public String title() {
+ return "Observer";
+ }
+
+ @Override
+ public void populate() {
+ if (!observerElement.getPhases().contains(observer)) {
+ back.open();
+ return;
+ }
+
+ // Back Arrow
+ inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> {
+ back.open();
+ }));
+
+ // Material Chooser
+ inventory.setItem(4, observerElement.toItem(player, clickType -> {
+ new SimulatorMaterialGui(player, simulator, observerElement::getMaterial, observerElement::setMaterial, this).open();
+ }));
+
+ // Delete
+ inventory.setItem(8, new SWItem(Material.BARRIER, "§eDelete", clickType -> {
+ observerElement.getPhases().remove(observer);
+ back.open();
+ SimulatorWatcher.update(simulator);
+ }));
+
+ int index = observerElement.getPhases().indexOf(observer);
+ int min;
+ if (index > 0) {
+ ObserverPhase previous = observerElement.getPhases().get(index - 1);
+ min = previous.getTickOffset() + 4;
+ } else {
+ min = 0;
+ }
+
+ int max;
+ if (index < observerElement.getPhases().size() - 1) {
+ ObserverPhase next = observerElement.getPhases().get(index + 1);
+ max = next.getTickOffset() - 4;
+ } else {
+ max = Integer.MAX_VALUE - 4;
+ }
+
+ //Tick Offset
+ int offset = observer.getTickOffset();
+ inventory.setItem(10, SWItem.getDye(offset < max ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
+ observer.setTickOffset(Math.min(max, offset + (clickType.isShiftClick() ? 5 : 1)));
+ SimulatorWatcher.update(simulator);
+ });
+
+ SWItem offsetItem = new SWItem(Material.REPEATER, "§eStart at§8:§7 " + offset, clickType -> {
+ new SimulatorAnvilGui<>(player, "Start at", offset + "", Integer::parseInt, integer -> {
+ if (integer < 0) return false;
+ observer.setTickOffset(Math.min(Math.max(integer, min), max));
+ SimulatorWatcher.update(simulator);
+ return true;
+ }, this).setItem(Material.REPEATER).open();
+ });
+ offsetItem.getItemStack().setAmount(Math.max(1, Math.min(offset, 64)));
+ inventory.setItem(19, offsetItem);
+
+ inventory.setItem(28, SWItem.getDye(offset > min ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
+ observer.setTickOffset(Math.max(min, offset - (clickType.isShiftClick() ? 5 : 1)));
+ SimulatorWatcher.update(simulator);
+ });
+
+ //Order
+ int order = observer.getOrder();
+ inventory.setItem(13, SWItem.getDye(order < SimulatorPhase.ORDER_LIMIT ? 10 : 8), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
+ observer.setOrder(Math.min(SimulatorPhase.ORDER_LIMIT, order + (clickType.isShiftClick() ? 5 : 1)));
+ SimulatorWatcher.update(simulator);
+ });
+
+ Material negativeNumbers = Material.getMaterial(Core.getVersion() >= 19 ? "RECOVERY_COMPASS" : "FIREWORK_STAR");
+ SWItem orderItem = new SWItem(order >= 0 ? Material.COMPASS : negativeNumbers, "§eActivation Order§8:§7 " + order, clickType -> {
+ new SimulatorAnvilGui<>(player, "Activation Order", order + "", Integer::parseInt, integer -> {
+ if (integer < -SimulatorPhase.ORDER_LIMIT) return false;
+ if (integer > SimulatorPhase.ORDER_LIMIT) return false;
+ observer.setOrder(integer);
+ SimulatorWatcher.update(simulator);
+ return true;
+ }, this).setItem(order >= 0 ? Material.COMPASS : negativeNumbers).open();
+ });
+ orderItem.getItemStack().setAmount(Math.max(1, Math.min(Math.abs(order), 30)));
+ inventory.setItem(22, orderItem);
+
+ inventory.setItem(31, SWItem.getDye(order > -SimulatorPhase.ORDER_LIMIT ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
+ observer.setOrder(Math.max(-SimulatorPhase.ORDER_LIMIT, order - (clickType.isShiftClick() ? 5 : 1)));
+ SimulatorWatcher.update(simulator);
+ });
+
+ // Update orientation
+ inventory.setItem(25, new SWItem(Material.SUNFLOWER, "§7", clickType -> {
+ }));
+ inventory.setItem(15, new SWItem(observer.getOrientation() == BlockFace.UP ? Material.LIME_CONCRETE : Material.GRAY_CONCRETE, "§eUp", clickType -> {
+ observer.setOrientation(BlockFace.UP);
+ SimulatorWatcher.update(simulator);
+ }));
+ inventory.setItem(33, new SWItem(observer.getOrientation() == BlockFace.DOWN ? Material.RED_CONCRETE : Material.GRAY_CONCRETE, "§eDown", clickType -> {
+ observer.setOrientation(BlockFace.DOWN);
+ SimulatorWatcher.update(simulator);
+ }));
+ inventory.setItem(16, new SWItem(observer.getOrientation() == BlockFace.NORTH ? Material.LIME_WOOL : Material.GRAY_WOOL, "§eNorth", clickType -> {
+ observer.setOrientation(BlockFace.NORTH);
+ SimulatorWatcher.update(simulator);
+ }));
+ inventory.setItem(34, new SWItem(observer.getOrientation() == BlockFace.SOUTH ? Material.RED_WOOL : Material.GRAY_WOOL, "§eSouth", clickType -> {
+ observer.setOrientation(BlockFace.SOUTH);
+ SimulatorWatcher.update(simulator);
+ }));
+ inventory.setItem(24, new SWItem(observer.getOrientation() == BlockFace.EAST ? Material.LIME_STAINED_GLASS : Material.GRAY_STAINED_GLASS, "§eEast", clickType -> {
+ observer.setOrientation(BlockFace.EAST);
+ SimulatorWatcher.update(simulator);
+ }));
+ inventory.setItem(26, new SWItem(observer.getOrientation() == BlockFace.WEST ? Material.RED_STAINED_GLASS : Material.GRAY_STAINED_GLASS, "§eWest", clickType -> {
+ observer.setOrientation(BlockFace.WEST);
+ SimulatorWatcher.update(simulator);
+ }));
+ }
+}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverSettingsGui.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverSettingsGui.java
new file mode 100644
index 00000000..8084c7b1
--- /dev/null
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/gui/SimulatorObserverSettingsGui.java
@@ -0,0 +1,142 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2023 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bausystem.features.simulator.gui;
+
+import de.steamwar.bausystem.features.simulator.SimulatorWatcher;
+import de.steamwar.bausystem.features.simulator.data.Simulator;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorAnvilGui;
+import de.steamwar.bausystem.features.simulator.gui.base.SimulatorBaseGui;
+import de.steamwar.inventory.SWItem;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.Arrays;
+
+public class SimulatorObserverSettingsGui extends SimulatorBaseGui {
+
+ private final ObserverElement observer;
+ private final SimulatorBaseGui back;
+
+ public SimulatorObserverSettingsGui(Player player, Simulator simulator, ObserverElement observer, SimulatorBaseGui back) {
+ super(player, simulator, 5 * 9);
+ this.observer = observer;
+ this.back = back;
+ }
+
+ @Override
+ public String title() {
+ return "Observer";
+ }
+
+ @Override
+ public void populate() {
+ if (observer.getPhases().isEmpty()) {
+ back.open();
+ return;
+ }
+
+ // Back Arrow
+ inventory.setItem(0, new SWItem(Material.ARROW, "§eBack", clickType -> {
+ back.open();
+ }));
+
+ // Material Chooser
+ inventory.setItem(4, observer.toItem(player, clickType -> {
+ new SimulatorMaterialGui(player, simulator, observer::getMaterial, observer::setMaterial, this).open();
+ }));
+
+ // Base Tick
+ int baseTicks = observer.getBaseTick();
+ inventory.setItem(9, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
+ observer.changeBaseTicks(clickType.isShiftClick() ? 5 : 1);
+ SimulatorWatcher.update(simulator);
+ });
+ SWItem baseTick = new SWItem(Material.REPEATER, "§eTicks§8:§7 " + baseTicks, clickType -> {
+ new SimulatorAnvilGui<>(player, "Ticks", baseTicks + "", Integer::parseInt, integer -> {
+ if (integer < 0) return false;
+ observer.changeBaseTicks(integer - baseTicks);
+ SimulatorWatcher.update(simulator);
+ return true;
+ }, this).setItem(Material.REPEATER).open();
+ });
+ baseTick.getItemStack().setAmount(Math.max(1, Math.min(baseTicks, 64)));
+ inventory.setItem(18, baseTick);
+ inventory.setItem(27, SWItem.getDye(baseTicks > 0 ? 1 : 8), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
+ if (baseTicks - (clickType.isShiftClick() ? 5 : 1) < 0) {
+ observer.changeBaseTicks(-baseTicks);
+ } else {
+ observer.changeBaseTicks(clickType.isShiftClick() ? -5 : -1);
+ }
+ SimulatorWatcher.update(simulator);
+ });
+
+ //Pos X
+ inventory.setItem(15, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
+ observer.move(clickType.isShiftClick() ? 5 : 1, 0, 0);
+ SimulatorWatcher.update(simulator);
+ });
+ inventory.setItem(24, new SWItem(Material.PAPER, "§eX§8:§7 " + observer.getPosition().getBlockX(), clickType -> {
+ new SimulatorAnvilGui<>(player, "X", observer.getPosition().getBlockX() + "", Integer::parseInt, i -> {
+ observer.getPosition().setX(i);
+ SimulatorWatcher.update(simulator);
+ return true;
+ }, this).open();
+ }));
+ inventory.setItem(33, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
+ observer.move(clickType.isShiftClick() ? -5 : -1, 0, 0);
+ SimulatorWatcher.update(simulator);
+ });
+
+ //Pos Y
+ inventory.setItem(16, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
+ observer.move(0, clickType.isShiftClick() ? 5 : 1, 0);
+ SimulatorWatcher.update(simulator);
+ });
+ inventory.setItem(25, new SWItem(Material.PAPER, "§eY§8:§7 " + observer.getPosition().getBlockY(), clickType -> {
+ new SimulatorAnvilGui<>(player, "Y", observer.getPosition().getBlockY() + "", Integer::parseInt, i -> {
+ observer.getPosition().setY(i);
+ SimulatorWatcher.update(simulator);
+ return true;
+ }, this).open();
+ }));
+ inventory.setItem(34, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
+ observer.move(0, clickType.isShiftClick() ? -5 : -1, 0);
+ SimulatorWatcher.update(simulator);
+ });
+
+ //Pos Z
+ inventory.setItem(17, SWItem.getDye(10), "§e+1", Arrays.asList("§7Shift§8: §e+5"), false, clickType -> {
+ observer.move(0, 0, clickType.isShiftClick() ? 5 : 1);
+ SimulatorWatcher.update(simulator);
+ });
+ inventory.setItem(26, new SWItem(Material.PAPER, "§eZ§8:§7 " + observer.getPosition().getBlockZ(), clickType -> {
+ new SimulatorAnvilGui<>(player, "Z", observer.getPosition().getBlockZ() + "", Integer::parseInt, i -> {
+ observer.getPosition().setZ(i);
+ SimulatorWatcher.update(simulator);
+ return true;
+ }, this).open();
+ }));
+ inventory.setItem(35, SWItem.getDye(1), "§e-1", Arrays.asList("§7Shift§8: §e-5"), false, clickType -> {
+ observer.move(0, 0, clickType.isShiftClick() ? -5 : -1);
+ SimulatorWatcher.update(simulator);
+ });
+ }
+}
diff --git a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java
index 15af2e4a..218c89a4 100644
--- a/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java
+++ b/BauSystem_Main/src/de/steamwar/bausystem/features/simulator/storage/SimFormatSimulatorLoader.java
@@ -23,6 +23,8 @@ import de.steamwar.bausystem.features.simulator.data.Simulator;
import de.steamwar.bausystem.features.simulator.data.SimulatorElement;
import de.steamwar.bausystem.features.simulator.data.SimulatorGroup;
import de.steamwar.bausystem.features.simulator.data.SimulatorPhase;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverElement;
+import de.steamwar.bausystem.features.simulator.data.observer.ObserverPhase;
import de.steamwar.bausystem.features.simulator.data.redstone.RedstoneElement;
import de.steamwar.bausystem.features.simulator.data.redstone.RedstonePhase;
import de.steamwar.bausystem.features.simulator.data.tnt.TNTElement;
@@ -94,6 +96,10 @@ public class SimFormatSimulatorLoader implements SimulatorLoader {
element = new RedstoneElement(position);
phaseConstructor = RedstonePhase::new;
break;
+ case "Observer":
+ element = new ObserverElement(position);
+ phaseConstructor = ObserverPhase::new;
+ break;
default:
element = null;
phaseConstructor = null;