Skip to content

Commit

Permalink
Report and ban update (saving urls into world save data)
Browse files Browse the repository at this point in the history
  • Loading branch information
ustc-zzzz committed Apr 2, 2023
1 parent 75a6785 commit 446b646
Show file tree
Hide file tree
Showing 22 changed files with 1,358 additions and 488 deletions.
26 changes: 22 additions & 4 deletions src/main/java/org/teacon/slides/ModRegistries.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegisterEvent;
import net.minecraftforge.registries.RegistryObject;
import org.teacon.slides.network.ProjectorURLPrefetchPacket;
import org.teacon.slides.network.ProjectorURLRequestPacket;
import org.teacon.slides.network.ProjectorUpdatePacket;
import org.teacon.slides.url.ProjectorURLArgument;
import org.teacon.slides.projector.*;

import javax.annotation.ParametersAreNonnullByDefault;
Expand All @@ -32,7 +36,9 @@ public final class ModRegistries {
// Last Update: Thu, 17 Dec 2020 15:00:00 +0800 (0 => 1)
// Last Update: Tue, 18 Jan 2022 20:00:00 +0800 (1 => 2)
// Last Update: Sun, 26 Mar 2023 22:00:00 +0800 (2 => 3)
public static final String NETWORK_VERSION = "2";
public static final String NETWORK_VERSION = "3";

public static final ResourceLocation PROJECTOR_URL_ID = new ResourceLocation(SlideShow.ID, "projector_url");

public static final ResourceLocation PROJECTOR_ID = new ResourceLocation(SlideShow.ID, "projector");

Expand Down Expand Up @@ -60,18 +66,30 @@ public static void register(final RegisterEvent event) {
event.register(ForgeRegistries.ITEMS.getRegistryKey(), PROJECTOR_ID, ProjectorItem::new);
event.register(ForgeRegistries.BLOCK_ENTITY_TYPES.getRegistryKey(), PROJECTOR_ID, ProjectorBlockEntity::create);
event.register(ForgeRegistries.MENU_TYPES.getRegistryKey(), PROJECTOR_ID, ProjectorContainerMenu::create);
event.register(ForgeRegistries.COMMAND_ARGUMENT_TYPES.getRegistryKey(), PROJECTOR_URL_ID, ProjectorURLArgument::create);
}

@SubscribeEvent
public static void setupCommon(final FMLCommonSetupEvent event) {
// register network channel
int index = 0;
// noinspection UnusedAssignment
var index = 0;
CHANNEL.registerMessage(index++,
ProjectorUpdatePacket.class,
ProjectorUpdatePacket::write,
ProjectorUpdatePacket::new,
ProjectorUpdatePacket::handle,
Optional.of(NetworkDirection.PLAY_TO_SERVER));
CHANNEL.registerMessage(index++,
ProjectorURLPrefetchPacket.class,
ProjectorURLPrefetchPacket::write,
ProjectorURLPrefetchPacket::new,
ProjectorURLPrefetchPacket::handle,
Optional.of(NetworkDirection.PLAY_TO_CLIENT));
CHANNEL.registerMessage(index++,
ProjectorURLRequestPacket.class,
ProjectorURLRequestPacket::write,
ProjectorURLRequestPacket::new,
ProjectorURLRequestPacket::handle,
Optional.of(NetworkDirection.PLAY_TO_SERVER));
SlideShow.LOGGER.info("Registered {} network packages (version {})", index, NETWORK_VERSION);
}
}
87 changes: 87 additions & 0 deletions src/main/java/org/teacon/slides/admin/SlideCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package org.teacon.slides.admin;

import com.mojang.brigadier.Command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.DynamicCommandExceptionType;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.apache.commons.lang3.StringUtils;
import org.teacon.slides.SlideShow;
import org.teacon.slides.url.ProjectorURLArgument;
import org.teacon.slides.url.ProjectorURLSavedData;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Optional;
import java.util.UUID;

import static net.minecraft.commands.Commands.argument;
import static net.minecraft.commands.Commands.literal;

