Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
324 lines
12 KiB
Java
324 lines
12 KiB
Java
package com.tiedup.remake.client.events;
|
|
|
|
import com.mojang.blaze3d.vertex.PoseStack;
|
|
import com.tiedup.remake.blocks.BlockMarker;
|
|
import com.tiedup.remake.blocks.entity.MarkerBlockEntity;
|
|
import com.tiedup.remake.cells.CellDataV2;
|
|
import com.tiedup.remake.cells.CellRegistryV2;
|
|
import com.tiedup.remake.cells.MarkerType;
|
|
import com.tiedup.remake.client.renderer.CellOutlineRenderer;
|
|
import com.tiedup.remake.core.TiedUpMod;
|
|
import com.tiedup.remake.items.ItemAdminWand;
|
|
import java.util.UUID;
|
|
import net.minecraft.client.Camera;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.player.LocalPlayer;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.client.event.RenderLevelStageEvent;
|
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
import net.minecraftforge.fml.common.Mod;
|
|
|
|
/**
|
|
* Event handler for rendering cell outlines when holding an admin wand.
|
|
*
|
|
* Phase: Kidnapper Revamp - Cell System
|
|
*
|
|
* Renders colored outlines around cell positions when:
|
|
* - Player is holding an Admin Wand
|
|
* - A cell is currently selected in the wand
|
|
*
|
|
* The outlines help builders visualize which blocks are part of the cell.
|
|
*
|
|
* Network sync: On dedicated servers, cell data is synced via PacketSyncCellData.
|
|
* On integrated servers, direct access to server data is used as a fallback.
|
|
*/
|
|
@Mod.EventBusSubscriber(
|
|
modid = TiedUpMod.MOD_ID,
|
|
bus = Mod.EventBusSubscriber.Bus.FORGE,
|
|
value = Dist.CLIENT
|
|
)
|
|
public class CellHighlightHandler {
|
|
|
|
// Client-side cache of cell data (synced from server via PacketSyncCellData)
|
|
private static final java.util.Map<UUID, CellDataV2> syncedCells =
|
|
new java.util.concurrent.ConcurrentHashMap<>();
|
|
|
|
// Legacy single-cell cache for backward compatibility
|
|
private static CellDataV2 cachedCellData = null;
|
|
private static UUID cachedCellId = null;
|
|
|
|
/**
|
|
* Render cell outlines after translucent blocks.
|
|
*/
|
|
@SubscribeEvent
|
|
public static void onRenderLevelStage(RenderLevelStageEvent event) {
|
|
// Only render after translucent stage (so outlines appear on top)
|
|
if (
|
|
event.getStage() !=
|
|
RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS
|
|
) {
|
|
return;
|
|
}
|
|
|
|
Minecraft mc = Minecraft.getInstance();
|
|
LocalPlayer player = mc.player;
|
|
|
|
if (player == null) return;
|
|
|
|
// Check if player is holding an Admin Wand
|
|
ItemStack mainHand = player.getMainHandItem();
|
|
ItemStack offHand = player.getOffhandItem();
|
|
|
|
boolean holdingAdminWand =
|
|
mainHand.getItem() instanceof ItemAdminWand ||
|
|
offHand.getItem() instanceof ItemAdminWand;
|
|
|
|
if (!holdingAdminWand) {
|
|
cachedCellData = null;
|
|
cachedCellId = null;
|
|
return;
|
|
}
|
|
|
|
PoseStack poseStack = event.getPoseStack();
|
|
Camera camera = event.getCamera();
|
|
|
|
// If holding Admin Wand, render nearby structure markers and preview
|
|
renderNearbyStructureMarkers(poseStack, camera, player);
|
|
renderAdminWandPreview(poseStack, camera, player, mainHand, offHand);
|
|
}
|
|
|
|
/**
|
|
* Render a preview outline showing where the Admin Wand will place a marker.
|
|
*/
|
|
private static void renderAdminWandPreview(
|
|
PoseStack poseStack,
|
|
Camera camera,
|
|
LocalPlayer player,
|
|
ItemStack mainHand,
|
|
ItemStack offHand
|
|
) {
|
|
// Get the block the player is looking at
|
|
net.minecraft.world.phys.HitResult hitResult =
|
|
Minecraft.getInstance().hitResult;
|
|
if (
|
|
hitResult == null ||
|
|
hitResult.getType() != net.minecraft.world.phys.HitResult.Type.BLOCK
|
|
) {
|
|
return;
|
|
}
|
|
|
|
net.minecraft.world.phys.BlockHitResult blockHit =
|
|
(net.minecraft.world.phys.BlockHitResult) hitResult;
|
|
BlockPos targetPos = blockHit.getBlockPos().above(); // Marker goes above the clicked block
|
|
|
|
// Get the current marker type from the wand
|
|
MarkerType type;
|
|
if (mainHand.getItem() instanceof ItemAdminWand) {
|
|
type = ItemAdminWand.getCurrentType(mainHand);
|
|
} else {
|
|
type = ItemAdminWand.getCurrentType(offHand);
|
|
}
|
|
|
|
Vec3 cameraPos = camera.getPosition();
|
|
float[] color = CellOutlineRenderer.getColorForType(type);
|
|
|
|
// Make preview semi-transparent and pulsing
|
|
float alpha =
|
|
0.5f + 0.3f * (float) Math.sin(System.currentTimeMillis() / 200.0);
|
|
float[] previewColor = { color[0], color[1], color[2], alpha };
|
|
|
|
// Setup rendering (depth test off so preview shows through blocks)
|
|
com.mojang.blaze3d.systems.RenderSystem.enableBlend();
|
|
com.mojang.blaze3d.systems.RenderSystem.defaultBlendFunc();
|
|
com.mojang.blaze3d.systems.RenderSystem.disableDepthTest();
|
|
com.mojang.blaze3d.systems.RenderSystem.depthMask(false);
|
|
com.mojang.blaze3d.systems.RenderSystem.setShader(
|
|
net.minecraft.client.renderer.GameRenderer::getPositionColorShader
|
|
);
|
|
|
|
CellOutlineRenderer.renderFilledBlock(
|
|
poseStack,
|
|
targetPos,
|
|
cameraPos,
|
|
previewColor
|
|
);
|
|
|
|
com.mojang.blaze3d.systems.RenderSystem.depthMask(true);
|
|
com.mojang.blaze3d.systems.RenderSystem.enableDepthTest();
|
|
com.mojang.blaze3d.systems.RenderSystem.disableBlend();
|
|
}
|
|
|
|
/**
|
|
* Render outlines for nearby structure markers (markers without cell IDs).
|
|
*/
|
|
private static void renderNearbyStructureMarkers(
|
|
PoseStack poseStack,
|
|
Camera camera,
|
|
LocalPlayer player
|
|
) {
|
|
Level level = player.level();
|
|
BlockPos playerPos = player.blockPosition();
|
|
Vec3 cameraPos = camera.getPosition();
|
|
|
|
// Collect markers first to check if we need to render anything
|
|
java.util.List<
|
|
java.util.Map.Entry<BlockPos, MarkerType>
|
|
> markersToRender = new java.util.ArrayList<>();
|
|
|
|
// Scan in a 32-block radius for structure markers
|
|
int radius = 32;
|
|
|
|
for (int x = -radius; x <= radius; x++) {
|
|
for (int y = -radius / 2; y <= radius / 2; y++) {
|
|
for (int z = -radius; z <= radius; z++) {
|
|
BlockPos pos = playerPos.offset(x, y, z);
|
|
|
|
if (
|
|
level.getBlockState(pos).getBlock() instanceof
|
|
BlockMarker
|
|
) {
|
|
BlockEntity be = level.getBlockEntity(pos);
|
|
if (be instanceof MarkerBlockEntity marker) {
|
|
// Only render structure markers (no cell ID)
|
|
if (marker.getCellId() == null) {
|
|
markersToRender.add(
|
|
java.util.Map.entry(
|
|
pos,
|
|
marker.getMarkerType()
|
|
)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Only setup rendering if we have markers to render
|
|
if (!markersToRender.isEmpty()) {
|
|
// Setup rendering state (depth test off so markers show through blocks)
|
|
com.mojang.blaze3d.systems.RenderSystem.enableBlend();
|
|
com.mojang.blaze3d.systems.RenderSystem.defaultBlendFunc();
|
|
com.mojang.blaze3d.systems.RenderSystem.disableDepthTest();
|
|
com.mojang.blaze3d.systems.RenderSystem.depthMask(false);
|
|
com.mojang.blaze3d.systems.RenderSystem.setShader(
|
|
net.minecraft.client.renderer
|
|
.GameRenderer::getPositionColorShader
|
|
);
|
|
|
|
for (var entry : markersToRender) {
|
|
BlockPos pos = entry.getKey();
|
|
MarkerType type = entry.getValue();
|
|
float[] baseColor = CellOutlineRenderer.getColorForType(type);
|
|
// Semi-transparent fill
|
|
float[] fillColor = {
|
|
baseColor[0],
|
|
baseColor[1],
|
|
baseColor[2],
|
|
0.4f,
|
|
};
|
|
CellOutlineRenderer.renderFilledBlock(
|
|
poseStack,
|
|
pos,
|
|
cameraPos,
|
|
fillColor
|
|
);
|
|
}
|
|
|
|
// Restore rendering state
|
|
com.mojang.blaze3d.systems.RenderSystem.depthMask(true);
|
|
com.mojang.blaze3d.systems.RenderSystem.enableDepthTest();
|
|
com.mojang.blaze3d.systems.RenderSystem.disableBlend();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get cell data on client side.
|
|
* First checks the network-synced cache, then falls back to integrated server access.
|
|
*
|
|
* @param cellId The cell UUID to look up
|
|
* @return CellDataV2 if found, null otherwise
|
|
*/
|
|
private static CellDataV2 getCellDataClient(UUID cellId) {
|
|
if (cellId == null) return null;
|
|
|
|
// Priority 1: Check network-synced cache (works on dedicated servers)
|
|
CellDataV2 synced = syncedCells.get(cellId);
|
|
if (synced != null) {
|
|
return synced;
|
|
}
|
|
|
|
// Priority 2: Check legacy single-cell cache
|
|
if (cellId.equals(cachedCellId) && cachedCellData != null) {
|
|
return cachedCellData;
|
|
}
|
|
|
|
// Priority 3: On integrated server, access server level directly (fallback)
|
|
Minecraft mc = Minecraft.getInstance();
|
|
if (mc.getSingleplayerServer() != null) {
|
|
ServerLevel serverLevel = mc.getSingleplayerServer().overworld();
|
|
if (serverLevel != null) {
|
|
CellRegistryV2 registry = CellRegistryV2.get(serverLevel);
|
|
CellDataV2 cell = registry.getCell(cellId);
|
|
if (cell != null) {
|
|
// Cache for future use
|
|
cachedCellId = cellId;
|
|
cachedCellData = cell;
|
|
return cell;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Not found - on dedicated server, packet hasn't arrived yet
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Update cached cell data (called from network sync - PacketSyncCellData).
|
|
* Stores in both the synced map and legacy cache for compatibility.
|
|
*
|
|
* @param cell The cell data received from server
|
|
*/
|
|
public static void updateCachedCell(CellDataV2 cell) {
|
|
if (cell != null) {
|
|
// Store in synced map
|
|
syncedCells.put(cell.getId(), cell);
|
|
|
|
// Also update legacy cache
|
|
cachedCellId = cell.getId();
|
|
cachedCellData = cell;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a cell from the cache (e.g., when cell is deleted).
|
|
*
|
|
* @param cellId The cell UUID to remove
|
|
*/
|
|
public static void removeCachedCell(UUID cellId) {
|
|
if (cellId != null) {
|
|
syncedCells.remove(cellId);
|
|
if (cellId.equals(cachedCellId)) {
|
|
cachedCellId = null;
|
|
cachedCellData = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all cached cell data.
|
|
* Called when disconnecting from server or on dimension change.
|
|
*/
|
|
public static void clearCache() {
|
|
syncedCells.clear();
|
|
cachedCellId = null;
|
|
cachedCellData = null;
|
|
}
|
|
}
|