Fix portal recognition/cache/repair timing
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user