add reload configuration
This commit is contained in:
@@ -8,3 +8,12 @@ This branch is Fabric-only and intentionally separates authority:
|
|||||||
Minecraft 26.2 uses the unobfuscated Mojang/official names and Java 25. This port therefore does not reuse the old Yarn-named common/client GUI classes from 0.2.2. Client rendering lives only in `src/client`, while server/gameplay code lives in `src/main`.
|
Minecraft 26.2 uses the unobfuscated Mojang/official names and Java 25. This port therefore does not reuse the old Yarn-named common/client GUI classes from 0.2.2. Client rendering lives only in `src/client`, while server/gameplay code lives in `src/main`.
|
||||||
|
|
||||||
Run `compiler.bat` on Windows or `./compiler.sh` on Linux/macOS. The script checks whether the existing JAR contains the same `mod_version+mc<minecraft_version>` as `gradle.properties`; matching builds offer Push/Recompile/Quit. After a successful build it offers Git push and retries failed pushes in groups of three.
|
Run `compiler.bat` on Windows or `./compiler.sh` on Linux/macOS. The script checks whether the existing JAR contains the same `mod_version+mc<minecraft_version>` as `gradle.properties`; matching builds offer Push/Recompile/Quit. After a successful build it offers Git push and retries failed pushes in groups of three.
|
||||||
|
|
||||||
|
## Commands (v0.3.2)
|
||||||
|
|
||||||
|
`/idt reload`
|
||||||
|
|
||||||
|
- Client player (non-operator): reloads only `item-despawn-timer-client.json`.
|
||||||
|
- Client player (operator/moderator): reloads the client config and requests a server-config reload. The server validates permission before accepting the request.
|
||||||
|
- Dedicated-server console: reloads only `item-despawn-timer-server.json`.
|
||||||
|
- The server-side `/idt reload` node requires Minecraft moderator/operator permission, so it is not advertised by the server command tree to ordinary players. The client-side command remains available because ordinary players are allowed to reload their own presentation config.
|
||||||
|
|||||||
+1
-1
@@ -3,6 +3,6 @@ org.gradle.configuration-cache=false
|
|||||||
minecraft_version=26.2
|
minecraft_version=26.2
|
||||||
loader_version=0.19.3
|
loader_version=0.19.3
|
||||||
fabric_version=0.160.0+26.2
|
fabric_version=0.160.0+26.2
|
||||||
mod_version=0.3.1
|
mod_version=0.3.2
|
||||||
maven_group=whirlfrenzy.itemdespawntimer
|
maven_group=whirlfrenzy.itemdespawntimer
|
||||||
archives_base_name=item-despawn-timer
|
archives_base_name=item-despawn-timer
|
||||||
|
|||||||
@@ -1,3 +1,17 @@
|
|||||||
package whirlfrenzy.itemdespawntimer.client;
|
package whirlfrenzy.itemdespawntimer.client;
|
||||||
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import whirlfrenzy.itemdespawntimer.network.TimerSyncPayload;
|
|
||||||
public final class ItemDespawnTimerClient implements ClientModInitializer { @Override public void onInitializeClient(){ ClientConfig.load(); ClientPlayNetworking.registerGlobalReceiver(TimerSyncPayload.TYPE,(p,c)->ClientTimerData.put(p.entityId(),p.age(),p.lifespan())); } }
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import whirlfrenzy.itemdespawntimer.client.command.ItemDespawnTimerClientCommands;
|
||||||
|
import whirlfrenzy.itemdespawntimer.network.TimerSyncPayload;
|
||||||
|
|
||||||
|
public final class ItemDespawnTimerClient implements ClientModInitializer {
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient() {
|
||||||
|
ClientConfig.load();
|
||||||
|
ItemDespawnTimerClientCommands.register();
|
||||||
|
ClientPlayNetworking.registerGlobalReceiver(
|
||||||
|
TimerSyncPayload.TYPE,
|
||||||
|
(payload, context) -> ClientTimerData.put(payload.entityId(), payload.age(), payload.lifespan()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package whirlfrenzy.itemdespawntimer.client.command;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||||
|
import net.fabricmc.fabric.api.client.command.v2.ClientCommands;
|
||||||
|
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import whirlfrenzy.itemdespawntimer.client.ClientConfig;
|
||||||
|
import whirlfrenzy.itemdespawntimer.network.ReloadConfigPayload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client-side /idt reload is intentionally available to every player.
|
||||||
|
* It always reloads the local presentation config. A C2S request is also sent;
|
||||||
|
* the server silently accepts it only when the player has operator/moderator permission.
|
||||||
|
*/
|
||||||
|
public final class ItemDespawnTimerClientCommands {
|
||||||
|
private ItemDespawnTimerClientCommands() {}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
|
||||||
|
dispatcher.register(ClientCommands.literal("idt")
|
||||||
|
.then(ClientCommands.literal("reload")
|
||||||
|
.executes(context -> {
|
||||||
|
ClientConfig.load();
|
||||||
|
context.getSource().sendFeedback(
|
||||||
|
Component.literal("[Item Despawn Timer] Client config reloaded."));
|
||||||
|
|
||||||
|
if (ClientPlayNetworking.canSend(ReloadConfigPayload.TYPE)) {
|
||||||
|
ClientPlayNetworking.send(new ReloadConfigPayload(true));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}))));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,18 +2,43 @@ package whirlfrenzy.itemdespawntimer;
|
|||||||
|
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||||
|
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.Identifier;
|
import net.minecraft.resources.Identifier;
|
||||||
|
import net.minecraft.server.permissions.Permissions;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import whirlfrenzy.itemdespawntimer.command.ItemDespawnTimerCommands;
|
||||||
import whirlfrenzy.itemdespawntimer.config.ServerConfig;
|
import whirlfrenzy.itemdespawntimer.config.ServerConfig;
|
||||||
|
import whirlfrenzy.itemdespawntimer.network.ReloadConfigPayload;
|
||||||
import whirlfrenzy.itemdespawntimer.network.TimerSyncPayload;
|
import whirlfrenzy.itemdespawntimer.network.TimerSyncPayload;
|
||||||
|
|
||||||
public final class ItemDespawnTimer implements ModInitializer {
|
public final class ItemDespawnTimer implements ModInitializer {
|
||||||
public static final String MOD_ID = "item-despawn-timer";
|
public static final String MOD_ID = "item-despawn-timer";
|
||||||
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
|
||||||
public static Identifier id(String path) { return Identifier.fromNamespaceAndPath(MOD_ID, path); }
|
|
||||||
@Override public void onInitialize() {
|
public static Identifier id(String path) {
|
||||||
|
return Identifier.fromNamespaceAndPath(MOD_ID, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitialize() {
|
||||||
ServerConfig.load();
|
ServerConfig.load();
|
||||||
|
|
||||||
PayloadTypeRegistry.clientboundPlay().register(TimerSyncPayload.TYPE, TimerSyncPayload.CODEC);
|
PayloadTypeRegistry.clientboundPlay().register(TimerSyncPayload.TYPE, TimerSyncPayload.CODEC);
|
||||||
|
PayloadTypeRegistry.serverboundPlay().register(ReloadConfigPayload.TYPE, ReloadConfigPayload.CODEC);
|
||||||
|
|
||||||
|
ServerPlayNetworking.registerGlobalReceiver(ReloadConfigPayload.TYPE, (payload, context) -> {
|
||||||
|
if (!payload.requested()) return;
|
||||||
|
|
||||||
|
// Never trust the client: only an operator/moderator may reload server configuration.
|
||||||
|
if (!context.player().permissions().hasPermission(Permissions.COMMANDS_MODERATOR)) return;
|
||||||
|
|
||||||
|
ServerConfig.load();
|
||||||
|
context.player().sendSystemMessage(
|
||||||
|
Component.literal("[Item Despawn Timer] Client and server configs reloaded."));
|
||||||
|
});
|
||||||
|
|
||||||
|
ItemDespawnTimerCommands.register();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package whirlfrenzy.itemdespawntimer.command;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.commands.Commands;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.permissions.Permissions;
|
||||||
|
import whirlfrenzy.itemdespawntimer.config.ServerConfig;
|
||||||
|
|
||||||
|
/** Server-side /idt commands. The reload branch is only sent to command sources with moderator permission. */
|
||||||
|
public final class ItemDespawnTimerCommands {
|
||||||
|
private ItemDespawnTimerCommands() {}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) ->
|
||||||
|
dispatcher.register(Commands.literal("idt")
|
||||||
|
.then(Commands.literal("reload")
|
||||||
|
.requires(source -> source.permissions().hasPermission(Permissions.COMMANDS_MODERATOR))
|
||||||
|
.executes(ItemDespawnTimerCommands::reloadServerConfig))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int reloadServerConfig(CommandContext<CommandSourceStack> context) {
|
||||||
|
ServerConfig.load();
|
||||||
|
context.getSource().sendSuccess(
|
||||||
|
() -> Component.literal("[Item Despawn Timer] Server config reloaded."), false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package whirlfrenzy.itemdespawntimer.network;
|
||||||
|
|
||||||
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import whirlfrenzy.itemdespawntimer.ItemDespawnTimer;
|
||||||
|
|
||||||
|
/** Client request to reload the server config. The server always validates operator permission. */
|
||||||
|
public record ReloadConfigPayload(boolean requested) implements CustomPacketPayload {
|
||||||
|
public static final Type<ReloadConfigPayload> TYPE = new Type<>(ItemDespawnTimer.id("reload_config"));
|
||||||
|
public static final StreamCodec<RegistryFriendlyByteBuf, ReloadConfigPayload> CODEC = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.BOOL, ReloadConfigPayload::requested,
|
||||||
|
ReloadConfigPayload::new);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<? extends CustomPacketPayload> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user