Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions game/src/main/java/net/onelitefeather/cygnus/Cygnus.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ public Cygnus() {
Path path = Paths.get("");
this.teamService = TeamService.of();
this.linearPhaseSeries = new LinearPhaseSeries<>("game");
this.ambientProvider = new AmbientProvider();
this.ambientProvider = new AmbientProvider(this.teamService.getTeams().get(Helper.SLENDER_ID));
this.staminaService = new StaminaService();
this.gameConfig = new GameConfigReader(path).getConfig();
MinecraftServer.getConnectionManager().setPlayerProvider(CygnusPlayer::new);
this.pageProvider = new PageProvider();
this.mapProvider = new GameMapProvider(path);
this.view = new GameViewImpl();
this.createTeams(this.gameConfig, this.teamService, this.ambientProvider);
this.createTeams(this.gameConfig, this.teamService);
this.initPhases();
this.initCommands();
this.initListener();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import net.theevilreaper.xerus.api.component.team.ColorComponent;
import net.theevilreaper.xerus.api.team.Team;
import net.theevilreaper.xerus.api.team.TeamService;
import net.onelitefeather.cygnus.ambient.AmbientProvider;
import net.onelitefeather.cygnus.common.config.GameConfig;
import org.jetbrains.annotations.NotNull;

Expand All @@ -26,12 +25,10 @@ public interface TeamCreator {
*
* @param gameConfig the configuration to get some values from it
* @param teamService the service to add the teams
* @param ambientProvider the provider to set the ambient team
*/
default void createTeams(
@NotNull GameConfig gameConfig,
@NotNull TeamService teamService,
@NotNull AmbientProvider ambientProvider
@NotNull TeamService teamService
) {
Team slenderTeam = Team.of(
Key.key("cygnus", GameConfig.SLENDER_TEAM_NAME.toLowerCase(Locale.ROOT)),
Expand All @@ -49,7 +46,6 @@ default void createTeams(
survivorTeam.add(ColorComponent.class, new ColorComponent(ColorData.LIGHT_GREEN));
survivorTeam.add(TeamNameComponent.class, new TeamNameComponent(GameConfig.SURVIVOR_TEAM_NAME));
teamService.add(survivorTeam);
ambientProvider.setTeam(survivorTeam);
teamService.add(survivorTeam);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,80 +9,106 @@
import net.minestom.server.potion.TimedPotion;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.timer.Task;
import net.minestom.server.utils.validate.Check;
import net.onelitefeather.cygnus.common.Messages;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.time.temporal.ChronoUnit;
import java.util.List;

import static net.onelitefeather.cygnus.common.util.Helper.getRandomPitchValue;

/**
* Provides ambient effects for a {@link Team} during a game phase.
*
* <p>The provider runs a repeating task that plays cave sounds at fixed tick
* intervals and applies a blindness effect with additional sounds at tick 77,
* simulating a "lights out" scenario. One full cycle spans {@value #CYCLE_LENGTH} ticks.</p>
*
* <p>Usage:</p>
* <pre>{@code
* AmbientProvider provider = new AmbientProvider();
* provider.setTeam(team);
* provider.startTask();
* // ...
* provider.stopTask();
* }</pre>
*
* @author theEvilReaper
* @version 1.0.0
* @version 2.0.0
* @since 1.0.0
**/
@SuppressWarnings({"java:S3252"})
*/
public final class AmbientProvider {

private static final int MAX_TICKS = 80;
private Task task;
private int currentTicks;
private final TimedPotion potionEffect;
private final Sound[] sounds;
private Team team;
private static final int CYCLE_LENGTH = 82;
private static final TimedPotion POTION_EFFECT =
new TimedPotion(new Potion(PotionEffect.BLINDNESS, (byte) 1, 200), 200);
private static final Sound[] SOUNDS = {
Sound.sound(SoundEvent.AMBIENT_CAVE, Sound.Source.MASTER, 1F, 1F),
Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 1F, 0F),
Sound.sound(SoundEvent.BLOCK_FIRE_EXTINGUISH, Sound.Source.MASTER, 1F, 1F),
Sound.sound(SoundEvent.ENTITY_WITHER_SPAWN, Sound.Source.MASTER, 5F, 0.7F)
};

public AmbientProvider() {
this.potionEffect = new TimedPotion(new Potion(PotionEffect.BLINDNESS, (byte) 1 , 200), 200);
this.sounds = new Sound[4];
this.sounds[0] = Sound.sound(SoundEvent.AMBIENT_CAVE, Sound.Source.MASTER, 1F, 1F);
this.sounds[1] = Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.MASTER, 1F, 0F);
this.sounds[2] = Sound.sound(SoundEvent.BLOCK_FIRE_EXTINGUISH, Sound.Source.MASTER, 1F, 1F);
this.sounds[3] = Sound.sound(SoundEvent.ENTITY_WITHER_SPAWN, Sound.Source.MASTER, 5F, 0.7F);
}
private final Team team;
private @Nullable Task task;
private int currentTicks;

// TODO: I think we can use here only the set reference from the team instead of the whole team reference
public void setTeam(@NotNull Team team) {
/**
* Creates a new instance of the {@link AmbientProvider}.
* @param team which is involved
*/
public AmbientProvider(Team team) {
this.team = team;
}

/**
* Starts the ambient task.
*/
public void startTask() {
if (task != null) return;
Check.argCondition(team == null, "The team variable can't be null");
task = MinecraftServer.getSchedulerManager().buildTask(this::tick).repeat(1, ChronoUnit.SECONDS).schedule();
task = MinecraftServer.getSchedulerManager()
.buildTask(this::tick)
.repeat(1, ChronoUnit.SECONDS)
.schedule();
}

/**
* Stops the ambient task.
*/
public void stopTask() {
if (task == null) return;
this.task.cancel();
this.task = null;
task.cancel();
task = null;
}

// TODO: The iteration over the players can be result into a race condition because the players from a team can be changed each time
/**
* Executes the ambient logic.
*/
public void tick() {
List<Player> players = List.copyOf(this.team.getPlayers());

switch (currentTicks) {
case 0, 15, 30, 45, 60:
for (Player player : this.team.getPlayers()) {
player.playSound(Sound.sound(SoundEvent.AMBIENT_CAVE, Sound.Source.MASTER, 1F, getRandomPitchValue()), player.getPosition());
case 0, 15, 30, 45, 60 -> {
Sound caveSound = Sound.sound(SoundEvent.AMBIENT_CAVE,
Sound.Source.MASTER, 1F, getRandomPitchValue());
for (Player player : players) {
player.playSound(caveSound, player.getPosition());
}
break;
case 77:
for (Player player : this.team.getPlayers()) {
player.addEffect(potionEffect.potion());
player.playSound(sounds[1], player.getPosition());
player.playSound(sounds[2], player.getPosition());
player.playSound(sounds[3], player.getPosition());
}
case 77 -> {
for (Player player : players) {
player.addEffect(POTION_EFFECT.potion());
player.playSound(SOUNDS[1], player.getPosition());
player.playSound(SOUNDS[2], player.getPosition());
player.playSound(SOUNDS[3], player.getPosition());
player.sendMessage(Messages.LIGHT_WENT_OUT);
}
break;
default: {
//NOTHING TODO here
}
default -> {
// Nothing to do here
}
}
if (currentTicks > MAX_TICKS) {
currentTicks = 0;
} else {
currentTicks++;
}

currentTicks = (currentTicks + 1) % CYCLE_LENGTH;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@NotNullByDefault
package net.onelitefeather.cygnus.ambient;

import org.jetbrains.annotations.NotNullByDefault;
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@ class TeamCreatorTest {
void testTeamCreation() {
GameConfig gameConfig = new GameConfigReader(Paths.get("")).getConfig();
TeamService teamService = TeamService.of();
AmbientProvider ambientProvider = new AmbientProvider();


TeamCreator teamCreator = new TeamCreator() {};
teamCreator.createTeams(gameConfig, teamService, ambientProvider);
teamCreator.createTeams(gameConfig, teamService);

for (int i = 0; i < teamService.getTeams().size(); i++) {
assertNotNull(teamService.getTeams().get(i));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package net.onelitefeather.cygnus.ambient;

import net.kyori.adventure.key.Key;
import net.minestom.server.network.packet.server.play.SoundEffectPacket;
import net.minestom.testing.Collector;
import net.minestom.testing.TestConnection;
import net.theevilreaper.xerus.api.team.Team;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.Instance;
import net.minestom.testing.Env;
import net.minestom.testing.extension.MicrotusExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.junit.jupiter.api.Assertions.*;

@ExtendWith(MicrotusExtension.class)
class AmbientProviderIntegrationTest {

@Test
void testCaveSoundAtTickZero(Env env) {
Instance instance = env.createFlatInstance();
TestConnection connection = env.createConnection();
Player player = connection.connect(instance);
Team team = Team.of(Key.key("cygnus", "test"));
team.addPlayer(player);

AmbientProvider provider = new AmbientProvider(team);
Collector<SoundEffectPacket> sounds = connection.trackIncoming(SoundEffectPacket.class);

provider.tick();
assertFalse(sounds.collect().isEmpty(), "Cave sound should have been played at tick 0");
env.destroyInstance(instance, true);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@ class StaminaHelperTest {
void testStaminaObjectCreation(@NotNull Env env) {
Instance testInstance = env.createFlatInstance();
GameConfig gameConfig = new GameConfigReader(Paths.get("")).getConfig();
AmbientProvider ambientProvider = new AmbientProvider();
TeamService teamService = TeamService.of();
TeamCreator teamCreator = new TeamCreator() {};
teamCreator.createTeams(gameConfig, teamService, ambientProvider);
teamCreator.createTeams(gameConfig, teamService);
StaminaService staminaService = new StaminaService();

assertNotNull(staminaService);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import net.minestom.testing.Env;
import net.minestom.testing.extension.MicrotusExtension;
import net.onelitefeather.cygnus.TeamCreator;
import net.onelitefeather.cygnus.ambient.AmbientProvider;
import net.onelitefeather.cygnus.common.Tags;
import net.onelitefeather.cygnus.common.config.GameConfig;
import net.onelitefeather.cygnus.common.config.GameConfigReader;
Expand Down Expand Up @@ -107,11 +106,10 @@ void testTeamAllocation(@NotNull Env env) {
@Test
void testSlenderTeleport(@NotNull Env env) {
Instance testInstance = env.createFlatInstance();
AmbientProvider ambientProvider = new AmbientProvider();
TeamService teamService = TeamService.of();
TeamCreator teamCreator = new TeamCreator() {
};
teamCreator.createTeams(gameConfig, teamService, ambientProvider);
teamCreator.createTeams(gameConfig, teamService);
Pos slenderSpawn = new Pos(10, 10, 10);
GameMap gameMap = new GameMap("Test", Pos.ZERO, slenderSpawn, Set.of(), Set.of(), List.of());
assertNotNull(gameMap);
Expand All @@ -138,11 +136,10 @@ void testNoTabListUpdate() {

@Test
void testInvalidUpdateTabList() {
AmbientProvider ambientProvider = new AmbientProvider();
TeamService teamService = TeamService.of();
TeamCreator teamCreator = new TeamCreator() {
};
teamCreator.createTeams(gameConfig, teamService, ambientProvider);
teamCreator.createTeams(gameConfig, teamService);

IllegalStateException exception = assertThrows(
IllegalStateException.class,
Expand All @@ -154,11 +151,10 @@ void testInvalidUpdateTabList() {

@Test
void testUpdateTabList(@NotNull Env env) {
AmbientProvider ambientProvider = new AmbientProvider();
TeamService teamService = TeamService.of();
TeamCreator teamCreator = new TeamCreator() {
};
teamCreator.createTeams(gameConfig, teamService, ambientProvider);
teamCreator.createTeams(gameConfig, teamService);

Set<Player> survivors = new HashSet<>();

Expand Down
Loading