9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

Support CE block display names in WorldEdit

This commit is contained in:
iqtester
2025-03-25 22:28:29 +08:00
parent 10b675ae5d
commit 08b6b352e1
4 changed files with 166 additions and 24 deletions

View File

@@ -7,6 +7,7 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import dev.dejvokep.boostedyaml.YamlDocument;
import net.momirealms.craftengine.bukkit.block.worldedit.WorldEditHook;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.plugin.injector.BukkitInjector;
import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers;
@@ -84,6 +85,8 @@ public class BukkitBlockManager extends AbstractBlockManager {
private final Map<Key, JsonElement> modBlockStates = new HashMap<>();
// Cached command suggestions
private final List<Suggestion> cachedSuggestions = new ArrayList<>();
// Cached Namespace
private final Set<String> cachedNamespaces = new HashSet<>();
// Event listeners
private final BlockEventListener blockEventListener;
private final FallingBlockRemoveListener fallingBlockRemoveListener;
@@ -235,6 +238,22 @@ public class BukkitBlockManager extends AbstractBlockManager {
for (String state : states) {
this.cachedSuggestions.add(Suggestion.suggestion(state));
}
this.cachedNamespaces.clear();
initCachedNamespaces();
}
private void initCachedNamespaces() {
for (Suggestion suggestion : this.cachedSuggestions) {
String id = suggestion.suggestion();
int index = id.indexOf(':');
if (index != -1) {
cachedNamespaces.add(id.substring(0, index));
}
}
}
public Collection<String> cachedNamespaces() {
return Collections.unmodifiableSet(cachedNamespaces);
}
public ImmutableMap<Key, List<Integer>> blockAppearanceArranger() {

View File

@@ -1,24 +0,0 @@
package net.momirealms.craftengine.bukkit.block;
import com.sk89q.worldedit.bukkit.BukkitBlockRegistry;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.world.block.BlockType;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import org.bukkit.Material;
import java.lang.reflect.Field;
public class WorldEditHook {
private static final Field field$BlockType$blockMaterial;
static {
field$BlockType$blockMaterial = ReflectionUtils.getDeclaredField(BlockType.class, "blockMaterial");
}
public static void register(Key id) throws ReflectiveOperationException {
BlockType blockType = new BlockType(id.toString(), blockState -> blockState);
field$BlockType$blockMaterial.set(blockType, LazyReference.from(() -> new BukkitBlockRegistry.BukkitBlockMaterial(null, Material.STONE)));
BlockType.REGISTRY.register(id.toString(), blockType);
}
}

View File

@@ -0,0 +1,31 @@
package net.momirealms.craftengine.bukkit.block.worldedit;
import java.util.Set;
import java.util.function.Predicate;
public class SuggestionHandler {
private final Predicate<String> matcher;
private SuggestionHandler(Predicate<String> matcher) {
this.matcher = matcher;
}
public boolean matches(String input) {
return matcher.test(input);
}
public static SuggestionHandler of(Integer... pos) {
Set<Integer> valid = Set.of(pos);
return new SuggestionHandler(input -> {
if (input.contains(" ")) return false;
String[] args = input.split(" ");
int index = input.endsWith(" ") ? args.length : args.length - 1;
return valid.contains(index);
});
}
public static SuggestionHandler custom(Predicate<String> matcher) {
return new SuggestionHandler(matcher);
}
}

View File

@@ -0,0 +1,116 @@
package net.momirealms.craftengine.bukkit.block.worldedit;
import com.google.common.collect.ImmutableMap;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.bukkit.BukkitBlockRegistry;
import com.sk89q.worldedit.event.platform.CommandSuggestionEvent;
import com.sk89q.worldedit.internal.util.Substring;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.eventbus.Subscribe;
import com.sk89q.worldedit.world.block.BlockType;
import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine;
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
import net.momirealms.craftengine.core.block.BlockStateParser;
import net.momirealms.craftengine.core.block.ImmutableBlockState;
import net.momirealms.craftengine.core.util.Key;
import net.momirealms.craftengine.core.util.ReflectionUtils;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.incendo.cloud.suggestion.Suggestion;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class WorldEditHook implements Listener {
private static final Field field$BlockType$blockMaterial;
private final Map<String, SuggestionHandler> handlers = ImmutableMap.of(
"//set", SuggestionHandler.of(1),
"//replace", SuggestionHandler.of(1, 2)
);
static {
WorldEdit.getInstance().getEventBus().register(new WorldEditHook());
field$BlockType$blockMaterial = ReflectionUtils.getDeclaredField(BlockType.class, "blockMaterial");
}
public static void register(Key id) throws ReflectiveOperationException {
BlockType blockType = new BlockType(id.toString(), blockState -> blockState);
field$BlockType$blockMaterial.set(blockType, LazyReference.from(() -> new BukkitBlockRegistry.BukkitBlockMaterial(null, Material.STONE)));
BlockType.REGISTRY.register(id.toString(), blockType);
}
public WorldEditHook() {
Bukkit.getPluginManager().registerEvents(this, BukkitCraftEngine.instance().bootstrap());
}
@Subscribe
public void onSuggestion(CommandSuggestionEvent event) {
String input = event.getArguments();
String command = input.substring(0, input.indexOf(" "));
SuggestionHandler handler = handlers.get(command);
if (handler == null || !handler.matches(input)) return;
int start = input.lastIndexOf(" ") + 1;
int end = input.length();
if (start == end) {
List<Substring> suggestions = BukkitCraftEngine.instance().blockManager().cachedNamespaces()
.stream()
.map(ns -> Substring.wrap(ns + ":", start, end))
.collect(Collectors.toList());
suggestions.addAll(event.getSuggestions());
event.setSuggestions(suggestions);
return;
}
String last = input.substring(start, end);
List<Substring> suggestions = new ArrayList<>();
for (Suggestion s : BukkitCraftEngine.instance().blockManager().cachedSuggestions()) {
String id = s.suggestion();
if (id.startsWith(last))
suggestions.add(Substring.wrap(id, start, end));
}
suggestions.addAll(event.getSuggestions());
event.setSuggestions(suggestions);
}
@EventHandler(priority = EventPriority.HIGH)
public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) {
String message = event.getMessage();
if (!message.startsWith("//")) return;
Collection<String> cachedNamespaces = BukkitCraftEngine.instance().blockManager().cachedNamespaces();
String[] args = message.split(" ");
boolean modified = false;
for (int i = 1; i < args.length; i++) {
String token = args[i];
int colon = token.indexOf(':');
if (colon == -1) continue;
String namespace = token.substring(0, colon);
if (!cachedNamespaces.contains(namespace)) continue;
ImmutableBlockState state = BlockStateParser.deserialize(token);
if (state == null) continue;
String internalId = BlockStateUtils.getBlockOwnerIdFromState(state.customBlockState().handle()).toString();
args[i] = internalId;
modified = true;
}
if (modified) {
event.setMessage(String.join(" ", args));
}
}
}