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`.
|
||||
|
||||
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
|
||||
loader_version=0.19.3
|
||||
fabric_version=0.160.0+26.2
|
||||
mod_version=0.3.1
|
||||
mod_version=0.3.2
|
||||
maven_group=whirlfrenzy.itemdespawntimer
|
||||
archives_base_name=item-despawn-timer
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
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.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.server.permissions.Permissions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import whirlfrenzy.itemdespawntimer.command.ItemDespawnTimerCommands;
|
||||
import whirlfrenzy.itemdespawntimer.config.ServerConfig;
|
||||
import whirlfrenzy.itemdespawntimer.network.ReloadConfigPayload;
|
||||
import whirlfrenzy.itemdespawntimer.network.TimerSyncPayload;
|
||||
|
||||
public final class ItemDespawnTimer implements ModInitializer {
|
||||
public static final String MOD_ID = "item-despawn-timer";
|
||||
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();
|
||||
|
||||
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