fix: позиция голограмм (getBlock.Location) + зона ворот (corner1/corner2)
This commit is contained in:
parent
b0afb3f6be
commit
eb4a670e9c
8 changed files with 124 additions and 13 deletions
|
|
@ -73,7 +73,7 @@ public class ChestHologram {
|
|||
continue;
|
||||
}
|
||||
|
||||
Location holoLoc = loc.clone().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
Location holoLoc = loc.getBlock().getLocation().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
try {
|
||||
if (useTextDisplay) {
|
||||
TextDisplay display = loc.getWorld().spawn(holoLoc, TextDisplay.class, d -> {
|
||||
|
|
@ -139,11 +139,11 @@ public class ChestHologram {
|
|||
|
||||
if (display instanceof TextDisplay td) {
|
||||
td.text(TextUtil.color(text));
|
||||
Location base = chest.getLocation().clone().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
Location base = chest.getLocation().getBlock().getLocation().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
td.teleport(base);
|
||||
} else if (display instanceof ArmorStand as) {
|
||||
as.setCustomName(text);
|
||||
Location base = chest.getLocation().clone().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
Location base = chest.getLocation().getBlock().getLocation().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
as.teleport(base);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ public class SetupCommand implements TabExecutor {
|
|||
|
||||
var locations = plugin.getConfigManager().getLocations();
|
||||
locations.setGate(gateId, center);
|
||||
locations.setGateZone(gateId, p1, p2);
|
||||
plugin.getConfigManager().saveConfig("locations.yml", locations.getConfig());
|
||||
|
||||
player.sendMessage(messages().get("setup.gate-placed", gateId, formatLoc(center)));
|
||||
|
|
|
|||
|
|
@ -225,12 +225,24 @@ public class LocationsConfig {
|
|||
config.set(path, list);
|
||||
}
|
||||
|
||||
/** Устанавливает ворота A или B (хранятся как gate-a / gate-b). */
|
||||
/** Устанавливает ворота A или B с зоной (хранятся как gate-a / gate-b + corner1/corner2). */
|
||||
public void setGate(String id, Location loc) {
|
||||
String key = "gate-" + id.toLowerCase();
|
||||
config.set(key, locationToString(loc));
|
||||
}
|
||||
|
||||
public void setGateZone(String id, Location corner1, Location corner2) {
|
||||
String prefix = "gate-" + id.toLowerCase();
|
||||
config.set(prefix + "-corner1", locationToString(corner1));
|
||||
config.set(prefix + "-corner2", locationToString(corner2));
|
||||
}
|
||||
|
||||
public Location getGateCorner(String id, int num) {
|
||||
String key = "gate-" + id.toLowerCase() + "-corner" + num;
|
||||
String str = config.getString(key);
|
||||
return str != null ? parseLocation(str) : null;
|
||||
}
|
||||
|
||||
public Location getGate(String id) {
|
||||
String key = "gate-" + id.toLowerCase();
|
||||
String str = config.getString(key);
|
||||
|
|
@ -251,6 +263,15 @@ public class LocationsConfig {
|
|||
return gates;
|
||||
}
|
||||
|
||||
/** Get all gate IDs that exist in config. */
|
||||
public List<String> getGateIds() {
|
||||
List<String> ids = new ArrayList<>();
|
||||
for (String id : List.of("a", "b")) {
|
||||
if (getGate(id) != null) ids.add(id);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
private String locationToString(Location loc) {
|
||||
// Use | as separator instead of , to avoid issues with negative coordinates in YAML
|
||||
return String.format(Locale.US, "%s|%.2f|%.2f|%.2f|%.1f|%.1f",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ public class ExitGate {
|
|||
private double savedProgress; // сохраняется при уходе игрока
|
||||
private boolean powered;
|
||||
|
||||
private int zoneMinX, zoneMinY, zoneMinZ;
|
||||
private int zoneMaxX, zoneMaxY, zoneMaxZ;
|
||||
private boolean hasZone;
|
||||
|
||||
public enum GateState {
|
||||
CLOSED,
|
||||
OPENING,
|
||||
|
|
@ -23,6 +27,22 @@ public class ExitGate {
|
|||
this.progress = 0.0;
|
||||
this.savedProgress = 0.0;
|
||||
this.powered = false;
|
||||
this.hasZone = false;
|
||||
}
|
||||
|
||||
/** Set the gate zone from two corner locations. */
|
||||
public void setZone(Location corner1, Location corner2) {
|
||||
zoneMinX = Math.min(corner1.getBlockX(), corner2.getBlockX());
|
||||
zoneMinY = Math.min(corner1.getBlockY(), corner2.getBlockY());
|
||||
zoneMinZ = Math.min(corner1.getBlockZ(), corner2.getBlockZ());
|
||||
zoneMaxX = Math.max(corner1.getBlockX(), corner2.getBlockX());
|
||||
zoneMaxY = Math.max(corner1.getBlockY(), corner2.getBlockY());
|
||||
zoneMaxZ = Math.max(corner1.getBlockZ(), corner2.getBlockZ());
|
||||
hasZone = true;
|
||||
}
|
||||
|
||||
private boolean hasZone() {
|
||||
return hasZone;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
|
|
@ -35,12 +55,71 @@ public class ExitGate {
|
|||
location.getBlock().setType(org.bukkit.Material.HOPPER, false);
|
||||
}
|
||||
|
||||
/** Build the gate structure fills the entire designated zone. */
|
||||
public void spawnGateStructure() {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return;
|
||||
|
||||
if (hasZone) {
|
||||
for (int x = zoneMinX; x <= zoneMaxX; x++) {
|
||||
for (int y = zoneMinY; y <= zoneMaxY; y++) {
|
||||
for (int z = zoneMinZ; z <= zoneMaxZ; z++) {
|
||||
world.getBlockAt(x, y, z).setType(org.bukkit.Material.IRON_BARS, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback: 3x3x3 zone around gate location
|
||||
int cx = location.getBlockX(), cy = location.getBlockY(), cz = location.getBlockZ();
|
||||
for (int x = cx - 1; x <= cx + 1; x++) {
|
||||
for (int y = cy; y <= cy + 2; y++) {
|
||||
for (int z = cz - 1; z <= cz + 1; z++) {
|
||||
world.getBlockAt(x, y, z).setType(org.bukkit.Material.IRON_BARS, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Button at gate center + (1, 1, 1)
|
||||
world.getBlockAt(location.clone().add(1, 1, 1)).setType(org.bukkit.Material.STONE_BUTTON, false);
|
||||
}
|
||||
|
||||
/** Remove the interaction block (e.g. when gate opens or on cleanup). */
|
||||
public void removeGateBlock() {
|
||||
if (location.getWorld() == null) return;
|
||||
location.getBlock().setType(org.bukkit.Material.AIR, false);
|
||||
}
|
||||
|
||||
/** Remove the entire gate zone + interaction block. */
|
||||
public void removeGateStructure() {
|
||||
World world = location.getWorld();
|
||||
if (world == null) return;
|
||||
|
||||
if (hasZone) {
|
||||
for (int x = zoneMinX; x <= zoneMaxX; x++) {
|
||||
for (int y = zoneMinY; y <= zoneMaxY; y++) {
|
||||
for (int z = zoneMinZ; z <= zoneMaxZ; z++) {
|
||||
world.getBlockAt(x, y, z).setType(org.bukkit.Material.AIR, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int cx = location.getBlockX(), cy = location.getBlockY(), cz = location.getBlockZ();
|
||||
for (int x = cx - 1; x <= cx + 1; x++) {
|
||||
for (int y = cy; y <= cy + 2; y++) {
|
||||
for (int z = cz - 1; z <= cz + 1; z++) {
|
||||
world.getBlockAt(x, y, z).setType(org.bukkit.Material.AIR, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove button at (1, 1, 1)
|
||||
world.getBlockAt(location.clone().add(1, 1, 1)).setType(org.bukkit.Material.AIR, false);
|
||||
|
||||
removeGateBlock();
|
||||
}
|
||||
|
||||
public GateState getState() {
|
||||
return state;
|
||||
}
|
||||
|
|
@ -102,7 +181,8 @@ public class ExitGate {
|
|||
if (progress >= 1.0) {
|
||||
progress = 1.0;
|
||||
state = GateState.OPEN;
|
||||
removeGateBlock();
|
||||
removeGateStructure();
|
||||
spawnOpenParticles();
|
||||
playOpenedSound();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,17 @@ public class GateManager {
|
|||
}
|
||||
|
||||
private void loadGates(LocationsConfig locations) {
|
||||
List<Location> gateLocations = locations.getExitGates();
|
||||
for (int i = 0; i < Math.min(gateLocations.size(), GATE_COUNT); i++) {
|
||||
gates.add(new ExitGate(gateLocations.get(i)));
|
||||
for (String id : locations.getGateIds()) {
|
||||
Location center = locations.getGate(id);
|
||||
if (center == null) continue;
|
||||
ExitGate gate = new ExitGate(center);
|
||||
Location c1 = locations.getGateCorner(id, 1);
|
||||
Location c2 = locations.getGateCorner(id, 2);
|
||||
if (c1 != null && c2 != null) {
|
||||
gate.setZone(c1, c2);
|
||||
}
|
||||
gates.add(gate);
|
||||
if (gates.size() >= GATE_COUNT) break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public class HookHologram {
|
|||
continue;
|
||||
}
|
||||
|
||||
Location holoLoc = loc.clone().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
Location holoLoc = loc.getBlock().getLocation().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
try {
|
||||
if (useTextDisplay) {
|
||||
TextDisplay display = loc.getWorld().spawn(holoLoc, TextDisplay.class, d -> {
|
||||
|
|
@ -128,7 +128,7 @@ public class HookHologram {
|
|||
String text = "§c⚓ Крюк §f#" + visibleIndex + "/" + total + "\n§7" + status;
|
||||
|
||||
double heightOffset = plugin.getConfigManager().getGame().getHookHologramHeightOffset();
|
||||
Location base = hook.getLocation().clone().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
Location base = hook.getLocation().getBlock().getLocation().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
|
||||
if (display instanceof TextDisplay td) {
|
||||
td.text(TextUtil.color(text));
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class GeneratorHologram {
|
|||
Location loc = gen.getLocation();
|
||||
if (loc.getWorld() == null) continue;
|
||||
|
||||
Location holoLoc = loc.clone().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
Location holoLoc = loc.getBlock().getLocation().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
try {
|
||||
if (useTextDisplay) {
|
||||
TextDisplay display = loc.getWorld().spawn(holoLoc, TextDisplay.class, d -> {
|
||||
|
|
@ -118,7 +118,7 @@ public class GeneratorHologram {
|
|||
text = "§6⚙ Генератор §f#" + (gen.getId() + 1) + "/" + total + "\n§e" + bar + " §f" + pct + "%";
|
||||
}
|
||||
|
||||
Location base = gen.getLocation().clone().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
Location base = gen.getLocation().getBlock().getLocation().add(0.5, 2.0 + heightOffset, 0.5);
|
||||
|
||||
if (display instanceof TextDisplay td) {
|
||||
td.text(TextUtil.color(text));
|
||||
|
|
|
|||
|
|
@ -321,8 +321,9 @@ public class GameplayPhase implements Phase {
|
|||
}
|
||||
plugin.getLogger().info("[GameplayPhase] Spawned blocks for " + hookManager.getAllHooks().size() + " hooks");
|
||||
|
||||
// Спавн блоков на местах ворот (Hopper — для открытия через ПКМ)
|
||||
// Спавн структуры ворот (рамка + кнопка + Hopper для взаимодействия)
|
||||
for (ExitGate gate : gateManager.getAllGates()) {
|
||||
gate.spawnGateStructure();
|
||||
gate.spawnGateBlock();
|
||||
}
|
||||
plugin.getLogger().info("[GameplayPhase] Spawned blocks for " + gateManager.getAllGates().size() + " gates");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue