Fix portal recognition/cache/repair timing
This commit is contained in:
@@ -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
@@ -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 |
@@ -28,5 +28,6 @@
|
||||
],
|
||||
"breaks": {
|
||||
"world-gamerules": "*"
|
||||
}
|
||||
},
|
||||
"icon": "assets/dartokloning/icon.png"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"mixins": [
|
||||
"ServerLevelGameRulesMixin",
|
||||
"PlayerListMixin"
|
||||
"PlayerListMixin",
|
||||
"NetherPortalBlockMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
||||
Reference in New Issue
Block a user