mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-28 03:19:14 +00:00
Merge pull request #154 from jhqwqmc/dev
feat(compatibility): 兼容FAWE的//set和//replace
This commit is contained in:
@@ -26,9 +26,6 @@ dependencies {
|
||||
compileOnly("pers.neige.neigeitems:NeigeItems:1.21.42")
|
||||
// Placeholder
|
||||
compileOnly("me.clip:placeholderapi:${rootProject.properties["placeholder_api_version"]}")
|
||||
// WorldEdit
|
||||
compileOnly("com.sk89q.worldedit:worldedit-core:7.2.19")
|
||||
compileOnly("com.sk89q.worldedit:worldedit-bukkit:7.2.19")
|
||||
// SlimeWorld
|
||||
compileOnly("com.infernalsuite.asp:api:4.0.0-SNAPSHOT")
|
||||
// ModelEngine
|
||||
@@ -44,6 +41,10 @@ dependencies {
|
||||
compileOnly("com.viaversion:viaversion-api:5.3.2")
|
||||
// Skript
|
||||
compileOnly("com.github.SkriptLang:Skript:2.11.0")
|
||||
// FAWE
|
||||
compileOnly(platform("com.intellectualsites.bom:bom-newest:1.52"))
|
||||
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Core")
|
||||
compileOnly("com.fastasyncworldedit:FastAsyncWorldEdit-Bukkit") { isTransitive = false }
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
package net.momirealms.craftengine.bukkit.compatibility.worldedit;
|
||||
|
||||
import com.fastasyncworldedit.core.configuration.Settings;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
import com.sk89q.worldedit.event.extent.EditSessionEvent;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
import com.sk89q.worldedit.util.eventbus.Subscribe;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
import net.momirealms.craftengine.bukkit.block.BukkitBlockManager;
|
||||
import net.momirealms.craftengine.bukkit.util.BlockStateUtils;
|
||||
import net.momirealms.craftengine.core.block.EmptyBlock;
|
||||
import net.momirealms.craftengine.core.plugin.CraftEngine;
|
||||
import net.momirealms.craftengine.core.world.CEWorld;
|
||||
import net.momirealms.craftengine.core.world.ChunkPos;
|
||||
import net.momirealms.craftengine.core.world.chunk.CEChunk;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class FastAsyncWorldEditDelegate extends AbstractDelegateExtent {
|
||||
private final Set<CEChunk> needSaveChunks;
|
||||
private final CEWorld ceWorld;
|
||||
|
||||
protected FastAsyncWorldEditDelegate(EditSessionEvent event) {
|
||||
super(event.getExtent());
|
||||
this.needSaveChunks = new HashSet<>();
|
||||
var weWorld = event.getWorld();
|
||||
var world = Bukkit.getWorld(requireNonNull(weWorld).getName());
|
||||
var ceWorld = CraftEngine.instance().worldManager().getWorld(requireNonNull(world).getUID());
|
||||
this.ceWorld = requireNonNull(ceWorld);
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
Settings.settings().EXTENT.ALLOWED_PLUGINS.add(FastAsyncWorldEditDelegate.class.getCanonicalName());
|
||||
WorldEdit.getInstance().getEventBus().register(new Object() {
|
||||
@Subscribe
|
||||
@SuppressWarnings("unused")
|
||||
public void onEditSessionEvent(EditSessionEvent event) {
|
||||
if (event.getStage() != EditSession.Stage.BEFORE_HISTORY) return;
|
||||
event.setExtent(new FastAsyncWorldEditDelegate(event));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBlocks(final Set<BlockVector3> vset, final Pattern pattern) {
|
||||
this.processBlocks(vset, pattern);
|
||||
return super.setBlocks(vset, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBlocks(final Region region, final Pattern pattern) {
|
||||
this.processBlocks(region, pattern);
|
||||
return super.setBlocks(region, pattern);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> int setBlocks(final Region region, final B block) {
|
||||
this.processBlocks(region, block);
|
||||
return super.setBlocks(region, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int replaceBlocks(Region region, Mask mask, Pattern pattern) {
|
||||
this.processBlocks(region, pattern);
|
||||
return super.replaceBlocks(region, mask, pattern);
|
||||
}
|
||||
@Override
|
||||
public <B extends BlockStateHolder<B>> int replaceBlocks(final Region region, final Set<BaseBlock> filter, final B replacement) {
|
||||
this.processBlocks(region, replacement);
|
||||
return super.replaceBlocks(region, filter, replacement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int replaceBlocks(final Region region, final Set<BaseBlock> filter, final Pattern pattern) {
|
||||
this.processBlocks(region, pattern);
|
||||
return super.replaceBlocks(region, filter, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(int x, int y, int z, T block) {
|
||||
try {
|
||||
BaseBlock oldBlockState = getBlock(x, y, z).toBaseBlock();
|
||||
this.processBlock(x, y, z, block.toBaseBlock(), oldBlockState);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Error when recording FastAsyncWorldEdit operation blocks", e);
|
||||
}
|
||||
return super.setBlock(x, y, z, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) {
|
||||
try {
|
||||
BaseBlock oldBlockState = getBlock(position).toBaseBlock();
|
||||
this.processBlock(position.x(), position.y(), position.z(), block.toBaseBlock(), oldBlockState);
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Error when recording FastAsyncWorldEdit operation blocks", e);
|
||||
}
|
||||
return super.setBlock(position, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Operation commitBefore() {
|
||||
saveAllChunks();
|
||||
return super.commitBefore();
|
||||
}
|
||||
|
||||
private void processBlocks(Iterable<BlockVector3> region, Pattern pattern) {
|
||||
try {
|
||||
for (BlockVector3 position : region) {
|
||||
BaseBlock blockState = pattern.applyBlock(position);
|
||||
BaseBlock oldBlockState = getBlock(position).toBaseBlock();
|
||||
int blockX = position.x();
|
||||
int blockY = position.y();
|
||||
int blockZ = position.z();
|
||||
this.processBlock(blockX, blockY, blockZ, blockState, oldBlockState);
|
||||
}
|
||||
saveAllChunks();
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Error when recording FastAsyncWorldEdit operation blocks", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processBlock(int blockX, int blockY, int blockZ, BaseBlock blockState, BaseBlock oldBlockState) throws IOException {
|
||||
int chunkX = blockX >> 4;
|
||||
int chunkZ = blockZ >> 4;
|
||||
int stateId = BlockStateUtils.blockDataToId(Bukkit.createBlockData(blockState.getAsString()));
|
||||
int oldStateId = BlockStateUtils.blockDataToId(Bukkit.createBlockData(oldBlockState.getAsString()));
|
||||
if (BlockStateUtils.isVanillaBlock(stateId) && BlockStateUtils.isVanillaBlock(oldStateId)) return;
|
||||
var ceChunk = this.ceWorld.getChunkAtIfLoaded(chunkX, chunkZ);
|
||||
if (ceChunk == null) {
|
||||
ceChunk = this.ceWorld.worldDataStorage().readChunkAt(this.ceWorld, new ChunkPos(chunkX, chunkZ));
|
||||
}
|
||||
var immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId);
|
||||
if (immutableBlockState == null) {
|
||||
ceChunk.setBlockState(blockX, blockY, blockZ, EmptyBlock.STATE);
|
||||
} else {
|
||||
ceChunk.setBlockState(blockX, blockY, blockZ, immutableBlockState);
|
||||
}
|
||||
this.needSaveChunks.add(ceChunk);
|
||||
}
|
||||
|
||||
private void saveAllChunks() {
|
||||
try {
|
||||
for (CEChunk ceChunk : this.needSaveChunks) {
|
||||
this.ceWorld.worldDataStorage().writeChunkAt(ceChunk.chunkPos(), ceChunk, true);
|
||||
}
|
||||
this.needSaveChunks.clear();
|
||||
} catch (Exception e) {
|
||||
CraftEngine.instance().logger().warn("Error when recording FastAsyncWorldEdit operation chunks", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,12 @@ public class WorldEditBlockRegister {
|
||||
this.isFAWE = isFAWE;
|
||||
CEBlockParser blockParser = new CEBlockParser(WorldEdit.getInstance());
|
||||
WorldEdit.getInstance().getBlockFactory().register(blockParser);
|
||||
if (isFAWE) {
|
||||
FastAsyncWorldEditDelegate.init();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void register(Key id) throws ReflectiveOperationException {
|
||||
BlockType blockType = new BlockType(id.toString(), blockState -> blockState);
|
||||
this.field$BlockType$blockMaterial.set(blockType, LazyReference.from(() -> new BukkitBlockRegistry.BukkitBlockMaterial(null, Material.STONE)));
|
||||
@@ -45,6 +49,7 @@ public class WorldEditBlockRegister {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public Stream<String> getSuggestions(String input) {
|
||||
Set<String> namespacesInUse = manager.namespacesInUse();
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ warning.config.image.invalid_font_chars: "<yellow>Issue found in file <arg:0> -
|
||||
warning.config.image.missing_char: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'char' argument.</yellow>"
|
||||
warning.config.image.codepoint_conflict: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is using a character '<arg:3>(<arg:4>)' in font <arg:2> that has been used by another image '<arg:5>'.</yellow>"
|
||||
warning.config.image.invalid_codepoint_grid: "<yellow>Issue found in file <arg:0> - Image '<arg:1>' has an invalid 'chars' codepoint grid.</yellow>"
|
||||
warning.config.image.invalid_char: "<yellow>Issue found in file <arg:0> - Image '<arg:1>' has a char parameter containing combining characters, which may result in image splitting.</yellow>"
|
||||
warning.config.image.file_not_found: "<yellow>Issue found in file <arg:0> - PNG file '<arg:2>' not found for image '<arg:1>'.</yellow>"
|
||||
warning.config.image.invalid_hex_value: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is using a unicode character '<arg:2>' that is not a valid hexadecimal (radix 16) value.</yellow>"
|
||||
warning.config.recipe.duplicate: "<yellow>Issue found in file <arg:0> - Duplicated recipe '<arg:1>'. Please check if there is the same configuration in other files.</yellow>"
|
||||
|
||||
@@ -80,6 +80,7 @@ warning.config.image.invalid_font_chars: "<yellow>在文件 <arg:0> 发现问题
|
||||
warning.config.image.missing_char: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 缺少必需的 'char' 参数</yellow>"
|
||||
warning.config.image.codepoint_conflict: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 在字体 <arg:2> 中使用的字符 '<arg:3>(<arg:4>)' 已被其他图片 '<arg:5>' 占用</yellow>"
|
||||
warning.config.image.invalid_codepoint_grid: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 的 'chars' 码位网格无效</yellow>"
|
||||
warning.config.image.invalid_char: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 的 'char' 参数包含组合字符可能导致图片分裂</yellow>"
|
||||
warning.config.image.file_not_found: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 的 PNG 文件 '<arg:2>' 未找到</yellow>"
|
||||
warning.config.image.invalid_hex_value: "<yellow>在文件 <arg:0> 发现问题 - 图片 '<arg:1>' 使用的 Unicode 字符 '<arg:2>' 不是有效的十六进制值</yellow>"
|
||||
warning.config.recipe.duplicate: "<yellow>在文件 <arg:0> 发现问题 - 重复的配方 '<arg:1>' 请检查其他文件中是否存在相同配置</yellow>"
|
||||
|
||||
@@ -462,7 +462,18 @@ public abstract class AbstractFontManager implements FontManager {
|
||||
if (character.length() == 1) {
|
||||
chars = List.of(character.toCharArray());
|
||||
} else {
|
||||
chars = List.of(CharacterUtils.decodeUnicodeToChars(character));
|
||||
if (character.startsWith("\\u")) {
|
||||
chars = List.of(CharacterUtils.decodeUnicodeToChars(character));
|
||||
} else {
|
||||
if (CharacterUtils.containsCombinedCharacter(character)) {
|
||||
TranslationManager.instance().log("warning.config.image.invalid_char", path.toString(), id.toString());
|
||||
}
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (char c : character.toCharArray()) {
|
||||
stringBuilder.append(String.format("\\u%04x", (int) c));
|
||||
}
|
||||
chars = List.of(CharacterUtils.decodeUnicodeToChars(stringBuilder.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.momirealms.craftengine.core.util;
|
||||
|
||||
import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class CharacterUtils {
|
||||
@@ -72,4 +73,27 @@ public class CharacterUtils {
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static boolean containsCombinedCharacter(String input) {
|
||||
if (input == null || input.isEmpty() || input.length() == 1) return false;
|
||||
for (int i = 0; i < input.length();) {
|
||||
int codePoint = input.codePointAt(i);
|
||||
i += Character.charCount(codePoint);
|
||||
int type = Character.getType(codePoint);
|
||||
if (type == Character.NON_SPACING_MARK ||
|
||||
type == Character.ENCLOSING_MARK ||
|
||||
type == Character.COMBINING_SPACING_MARK ||
|
||||
type == Character.FORMAT ||
|
||||
type == Character.CONTROL ||
|
||||
type == Character.SURROGATE ||
|
||||
type == Character.PRIVATE_USE ||
|
||||
Pattern.compile("[\\p{Mn}\\p{Me}\\p{Mc}\\p{Cf}]").matcher(new String(Character.toChars(codePoint))).find()
|
||||
) return true;
|
||||
if (i < input.length()) {
|
||||
int nextCodePoint = input.codePointAt(i);
|
||||
if (Character.isSurrogatePair(Character.toChars(codePoint)[0], Character.toChars(nextCodePoint)[0])) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G
|
||||
# Rule: [major update].[feature update].[bug fix]
|
||||
project_version=0.0.53-beta.1
|
||||
config_version=31
|
||||
lang_version=9
|
||||
lang_version=10
|
||||
project_group=net.momirealms
|
||||
latest_supported_version=1.21.5
|
||||
|
||||
|
||||
Reference in New Issue
Block a user