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() {
|
private void registerServices() {
|
||||||
Round round = Round.createSingletonInstance();
|
Round round = Round.createSingletonInstance();
|
||||||
roundService = new RoundService(round);
|
roundService = RoundService.createSingletonInstance(round);
|
||||||
playerService = new PlayerService(roundService);
|
playerService = new PlayerService(roundService);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ import com.alttd.hunger_games.Main;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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.ConfigurationSection;
|
||||||
import org.bukkit.configuration.InvalidConfigurationException;
|
import org.bukkit.configuration.InvalidConfigurationException;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
@ -18,6 +21,7 @@ import java.lang.reflect.Modifier;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
|
@ -107,6 +111,38 @@ abstract class AbstractConfig {
|
||||||
return yaml.getDouble(path, yaml.getDouble(path));
|
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) {
|
<T> List<String> getList(String prefix, String path, T def) {
|
||||||
path = prefix + path;
|
path = prefix + path;
|
||||||
yaml.addDefault(path, def);
|
yaml.addDefault(path, def);
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,15 @@ package com.alttd.hunger_games.config;
|
||||||
|
|
||||||
import com.alttd.hunger_games.data_objects.GameStage;
|
import com.alttd.hunger_games.data_objects.GameStage;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
|
@ -93,4 +96,27 @@ public class Config extends AbstractConfig {
|
||||||
return gameStageList;
|
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 {
|
public enum ROUND_STATE {
|
||||||
PLAYER_REGISTRATION,
|
PLAYER_REGISTRATION,
|
||||||
COUNTDOWN,
|
COUNTDOWN,
|
||||||
|
SAFE_PHASE,
|
||||||
KILL_PHASE,
|
KILL_PHASE,
|
||||||
FINALE,
|
FINALE,
|
||||||
ENDED;
|
ENDED;
|
||||||
|
|
@ -20,6 +21,7 @@ public enum ROUND_STATE {
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
case PLAYER_REGISTRATION -> "Player Registration";
|
case PLAYER_REGISTRATION -> "Player Registration";
|
||||||
case COUNTDOWN -> "Countdown";
|
case COUNTDOWN -> "Countdown";
|
||||||
|
case SAFE_PHASE -> "Safe Phase";
|
||||||
case KILL_PHASE -> "Kill Phase";
|
case KILL_PHASE -> "Kill Phase";
|
||||||
case FINALE -> "Finale";
|
case FINALE -> "Finale";
|
||||||
case ENDED -> "Ended";
|
case ENDED -> "Ended";
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ public class PlayerService implements RoundListener {
|
||||||
public void stateChange(ROUND_STATE roundState) {
|
public void stateChange(ROUND_STATE roundState) {
|
||||||
this.roundState = roundState;
|
this.roundState = roundState;
|
||||||
switch (roundState) {
|
switch (roundState) {
|
||||||
case PLAYER_REGISTRATION, KILL_PHASE -> {
|
case PLAYER_REGISTRATION, KILL_PHASE, SAFE_PHASE -> {
|
||||||
//Nothing
|
//Nothing
|
||||||
}
|
}
|
||||||
case COUNTDOWN -> {
|
case COUNTDOWN -> {
|
||||||
|
|
@ -94,7 +94,7 @@ public class PlayerService implements RoundListener {
|
||||||
}
|
}
|
||||||
return switch (roundState) {
|
return switch (roundState) {
|
||||||
case PLAYER_REGISTRATION, COUNTDOWN -> Optional.of(PLAYER_STATE.REGISTERED);
|
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 {
|
public class RoundService implements RoundListener {
|
||||||
|
|
||||||
|
private static RoundService instance = null;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private ROUND_STATE roundState;
|
private ROUND_STATE roundState;
|
||||||
private final HashMap<UUID, PLAYER_STATE> players = new HashMap<>();
|
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);
|
this.roundState = round.register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user