feat: Pausing the game and many other changes
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
package cz.jzitnik;
|
package cz.jzitnik;
|
||||||
|
|
||||||
import cz.jzitnik.game.GameSaver;
|
import cz.jzitnik.game.GameSaver;
|
||||||
|
import cz.jzitnik.game.context.list.GameLoopContext;
|
||||||
import cz.jzitnik.game.logic.CustomLogicProvider;
|
import cz.jzitnik.game.logic.CustomLogicProvider;
|
||||||
import cz.jzitnik.game.mobs.EntityLogicProvider;
|
import cz.jzitnik.game.mobs.EntityLogicProvider;
|
||||||
import cz.jzitnik.game.threads.ThreadProvider;
|
import cz.jzitnik.game.threads.ThreadProvider;
|
||||||
@ -38,15 +39,21 @@ public class Main {
|
|||||||
var gameSaver = new GameSaver();
|
var gameSaver = new GameSaver();
|
||||||
var game = gameSaver.load();
|
var game = gameSaver.load();
|
||||||
|
|
||||||
final boolean[] isRunning = { true };
|
game.registerContext(Terminal.class, terminal);
|
||||||
|
|
||||||
|
GameLoopContext gameLoopContext = game.getContext(GameLoopContext.class);
|
||||||
EntityLogicProvider entityLogicProvider = new EntityLogicProvider();
|
EntityLogicProvider entityLogicProvider = new EntityLogicProvider();
|
||||||
CustomLogicProvider customLogicProvider = new CustomLogicProvider();
|
CustomLogicProvider customLogicProvider = new CustomLogicProvider();
|
||||||
|
|
||||||
ThreadProvider threadProvider = new ThreadProvider(game, screenRenderer, terminal, isRunning);
|
ThreadProvider threadProvider = new ThreadProvider(game, screenRenderer, terminal);
|
||||||
threadProvider.start();
|
threadProvider.start();
|
||||||
|
|
||||||
while (isRunning[0]) {
|
while (true) {
|
||||||
|
if (!gameLoopContext.isRunning()) {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
entityLogicProvider.update(game);
|
entityLogicProvider.update(game);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
@ -64,10 +71,6 @@ public class Main {
|
|||||||
|
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Closing terminal");
|
|
||||||
terminal.trackMouse(Terminal.MouseTracking.Off);
|
|
||||||
terminal.close();
|
|
||||||
} catch (IOException | InterruptedException ignored) {
|
} catch (IOException | InterruptedException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,6 @@ public class Game {
|
|||||||
private final List<Block>[][] world = (List<Block>[][]) new CopyOnWriteArrayList[256][512];
|
private final List<Block>[][] world = (List<Block>[][]) new CopyOnWriteArrayList[256][512];
|
||||||
private final Player player = new Player();
|
private final Player player = new Player();
|
||||||
private transient boolean mining = false;
|
private transient boolean mining = false;
|
||||||
@Setter
|
|
||||||
private transient Window window = Window.WORLD;
|
private transient Window window = Window.WORLD;
|
||||||
private final Inventory inventory = new Inventory();
|
private final Inventory inventory = new Inventory();
|
||||||
private transient EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
|
private transient EntitySpawnProvider entitySpawnProvider = new EntitySpawnProvider();
|
||||||
@ -77,6 +76,11 @@ public class Game {
|
|||||||
return daytime > 200 && daytime < 400;
|
return daytime > 200 && daytime < 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setWindow(Window window) {
|
||||||
|
this.window = window;
|
||||||
|
gameStates.dependencies.windowSwitchHandlerProvider.handle(this);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current coordinates of the player (bottom half).
|
* Returns the current coordinates of the player (bottom half).
|
||||||
*
|
*
|
||||||
@ -667,7 +671,11 @@ public class Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getContext(Class clazz) {
|
public <T> T getContext(Class<T> clazz) {
|
||||||
return gameStates.globalContextProvider.getMap(clazz);
|
return gameStates.globalContextProvider.getMap(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerContext(Class clazz, Object instance) {
|
||||||
|
gameStates.globalContextProvider.registerContext(clazz, instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package cz.jzitnik.game.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public @interface WindowSwitchHandler {
|
||||||
|
}
|
@ -17,7 +17,7 @@ public class Bed implements RightClickHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void onBlockRightClick(int x, int y, Game game, ScreenRenderer screenRenderer) {
|
public void onBlockRightClick(int x, int y, Game game, ScreenRenderer screenRenderer) {
|
||||||
BedSleepGlobalContext bedSleepGlobalContext =
|
BedSleepGlobalContext bedSleepGlobalContext =
|
||||||
(BedSleepGlobalContext) game.getContext(BedSleepGlobalContext.class);
|
game.getContext(BedSleepGlobalContext.class);
|
||||||
|
|
||||||
if (bedSleepGlobalContext.isSleeping() || game.getDaytime() < 200 || game.getDaytime() > 500) {
|
if (bedSleepGlobalContext.isSleeping() || game.getDaytime() < 200 || game.getDaytime() > 500) {
|
||||||
return; // already in progress
|
return; // already in progress
|
||||||
|
@ -11,7 +11,8 @@ public class GlobalContextProvider {
|
|||||||
private final Map<Class, Object> data = new HashMap<>();
|
private final Map<Class, Object> data = new HashMap<>();
|
||||||
private boolean loaded = false;
|
private boolean loaded = false;
|
||||||
|
|
||||||
public Object getMap(Class<?> clazz) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T getMap(Class<T> clazz) {
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
Reflections reflections = new Reflections("cz.jzitnik.game.context");
|
Reflections reflections = new Reflections("cz.jzitnik.game.context");
|
||||||
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(GlobalContext.class);
|
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(GlobalContext.class);
|
||||||
@ -28,6 +29,10 @@ public class GlobalContextProvider {
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.get(clazz);
|
return clazz.cast(data.get(clazz));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerContext(Class clazz, Object instance) {
|
||||||
|
data.put(clazz, instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
package cz.jzitnik.game.context.list;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.annotations.GlobalContext;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@GlobalContext
|
||||||
|
public class GameLoopContext {
|
||||||
|
private boolean isRunning = true;
|
||||||
|
}
|
@ -7,6 +7,7 @@ import cz.jzitnik.game.handlers.events.EventHandlerProvider;
|
|||||||
import cz.jzitnik.game.handlers.pickup.PickupHandlerProvider;
|
import cz.jzitnik.game.handlers.pickup.PickupHandlerProvider;
|
||||||
import cz.jzitnik.game.handlers.place.PlaceHandler;
|
import cz.jzitnik.game.handlers.place.PlaceHandler;
|
||||||
import cz.jzitnik.game.handlers.tooluse.ToolUseProvider;
|
import cz.jzitnik.game.handlers.tooluse.ToolUseProvider;
|
||||||
|
import cz.jzitnik.game.handlers.windowswitch.WindowSwitchHandlerProvider;
|
||||||
import cz.jzitnik.game.mobs.EntityHurtAnimation;
|
import cz.jzitnik.game.mobs.EntityHurtAnimation;
|
||||||
import cz.jzitnik.game.mobs.EntityKill;
|
import cz.jzitnik.game.mobs.EntityKill;
|
||||||
import cz.jzitnik.game.smelting.Smelting;
|
import cz.jzitnik.game.smelting.Smelting;
|
||||||
@ -20,6 +21,7 @@ public class Dependencies {
|
|||||||
public EntityHurtAnimation entityHurtAnimation = new EntityHurtAnimation();
|
public EntityHurtAnimation entityHurtAnimation = new EntityHurtAnimation();
|
||||||
public EntityKill entityKill = new EntityKill();
|
public EntityKill entityKill = new EntityKill();
|
||||||
public PickupHandlerProvider pickupHandlerProvider = new PickupHandlerProvider();
|
public PickupHandlerProvider pickupHandlerProvider = new PickupHandlerProvider();
|
||||||
|
public WindowSwitchHandlerProvider windowSwitchHandlerProvider = new WindowSwitchHandlerProvider();
|
||||||
public GameSaver gameSaver = new GameSaver();
|
public GameSaver gameSaver = new GameSaver();
|
||||||
public EventHandlerProvider eventHandlerProvider = new EventHandlerProvider();
|
public EventHandlerProvider eventHandlerProvider = new EventHandlerProvider();
|
||||||
public Smelting smelting = new Smelting();
|
public Smelting smelting = new Smelting();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package cz.jzitnik.game.entities;
|
package cz.jzitnik.game.entities;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.context.list.GameLoopContext;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package cz.jzitnik.game.handlers.windowswitch;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
|
||||||
|
public interface WindowSwitchHandlerInterface {
|
||||||
|
void handle(Game game);
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package cz.jzitnik.game.handlers.windowswitch;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.annotations.WindowSwitchHandler;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
|
public class WindowSwitchHandlerProvider {
|
||||||
|
public final List<WindowSwitchHandlerInterface> handler = new ArrayList<>();
|
||||||
|
|
||||||
|
public WindowSwitchHandlerProvider() {
|
||||||
|
registerHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(Game game) {
|
||||||
|
handler.forEach(handler -> handler.handle(game));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerHandlers() {
|
||||||
|
Reflections reflections = new Reflections("cz.jzitnik.game.handlers.windowswitch.handlers");
|
||||||
|
Set<Class<?>> handlerClasses = reflections.getTypesAnnotatedWith(WindowSwitchHandler.class);
|
||||||
|
|
||||||
|
for (Class<?> clazz : handlerClasses) {
|
||||||
|
if (WindowSwitchHandlerInterface.class.isAssignableFrom(clazz)) {
|
||||||
|
try {
|
||||||
|
WindowSwitchHandlerInterface handlerInstance = (WindowSwitchHandlerInterface) clazz.getDeclaredConstructor()
|
||||||
|
.newInstance();
|
||||||
|
handler.add(handlerInstance);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package cz.jzitnik.game.handlers.windowswitch.handlers;
|
||||||
|
|
||||||
|
import cz.jzitnik.game.Game;
|
||||||
|
import cz.jzitnik.game.annotations.WindowSwitchHandler;
|
||||||
|
import cz.jzitnik.game.context.list.GameLoopContext;
|
||||||
|
import cz.jzitnik.game.handlers.windowswitch.WindowSwitchHandlerInterface;
|
||||||
|
import cz.jzitnik.game.ui.Window;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@WindowSwitchHandler
|
||||||
|
public class GamePauseHandler implements WindowSwitchHandlerInterface {
|
||||||
|
private final Window[] pausedWindows = {Window.ESC, Window.DEATH_SCREEN, Window.OPTIONS, Window.SAVE_EXIT, Window.SAVED};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Game game) {
|
||||||
|
GameLoopContext gameLoopContext = game.getContext(GameLoopContext.class);
|
||||||
|
gameLoopContext.setRunning(!Arrays.asList(pausedWindows).contains(game.getWindow()));
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ import cz.jzitnik.game.annotations.Flamable;
|
|||||||
import cz.jzitnik.game.entities.Block;
|
import cz.jzitnik.game.entities.Block;
|
||||||
import cz.jzitnik.game.entities.items.Item;
|
import cz.jzitnik.game.entities.items.Item;
|
||||||
import cz.jzitnik.game.logic.CustomLogicInterface;
|
import cz.jzitnik.game.logic.CustomLogicInterface;
|
||||||
|
import cz.jzitnik.game.sprites.Steve;
|
||||||
import cz.jzitnik.tui.ScreenRenderer;
|
import cz.jzitnik.tui.ScreenRenderer;
|
||||||
|
|
||||||
@CustomLogic
|
@CustomLogic
|
||||||
@ -59,7 +60,7 @@ public class LavaFireLogic implements CustomLogicInterface {
|
|||||||
block.setOnFire(true);
|
block.setOnFire(true);
|
||||||
block.setBurningTime(0);
|
block.setBurningTime(0);
|
||||||
}
|
}
|
||||||
} else if (!block.getClass().isAnnotationPresent(FireImmune.class)) {
|
} else if (!block.getClass().isAnnotationPresent(FireImmune.class) && !block.getBlockId().equals("steve")) {
|
||||||
int dealDamage = game.getInventory().getItemInHand().map(Item::getDealDamage).orElse(1);
|
int dealDamage = game.getInventory().getItemInHand().map(Item::getDealDamage).orElse(1);
|
||||||
if (block.getHp() - dealDamage <= 0) {
|
if (block.getHp() - dealDamage <= 0) {
|
||||||
// Mob is killed
|
// Mob is killed
|
||||||
|
@ -22,7 +22,6 @@ public class ThreadProvider {
|
|||||||
private final Game game;
|
private final Game game;
|
||||||
private final ScreenRenderer screenRenderer;
|
private final ScreenRenderer screenRenderer;
|
||||||
private final Terminal terminal;
|
private final Terminal terminal;
|
||||||
private final boolean[] isRunning;
|
|
||||||
private final List<Thread> list = new ArrayList<>();
|
private final List<Thread> list = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,11 +42,10 @@ public class ThreadProvider {
|
|||||||
* @param terminal The terminal.
|
* @param terminal The terminal.
|
||||||
* @param isRunning A shared boolean array for controlling thread execution.
|
* @param isRunning A shared boolean array for controlling thread execution.
|
||||||
*/
|
*/
|
||||||
public ThreadProvider(Game game, ScreenRenderer screenRenderer, Terminal terminal, boolean[] isRunning) {
|
public ThreadProvider(Game game, ScreenRenderer screenRenderer, Terminal terminal) {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
this.screenRenderer = screenRenderer;
|
this.screenRenderer = screenRenderer;
|
||||||
this.terminal = terminal;
|
this.terminal = terminal;
|
||||||
this.isRunning = isRunning;
|
|
||||||
registerHandlers();
|
registerHandlers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,8 +75,6 @@ public class ThreadProvider {
|
|||||||
params[i] = screenRenderer;
|
params[i] = screenRenderer;
|
||||||
else if (type == Terminal.class)
|
else if (type == Terminal.class)
|
||||||
params[i] = terminal;
|
params[i] = terminal;
|
||||||
else if (type == boolean[].class)
|
|
||||||
params[i] = isRunning;
|
|
||||||
else if (type == Player.class)
|
else if (type == Player.class)
|
||||||
params[i] = game.getPlayer();
|
params[i] = game.getPlayer();
|
||||||
else {
|
else {
|
||||||
|
@ -102,12 +102,13 @@ public class InputHandlerThread extends Thread {
|
|||||||
case 'q' -> {
|
case 'q' -> {
|
||||||
if (game.getWindow() != Window.WORLD) {
|
if (game.getWindow() != Window.WORLD) {
|
||||||
game.setWindow(Window.WORLD);
|
game.setWindow(Window.WORLD);
|
||||||
|
screenRenderer.render(game);
|
||||||
} else {
|
} else {
|
||||||
game.setWindow(Window.ESC);
|
game.setWindow(Window.ESC);
|
||||||
game.getGameStates().dependencies.escape.reset();
|
game.getGameStates().dependencies.escape.reset();
|
||||||
}
|
|
||||||
screenRenderer.render(game);
|
screenRenderer.render(game);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
default -> {
|
default -> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import cz.jzitnik.game.sprites.ui.Font.*;
|
|||||||
import cz.jzitnik.tui.ScreenRenderer;
|
import cz.jzitnik.tui.ScreenRenderer;
|
||||||
import cz.jzitnik.tui.utils.Menu;
|
import cz.jzitnik.tui.utils.Menu;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the in-game escape menu functionality, including rendering options,
|
* Handles the in-game escape menu functionality, including rendering options,
|
||||||
* handling mouse input, and managing save and exit logic.
|
* handling mouse input, and managing save and exit logic.
|
||||||
@ -74,6 +76,15 @@ public class Escape {
|
|||||||
game.getGameStates().dependencies.gameSaver.save(game);
|
game.getGameStates().dependencies.gameSaver.save(game);
|
||||||
game.setWindow(Window.SAVED);
|
game.setWindow(Window.SAVED);
|
||||||
screenRenderer.render(game);
|
screenRenderer.render(game);
|
||||||
|
|
||||||
|
Terminal terminal = game.getContext(Terminal.class);
|
||||||
|
terminal.trackMouse(Terminal.MouseTracking.Off);
|
||||||
|
try {
|
||||||
|
terminal.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import cz.jzitnik.game.sprites.SimpleSprite;
|
|||||||
import cz.jzitnik.game.blocks.Chest;
|
import cz.jzitnik.game.blocks.Chest;
|
||||||
import cz.jzitnik.game.blocks.Furnace;
|
import cz.jzitnik.game.blocks.Furnace;
|
||||||
import cz.jzitnik.game.ui.Healthbar;
|
import cz.jzitnik.game.ui.Healthbar;
|
||||||
|
import cz.jzitnik.game.ui.Window;
|
||||||
import cz.jzitnik.tui.utils.SpriteCombiner;
|
import cz.jzitnik.tui.utils.SpriteCombiner;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -29,6 +30,7 @@ public class ScreenRenderer {
|
|||||||
private final SpriteList spriteList;
|
private final SpriteList spriteList;
|
||||||
private final Terminal terminal;
|
private final Terminal terminal;
|
||||||
private boolean rendering = false;
|
private boolean rendering = false;
|
||||||
|
private Window currentlyRenderingWindow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a {@code ScreenRenderer} with the given sprite list and terminal.
|
* Constructs a {@code ScreenRenderer} with the given sprite list and terminal.
|
||||||
@ -100,10 +102,11 @@ public class ScreenRenderer {
|
|||||||
* @param game Current game state to render.
|
* @param game Current game state to render.
|
||||||
*/
|
*/
|
||||||
public void render(Game game) {
|
public void render(Game game) {
|
||||||
if (rendering) {
|
if (rendering && game.getWindow() == currentlyRenderingWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rendering = true;
|
rendering = true;
|
||||||
|
currentlyRenderingWindow = game.getWindow();
|
||||||
log.debug("Rendering frame");
|
log.debug("Rendering frame");
|
||||||
var world = game.getWorld();
|
var world = game.getWorld();
|
||||||
StringBuilder main = new StringBuilder();
|
StringBuilder main = new StringBuilder();
|
||||||
|
Reference in New Issue
Block a user