diff --git a/.gitignore b/.gitignore
index 29a880c..5211a0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ target/
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
+.idea/FuzzierSettings.xml
*.iws
*.iml
*.ipr
diff --git a/pom.xml b/pom.xml
index 9e81c13..9d4c238 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,14 @@
UTF-8
+
+
+ be.0110.repo-releases
+ 0110.be repository
+ https://mvn.0110.be/releases
+
+
+
org.projectlombok
@@ -153,5 +161,16 @@
ffmpeg-platform
6.1.1-1.5.10
+
+
+ be.tarsos.dsp
+ core
+ 2.5
+
+
+ be.tarsos.dsp
+ jvm
+ 2.5
+
diff --git a/src/main/java/cz/jzitnik/config/Debugging.java b/src/main/java/cz/jzitnik/config/Debugging.java
index 8ae4227..1f46f8b 100644
--- a/src/main/java/cz/jzitnik/config/Debugging.java
+++ b/src/main/java/cz/jzitnik/config/Debugging.java
@@ -6,6 +6,6 @@ import lombok.Getter;
@Getter
@Config
public class Debugging {
- private final boolean renderColliders = true;
- private final boolean renderPlayerCollider = true;
+ private final boolean renderColliders = false;
+ private final boolean renderPlayerCollider = false;
}
diff --git a/src/main/java/cz/jzitnik/config/MicrophoneConfig.java b/src/main/java/cz/jzitnik/config/MicrophoneConfig.java
new file mode 100644
index 0000000..add5dc6
--- /dev/null
+++ b/src/main/java/cz/jzitnik/config/MicrophoneConfig.java
@@ -0,0 +1,10 @@
+package cz.jzitnik.config;
+
+import cz.jzitnik.annotations.Config;
+import lombok.Getter;
+
+@Getter
+@Config
+public class MicrophoneConfig {
+ private final float volumeThreshold = 3f;
+}
diff --git a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java
index 8c74fb0..448ecd8 100644
--- a/src/main/java/cz/jzitnik/game/mobs/HittableMob.java
+++ b/src/main/java/cz/jzitnik/game/mobs/HittableMob.java
@@ -5,7 +5,6 @@ import cz.jzitnik.annotations.injectors.InjectConfig;
import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.config.Debugging;
-import cz.jzitnik.events.FullRoomDraw;
import cz.jzitnik.events.RerenderScreen;
import cz.jzitnik.game.GameRoom;
import cz.jzitnik.game.GameState;
diff --git a/src/main/java/cz/jzitnik/game/mobs/tasks/AStarAlg.java b/src/main/java/cz/jzitnik/game/mobs/tasks/AStarAlg.java
index 394e800..d03a13d 100644
--- a/src/main/java/cz/jzitnik/game/mobs/tasks/AStarAlg.java
+++ b/src/main/java/cz/jzitnik/game/mobs/tasks/AStarAlg.java
@@ -7,9 +7,6 @@ import java.util.*;
public class AStarAlg {
- // Boundaries matching your Player switch statement
- // Player: if (x <= 30) return -> means 30 is the edge, valid area is > 30?
- // User Update: "he can be on 30". So valid range is [30, 155]
private static final int MIN_X = 30;
private static final int MAX_X = 155;
private static final int MIN_Y = 10;
@@ -19,14 +16,12 @@ public class AStarAlg {
PriorityQueue openSet = new PriorityQueue<>(Comparator.comparingInt(n -> n.f));
Set closedSet = new HashSet<>();
- // We use Chebyshev distance for the heuristic (best for 8-way movement)
Node startNode = new Node(start.getX(), start.getY(), 0, getHeuristic(start, target), null);
openSet.add(startNode);
while (!openSet.isEmpty()) {
Node current = openSet.poll();
- // Reached target?
if (current.x == target.getX() && current.y == target.getY()) {
return reconstructPath(current);
}
@@ -39,13 +34,7 @@ public class AStarAlg {
String neighborKey = neighbor.x + "," + neighbor.y;
if (closedSet.contains(neighborKey)) continue;
- // Check collisions and boundaries
if (!isValidPosition(neighbor.x, neighbor.y, colliders)) {
- // EDGE CASE FIX:
- // If the Player (target) is standing exactly on a wall/edge that the Mob considers invalid,
- // A* will usually fail.
- // We add a check: if this neighbor IS the target, we allow it.
- // This lets the mob walk right up to the player's face even if they are hugging the wall.
if (neighbor.x != target.getX() || neighbor.y != target.getY()) {
continue;
}
@@ -65,7 +54,6 @@ public class AStarAlg {
private static List getNeighbors(Node current, RoomCords target) {
List neighbors = new ArrayList<>();
- // Added Diagonal Directions
int[][] directions = {
{0, 1}, {0, -1}, {1, 0}, {-1, 0}, // Up, Down, Right, Left
{1, 1}, {1, -1}, {-1, 1}, {-1, -1} // Diagonals
@@ -81,14 +69,10 @@ public class AStarAlg {
}
private static boolean isValidPosition(int x, int y, List colliders) {
- // Updated checks to be inclusive so 30 is valid.
- // Valid X: 30 to 155
if (x < MIN_X || x > MAX_X) return false;
- // Valid Y: 10 to 110
if (y < MIN_Y || y > MAX_Y) return false;
- // Check Colliders
RoomCords temp = new RoomCords(x, y);
for (GameRoomPart part : colliders) {
if (part.isWithin(temp)) {
@@ -109,7 +93,6 @@ public class AStarAlg {
return path;
}
- // Changed to Chebyshev Distance for better diagonal estimation
private static int getHeuristic(RoomCords a, RoomCords b) {
int dx = Math.abs(a.getX() - b.getX());
int dy = Math.abs(a.getY() - b.getY());
diff --git a/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java b/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java
index a8fe416..8c0294b 100644
--- a/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java
+++ b/src/main/java/cz/jzitnik/game/mobs/tasks/BlindMobFollowingPlayerTask.java
@@ -4,12 +4,13 @@ import cz.jzitnik.annotations.injectors.InjectConfig;
import cz.jzitnik.annotations.injectors.InjectDependency;
import cz.jzitnik.annotations.injectors.InjectState;
import cz.jzitnik.config.Debugging;
+import cz.jzitnik.config.MicrophoneConfig;
import cz.jzitnik.game.GameState;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.mobs.Mob;
import cz.jzitnik.game.utils.RoomCords;
+import cz.jzitnik.states.MicrophoneState;
import cz.jzitnik.states.ScreenBuffer;
-import cz.jzitnik.states.SoundState;
import cz.jzitnik.states.TerminalState;
import cz.jzitnik.utils.events.EventManager;
import cz.jzitnik.utils.roomtasks.RoomTask;
@@ -46,11 +47,14 @@ public class BlindMobFollowingPlayerTask extends RoomTask {
private Debugging debugging;
@InjectState
- private SoundState soundState;
+ private MicrophoneState microphoneState;
+
+ @InjectConfig
+ private MicrophoneConfig microphoneConfig;
@Override
public void run() {
- if (playerCords == null || (soundState.isMicrophoneSetup() && soundState.getSoundVolume() > 2f)) {
+ if (playerCords == null || (microphoneState.isMicrophoneSetup() && microphoneState.getMicrophoneVolume() > microphoneConfig.getVolumeThreshold())) {
playerCords = gameState.getPlayer().getPlayerCords().clone();
}
diff --git a/src/main/java/cz/jzitnik/game/setup/GameSetup.java b/src/main/java/cz/jzitnik/game/setup/GameSetup.java
index 7a9c427..8f2fbb9 100644
--- a/src/main/java/cz/jzitnik/game/setup/GameSetup.java
+++ b/src/main/java/cz/jzitnik/game/setup/GameSetup.java
@@ -20,7 +20,7 @@ public class GameSetup {
private DependencyManager dependencyManager;
public void setup() {
- //gameState.setScreen(new IntroScene(dependencyManager));
+ gameState.setScreen(new IntroScene(dependencyManager));
GameRoom mainRoom = new MainRoom(dependencyManager, resourceManager);
GameRoom rightRoom = new GameRoom(ResourceManager.Resource.ROOM2);
diff --git a/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java b/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java
index 079c704..79d32e8 100644
--- a/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java
+++ b/src/main/java/cz/jzitnik/game/setup/mobs/Zombie.java
@@ -2,6 +2,7 @@ package cz.jzitnik.game.setup.mobs;
import cz.jzitnik.game.ResourceManager;
import cz.jzitnik.game.mobs.HittableMob;
+import cz.jzitnik.game.mobs.tasks.BlindMobFollowingPlayerTask;
import cz.jzitnik.game.mobs.tasks.MobFollowingPlayerTask;
import cz.jzitnik.game.utils.RoomCords;
import lombok.extern.slf4j.Slf4j;
@@ -11,8 +12,8 @@ public class Zombie extends HittableMob {
public Zombie(ResourceManager resourceManager, RoomCords cords) {
super(resourceManager.getResource(ResourceManager.Resource.PLAYER_FRONT), null, cords, 10);
- //setTask(new BlindMobFollowingPlayerTask(this, 1, 100));
- setTask(new MobFollowingPlayerTask(this, 1, 100));
+ setTask(new BlindMobFollowingPlayerTask(this, 1, 100));
+ //setTask(new MobFollowingPlayerTask(this, 1, 100));
}
@Override
diff --git a/src/main/java/cz/jzitnik/screens/scenes/Scene.java b/src/main/java/cz/jzitnik/screens/scenes/Scene.java
index c11ec1d..6c390a0 100644
--- a/src/main/java/cz/jzitnik/screens/scenes/Scene.java
+++ b/src/main/java/cz/jzitnik/screens/scenes/Scene.java
@@ -51,7 +51,7 @@ public abstract class Scene extends Screen {
if (!isRenderedAlready) {
isRenderedAlready = true;
render();
- } else if (currentPart != null && !onEndAction.getClass().equals(OnEndAction.Repeat.class)) {
+ } else if (currentPart != null && onEndAction.getClass().equals(OnEndAction.Repeat.class)) {
currentPart.fullRender();
}
}
@@ -77,7 +77,7 @@ public abstract class Scene extends Screen {
} else if (onEndAction.getClass().equals(OnEndAction.SwitchToScreen.class)) {
OnEndAction.SwitchToScreen switchToScreen = (OnEndAction.SwitchToScreen) onEndAction;
gameState.setScreen(switchToScreen.getScreen());
- eventManager.emitEvent(new FullRoomDraw(true));
+ switchToScreen.getScreen().fullRender();
}
}
diff --git a/src/main/java/cz/jzitnik/sound/SoundPlayer.java b/src/main/java/cz/jzitnik/sound/SoundPlayer.java
index 71b481a..ea18f7a 100644
--- a/src/main/java/cz/jzitnik/sound/SoundPlayer.java
+++ b/src/main/java/cz/jzitnik/sound/SoundPlayer.java
@@ -2,7 +2,6 @@ package cz.jzitnik.sound;
import javax.sound.sampled.*;
-import javax.sound.sampled.*;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;
@@ -13,7 +12,7 @@ public class SoundPlayer {
private final AtomicReference currentLine = new AtomicReference<>();
public void playSound(String filePath, int backendVolume, int masterVolume) {
- long threadId = Thread.currentThread().getId();
+ long threadId = Thread.currentThread().threadId();
if (!filePath.endsWith(".ogg") || masterVolume == 0) {
return;
diff --git a/src/main/java/cz/jzitnik/states/SoundState.java b/src/main/java/cz/jzitnik/states/MicrophoneState.java
similarity index 68%
rename from src/main/java/cz/jzitnik/states/SoundState.java
rename to src/main/java/cz/jzitnik/states/MicrophoneState.java
index ebc8b47..1095ddd 100644
--- a/src/main/java/cz/jzitnik/states/SoundState.java
+++ b/src/main/java/cz/jzitnik/states/MicrophoneState.java
@@ -5,7 +5,7 @@ import lombok.Data;
@Data
@State
-public class SoundState {
- private double soundVolume;
+public class MicrophoneState {
+ private double microphoneVolume;
private boolean microphoneSetup = false;
}
diff --git a/src/main/java/cz/jzitnik/threads/MicrophoneThread.java b/src/main/java/cz/jzitnik/threads/MicrophoneThread.java
index 163a91b..16f5041 100644
--- a/src/main/java/cz/jzitnik/threads/MicrophoneThread.java
+++ b/src/main/java/cz/jzitnik/threads/MicrophoneThread.java
@@ -1,78 +1,73 @@
package cz.jzitnik.threads;
+import be.tarsos.dsp.AudioDispatcher;
+import be.tarsos.dsp.AudioEvent;
+import be.tarsos.dsp.AudioProcessor;
+import be.tarsos.dsp.filters.HighPass;
+import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import cz.jzitnik.annotations.ThreadRegistry;
import cz.jzitnik.annotations.injectors.InjectState;
-import cz.jzitnik.states.SoundState;
+import cz.jzitnik.states.MicrophoneState;
import cz.jzitnik.utils.ShutdownableThread;
import lombok.extern.slf4j.Slf4j;
-import javax.sound.sampled.*;
+import javax.sound.sampled.LineUnavailableException;
@Slf4j
@ThreadRegistry
public class MicrophoneThread extends ShutdownableThread {
@InjectState
- private SoundState soundState;
+ private MicrophoneState microphoneState;
- private volatile boolean running = true;
+ private AudioDispatcher dispatcher;
@Override
public void run() {
- AudioFormat format = new AudioFormat(44100, 16, 1, true, false);
- DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
-
- if (!AudioSystem.isLineSupported(info)) {
- log.error("Line not supported: {}", info);
- return;
- }
-
- TargetDataLine line = null;
-
try {
- line = (TargetDataLine) AudioSystem.getLine(info);
- line.open(format);
- line.start();
+ dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(44100, 2048, 0);
- byte[] buffer = new byte[2048];
+ dispatcher.addAudioProcessor(new HighPass(120, 44100));
- while (running && !Thread.currentThread().isInterrupted()) {
- int bytesRead = line.read(buffer, 0, buffer.length);
+ dispatcher.addAudioProcessor(new AudioProcessor() {
+ private static final double NOISE_GATE_THRESHOLD = 1.5;
- if (bytesRead > 0) {
- double volume = calculateRMS(buffer, bytesRead);
- soundState.setSoundVolume(volume);
- soundState.setMicrophoneSetup(true);
+ @Override
+ public boolean process(AudioEvent audioEvent) {
+ double rms = audioEvent.getRMS();
+
+ double volume = rms * 100;
+
+ if (volume < NOISE_GATE_THRESHOLD) {
+ volume = 0;
+ }
+
+ microphoneState.setMicrophoneVolume(volume);
+ microphoneState.setMicrophoneSetup(true);
+
+ return true;
}
- }
+
+ @Override
+ public void processingFinished() {
+ log.info("Microphone processing stopped.");
+ }
+ });
+
+ dispatcher.run();
+
} catch (LineUnavailableException e) {
log.error("Microphone line unavailable: {}", e.getMessage());
- } finally {
- if (line != null) {
- line.stop();
- line.close();
- }
+ } catch (Exception e) {
+ log.error("Error in MicrophoneThread: {}", e.getMessage(), e);
}
}
+ @Override
public void shutdown() {
- this.running = false;
+ if (dispatcher != null && !dispatcher.isStopped()) {
+ dispatcher.stop();
+ }
+
this.interrupt();
}
-
- private double calculateRMS(byte[] buffer, int bytesRead) {
- long sum = 0;
-
- for (int i = 0; i < bytesRead; i += 2) {
- int low = buffer[i];
- int high = buffer[i + 1];
-
- int sample = (high << 8) | (low & 0xFF);
-
- sum += (long) sample * sample;
- }
-
- double rms = Math.sqrt(sum / (bytesRead / 2.0));
-
- return (rms / 32768.0) * 100;
- }
}
diff --git a/src/main/java/cz/jzitnik/utils/DependencyManager.java b/src/main/java/cz/jzitnik/utils/DependencyManager.java
index eb35f70..acae27d 100644
--- a/src/main/java/cz/jzitnik/utils/DependencyManager.java
+++ b/src/main/java/cz/jzitnik/utils/DependencyManager.java
@@ -1,7 +1,7 @@
package cz.jzitnik.utils;
-// Don't blame me that I'm using field injection instead of construction injection. I just like it more leave me alone.
-// Yes I know I'll suffer in the unit tests. (who said there will be any? hmmm)
+// Don't blame me that I'm using field injection instead of construction injection. I just like it more, leave me alone.
+// Yes, I know I'll suffer in the unit tests. (who said there will be any? hmmm)
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.MutableClassToInstanceMap;
diff --git a/src/main/java/cz/jzitnik/utils/RerenderUtils.java b/src/main/java/cz/jzitnik/utils/RerenderUtils.java
index 7e4326a..b3dcc85 100644
--- a/src/main/java/cz/jzitnik/utils/RerenderUtils.java
+++ b/src/main/java/cz/jzitnik/utils/RerenderUtils.java
@@ -84,7 +84,6 @@ public class RerenderUtils {
}
}
- // TODO: Remove duplicates
for (Mob object: currentRoom.getMobs()) {
RoomCords startObjectCords = object.getCords();
BufferedImage texture = object.getTexture();