sevveral fixes and improvements

added:
 inline command: showoff `.item`
 clicking coordinates open a url to visit that area in web map
 added sound for player join/leave/death to annoy everyone
 increased the search radius of /back command. (200 from 100)

fix:
  inline ping is not case-insensitive
  time does not pass faster when everybody is sleeping

code cleanup
This commit is contained in:
iceBear67 committed 2026-07-18 14:13:17 +08:00
1 parent c7cd4acc63
commit 3096e7c838
9 files changed
+123 -10

No files matched your search

@@ -7,6 +7,7 @@ import io.ib67.sfcraft.module.*;
import io.ib67.sfcraft.module.chat.ChatPrefixModule; import io.ib67.sfcraft.module.chat.ChatPrefixModule;
import io.ib67.sfcraft.module.chat.decorator.ChatPingModule; import io.ib67.sfcraft.module.chat.decorator.ChatPingModule;
import io.ib67.sfcraft.module.chat.decorator.ChatSendLocModule; import io.ib67.sfcraft.module.chat.decorator.ChatSendLocModule;
import io.ib67.sfcraft.module.chat.decorator.ChatShowoffModule;
import io.ib67.sfcraft.module.compat.ModCompatModule; import io.ib67.sfcraft.module.compat.ModCompatModule;
import io.ib67.sfcraft.module.room.CreativeRoomModule; import io.ib67.sfcraft.module.room.CreativeRoomModule;
import io.ib67.sfcraft.module.supervisor.WebModule; import io.ib67.sfcraft.module.supervisor.WebModule;
@@ -61,6 +62,8 @@ public class SFCraftInitializer extends GuiceModInitializer {
registerFeature(RoomModule.class); registerFeature(RoomModule.class);
registerFeature(CreativeRoomModule.class); registerFeature(CreativeRoomModule.class);
registerFeature(ChatPrefixModule.class); registerFeature(ChatPrefixModule.class);
registerFeature(SoundModule.class);
registerFeature(ChatShowoffModule.class);
registerWebModules(); registerWebModules();
} }
@@ -9,10 +9,16 @@ import org.spongepowered.asm.mixin.injection.*;
@Mixin(ServerLevel.class) @Mixin(ServerLevel.class)
public abstract class ServerWorldMixin { public abstract class ServerWorldMixin {
@ModifyArg(method = "tickTime", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/storage/ServerLevelData;setGameTime(J)V")) @ModifyArg(method = "tickTime", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/storage/ServerLevelData;setGameTime(J)V"))
public long setTimeOfDay(long timeOfDay) { public long setTimeOfDay(long timeOfDay) {
int i = ((ServerLevel) (Object) this).getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE); var _this = ((ServerLevel) (Object) this);
int i = _this.getGameRules().get(GameRules.PLAYERS_SLEEPING_PERCENTAGE);
if (((ServerWorldBridge) this).getSleepStatus().areEnoughSleeping(i)) { if (((ServerWorldBridge) this).getSleepStatus().areEnoughSleeping(i)) {
var dt = _this.dimensionTypeRegistration();
var clock = dt.value().defaultClock();
if(clock.isEmpty()) return timeOfDay;
_this.clockManager().addTicks(clock.get(), 10);
MixinHelper.spedUp = true; MixinHelper.spedUp = true;
return timeOfDay + 10; return timeOfDay + 10;
} }
@@ -15,8 +15,6 @@ import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
public class ElytraSpeedMeterModule extends ServerModule { public class ElytraSpeedMeterModule extends ServerModule {
private static final int BAR_LEN = 20;
private static final int MAX_NORMAL_SPEED = 6;
private static final int THRESHLD_OF_ELYTRA_FLY = 8; private static final int THRESHLD_OF_ELYTRA_FLY = 8;
private static final Component[] ELYTRA_DURABILITY = new Component[100]; private static final Component[] ELYTRA_DURABILITY = new Component[100];
private final Object2ObjectMap<Player, BlockPos> playerFlyMap = new Object2ObjectOpenHashMap<>(); private final Object2ObjectMap<Player, BlockPos> playerFlyMap = new Object2ObjectOpenHashMap<>();
@@ -0,0 +1,66 @@
package io.ib67.sfcraft.module;
import com.google.common.collect.Lists;
import io.ib67.kiwi.RandomHelper;
import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.callback.SFCallbacks;
import io.ib67.sfcraft.inject.MinecraftServerSupplier;
import jakarta.inject.Inject;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.animal.chicken.ChickenSoundVariants;
import net.minecraft.world.entity.player.Player;
import java.util.Arrays;
import java.util.List;
public class SoundModule extends ServerModule {
public static final List<SoundEvent> DEATH_SOUNDS = Lists.newArrayList(
SoundEvents.BEE_DEATH,
SoundEvents.PLAYER_DEATH
);
protected SoundEvent join = SoundEvents.UI_TOAST_IN;
protected SoundEvent leave = SoundEvents.UI_TOAST_OUT;
protected final MinecraftServerSupplier serverSupplier;
@Inject
public SoundModule(MinecraftServerSupplier serverSupplier) {
this.serverSupplier = serverSupplier;
}
@Override
public void onInitialize() {
SFCallbacks.PLAYER_DEATH.register(this::playDeathSound);
ServerPlayConnectionEvents.JOIN.register(this::playJoinSound);
ServerPlayConnectionEvents.DISCONNECT.register(this::playLeaveSound);
}
@Override
public void onEnable() {
var sounds = SoundEvents.CHICKEN_SOUNDS.get(ChickenSoundVariants.SoundSet.CLASSIC).adultSounds();
DEATH_SOUNDS.add(sounds.hurtSound().value());
join = SoundEvents.NOTE_BLOCK_HAT.value();
join = SoundEvents.NOTE_BLOCK_BASS.value();
}
private void playLeaveSound(ServerGamePacketListenerImpl serverGamePacketListener, MinecraftServer minecraftServer) {
PlayerLookup.all(serverSupplier.get()).forEach(it -> it.playSound(leave));
}
private void playJoinSound(ServerGamePacketListenerImpl serverGamePacketListener, PacketSender packetSender, MinecraftServer minecraftServer) {
PlayerLookup.all(serverSupplier.get()).forEach(it -> it.playSound(join));
}
private void playDeathSound(Player player, DamageSource damageSource) {
var rand = RandomHelper.number(0, DEATH_SOUNDS.size() - 1);
PlayerLookup.all(serverSupplier.get()).forEach(it -> it.playSound(DEATH_SOUNDS.get(rand)));
}
}
@@ -20,9 +20,10 @@ import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource; import net.minecraft.sounds.SoundSource;
import net.minecraft.util.CommonColors; import net.minecraft.util.CommonColors;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import org.jspecify.annotations.NonNull;
public class ChatPingModule extends ServerModule implements ChatDecorator { public class ChatPingModule extends ServerModule implements ChatDecorator {
private static final Pattern PING = Pattern.compile("(@[\\w]+)?"); //todo remove the need of prefix private static final Pattern PING = Pattern.compile("(@[\\w]+)?");
@Inject @Inject
MinecraftServerSupplier serverSupplier; MinecraftServerSupplier serverSupplier;
@Inject @Inject
@@ -34,7 +35,7 @@ public class ChatPingModule extends ServerModule implements ChatDecorator {
} }
@Override @Override
public Component decorate(@Nullable ServerPlayer sender, Component message) { public @NonNull Component decorate(@Nullable ServerPlayer sender, @NonNull Component message) {
if (!isEnabled()) { if (!isEnabled()) {
return message; return message;
} }
@@ -69,7 +70,7 @@ public class ChatPingModule extends ServerModule implements ChatDecorator {
for (int i = 0; i < match.groupCount(); i++) { for (int i = 0; i < match.groupCount(); i++) {
var r = match.group(); var r = match.group();
if (r.isEmpty()) continue; if (r.isEmpty()) continue;
final var d = r.substring(1); final var d = r.substring(1).toLowerCase();
return playerNames.stream() return playerNames.stream()
.filter(it -> it.toLowerCase().startsWith(d)) .filter(it -> it.toLowerCase().startsWith(d))
.peek(it -> foundPlayers.add(serverSupplier.get().getPlayerList().getPlayerByName(it))) .peek(it -> foundPlayers.add(serverSupplier.get().getPlayerList().getPlayerByName(it)))
@@ -14,6 +14,9 @@ import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects; import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NonNull;
import java.net.URI;
public class ChatSendLocModule extends ServerModule implements ChatDecorator { public class ChatSendLocModule extends ServerModule implements ChatDecorator {
@Inject @Inject
@@ -25,7 +28,7 @@ public class ChatSendLocModule extends ServerModule implements ChatDecorator {
} }
@Override @Override
public Component decorate(@Nullable ServerPlayer sender, Component message) { public @NonNull Component decorate(@Nullable ServerPlayer sender, @NonNull Component message) {
if (!isEnabled()) return message; if (!isEnabled()) return message;
if (sender != null) { if (sender != null) {
if (!SFConsts.USE_BROADCAST_LOCATION.hasPermission(sender)) { if (!SFConsts.USE_BROADCAST_LOCATION.hasPermission(sender)) {
@@ -46,7 +49,9 @@ public class ChatSendLocModule extends ServerModule implements ChatDecorator {
return Component return Component
.literal(" " + x + ", " + y + ", " + z + world + " ") .literal(" " + x + ", " + y + ", " + z + world + " ")
.withColor(Helper.fromRgb(63, 254, 254)) .withColor(Helper.fromRgb(63, 254, 254))
.withStyle(style -> style.withClickEvent(new ClickEvent.RunCommand("/gps " + key + " " + x + " " + y + " " + z))); .withStyle(style -> style.withClickEvent(new ClickEvent.OpenUrl(URI.create(
"https://mc.sfclub.cc/map/?world=" + key.identifier().toString().replace(':', '_') + "&zoom=5&x=" + x + "&z=" + z
))));
} }
private static String translate(ResourceKey<Level> registryKey) { private static String translate(ResourceKey<Level> registryKey) {
@@ -0,0 +1,34 @@
package io.ib67.sfcraft.module.chat.decorator;
import com.google.inject.Inject;
import io.ib67.sfcraft.ServerModule;
import io.ib67.sfcraft.registry.chat.SimpleMessageDecorator;
import net.minecraft.network.chat.ChatDecorator;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class ChatShowoffModule extends ServerModule implements ChatDecorator {
@Inject
SimpleMessageDecorator messageDecorator;
@Override
public void onInitialize() {
messageDecorator.registerDecorator(this);
}
@Override
public @NonNull Component decorate(@Nullable ServerPlayer player, Component message) {
if (!isEnabled()) {
return message;
}
return ReplaceHelper.replace(player, message, ".item", this::generateShowoffText);
}
private Component generateShowoffText(ServerPlayer serverPlayer) {
var item = serverPlayer.getMainHandItem();
return item.getDisplayName();
}
}
@@ -39,7 +39,7 @@ public class BackModule extends ServerModule {
var wld = player.level().getServer().getLevel(pos.dimension()); var wld = player.level().getServer().getLevel(pos.dimension());
var _pos = pos.pos(); var _pos = pos.pos();
if (wld == null) return 0; if (wld == null) return 0;
var nearby = wld.getNearestPlayer(_pos.getX(), _pos.getY(), _pos.getZ(), 100, true); var nearby = wld.getNearestPlayer(_pos.getX(), _pos.getY(), _pos.getZ(), 200, true);
if (nearby != null) { if (nearby != null) {
_pos = nearby.blockPosition(); _pos = nearby.blockPosition();
Helper.teleportSafely(player, wld, _pos.getX(), _pos.getY(), _pos.getZ(),0,0); Helper.teleportSafely(player, wld, _pos.getX(), _pos.getY(), _pos.getZ(),0,0);
+1 -1
View File
@@ -4,6 +4,7 @@
"package": "io.ib67.sfcraft.mixin", "package": "io.ib67.sfcraft.mixin",
"compatibilityLevel": "JAVA_21", "compatibilityLevel": "JAVA_21",
"mixins": [ "mixins": [
"server.ServerWorldMixin"
], ],
"client": [ "client": [
], ],
@@ -25,7 +26,6 @@
"server.ServerLoginNetworkHandlerMixin", "server.ServerLoginNetworkHandlerMixin",
"server.ServerPlayerEntityMixin", "server.ServerPlayerEntityMixin",
"server.ServerPlayNetworkHandlerMixin", "server.ServerPlayNetworkHandlerMixin",
"server.ServerWorldMixin",
"server.SleepManagerMixin", "server.SleepManagerMixin",
"server.subserver.PlayerListS2CPacket$EntryMixin", "server.subserver.PlayerListS2CPacket$EntryMixin",
"server.subserver.PlayerManagerMixin", "server.subserver.PlayerManagerMixin",