Skip to content

Commit

Permalink
Add Display Mode Tool
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhuRuoLing committed Nov 8, 2024
1 parent ec363ed commit 84d7411
Show file tree
Hide file tree
Showing 18 changed files with 498 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Gadgets that online convention organizers may find useful when holding conventio
- 加速玩家:使用 `/accelerate` 命令改变玩家速度(或者使用 `/bathappy` 别名,让森林蝙蝠快乐)。
- `/accelerate <player> <multiply|add|set> <x> <y> <z>`
- `/accelerate <player> multiply <factor>`
- 展示模式工具:在方块上使用后该方块打开的gui将无法在非创造模式下进行任何操作,仅能查看。
- 未完待续 To be continued

## 鸣谢
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/teacon/powertool/PowerTool.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.teacon.powertool;

import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.Mod;
import org.teacon.powertool.attachment.PowerToolAttachments;
Expand All @@ -23,4 +24,9 @@ public PowerTool(ModContainer modContainer, IEventBus bus) {
PowerToolAttachments.register(bus);
PowerToolConfig.init(modContainer);
}

@SubscribeEvent
public void on(){

}
}
130 changes: 130 additions & 0 deletions src/main/java/org/teacon/powertool/PowerToolEvents.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package org.teacon.powertool;

import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.level.BlockEvent;
import net.neoforged.neoforge.event.level.ChunkWatchEvent;
import net.neoforged.neoforge.event.level.ExplosionEvent;
import net.neoforged.neoforge.network.PacketDistributor;
import org.teacon.powertool.attachment.PowerToolAttachments;
import org.teacon.powertool.network.client.UpdateDisplayChunkDataPacket;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@EventBusSubscriber(modid = PowerTool.MODID)
public class PowerToolEvents {

@SubscribeEvent
public static void on(ChunkWatchEvent.Sent event) {
ChunkPos chunkPos = event.getPos();
List<BlockPos> list = event.getChunk().getData(PowerToolAttachments.DISPLAY_MODE);
PacketDistributor.sendToPlayer(
event.getPlayer(),
new UpdateDisplayChunkDataPacket(
chunkPos.x,
chunkPos.z,
list
)
);
}

@SubscribeEvent
public static void on(ExplosionEvent.Detonate event) {
Map<ChunkPos, List<BlockPos>> map = new HashMap<>();
for (BlockPos affectedBlock : event.getAffectedBlocks()) {
map.computeIfAbsent(new ChunkPos(affectedBlock), it -> new ArrayList<>())
.add(affectedBlock);
}
map.entrySet()
.stream()
.map(it -> Map.entry(
Map.entry(
event.getLevel().getChunk(it.getKey().x, it.getKey().z),
it.getKey()
),
it.getValue()
))
.collect(Util.toMap())
.forEach((entry, list) -> {
LevelChunk chunk = entry.getKey();
ChunkPos pos = entry.getValue();
for (BlockPos blockPos : list) {
removeDisplayMode(
(ServerLevel) event.getLevel(),
pos,
chunk,
blockPos,
null
);
}
});
}

private static void removeDisplayMode(
ServerLevel level,
ChunkPos chunkPos,
ChunkAccess chunk,
BlockPos pos,
@Nullable ServerPlayer player
) {
List<BlockPos> displayEnabledPosList = chunk.getData(PowerToolAttachments.DISPLAY_MODE);
displayEnabledPosList.remove(pos);
chunk.setUnsaved(true);
chunk.setData(PowerToolAttachments.DISPLAY_MODE, displayEnabledPosList);
UpdateDisplayChunkDataPacket data = new UpdateDisplayChunkDataPacket(
chunkPos.x,
chunkPos.z,
displayEnabledPosList
);
if (player == null) {
PacketDistributor.sendToPlayersTrackingChunk(
level,
chunkPos,
data
);
return;
}
PacketDistributor.sendToPlayer(
player,
data
);
}

private static void removeDisplayMode(
ServerLevel level,
BlockPos pos,
@Nullable ServerPlayer player
) {
ChunkPos chunkPos = new ChunkPos(pos);
ChunkAccess chunk = level.getChunk(pos);
removeDisplayMode(
level,
chunkPos,
chunk,
pos,
player
);
}

@SubscribeEvent
public static void on(BlockEvent.BreakEvent event) {
ServerLevel level = (ServerLevel) event.getLevel();
BlockPos pos = event.getPos();
removeDisplayMode(
level,
pos,
(ServerPlayer) event.getPlayer()
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.teacon.powertool.attachment;

import net.minecraft.core.BlockPos;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.attachment.AttachmentType;
import net.neoforged.neoforge.registries.DeferredHolder;
Expand All @@ -8,14 +9,24 @@
import org.teacon.powertool.PowerTool;
import org.teacon.powertool.network.attachment.Permission;

import java.util.ArrayList;
import java.util.List;

public class PowerToolAttachments {

private static final DeferredRegister<AttachmentType<?>> ATTACHMENT_TYPE = DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, PowerTool.MODID);

public static final DeferredHolder<AttachmentType<?>,AttachmentType<Permission>> PERMISSION = ATTACHMENT_TYPE.register(Permission.KEY.getPath(),
() -> AttachmentType.builder(Permission::new).build());

public static void register(IEventBus bus){

public static final DeferredHolder<AttachmentType<?>, AttachmentType<Permission>> PERMISSION = ATTACHMENT_TYPE.register(Permission.KEY.getPath(),
() -> AttachmentType.builder(Permission::new).build());

public static final DeferredHolder<AttachmentType<?>, AttachmentType<List<BlockPos>>> DISPLAY_MODE = ATTACHMENT_TYPE.register(
"display_mode",
() -> AttachmentType.<List<BlockPos>>builder(() -> new ArrayList<>())
.serialize(BlockPos.CODEC.listOf())
.build()
);

public static void register(IEventBus bus) {
ATTACHMENT_TYPE.register(bus);
}
}
36 changes: 36 additions & 0 deletions src/main/java/org/teacon/powertool/client/ClientEvents.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent;
import net.neoforged.neoforge.client.event.ClientTickEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent;
import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent;
import net.neoforged.neoforge.client.event.ScreenEvent;
import net.neoforged.neoforge.client.gui.VanillaGuiLayers;
import org.lwjgl.glfw.GLFW;
import org.teacon.powertool.PowerTool;
import org.teacon.powertool.block.PowerToolBlocks;
import org.teacon.powertool.block.entity.PeriodicCommandBlockEntity;
Expand Down Expand Up @@ -101,6 +103,40 @@ static void drawRegisterInfo(Minecraft mc, GuiGraphics guiGraphics, ItemStack re
guiGraphics.pose().popPose();
}

@SubscribeEvent
static void on(ScreenEvent.MouseButtonPressed.Pre event) {
event.setCanceled(DisplayModeClient.INSTANCE.isDisplayModeEnabledOn(event.getScreen()));
}

@SubscribeEvent
static void on(ScreenEvent.MouseButtonReleased.Pre event) {
event.setCanceled(DisplayModeClient.INSTANCE.isDisplayModeEnabledOn(event.getScreen()));
}

@SubscribeEvent
static void on(ScreenEvent.KeyPressed.Pre event) {
if (event.getKeyCode() != GLFW.GLFW_KEY_ESCAPE) {
event.setCanceled(DisplayModeClient.INSTANCE.isDisplayModeEnabledOn(event.getScreen()));
}
}

@SubscribeEvent
static void on(ScreenEvent.KeyReleased.Pre event) {
if (event.getKeyCode() != GLFW.GLFW_KEY_ESCAPE) {
event.setCanceled(DisplayModeClient.INSTANCE.isDisplayModeEnabledOn(event.getScreen()));
}
}

@SubscribeEvent
static void on(ScreenEvent.CharacterTyped.Pre event) {
event.setCanceled(DisplayModeClient.INSTANCE.isDisplayModeEnabledOn(event.getScreen()));
}

@SubscribeEvent
static void on(ClientPlayerNetworkEvent.LoggingOut event) {
DisplayModeClient.INSTANCE.clear();
}

@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD, modid = PowerTool.MODID)
public static final class OnModBus {
@SubscribeEvent
Expand Down
45 changes: 45 additions & 0 deletions src/main/java/org/teacon/powertool/client/DisplayModeClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.teacon.powertool.client;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.ChunkPos;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DisplayModeClient {
public static final DisplayModeClient INSTANCE = new DisplayModeClient();
private final Map<ChunkPos, List<BlockPos>> data = new HashMap<>();
private BlockPos interactionSourcePos = null;

public boolean isDisplayModeEnabledOn(Screen screen) {
Player player = Minecraft.getInstance().player;
if (player == null || interactionSourcePos == null || player.getAbilities().instabuild) {
return false;
}
if (screen instanceof AbstractContainerScreen<? extends AbstractContainerMenu> abstractContainerScreen) {
ChunkPos pos = new ChunkPos(interactionSourcePos);
if (data.containsKey(pos)){
return data.get(pos).contains(interactionSourcePos);
}
}
return false;
}

public void clear() {
data.clear();
}

public void updateInteractionSource(BlockPos pos){
this.interactionSourcePos = pos;
}

public void update(ChunkPos chunkPos, List<BlockPos> blockPosList) {
data.put(chunkPos, blockPosList);
}
}
98 changes: 98 additions & 0 deletions src/main/java/org/teacon/powertool/item/DisplayModeToolItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.teacon.powertool.item;

import net.minecraft.ChatFormatting;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.neoforged.neoforge.network.PacketDistributor;
import org.teacon.powertool.attachment.PowerToolAttachments;
import org.teacon.powertool.network.client.UpdateDisplayChunkDataPacket;
import org.teacon.powertool.utils.VanillaUtils;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.ArrayList;
import java.util.List;

@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public class DisplayModeToolItem extends Item {
public DisplayModeToolItem(Properties properties) {
super(properties);
}

@Override
public boolean isFoil(ItemStack stack) {
return true;
}

@Override
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
tooltipComponents.add(
Component.translatable("tooltip.powertool.display_tool")
.withStyle(ChatFormatting.GRAY)
);
}

@Override
public InteractionResult useOn(UseOnContext context) {
Level level = context.getLevel();
BlockPos pos = context.getClickedPos();
Player player = context.getPlayer();
if (player == null || !player.getAbilities().instabuild) {
return InteractionResult.FAIL;
}
if (context.getLevel().isClientSide) {
return InteractionResult.SUCCESS;
}
BlockState blockState = level.getBlockState(pos);
MenuProvider menuProvider = blockState.getMenuProvider(level, pos);
Component blockName = VanillaUtils.getName(blockState.getBlock());
if (menuProvider == null) {
player.displayClientMessage(
Component.translatable("powertool.gui.display_mode_error", blockName)
.withStyle(ChatFormatting.RED),
true
);
return InteractionResult.SUCCESS;
}
ChunkPos chunkPos = new ChunkPos(pos);
ChunkAccess chunk = level.getChunkAt(pos);
List<BlockPos> displayEnabledPosList = new ArrayList<>(chunk.getData(PowerToolAttachments.DISPLAY_MODE));
if (displayEnabledPosList.contains(pos)) {
displayEnabledPosList.remove(pos);
player.displayClientMessage(
Component.translatable("powertool.gui.display_mode_disabled", blockName),
true
);
} else {
displayEnabledPosList.add(pos);
player.displayClientMessage(
Component.translatable("powertool.gui.display_mode_enabled", blockName),
true
);
}
chunk.setUnsaved(true);
chunk.setData(PowerToolAttachments.DISPLAY_MODE, displayEnabledPosList);
PacketDistributor.sendToPlayer(
(ServerPlayer) player,
new UpdateDisplayChunkDataPacket(
chunkPos.x,
chunkPos.z,
displayEnabledPosList
)
);
return InteractionResult.SUCCESS;
}
}
Loading

0 comments on commit 84d7411

Please sign in to comment.