Compare commits

...

11 commits

Author SHA1 Message Date
f129675d6b Update Changelog.md 2024-10-23 15:17:45 +09:00
df1e6a8735 Pause MCMusic when "Ping" packet is received
This prevents Minecraft's music from playing at the same time as
user-provided battle/silly music.
2024-10-23 15:01:31 +09:00
bea720f4be Minor refactoring/fix 2024-10-23 13:36:37 +09:00
b4ce369c23 Store remaining turn seconds in PacketBattlePing 2024-10-22 20:40:42 +09:00
bb061d93ca Use "PacketBattlePing" for "pings"
More efficient than using "PacketBattleInfo" every 4 seconds which is
heftier than a single battleID.

Currently "PacketBattlePing" is used to cause the client to show the
BattleGUI if it is not open.
2024-10-22 20:10:50 +09:00
bd8111ce87 Update Changelog.md 2024-10-22 17:12:20 +09:00
9dbfe4c3f5 Update Changelog.md 2024-10-22 17:09:34 +09:00
edf40bd38e Allow leaving battle gui temporarily, refactorings 2024-10-22 16:54:52 +09:00
e87be5f63b Update Changelog.md 2024-10-22 13:23:53 +09:00
470a6e5205 Version bump, 1.26.1 of mod, 21.1.72 neoforge 2024-10-22 13:22:35 +09:00
4cab3109a5 Minor refactoring/fixes 2024-10-22 13:22:21 +09:00
14 changed files with 138 additions and 16 deletions

View file

@ -1,5 +1,15 @@
# Upcoming changes # Upcoming changes
Minor fixes/refactorings that should make the mod more robust.
Port to NeoForge-21.1.72 (Minecraft 1.21.1).
Allow leaving battle GUI with Escape key (temporarily), and some refactorings
to (hopefully) fix that pesky transient client-freeze-bug.
Minecraft's music should be paused during battle, even if it starts mid-battle.
(Minecraft's music may play up to 4 seconds before it is paused by TBMM.)
# Version Forge-1.26.0 # Version Forge-1.26.0
Port to Forge 52.0.21 (Minecraft 1.21.1). Port to Forge 52.0.21 (Minecraft 1.21.1).

View file

@ -74,7 +74,7 @@ configured for them.)
Simply invoke `./gradlew build` in the mod directory and after some time the Simply invoke `./gradlew build` in the mod directory and after some time the
finished jar will be saved at finished jar will be saved at
`build/libs/TurnBasedMinecraft-NeoForge-1.26.0-all.jar` `build/libs/TurnBasedMinecraft-NeoForge-1.26.1-all.jar`
# Reproducibility # Reproducibility

View file