@FieldsAreNonnullByDefault
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.FORGE)
public class SlideCommand {
private static final DynamicCommandExceptionType URL_NOT_EXIST = new DynamicCommandExceptionType(v -> Component.translatable("command.slide_show.failed.url_not_exist", v));

@SubscribeEvent
public static void onCommandsRegister(RegisterCommandsEvent event) {
var node = event.getDispatcher().register(command(SlideShow.ID.replace('_', '-')));
event.getDispatcher().register(literal(StringUtils.substringBefore(SlideShow.ID, '_')).redirect(node));
}

private static LiteralArgumentBuilder<CommandSourceStack> command(String name) {
return literal(name)
.then(literal("block")
.then(argument("url", new ProjectorURLArgument())
.executes(SlideCommand::blockByProjectorUrl)))
.then(literal("unblock")
.then(argument("url", new ProjectorURLArgument())
.executes(SlideCommand::unblockByProjectorUrl)));
}

private static int blockByProjectorUrl(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
// noinspection DuplicatedCode
var level = ctx.getSource().getLevel();
var data = ProjectorURLSavedData.get(level);
var arg = ProjectorURLArgument.getUrl(ctx, "url");
var urlOptional = arg.map(data::getUrlById, Optional::of);
var uuidOptional = arg.map(Optional::of, data::getIdByUrl);
if (urlOptional.isPresent() && uuidOptional.isPresent()) {
var url = urlOptional.get();
var uuid = uuidOptional.get();
if (data.setBlockedStatusByCommand(uuid, url, ctx.getSource(), true)) {
var msg = Component.translatable("command.slide_show.block_projector_url.success", url, uuid);
ctx.getSource().sendSuccess(msg, true);
return Command.SINGLE_SUCCESS;
}
}
throw URL_NOT_EXIST.create(arg.map(UUID::toString, u -> u.toUrl().toString()));
}

private static int unblockByProjectorUrl(CommandContext<CommandSourceStack> ctx) throws CommandSyntaxException {
// noinspection DuplicatedCode
var level = ctx.getSource().getLevel();
var data = ProjectorURLSavedData.get(level);
var arg = ProjectorURLArgument.getUrl(ctx, "url");
var urlOptional = arg.map(data::getUrlById, Optional::of);
var uuidOptional = arg.map(Optional::of, data::getIdByUrl);
if (urlOptional.isPresent() && uuidOptional.isPresent()) {
var url = urlOptional.get();
var uuid = uuidOptional.get();
if (data.setBlockedStatusByCommand(uuid, url, ctx.getSource(), false)) {
var msg = Component.translatable("command.slide_show.unblock_projector_url.success", url, uuid);
ctx.getSource().sendSuccess(msg, true);
return Command.SINGLE_SUCCESS;
}
}
throw URL_NOT_EXIST.create(arg.map(UUID::toString, u -> u.toUrl().toString()));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.teacon.slides.permission;
package org.teacon.slides.admin;

import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.teacon.slides.network;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.PacketDistributor;
import org.teacon.slides.ModRegistries;
import org.teacon.slides.renderer.SlideState;
import org.teacon.slides.url.ProjectorURL;
import org.teacon.slides.url.ProjectorURLSavedData;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Set;
import java.util.UUID;
import java.util.function.Supplier;

@FieldsAreNonnullByDefault
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public final class ProjectorURLPrefetchPacket {
private final ImmutableSet<UUID> blockedIdSet;

private final ImmutableSet<UUID> nonExistentIdSet;

private final ImmutableMap<UUID, ProjectorURL> unblockedIdMap;

private enum Status {
END, BLOCKED, NON_EXISTENT, UNBLOCKED
}

public ProjectorURLPrefetchPacket(Set<UUID> idSet, ProjectorURLSavedData data) {
var blockedIdSetBuilder = ImmutableSet.<UUID>builder();
var nonExistentIdSetBuilder = ImmutableSet.<UUID>builder();
var unblockedIdMapBuilder = ImmutableMap.<UUID, ProjectorURL>builder();
for (var id : idSet) {
var url = data.getUrlById(id);
var isBlocked = data.isUrlBlocked(id);
if (isBlocked) {
blockedIdSetBuilder.add(id);
} else if (url.isEmpty()) {
nonExistentIdSetBuilder.add(id);
} else {
unblockedIdMapBuilder.put(id, url.get());
}
}
this.blockedIdSet = blockedIdSetBuilder.build();
this.nonExistentIdSet = nonExistentIdSetBuilder.build();
this.unblockedIdMap = unblockedIdMapBuilder.build();
}

public ProjectorURLPrefetchPacket(FriendlyByteBuf buf) {
var blockedIdSetBuilder = ImmutableSet.<UUID>builder();
var nonExistentIdSetBuilder = ImmutableSet.<UUID>builder();
var unblockedIdMapBuilder = ImmutableMap.<UUID, ProjectorURL>builder();
while (true) {
switch (buf.readEnum(Status.class)) {
case END -> {
this.blockedIdSet = blockedIdSetBuilder.build();
this.nonExistentIdSet = nonExistentIdSetBuilder.build();
this.unblockedIdMap = unblockedIdMapBuilder.build();
return;
}
case BLOCKED -> blockedIdSetBuilder.add(buf.readUUID());
case NON_EXISTENT -> nonExistentIdSetBuilder.add(buf.readUUID());
case UNBLOCKED -> unblockedIdMapBuilder.put(buf.readUUID(), new ProjectorURL(buf.readUtf()));
}
}
}

public void write(FriendlyByteBuf buf) {
this.blockedIdSet.forEach(uuid -> buf.writeEnum(Status.BLOCKED).writeUUID(uuid));
this.nonExistentIdSet.forEach(uuid -> buf.writeEnum(Status.NON_EXISTENT).writeUUID(uuid));
this.unblockedIdMap.forEach((uuid, url) -> buf.writeEnum(Status.UNBLOCKED).writeUUID(uuid).writeUtf(url.toUrl().toString()));
buf.writeEnum(Status.END);
}

public void sendToAll() {
ModRegistries.CHANNEL.send(PacketDistributor.ALL.noArg(), this);
}

public void sendToClient(ServerPlayer player) {
ModRegistries.CHANNEL.send(PacketDistributor.PLAYER.with(() -> player), this);
}

public void handle(Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> SlideState.applyPrefetch(this.blockedIdSet, this.nonExistentIdSet, this.unblockedIdMap));
context.get().setPacketHandled(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.teacon.slides.network;

import com.google.common.collect.ImmutableSet;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent;
import org.teacon.slides.ModRegistries;
import org.teacon.slides.projector.ProjectorBlockEntity;
import org.teacon.slides.url.ProjectorURLSavedData;

import javax.annotation.ParametersAreNonnullByDefault;
import java.util.LinkedHashSet;
import java.util.UUID;
import java.util.function.Supplier;

@FieldsAreNonnullByDefault
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public final class ProjectorURLRequestPacket {
private final ImmutableSet<BlockPos> requestedPosSet;

public ProjectorURLRequestPacket(Iterable<BlockPos> requested) {
this.requestedPosSet = ImmutableSet.copyOf(requested);
}

public ProjectorURLRequestPacket(FriendlyByteBuf buf) {
var builder = ImmutableSet.<BlockPos>builder();
for (var hasNext = buf.readBoolean(); hasNext; hasNext = buf.readBoolean()) {
builder.add(new BlockPos(buf.readVarInt(), buf.readVarInt(), buf.readVarInt()));
}
this.requestedPosSet = builder.build();
}

public void write(FriendlyByteBuf buf) {
for (var pos : this.requestedPosSet) {
buf.writeBoolean(true);
buf.writeVarInt(pos.getX());
buf.writeVarInt(pos.getY());
buf.writeVarInt(pos.getZ());
}
buf.writeBoolean(false);
}

public void sendToServer() {
ModRegistries.CHANNEL.sendToServer(this);
}

public void handle(Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> {
var player = context.get().getSender();
if (player != null) {
var level = player.getLevel();
var imageLocations = new LinkedHashSet<UUID>(this.requestedPosSet.size());
for (var pos : this.requestedPosSet) {
// prevent remote chunk loading
if (level.isLoaded(pos) && level.getBlockEntity(pos) instanceof ProjectorBlockEntity tile) {
imageLocations.add(tile.getImageLocation());
}
}
var data = ProjectorURLSavedData.get(level);
new ProjectorURLPrefetchPacket(imageLocations, data).sendToClient(player);
}
});
context.get().setPacketHandled(true);
}
}
Loading

0 comments on commit 446b646

Please sign in to comment.