Introduce singleton pattern for services, add safe phase to round state, and implement PlayerTeleporterService with destination-based teleporting
This commit is contained in:
parent
2746a43837
commit
0cf662dfef
|
|
@ -30,7 +30,7 @@ public final class Main extends JavaPlugin {
|
|||
|
||||
private void registerServices() {
|
||||
Round round = Round.createSingletonInstance();
|
||||
roundService = new RoundService(round);
|
||||
roundService = RoundService.createSingletonInstance(round);
|
||||
playerService = new PlayerService(roundService);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import com.alttd.hunger_games.Main;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.NonNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
|
@ -18,6 +21,7 @@ import java.lang.reflect.Modifier;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
|
|
@ -107,6 +111,38 @@ abstract class AbstractConfig {
|
|||
return yaml.getDouble(path, yaml.getDouble(path));
|
||||
}
|
||||
|
||||
boolean contains(String prefix, String path) {
|
||||
path = prefix + path;
|
||||
return !yaml.contains(path);
|
||||
}
|
||||
|
||||
Optional<Location> getLocation(String prefix, String path) {
|
||||
if (contains(prefix, path)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String rootPath = prefix + path + ".";
|
||||
if (contains(rootPath, "world") || contains(rootPath, path + "x") || contains(rootPath, path + "y") || contains(rootPath, path + "z")) {
|
||||
log.error("Invalid location configuration for {}", path);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String worldString = getString(rootPath, "world", null);
|
||||
|
||||
double x = getDouble(rootPath, "x", 0);
|
||||
double y = getDouble(rootPath, "y", 0);
|
||||
double z = getDouble(rootPath, "z", 0);
|
||||
|
||||
World world = Bukkit.getWorld(worldString);
|
||||
|
||||
if (world == null) {
|
||||
log.error("Invalid world for location {}", path);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(new Location(world, x, y, z));
|
||||
}
|
||||
|
||||
<T> List<String> getList(String prefix, String path, T def) {
|
||||
path = prefix + path;
|
||||
yaml.addDefault(path, def);
|
||||
|
|
|
|||
|
|
@ -2,12 +2,15 @@ package com.alttd.hunger_games.config;
|
|||
|
||||
import com.alttd.hunger_games.data_objects.GameStage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
|
|
@ -93,4 +96,27 @@ public class Config extends AbstractConfig {
|
|||
return gameStageList;
|
||||
}
|
||||
}
|
||||
|
||||
public static class DESTINATION {
|
||||
private static final String prefix = "destination.";
|
||||
public static Location START_CENTER = null;
|
||||
public static int START_RADIUS = 15;
|
||||
public static Location FINALE_CENTER = null;
|
||||
public static int FINALE_RADIUS = 10;
|
||||
public static Location SPECTATOR_AREA = null;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void load() {
|
||||
Config.DESTINATION.START_RADIUS = config.getInt(prefix, "start-radius", START_RADIUS);
|
||||
config.getLocation(prefix, "start-center")
|
||||
.ifPresent(location -> DESTINATION.START_CENTER = location);
|
||||
|
||||
config.getLocation(prefix, "spectator-area")
|
||||
.ifPresent(location -> DESTINATION.SPECTATOR_AREA = location);
|
||||
|
||||
DESTINATION.FINALE_RADIUS = config.getInt(prefix, "finale-radius", FINALE_RADIUS);
|
||||
config.getLocation(prefix, "finale-center")
|
||||
.ifPresent(location -> DESTINATION.FINALE_CENTER = location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
package com.alttd.hunger_games.data_objects;
|
||||
|
||||
public enum DESTINATION {
|
||||
START_AREA,
|
||||
FINALE_AREA,
|
||||
SPECTATOR_AREA;
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import java.util.Optional;
|
|||
public enum ROUND_STATE {
|
||||
PLAYER_REGISTRATION,
|
||||
COUNTDOWN,
|
||||
SAFE_PHASE,
|
||||
KILL_PHASE,
|
||||
FINALE,
|
||||
ENDED;
|
||||
|
|
@ -20,6 +21,7 @@ public enum ROUND_STATE {
|
|||
return switch (this) {
|
||||
case PLAYER_REGISTRATION -> "Player Registration";
|
||||
case COUNTDOWN -> "Countdown";
|
||||
case SAFE_PHASE -> "Safe Phase";
|
||||
case KILL_PHASE -> "Kill Phase";
|
||||
case FINALE -> "Finale";
|
||||
case ENDED -> "Ended";
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public class PlayerService implements RoundListener {
|
|||
public void stateChange(ROUND_STATE roundState) {
|
||||
this.roundState = roundState;
|
||||
switch (roundState) {
|
||||
case PLAYER_REGISTRATION, KILL_PHASE -> {
|
||||
case PLAYER_REGISTRATION, KILL_PHASE, SAFE_PHASE -> {
|
||||
//Nothing
|
||||
}
|
||||
case COUNTDOWN -> {
|
||||
|
|
@ -94,7 +94,7 @@ public class PlayerService implements RoundListener {
|
|||
}
|
||||
return switch (roundState) {
|
||||
case PLAYER_REGISTRATION, COUNTDOWN -> Optional.of(PLAYER_STATE.REGISTERED);
|
||||
case KILL_PHASE, FINALE, ENDED -> Optional.of(PLAYER_STATE.SPECTATING);
|
||||
case KILL_PHASE, FINALE, ENDED, SAFE_PHASE -> Optional.of(PLAYER_STATE.SPECTATING);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
package com.alttd.hunger_games.services;
|
||||
|
||||
import com.alttd.hunger_games.config.Config;
|
||||
import com.alttd.hunger_games.data_objects.DESTINATION;
|
||||
import com.alttd.hunger_games.data_objects.ROUND_STATE;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@NoArgsConstructor
|
||||
public class PlayerTeleporterService implements RoundListener {
|
||||
|
||||
private static PlayerTeleporterService instance = null;
|
||||
|
||||
private final Map<DESTINATION, Integer> placementCount = new HashMap<>();
|
||||
private final Map<DESTINATION, Set<Location>> usedLocations = new HashMap<>();
|
||||
|
||||
public static PlayerTeleporterService createSingletonInstance() {
|
||||
if (instance != null) {
|
||||
throw new IllegalStateException("PlayerTeleporterService is already initialized.");
|
||||
}
|
||||
instance = new PlayerTeleporterService();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void teleportPlayer(Player player, DESTINATION destination) {
|
||||
player.teleport(getLocationFromDestination(destination));
|
||||
}
|
||||
|
||||
private Location getLocationFromDestination(DESTINATION destination) {
|
||||
return switch (destination) {
|
||||
case START_AREA -> {
|
||||
Location startCenter = Config.DESTINATION.START_CENTER;
|
||||
if (startCenter == null) {
|
||||
throw new IllegalStateException("Start center is not set.");
|
||||
}
|
||||
int startRadius = Config.DESTINATION.START_RADIUS;
|
||||
yield calculateLocation(destination, startCenter, startRadius);
|
||||
}
|
||||
case FINALE_AREA -> {
|
||||
Location finaleCenter = Config.DESTINATION.FINALE_CENTER;
|
||||
if (finaleCenter == null) {
|
||||
throw new IllegalStateException("Finale center is not set.");
|
||||
}
|
||||
int finaleRadius = Config.DESTINATION.FINALE_RADIUS;
|
||||
yield calculateLocation(destination, finaleCenter, finaleRadius);
|
||||
}
|
||||
case SPECTATOR_AREA -> {
|
||||
Location spectatorArea = Config.DESTINATION.SPECTATOR_AREA;
|
||||
if (spectatorArea == null) {
|
||||
throw new IllegalStateException("Spectator area is not set.");
|
||||
}
|
||||
yield spectatorArea;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Location calculateLocation(DESTINATION destination, Location center, int radius) {
|
||||
int count = placementCount.merge(destination, 1, Integer::sum);
|
||||
double angleDegrees = vanDerCorput(count - 1) * 360.0;
|
||||
double angleRadians = Math.toRadians(angleDegrees);
|
||||
double x = center.getX() + radius * Math.cos(angleRadians);
|
||||
double z = center.getZ() + radius * Math.sin(angleRadians);
|
||||
Location location = new Location(center.getWorld(), x, center.getY(), z);
|
||||
usedLocations.computeIfAbsent(destination, k -> new HashSet<>()).add(location);
|
||||
return location;
|
||||
}
|
||||
|
||||
private static double vanDerCorput(int n) {
|
||||
double result = 0.0;
|
||||
double denominator = 1.0;
|
||||
while (n > 0) {
|
||||
denominator *= 2.0;
|
||||
result += (n % 2) / denominator;
|
||||
n /= 2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stateChange(ROUND_STATE roundState) {
|
||||
placementCount.clear();
|
||||
usedLocations.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,11 +9,21 @@ import java.util.stream.Collectors;
|
|||
|
||||
public class RoundService implements RoundListener {
|
||||
|
||||
private static RoundService instance = null;
|
||||
|
||||
@Getter
|
||||
private ROUND_STATE roundState;
|
||||
private final HashMap<UUID, PLAYER_STATE> players = new HashMap<>();
|
||||
|
||||
public RoundService(Round round) {
|
||||
public static RoundService createSingletonInstance(Round round) {
|
||||
if (instance != null) {
|
||||
throw new IllegalStateException("RoundService is already initialized.");
|
||||
}
|
||||
instance = new RoundService(round);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private RoundService(Round round) {
|
||||
this.roundState = round.register(this);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user