feat:
1.制作中打开供应器高亮对应样板 2.优化高亮工具类
This commit is contained in:
parent
247081939f
commit
f254da43f4
|
|
@ -0,0 +1,47 @@
|
|||
package com.extendedae_plus.content;
|
||||
|
||||
import appeng.api.crafting.IPatternDetails;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public final class PatternHighlightStore {
|
||||
// 使用同步的 WeakHashMap 存储高亮状态,键为 IPatternDetails,值为 Boolean
|
||||
private static final Map<IPatternDetails, Boolean> HIGHLIGHTS = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
// 私有构造方法,防止实例化
|
||||
private PatternHighlightStore() {}
|
||||
|
||||
/**
|
||||
* 设置指定 details 的高亮状态。
|
||||
* @param details 需要设置的 IPatternDetails 实例
|
||||
* @param highlighted 是否高亮
|
||||
*/
|
||||
public static void setHighlight(IPatternDetails details, boolean highlighted) {
|
||||
if (details == null) return;
|
||||
if (highlighted) {
|
||||
HIGHLIGHTS.put(details, Boolean.TRUE); // 设置为高亮
|
||||
} else {
|
||||
HIGHLIGHTS.remove(details); // 移除高亮
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定 details 的高亮状态。
|
||||
* @param details 需要查询的 IPatternDetails 实例
|
||||
* @return 是否高亮
|
||||
*/
|
||||
public static boolean getHighlight(IPatternDetails details) {
|
||||
if (details == null) return false;
|
||||
Boolean v = HIGHLIGHTS.get(details);
|
||||
return v != null && v;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有高亮状态(在供应器界面关闭时调用)。
|
||||
*/
|
||||
public static void clearAll() {
|
||||
HIGHLIGHTS.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
package com.extendedae_plus.mixin.ae2.client.gui;
|
||||
|
||||
import appeng.api.crafting.PatternDetailsHelper;
|
||||
import appeng.api.stacks.AEKey;
|
||||
import appeng.client.Point;
|
||||
import appeng.client.gui.AEBaseScreen;
|
||||
|
|
@ -12,12 +13,14 @@ import appeng.client.gui.style.Text;
|
|||
import appeng.client.gui.style.TextAlignment;
|
||||
import appeng.menu.slot.AppEngSlot;
|
||||
import com.extendedae_plus.api.ExPatternPageAccessor;
|
||||
import com.extendedae_plus.content.PatternHighlightStore;
|
||||
import com.extendedae_plus.network.CraftingMonitorJumpC2SPacket;
|
||||
import com.extendedae_plus.network.CraftingMonitorOpenProviderC2SPacket;
|
||||
import com.extendedae_plus.network.ModNetwork;
|
||||
import com.extendedae_plus.util.GuiUtil;
|
||||
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.Rect2i;
|
||||
|
|
@ -150,40 +153,49 @@ public abstract class AEBaseScreenMixin {
|
|||
@Inject(method = "renderSlot", at = @At("TAIL"))
|
||||
private void eap$renderSlotAmounts(GuiGraphics guiGraphics, Slot s, CallbackInfo ci) {
|
||||
Object self = this;
|
||||
|
||||
|
||||
// 只处理AppEngSlot类型的槽位
|
||||
if (!(s instanceof AppEngSlot appEngSlot)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 检查槽位是否可见且有效
|
||||
if (!appEngSlot.isActive() || !appEngSlot.isSlotEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 获取槽位中的物品
|
||||
var itemStack = appEngSlot.getItem();
|
||||
if (itemStack.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 使用GuiUtil的格式化方法获取数量文本
|
||||
String amountText = GuiUtil.getPatternOutputText(itemStack);
|
||||
if (amountText.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 在槽位右下角绘制数量文本
|
||||
Font font = eap$getFont(self);
|
||||
GuiUtil.drawAmountText(guiGraphics, font, amountText, appEngSlot.x, appEngSlot.y, 0.6f);
|
||||
|
||||
try {
|
||||
var details = PatternDetailsHelper.decodePattern(itemStack, Minecraft.getInstance().level, false);
|
||||
if (PatternHighlightStore.getHighlight(details)) {
|
||||
try {
|
||||
GuiUtil.drawSlotRainbowHighlight(guiGraphics, s.x, s.y);
|
||||
} catch (Throwable ignored) {}
|
||||
}
|
||||
} catch (Throwable ignore) {}
|
||||
}
|
||||
|
||||
// 在 AEBaseScreen.drawText 完成某个文本绘制后,若该文本为“样板”标签,则紧接着绘制页码。
|
||||
@Inject(method = "drawText", at = @At("TAIL"), remap = false)
|
||||
private void eap$appendPageAfterPatternsLabel(GuiGraphics guiGraphics,
|
||||
Text text,
|
||||
@Nullable TextOverride override,
|
||||
CallbackInfo ci) {
|
||||
Text text,
|
||||
@Nullable TextOverride override,
|
||||
CallbackInfo ci) {
|
||||
Object self = this;
|
||||
if (!(self instanceof GuiExPatternProvider)) {
|
||||
return;
|
||||
|
|
@ -237,8 +249,10 @@ public abstract class AEBaseScreenMixin {
|
|||
if (!isPatterns) {
|
||||
String label = content.getString();
|
||||
if (label != null) {
|
||||
if (label.equals(Component.translatable("gui.pattern_provider.patterns").getString())) isPatterns = true;
|
||||
else if (label.equals(Component.translatable("gui.extendedae.patterns").getString())) isPatterns = true;
|
||||
if (label.equals(Component.translatable("gui.pattern_provider.patterns").getString()))
|
||||
isPatterns = true;
|
||||
else if (label.equals(Component.translatable("gui.extendedae.patterns").getString()))
|
||||
isPatterns = true;
|
||||
else if (label.equals(Component.translatable("gui.ae2.patterns").getString())) isPatterns = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -263,16 +277,18 @@ public abstract class AEBaseScreenMixin {
|
|||
if (v instanceof Integer i) {
|
||||
max = Math.max(1, i);
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
String pageText = "第"+cur+"页" + "/" + max + "页";
|
||||
String pageText = "第" + cur + "页" + "/" + max + "页";
|
||||
|
||||
ScreenStyle style = eap$getStyle(self);
|
||||
int color = 0xFFFFFFFF;
|
||||
if (style != null) {
|
||||
try {
|
||||
color = style.getColor(PaletteColor.DEFAULT_TEXT_COLOR).toARGB();
|
||||
} catch (Throwable ignored) {}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
int padding = 4;
|
||||
if (scale == 1.0f) {
|
||||
|
|
@ -284,6 +300,7 @@ public abstract class AEBaseScreenMixin {
|
|||
guiGraphics.drawString(font, pageText, lineWidth + padding, 0, color, false);
|
||||
guiGraphics.pose().popPose();
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.extendedae_plus.mixin.ae2.client.gui;
|
||||
|
||||
import appeng.client.gui.implementations.PatternProviderScreen;
|
||||
import com.extendedae_plus.content.PatternHighlightStore;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(value = AbstractContainerScreen.class, remap = false)
|
||||
public class PatternProviderCloseMixin {
|
||||
|
||||
@Shadow
|
||||
protected AbstractContainerMenu menu;
|
||||
|
||||
@Inject(method = "removed", at = @At("HEAD"))
|
||||
private void onRemoved(CallbackInfo ci) {
|
||||
try {
|
||||
if (((Object) this) instanceof PatternProviderScreen) {
|
||||
PatternHighlightStore.clearAll();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ import appeng.api.crafting.PatternDetailsHelper;
|
|||
import appeng.client.gui.AEBaseScreen;
|
||||
import appeng.client.gui.Icon;
|
||||
import appeng.client.gui.me.patternaccess.PatternContainerRecord;
|
||||
import appeng.client.gui.me.patternaccess.PatternSlot;
|
||||
import appeng.client.gui.style.ScreenStyle;
|
||||
import appeng.client.gui.widgets.AETextField;
|
||||
import appeng.client.gui.widgets.IconButton;
|
||||
|
|
@ -13,6 +12,7 @@ import com.extendedae_plus.config.ModConfigs;
|
|||
import com.extendedae_plus.mixin.extendedae.accessor.GuiExPatternTerminalAccessor;
|
||||
import com.extendedae_plus.network.ModNetwork;
|
||||
import com.extendedae_plus.network.OpenProviderUiC2SPacket;
|
||||
import com.extendedae_plus.util.GuiUtil;
|
||||
import com.glodblock.github.extendedae.client.gui.GuiExPatternTerminal;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
|
|
@ -76,41 +76,6 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
super(menu, playerInventory, title, style);
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static int eap$withAlpha(int rgb, int alpha255) {
|
||||
return ((alpha255 & 0xFF) << 24) | (rgb & 0x00FFFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 HSV 转换为 RGB(返回 0xRRGGBB,不含 alpha)。
|
||||
* h: 0.0~1.0,s: 0.0~1.0,v: 0.0~1.0
|
||||
*/
|
||||
@Unique
|
||||
private static int eap$hsvToRgb(float h, float s, float v) {
|
||||
if (s <= 0.0f) {
|
||||
int g = Math.round(v * 255.0f);
|
||||
return (g << 16) | (g << 8) | g;
|
||||
}
|
||||
float hh = (h - (float) Math.floor(h)) * 6.0f;
|
||||
int sector = (int) Math.floor(hh);
|
||||
float f = hh - sector;
|
||||
float p = v * (1.0f - s);
|
||||
float q = v * (1.0f - s * f);
|
||||
float t = v * (1.0f - s * (1.0f - f));
|
||||
float r, g, b;
|
||||
switch (sector) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
default: r = v; g = p; b = q; break;
|
||||
}
|
||||
int ri = Math.round(r * 255.0f);
|
||||
int gi = Math.round(g * 255.0f);
|
||||
int bi = Math.round(b * 255.0f);
|
||||
return (ri << 16) | (gi << 8) | bi;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前选择的样板供应器ID
|
||||
|
|
@ -579,53 +544,9 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
return;
|
||||
}
|
||||
|
||||
// 彩虹色的流转:基于时间在 HSV 色环上循环(4 秒为一周期)
|
||||
long now = System.currentTimeMillis();
|
||||
final long rainbowPeriodMs = 4000L;
|
||||
float hue = (now % rainbowPeriodMs) / (float) rainbowPeriodMs; // 0.0 ~ 1.0
|
||||
int rainbowRgb = eap$hsvToRgb(hue, 1.0f, 1.0f);
|
||||
// 使用 GuiUtil 的通用绘制方法绘制槽位高亮(包含彩虹流转效果)
|
||||
GuiUtil.drawPatternSlotHighlights(guiGraphics, this.menu.slots, this.matchedStack, this.matchedProvider);
|
||||
|
||||
for (Slot slot : this.menu.slots) {
|
||||
if (!(slot instanceof PatternSlot ps)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int sx = slot.x;
|
||||
int sy = slot.y;
|
||||
|
||||
boolean isMatchedSlot = this.matchedStack != null && this.matchedStack.contains(slot.getItem());
|
||||
boolean isMatchedProvider = false;
|
||||
try {
|
||||
PatternContainerRecord container = ps.getMachineInv();
|
||||
isMatchedProvider = this.matchedProvider != null && this.matchedProvider.contains(container);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
// 依据命中状态选择颜色方案
|
||||
int borderColor;
|
||||
int backgroundColor;
|
||||
|
||||
if (isMatchedSlot) {
|
||||
// 命中槽位:使用彩虹色边框与浅底色(固定透明度,呈现色相流转效果)
|
||||
borderColor = eap$withAlpha(rainbowRgb, 0xA0);
|
||||
backgroundColor = eap$withAlpha(rainbowRgb, 0x3C);
|
||||
} else if (!isMatchedProvider) {
|
||||
borderColor = eap$withAlpha(0xFFFFFF, 0x40);
|
||||
backgroundColor = eap$withAlpha(0x000000, 0x18);
|
||||
} else {
|
||||
borderColor = eap$withAlpha(0xFFFFFF, 0x30);
|
||||
backgroundColor = eap$withAlpha(0xFFFFFF, 0x14);
|
||||
}
|
||||
|
||||
// 绘制 18x18 边框(1px 宽)
|
||||
eap$fill(guiGraphics, new Rect2i(sx - 1, sy - 1, 18, 1), borderColor);
|
||||
eap$fill(guiGraphics, new Rect2i(sx - 1, sy + 16, 18, 1), borderColor);
|
||||
eap$fill(guiGraphics, new Rect2i(sx - 1, sy, 1, 16), borderColor);
|
||||
eap$fill(guiGraphics, new Rect2i(sx + 16, sy, 1, 16), borderColor);
|
||||
|
||||
// 绘制 16x16 浅底色(半透明,叠加在槽位上方)
|
||||
eap$fill(guiGraphics, new Rect2i(sx, sy, 16, 16), backgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import appeng.menu.AEBaseMenu;
|
|||
import appeng.menu.locator.MenuLocators;
|
||||
import appeng.menu.me.crafting.CraftingCPUMenu;
|
||||
import appeng.parts.AEBasePart;
|
||||
import com.extendedae_plus.content.PatternHighlightStore;
|
||||
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
|
@ -99,6 +100,9 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
} else {
|
||||
host.openMenu(player, MenuLocators.forBlockEntity(pbe));
|
||||
}
|
||||
|
||||
PatternHighlightStore.setHighlight(pattern, true);
|
||||
|
||||
context.setPacketHandled(true);
|
||||
return;
|
||||
} catch (Throwable t) {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,17 @@ package com.extendedae_plus.util;
|
|||
|
||||
import appeng.api.crafting.PatternDetailsHelper;
|
||||
import appeng.api.stacks.GenericStack;
|
||||
import appeng.client.gui.me.patternaccess.PatternContainerRecord;
|
||||
import appeng.client.gui.me.patternaccess.PatternSlot;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* GUI工具类,提供样板获取、绘制等通用功能
|
||||
|
|
@ -77,4 +83,105 @@ public class GuiUtil {
|
|||
guiGraphics.drawString(font, text, (int)(textX / scale), (int)(textY / scale), 0xFFFFFFFF, true);
|
||||
guiGraphics.pose().popPose();
|
||||
}
|
||||
|
||||
// Helper: add alpha channel to RGB (rgb is 0xRRGGBB)
|
||||
private static int withAlpha(int rgb, int alpha255) {
|
||||
return ((alpha255 & 0xFF) << 24) | (rgb & 0x00FFFFFF);
|
||||
}
|
||||
|
||||
// HSV -> RGB (returns 0xRRGGBB)
|
||||
private static int hsvToRgb(float h, float s, float v) {
|
||||
if (s <= 0.0f) {
|
||||
int g = Math.round(v * 255.0f);
|
||||
return (g << 16) | (g << 8) | g;
|
||||
}
|
||||
float hh = (h - (float) Math.floor(h)) * 6.0f;
|
||||
int sector = (int) Math.floor(hh);
|
||||
float f = hh - sector;
|
||||
float p = v * (1.0f - s);
|
||||
float q = v * (1.0f - s * f);
|
||||
float t = v * (1.0f - s * (1.0f - f));
|
||||
float r, g, b;
|
||||
switch (sector) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
default: r = v; g = p; b = q; break;
|
||||
}
|
||||
int ri = Math.round(r * 255.0f);
|
||||
int gi = Math.round(g * 255.0f);
|
||||
int bi = Math.round(b * 255.0f);
|
||||
return (ri << 16) | (gi << 8) | bi;
|
||||
}
|
||||
|
||||
// 返回当前时间对应的彩虹色(0xRRGGBB),周期固定为 4000ms
|
||||
private static int getRainbowRgb() {
|
||||
long now = System.currentTimeMillis();
|
||||
final long rainbowPeriodMs = 4000L;
|
||||
float hue = (now % rainbowPeriodMs) / (float) rainbowPeriodMs; // 0.0 ~ 1.0
|
||||
return hsvToRgb(hue, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
// 在给定槽位坐标绘制 1px 边框(18x18)和 16x16 半透明背景
|
||||
private static void drawSlotBox(GuiGraphics guiGraphics, int sx, int sy, int borderColor, int backgroundColor) {
|
||||
guiGraphics.fill(sx - 1, sy - 1, sx + 17, sy, borderColor);
|
||||
guiGraphics.fill(sx - 1, sy + 16, sx + 17, sy + 17, borderColor);
|
||||
guiGraphics.fill(sx - 1, sy, sx, sy + 16, borderColor);
|
||||
guiGraphics.fill(sx + 16, sy, sx + 17, sy + 16, borderColor);
|
||||
guiGraphics.fill(sx, sy, sx + 16, sy + 16, backgroundColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在槽位上绘制彩色流转的高亮和浅底色
|
||||
*/
|
||||
public static void drawPatternSlotHighlights(GuiGraphics guiGraphics, List<Slot> slots, Set<ItemStack> matchedStack, Set<PatternContainerRecord> matchedProvider) {
|
||||
if (slots == null) return;
|
||||
|
||||
int rainbowRgb = getRainbowRgb();
|
||||
|
||||
for (Slot slot : slots) {
|
||||
if (!(slot instanceof PatternSlot ps)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int sx = slot.x;
|
||||
int sy = slot.y;
|
||||
|
||||
boolean isMatchedSlot = matchedStack != null && matchedStack.contains(slot.getItem());
|
||||
boolean isMatchedProvider = false;
|
||||
try {
|
||||
PatternContainerRecord container = ps.getMachineInv();
|
||||
isMatchedProvider = matchedProvider != null && matchedProvider.contains(container);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
int borderColor;
|
||||
int backgroundColor;
|
||||
|
||||
if (isMatchedSlot) {
|
||||
borderColor = withAlpha(rainbowRgb, 0xA0);
|
||||
backgroundColor = withAlpha(rainbowRgb, 0x3C);
|
||||
} else if (!isMatchedProvider) {
|
||||
borderColor = withAlpha(0xFFFFFF, 0x40);
|
||||
backgroundColor = withAlpha(0x000000, 0x18);
|
||||
} else {
|
||||
borderColor = withAlpha(0xFFFFFF, 0x30);
|
||||
backgroundColor = withAlpha(0xFFFFFF, 0x14);
|
||||
}
|
||||
|
||||
drawSlotBox(guiGraphics, sx, sy, borderColor, backgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定槽位坐标绘制彩虹流转的边框与浅底色(用于非 PatternSlot 的高亮场景)
|
||||
*/
|
||||
public static void drawSlotRainbowHighlight(GuiGraphics guiGraphics, int sx, int sy) {
|
||||
int rainbowRgb = getRainbowRgb();
|
||||
int borderColor = withAlpha(rainbowRgb, 0xA0);
|
||||
int backgroundColor = withAlpha(rainbowRgb, 0x3C);
|
||||
drawSlotBox(guiGraphics, sx, sy, borderColor, backgroundColor);
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
"ae2.accessor.PatternAccessTermScreenSlotsRowAccessor",
|
||||
"ae2.client.gui.AEBaseScreenMixin",
|
||||
"ae2.client.gui.PatternEncodingTermScreenMixin",
|
||||
"ae2.client.gui.PatternProviderCloseMixin",
|
||||
"ae2.client.gui.PatternProviderScreenMixin",
|
||||
"ae2.client.gui.SlotGridLayoutMixin",
|
||||
"extendedae.accessor.GuiExPatternTerminalAccessor",
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
"mixins": [
|
||||
"ae2.AEProcessingPatternMixin",
|
||||
"ae2.CraftingCPUClusterMixin",
|
||||
"ae2.IPatternDetailsMixin",
|
||||
"ae2.accessor.MEStorageMenuAccessor",
|
||||
"ae2.accessor.PatternEncodingTermMenuAccessor",
|
||||
"ae2.accessor.PatternProviderLogicAccessor",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user