@ -1,7 +1,7 @@
plugins { plugins {
id 'java-library' id 'java-library'
id 'maven-publish' id 'maven-publish'
id 'net.neoforged.moddev' version '1.0.20' id 'net.neoforged.moddev' version '1.0.21'
} }
tasks.named('wrapper', Wrapper).configure { tasks.named('wrapper', Wrapper).configure {

View file

@ -21,7 +21,7 @@ minecraft_version=1.21.1
minecraft_version_range=[1.21.1, 1.22) minecraft_version_range=[1.21.1, 1.22)
# The Neo version must agree with the Minecraft version to get a valid artifact # The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=21.1.69 neo_version=21.1.72
# The Neo version range can use any version of Neo as bounds # The Neo version range can use any version of Neo as bounds
neo_version_range=[21.1.0,) neo_version_range=[21.1.0,)
# The loader version range can only use the major version of FML as bounds # The loader version range can only use the major version of FML as bounds
@ -37,7 +37,7 @@ mod_name=TurnBasedMinecraftMod
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT mod_license=MIT
# The mod version. See https://semver.org/ # The mod version. See https://semver.org/
mod_version=1.26.0 mod_version=1.26.1
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources. # This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html # See https://maven.apache.org/guides/mini/guide-naming-conventions.html

View file

@ -28,6 +28,7 @@ public class BattleGui extends Screen {
private MenuState state; private MenuState state;
private boolean stateChanged; private boolean stateChanged;
private String info; private String info;
private Long waitMissingBattleTicks;
private enum MenuState { private enum MenuState {
MAIN_MENU(0), ATTACK_TARGET(1), ITEM_ACTION(2), WAITING(3), SWITCH_ITEM(4), USE_ITEM(5); MAIN_MENU(0), ATTACK_TARGET(1), ITEM_ACTION(2), WAITING(3), SWITCH_ITEM(4), USE_ITEM(5);
@ -91,6 +92,7 @@ public class BattleGui extends Screen {
elapsedTime = 0; elapsedTime = 0;
state = MenuState.MAIN_MENU; state = MenuState.MAIN_MENU;
stateChanged = true; stateChanged = true;
waitMissingBattleTicks = null;
} }
private void setState(MenuState state) { private void setState(MenuState state) {
@ -224,13 +226,31 @@ public class BattleGui extends Screen {
} }
} }
private int colorFromTicks(final Long ticks) {
if (ticks < 20 * 10) {
double value = (20 * 10 - ticks.intValue()) / (20.0 * 10.0);
return 0xFF0000FF | (((int)(value * 255.0)) << 8) | (((int)(value * 255.0)) << 16);
} else {
return 0xFF0000FF;
}
}
@Override @Override
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
if (TurnBasedMinecraftMod.proxy.getLocalBattle() == null) { if (TurnBasedMinecraftMod.proxy.getLocalBattle() == null) {
if (waitMissingBattleTicks == null) {
waitMissingBattleTicks = 0L;
} else {
waitMissingBattleTicks += 1L;
}
// drawHoveringText("Waiting...", width / 2 - 50, height / 2); // drawHoveringText("Waiting...", width / 2 - 50, height / 2);
drawString(guiGraphics, "Waiting...", width / 2 - 50, height / 2, 0xFFFFFFFF); drawString(guiGraphics, "Waiting...", width / 2 - 50, height / 2, colorFromTicks(waitMissingBattleTicks));
super.render(guiGraphics, mouseX, mouseY, partialTicks);
return; return;
} else {
waitMissingBattleTicks = null;
} }
if (TurnBasedMinecraftMod.proxy.getLocalBattle().getState() == Battle.State.DECISION if (TurnBasedMinecraftMod.proxy.getLocalBattle().getState() == Battle.State.DECISION
&& timeRemaining.get() > 0) { && timeRemaining.get() > 0) {
long nextInstant = System.nanoTime(); long nextInstant = System.nanoTime();
@ -351,9 +371,13 @@ public class BattleGui extends Screen {
} }
@Override @Override
public boolean keyPressed(int a, int b, int c) { public boolean keyPressed(int keyCode, int b, int c) {
if (getMinecraft().player.isCreative()) { if (getMinecraft().player.isCreative()) {
return super.keyPressed(a, b, c); return super.keyPressed(keyCode, b, c);
} else if (keyCode == 256) {
getMinecraft().setScreen(null);
TurnBasedMinecraftMod.proxy.displayString("Leaving GUI, but the battle continues!");
return true;
} }
return false; // TODO verify return value return false; // TODO verify return value
} }

View file

@ -180,7 +180,7 @@ public class BattleMusic
if(initialized && next != null) if(initialized && next != null)
{ {
logger.debug("play called with file " + next.getName() + " and vol " + volume); logger.debug("play called with file " + next.getName() + " and vol " + volume);
Minecraft.getInstance().getSoundManager().pause(); TurnBasedMinecraftMod.proxy.pauseMCMusic();
String suffix = next.getName().substring(next.getName().length() - 3).toLowerCase(); String suffix = next.getName().substring(next.getName().length() - 3).toLowerCase();
if(suffix.equals("mid") && sequencer != null) if(suffix.equals("mid") && sequencer != null)
{ {
@ -362,7 +362,7 @@ public class BattleMusic
} }
if(resumeMCSounds) if(resumeMCSounds)
{ {
Minecraft.getInstance().getSoundManager().resume(); TurnBasedMinecraftMod.proxy.resumeMCMusic();
} }
isPlaying = false; isPlaying = false;
} }

View file

@ -370,6 +370,10 @@ public class ClientProxy extends CommonProxy {
break; break;
case TURN_BEGIN: case TURN_BEGIN:
TurnBasedMinecraftMod.proxy.displayString("The turn begins!"); TurnBasedMinecraftMod.proxy.displayString("The turn begins!");
if (TurnBasedMinecraftMod.proxy.getLocalBattle() == null || TurnBasedMinecraftMod.proxy.getLocalBattle().getId() != pkt.getAmount()) {
TurnBasedMinecraftMod.proxy.createLocalBattle(pkt.getAmount());
}
TurnBasedMinecraftMod.proxy.battleStarted();
TurnBasedMinecraftMod.proxy.battleGuiTurnBegin(); TurnBasedMinecraftMod.proxy.battleGuiTurnBegin();
break; break;
case TURN_END: case TURN_END:
@ -1478,4 +1482,14 @@ public class ClientProxy extends CommonProxy {
public void showClientConfigGui() { public void showClientConfigGui() {
Minecraft.getInstance().setScreen(new ClientConfigGui(null, null)); Minecraft.getInstance().setScreen(new ClientConfigGui(null, null));
} }
@Override
public void pauseMCMusic() {
Minecraft.getInstance().getSoundManager().pause();
}
@Override
public void resumeMCMusic() {
Minecraft.getInstance().getSoundManager().resume();
}
} }

View file

@ -2,6 +2,7 @@ package com.burnedkirby.TurnBasedMinecraft.common;
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattleInfo; import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattleInfo;
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattleMessage; import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattleMessage;
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattlePing;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
@ -49,6 +50,8 @@ public class Battle {
private ResourceKey<Level> dimension; private ResourceKey<Level> dimension;
private long pingTimerNanos;
public enum State { public enum State {
DECISION(0), DECISION(0),
ACTION(1), ACTION(1),
@ -122,6 +125,7 @@ public class Battle {
undecidedCount = new AtomicInteger(0); undecidedCount = new AtomicInteger(0);
random = new Random(); random = new Random();
this.dimension = dimension; this.dimension = dimension;
pingTimerNanos = 0;
if (sideA != null) { if (sideA != null) {
for (Entity e : sideA) { for (Entity e : sideA) {
EntityInfo entityInfo; EntityInfo entityInfo;
@ -447,12 +451,22 @@ public class Battle {
if (!isServer) { if (!isServer) {
return; return;
} }
PacketBattleInfo infoPacket = new PacketBattleInfo(getSideAIDs(), getSideBIDs(), timer, TurnBasedMinecraftMod.proxy.getConfig().getDecisionDurationNanos(), !TurnBasedMinecraftMod.proxy.getConfig().isBattleDecisionDurationForever()); PacketBattleInfo infoPacket = new PacketBattleInfo(getId(), getSideAIDs(), getSideBIDs(), timer, TurnBasedMinecraftMod.proxy.getConfig().getDecisionDurationNanos(), !TurnBasedMinecraftMod.proxy.getConfig().isBattleDecisionDurationForever());
for (Combatant p : players.values()) { for (Combatant p : players.values()) {
PacketDistributor.sendToPlayer((ServerPlayer)p.entity, infoPacket); PacketDistributor.sendToPlayer((ServerPlayer)p.entity, infoPacket);
} }
} }
protected void notifyPlayersBattlePing() {
if (!isServer) {
return;
}
PacketBattlePing pingPacket = new PacketBattlePing(getId(), (int)(timer / 1000000000L));
for (Combatant p : players.values()) {
PacketDistributor.sendToPlayer((ServerPlayer)p.entity, pingPacket);
}
}
protected void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount) { protected void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount) {
sendMessageToAllPlayers(type, from, to, amount, new String()); sendMessageToAllPlayers(type, from, to, amount, new String());
} }
@ -651,6 +665,11 @@ public class Battle {
} }
private boolean update(final long dt) { private boolean update(final long dt) {
pingTimerNanos += dt;
if (pingTimerNanos >= 4000000000L) {
pingTimerNanos = 0;
notifyPlayersBattlePing();
}
if (battleEnded) { if (battleEnded) {
Collection<Combatant> combatants = new ArrayList<Combatant>(); Collection<Combatant> combatants = new ArrayList<Combatant>();
combatants.addAll(sideA.values()); combatants.addAll(sideA.values());

View file

@ -27,7 +27,7 @@ public class BattleUpdater
@SubscribeEvent @SubscribeEvent
public void update(ServerTickEvent.Post tickEvent) { public void update(ServerTickEvent.Post tickEvent) {
//if(tickEvent.phase != TickEvent.Phase.START && isRunning.get() && ++tick > tickLimit) { //if(tickEvent.phase != TickEvent.Phase.START && isRunning.get() && ++tick > tickLimit) {
if(isRunning.get() && ++tick > tickLimit) { if(isRunning.get() && ++tick > tickLimit && tickEvent.hasTime()) {
tick = 0; tick = 0;
manager.battleMap.entrySet().removeIf(entry -> entry.getValue().update()); manager.battleMap.entrySet().removeIf(entry -> entry.getValue().update());
manager.updateRecentlyLeftBattle(); manager.updateRecentlyLeftBattle();

View file

@ -177,4 +177,7 @@ public class CommonProxy
public static final StreamCodec<ByteBuf, Collection<Integer>> COLLECTION_INT_CODEC = ByteBufCodecs.INT.apply(ByteBufCodecs.collection(ArrayList::new)); public static final StreamCodec<ByteBuf, Collection<Integer>> COLLECTION_INT_CODEC = ByteBufCodecs.INT.apply(ByteBufCodecs.collection(ArrayList::new));
public void showClientConfigGui() {} public void showClientConfigGui() {}
public void pauseMCMusic() {}
public void resumeMCMusic() {}
} }

View file

@ -27,7 +27,6 @@ import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.fml.event.lifecycle.FMLDedicatedServerSetupEvent; import net.neoforged.fml.event.lifecycle.FMLDedicatedServerSetupEvent;
import net.neoforged.fml.loading.FMLEnvironment; import net.neoforged.fml.loading.FMLEnvironment;
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.neoforge.event.RegisterCommandsEvent;
import net.neoforged.neoforge.event.server.ServerStartingEvent; import net.neoforged.neoforge.event.server.ServerStartingEvent;
@ -42,7 +41,7 @@ import org.apache.logging.log4j.Logger;
public class TurnBasedMinecraftMod { public class TurnBasedMinecraftMod {
public static final String MODID = "com_burnedkirby_turnbasedminecraft"; public static final String MODID = "com_burnedkirby_turnbasedminecraft";
public static final String NAME = "Turn Based Minecraft Mod"; public static final String NAME = "Turn Based Minecraft Mod";
public static final String VERSION = "1.26.0"; public static final String VERSION = "1.26.1";
public static final String CONFIG_FILENAME = "TBM_Config.toml"; public static final String CONFIG_FILENAME = "TBM_Config.toml";
public static final String DEFAULT_CONFIG_FILENAME = "TBM_Config_DEFAULT.toml"; public static final String DEFAULT_CONFIG_FILENAME = "TBM_Config_DEFAULT.toml";
public static final String CONFIG_DIRECTORY = "config/TurnBasedMinecraft/"; public static final String CONFIG_DIRECTORY = "config/TurnBasedMinecraft/";
@ -53,7 +52,7 @@ public class TurnBasedMinecraftMod {
public static final String MUSIC_SILLY = MUSIC_ROOT + "silly/"; public static final String MUSIC_SILLY = MUSIC_ROOT + "silly/";
public static final String MUSIC_BATTLE = MUSIC_ROOT + "battle/"; public static final String MUSIC_BATTLE = MUSIC_ROOT + "battle/";
private static final String PROTOCOL_VERSION = Integer.toString(3); private static final String PROTOCOL_VERSION = Integer.toString(4);
private static final ResourceLocation HANDLER_ID = ResourceLocation.fromNamespaceAndPath(MODID, "main_channel"); private static final ResourceLocation HANDLER_ID = ResourceLocation.fromNamespaceAndPath(MODID, "main_channel");
protected static Logger logger = LogManager.getLogger(); protected static Logger logger = LogManager.getLogger();
@ -89,6 +88,8 @@ public class TurnBasedMinecraftMod {
registrar.playToClient(PacketClientGUI.TYPE, PacketClientGUI.STREAM_CODEC, new PacketClientGUI.PayloadHandler()); registrar.playToClient(PacketClientGUI.TYPE, PacketClientGUI.STREAM_CODEC, new PacketClientGUI.PayloadHandler());
registrar.playToClient(PacketBattlePing.TYPE, PacketBattlePing.STREAM_CODEC, new PacketBattlePing.PayloadHandler());
logger.debug("Register packets com_burnedkirby_turnbasedminecraft"); logger.debug("Register packets com_burnedkirby_turnbasedminecraft");
} }

View file

@ -16,11 +16,13 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection; import java.util.Collection;
public record PacketBattleInfo(Collection<Integer> sideA, Collection<Integer> sideB, long decisionNanos, long maxDecisionNanos, boolean turnTimerEnabled) implements CustomPacketPayload public record PacketBattleInfo(int battleID, Collection<Integer> sideA, Collection<Integer> sideB, long decisionNanos, long maxDecisionNanos, boolean turnTimerEnabled) implements CustomPacketPayload
{ {
public static final CustomPacketPayload.Type<PacketBattleInfo> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattleinfo")); public static final CustomPacketPayload.Type<PacketBattleInfo> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattleinfo"));
public static final StreamCodec<ByteBuf, PacketBattleInfo> STREAM_CODEC = StreamCodec.composite( public static final StreamCodec<ByteBuf, PacketBattleInfo> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.INT,
PacketBattleInfo::battleID,
CommonProxy.COLLECTION_INT_CODEC, CommonProxy.COLLECTION_INT_CODEC,
PacketBattleInfo::sideA, PacketBattleInfo::sideA,
CommonProxy.COLLECTION_INT_CODEC, CommonProxy.COLLECTION_INT_CODEC,
@ -45,7 +47,7 @@ public record PacketBattleInfo(Collection<Integer> sideA, Collection<Integer> si
ctx.enqueueWork(() -> { ctx.enqueueWork(() -> {
if(TurnBasedMinecraftMod.proxy.getLocalBattle() == null) if(TurnBasedMinecraftMod.proxy.getLocalBattle() == null)
{ {
return; TurnBasedMinecraftMod.proxy.createLocalBattle(pkt.battleID);
} }
TurnBasedMinecraftMod.proxy.getLocalBattle().clearCombatants(); TurnBasedMinecraftMod.proxy.getLocalBattle().clearCombatants();
for(Integer id : pkt.sideA) for(Integer id : pkt.sideA)
@ -64,6 +66,7 @@ public record PacketBattleInfo(Collection<Integer> sideA, Collection<Integer> si
TurnBasedMinecraftMod.proxy.getLocalBattle().addCombatantToSideB(e); TurnBasedMinecraftMod.proxy.getLocalBattle().addCombatantToSideB(e);
} }
} }
TurnBasedMinecraftMod.proxy.setBattleGuiAsGui();
TurnBasedMinecraftMod.proxy.setBattleGuiTime((int)(pkt.decisionNanos / 1000000000L)); TurnBasedMinecraftMod.proxy.setBattleGuiTime((int)(pkt.decisionNanos / 1000000000L));
TurnBasedMinecraftMod.proxy.setBattleGuiBattleChanged(); TurnBasedMinecraftMod.proxy.setBattleGuiBattleChanged();
TurnBasedMinecraftMod.proxy.setBattleGuiTurnTimerEnabled(pkt.turnTimerEnabled); TurnBasedMinecraftMod.proxy.setBattleGuiTurnTimerEnabled(pkt.turnTimerEnabled);

View file

@ -0,0 +1,47 @@
package com.burnedkirby.TurnBasedMinecraft.common.networking;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import io.netty.buffer.ByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.neoforged.neoforge.network.handling.IPayloadHandler;
import org.jetbrains.annotations.NotNull;
public record PacketBattlePing(int battleID, int remainingSeconds) implements CustomPacketPayload {
public static final CustomPacketPayload.Type<PacketBattlePing> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattleping"));
public static final StreamCodec<ByteBuf, PacketBattlePing> STREAM_CODEC = StreamCodec.composite(
ByteBufCodecs.INT,
PacketBattlePing::battleID,
ByteBufCodecs.VAR_INT,
PacketBattlePing::remainingSeconds,
PacketBattlePing::new
);
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static class PayloadHandler implements IPayloadHandler<PacketBattlePing> {
@Override
public void handle(final @NotNull PacketBattlePing pkt, IPayloadContext ctx) {
ctx.enqueueWork(() -> {
if (TurnBasedMinecraftMod.proxy.getLocalBattle() == null) {
TurnBasedMinecraftMod.proxy.createLocalBattle(pkt.battleID);
}
TurnBasedMinecraftMod.proxy.setBattleGuiAsGui();
TurnBasedMinecraftMod.proxy.setBattleGuiBattleChanged();
TurnBasedMinecraftMod.proxy.setBattleGuiTime(pkt.remainingSeconds);
TurnBasedMinecraftMod.proxy.pauseMCMusic();
}).exceptionally(e -> {
ctx.disconnect(Component.literal("Exception handling PacketBattlePing! " + e.getMessage()));
return null;
});
}
}
}

View file

@ -41,6 +41,7 @@ public record PacketBattleRequestInfo(int battleID) implements CustomPacketPaylo
return; return;
} }
ctx.reply(new PacketBattleInfo( ctx.reply(new PacketBattleInfo(
b.getId(),
b.getSideAIDs(), b.getSideAIDs(),
b.getSideBIDs(), b.getSideBIDs(),
b.getTimerNanos(), b.getTimerNanos(),