Fix portal recognition/cache/repair timing

This commit is contained in:
Darto KLoning
2026-09-09 07:13:48 +07:00
parent 90455467e1
commit c0f8ad9280
8 changed files with 105 additions and 4 deletions
+8
View File
@@ -455,3 +455,11 @@ Karena project ini menargetkan Java 25, compile final sebaiknya dilakukan menggu
## License
Lobby Systems is **proprietary software — All Rights Reserved**. Public access to this repository is for viewing, auditing, and reference only. Using, running, compiling, modifying, redistributing, or re-uploading the mod requires prior written permission from DartoKloning. See [`LICENSE`](LICENSE) for the complete terms.
## v1.6.1
- Fixed a newly-created Lobby Systems visual portal being able to use vanilla Nether routing on its first entry.
- Managed `minecraft:nether_portal` surfaces are now explicitly intercepted so Lobby Systems exclusively owns their destination.
- Reduced the creator-side post-create trigger suppression from the old 100-tick window to the configured portal check interval.
- Added the Lobby Systems mod icon to Fabric metadata.
+1 -1
View File
@@ -5,6 +5,6 @@ minecraft_version=26.2
loader_version=0.19.3
loom_version=1.17-SNAPSHOT
fabric_api_version=0.156.0+26.2
mod_version=1.6.0
mod_version=1.6.1
maven_group=id.dartokloning
archives_base_name=lobby-systems
@@ -49,6 +49,17 @@ public final class LobbySystemsMod implements ModInitializer {
private static final StarterKitManager STARTER_KITS = new StarterKitManager();
private static int saveTicker;
/**
* Used by the NetherPortalBlock mixin to distinguish Lobby Systems visual
* portals from ordinary vanilla Nether portals.
*/
public static boolean isManagedPortalBlock(Level level, BlockPos pos) {
if (level == null || pos == null) return false;
return PORTALS.isManagedVisualBlock(
level.dimension().identifier().toString(),
pos.getX(), pos.getY(), pos.getZ());
}
@Override
public void onInitialize() {
LobbyLog.startup();
@@ -885,7 +896,11 @@ public final class LobbySystemsMod implements ModInitializer {
return 0;
}
PORTALS.suppress(player.getUUID(), Math.max(CONFIG.get().portalCooldownTicks, 100));
// Only guard the command tick itself. Older builds suppressed the
// creator for at least 100 ticks, which left a window where the custom
// portal trigger was disabled while vanilla Nether routing was still
// active. The NetherPortalBlock mixin now owns that vanilla suppression.
PORTALS.suppress(player.getUUID(), Math.max(1, CONFIG.get().portalCheckIntervalTicks));
player.sendSystemMessage(Component.literal(
"§aPortal §f" + name + "§a dibuat. §7" + portal.sourceDimension + " §8→ §f" + targetId
+ "\n§dVisual portal aktif §7(" + visualBlocks + " blok, axis=" + visualAxis + ")."
@@ -85,6 +85,30 @@ public final class PortalManager {
return portals.size();
}
/**
* Returns true when the given block position belongs to a Lobby Systems
* portal that uses vanilla nether_portal only as its visual surface.
*
* Vanilla portal routing must be suppressed for these blocks; Lobby Systems
* is the sole owner of their destination.
*/
public boolean isManagedVisualBlock(String dimension, int x, int y, int z) {
List<Map.Entry<String, PortalDefinition>> candidates = byDimension.get(dimension);
if (candidates == null || candidates.isEmpty()) return false;
// Test the center of the block against the inclusive WorldEdit region.
double cx = x + 0.5D;
double cy = y + 0.5D;
double cz = z + 0.5D;
for (Map.Entry<String, PortalDefinition> entry : candidates) {
PortalDefinition portal = entry.getValue();
if (portal.hasNetherPortalVisual() && portal.contains(cx, cy, cz)) {
return true;
}
}
return false;
}
public void tick(MinecraftServer server, int intervalTicks, int cooldownTicks, PortalTrigger trigger) {
tick++;
cooldownUntil.entrySet().removeIf(e -> e.getValue() <= tick);
@@ -0,0 +1,52 @@
package id.dartokloning.lobbysystems.mixin;
import id.dartokloning.lobbysystems.LobbySystemsMod;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.InsideBlockEffectApplier;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.NetherPortalBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.portal.TeleportTransition;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
/**
* Makes vanilla nether_portal blocks inside Lobby Systems portal regions purely
* visual. Ordinary Nether portals outside managed regions keep vanilla behavior.
*/
@Mixin(NetherPortalBlock.class)
public abstract class NetherPortalBlockMixin {
@Inject(method = "entityInside", at = @At("HEAD"), cancellable = true)
private void dartokloning$cancelVanillaPortalEntry(
BlockState state,
Level level,
BlockPos pos,
Entity entity,
InsideBlockEffectApplier effectApplier,
boolean isPrecise,
CallbackInfo ci) {
if (!level.isClientSide() && LobbySystemsMod.isManagedPortalBlock(level, pos)) {
ci.cancel();
}
}
// Defense in depth: if another mod or a stale portal processor reaches the
// destination lookup anyway, managed Lobby Systems portal blocks still never
// resolve through vanilla Nether routing.
@Inject(method = "getPortalDestination", at = @At("HEAD"), cancellable = true)
private void dartokloning$cancelVanillaDestination(
ServerLevel currentLevel,
Entity entity,
BlockPos portalEntryPos,
CallbackInfoReturnable<TeleportTransition> cir) {
if (LobbySystemsMod.isManagedPortalBlock(currentLevel, portalEntryPos)) {
cir.setReturnValue(null);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

+2 -1
View File
@@ -28,5 +28,6 @@
],
"breaks": {
"world-gamerules": "*"
}
},
"icon": "assets/dartokloning/icon.png"
}
+2 -1
View File
@@ -4,7 +4,8 @@
"compatibilityLevel": "JAVA_25",
"mixins": [
"ServerLevelGameRulesMixin",
"PlayerListMixin"
"PlayerListMixin",
"NetherPortalBlockMixin"
],
"injectors": {
"defaultRequire": 1