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
23 changes: 11 additions & 12 deletions LICENSE → LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# Friday Night Funkin': Java Edition License

The original game (created by Cameron Taylor and the Funkin' Crew) uses a license called the *Apache License*, which is a permissive, free software license that allows users to freely use, modify, and distribute the software for any purpose, including commercially.

Because Friday Night Funkin': Java Edition (FNF:JE) is based off of the base game, we also adapt the same license they have to maintain consistency.

## License

```
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Expand Down Expand Up @@ -175,18 +184,7 @@ Apache License

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright 2026 String

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -199,3 +197,4 @@ Apache License
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
19 changes: 12 additions & 7 deletions core/src/main/java/me/stringfromjava/funkin/Funkin.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,18 @@ public static FunkinGame getGame() {
*/
public static class Signals {

public static final FunkinSignal preRender = new FunkinSignal();
public static final FunkinSignal postRender = new FunkinSignal();
public static final FunkinSignal preScreenSwitch = new FunkinSignal();
public static final FunkinSignal postScreenSwitch = new FunkinSignal();
public static final FunkinSignal preGameClose = new FunkinSignal();
public static final FunkinSignal postGameClose = new FunkinSignal();
public static final FunkinSignal soundPlayed = new FunkinSignal();
public static final FunkinSignal<RenderSignalData> preRender = new FunkinSignal<>();
public static final FunkinSignal<RenderSignalData> postRender = new FunkinSignal<>();
public static final FunkinSignal<ScreenSwitchSignalData> preScreenSwitch = new FunkinSignal<>();
public static final FunkinSignal<ScreenSwitchSignalData> postScreenSwitch = new FunkinSignal<>();
public static final FunkinSignal<Void> preGameClose = new FunkinSignal<>();
public static final FunkinSignal<Void> postGameClose = new FunkinSignal<>();
public static final FunkinSignal<SoundPlayedSignalData> preSoundPlayed = new FunkinSignal<>();
public static final FunkinSignal<SoundPlayedSignalData> postSoundPlayed = new FunkinSignal<>();

public record RenderSignalData(float delta) {}
public record ScreenSwitchSignalData(FunkinScreen screen) {}
public record SoundPlayedSignalData(FunkinSound sound) {}

private Signals() {
}
Expand Down
10 changes: 8 additions & 2 deletions core/src/main/java/me/stringfromjava/funkin/FunkinGame.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package me.stringfromjava.funkin;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import me.stringfromjava.funkin.backend.display.cache.TextureCache;
import me.stringfromjava.funkin.game.InitScreen;

import java.util.Set;

import static me.stringfromjava.funkin.Funkin.Signals.RenderSignalData;

/**
* An enhanced version of libGDX's {@link Game} object.
* <p>
Expand All @@ -24,8 +27,11 @@ public void create() {
@Override
public void render() {
super.render();
Funkin.Signals.preRender.dispatch();
Funkin.Signals.postRender.dispatch();

float delta = Gdx.graphics.getDeltaTime();

Funkin.Signals.preRender.dispatch(new RenderSignalData(delta));
Funkin.Signals.postRender.dispatch(new RenderSignalData(delta));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

/**
* An enhanced version of libGDX's {@link Sound}.
* <p>
* This is mostly for ensuring that a sound's volume changes when the users'
* global volume changes.
*/
public class FunkinSound implements Sound {

Expand Down Expand Up @@ -40,7 +43,7 @@ public FunkinSound(FileHandle path) {

@Override
public long play() {
return thisSound.play();
return thisSound.play(volume, pitch, pan);
}

@Override
Expand All @@ -54,12 +57,13 @@ public long play(float volume, float pitch) {

@Override
public long play(float volume, float pitch, float pan) {
Funkin.Signals.soundPlayed.dispatch();
Funkin.Signals.preSoundPlayed.dispatch(new Funkin.Signals.SoundPlayedSignalData(this));
this.volume = volume * Funkin.masterVolume;
this.pitch = pitch;
this.pan = pan;
this.looping = false;
this.isPaused = false;
Funkin.Signals.postSoundPlayed.dispatch(new Funkin.Signals.SoundPlayedSignalData(this));
return thisSound.play(volume, pitch, pan);
}

Expand All @@ -79,12 +83,13 @@ public long loop(float volume, float pitch) {

@Override
public long loop(float volume, float pitch, float pan) {
Funkin.Signals.soundPlayed.dispatch();
Funkin.Signals.preSoundPlayed.dispatch(new Funkin.Signals.SoundPlayedSignalData(this));
this.volume = volume * Funkin.masterVolume;
this.pitch = pitch;
this.pan = pan;
this.looping = true;
this.isPaused = false;
Funkin.Signals.postSoundPlayed.dispatch(new Funkin.Signals.SoundPlayedSignalData(this));
return thisSound.loop(volume, pitch, pan);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,78 @@

/**
* Utility class for creating objects that can execute multiple
* runnables when it is dispatched (or triggered).
* callbacks when it is dispatched (or triggered).
*/
public class FunkinSignal {
public class FunkinSignal<T> {

private ArrayList<Runnable> runnables;
private final ArrayList<SignalHandler<T>> callbacks;
private final ArrayList<SignalHandler<T>> tempCallbacks; // Callbacks that are added with addOnce().

public FunkinSignal() {
runnables = new ArrayList<>();
callbacks = new ArrayList<>();
tempCallbacks = new ArrayList<>();
}

/**
* Adds a new {@link Runnable} to {@code this} signal to be executed upon
* {@code dispatch()} being called.
*
* @param runnable The new runnable to add to the signal.
* @param callback The new callback to add to the signal.
*/
public void add(Runnable runnable) {
if (runnable != null) {
runnables.add(runnable);
public void add(SignalHandler<T> callback) {
if (callback != null) {
callbacks.add(callback);
}
}

/**
* Removes all runnables from {@code this} signal.
* Adds a temporary {@link Runnable} that only gets ran <i>once</i>.
* When {@code dispatch()} is executed, the temporary {@link Runnable} is removed.
*
* @param callback The new temporary callback to add.
*/
public void addOnce(SignalHandler<T> callback) {
if (callback != null) {
tempCallbacks.add(callback);
}
}

/**
* Removes all callbacks from {@code this} signal.
*/
public void clear() {
runnables.clear();
callbacks.clear();
tempCallbacks.clear();
}

/**
* Triggers {@code this} signal and executes all runnables.
* Triggers {@code this} signal and executes all callbacks.
*/
public void dispatch() {
for (Runnable runnable : runnables) {
if (runnable != null) {
runnable.run();
dispatch(null);
}

/**
* Triggers {@code this} signal and executes all callbacks.
*
* @param data The parameters that {@code this} signal takes.
*/
public void dispatch(T data) {
for (SignalHandler<T> callback : callbacks) {
if (callback != null) {
callback.execute(data);
}
}

for (SignalHandler<T> callback : tempCallbacks) {
if (callback != null) {
callback.execute(data);
tempCallbacks.remove(callback);
}
}
}

public interface SignalHandler<T> {
void execute(T data);
}
}