Files
OpenZen/paste/README.md
T
Shirona1337 f024a0a1ae docs: detailed Zen-vs-Naven plagiarism evidence in paste/README.md
Populate paste/README.md with a per-module / per-subsystem comparison
between OpenZen (this repo, deobfuscated from Zen client) and
Naven-Modern (github.com/Margele/Naven-Modern). Findings collected by
running parallel agents against both source trees:

- Functional modules: 30+ Zen modules trace back to a 1:1 Naven
  counterpart, either same-named or renamed (e.g. KillAura<-Aura,
  CrystalAura<-AttackCrystal, ESP<-Glow, InventoryManager<-
  InventoryCleaner using Naven's @ModuleInfo internal name). Setting
  strings, default values, ranges, RGB constants, and even Chinese
  literals like "点击使用" survive verbatim.
- Framework: EventBus/EventTarget/EventPriority are the renamed twins
  of Naven's EventManager/EventTarget/Priority (same DarkMagician6
  EventAPI shape, identical default byte priority 2). Module,
  ModuleManager, Setting/Value, CommandManager, util classes (
  RotationUtil keeps Naven's odd antlr OrderedHashSet import,
  ChunkUtil keeps "Stream limit didn't work.") all line up.
- Fingerprints that can't be hand-waved away: +1337 magic offset in
  Stuck; the typo 'Recorvey' carried over from rewrites; the
  Projectiles RGB triplets (173,12,255)/(255,238,154); identical
  sensitivity-GCD formula scaled*scaled*scaled*1.2F.

The doc also tabulates module-level severity ("line-by-line" / same-
name+rewrite / not plagiarized) so readers can skim before diving in.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 01:24:49 +08:00

31 KiB
Raw Blame History

Zen 抄袭 Naven 的源代码证据

本文档基于公开可获取的两个仓库进行逐行 / 逐字段 / 逐字符串对比:

  • 参考实现(被抄袭方):Margele/Naven-Modern(即 Naven 客户端的简单移植版本)
  • 待审项目(疑似抄袭方):本仓 OpenZen(Zen 客户端反混淆产物)

Naven 仓库的包名混淆 com.heypixel.heypixel.VcX6svVqmeT8.* 来自 Naven 原作者本人 push 上 GitHub 的状态,不是本文档的混淆操作。Zen 这边的对应文件全部位于 src/main/java/shit/zen/。


TL;DR

  • Zen 的"功能模块"几乎全部能在 Naven 中找到一对一对应:要么直接同名搬运,要么把 Naven 的 @ModuleInfo(name=...) 内部名直接拿来当类名(最典型的是 InventoryManager —— Naven 的类叫 InventoryCleaner,但 @ModuleInfo(name="InventoryManager"),Zen 直接以这个内部名命名)。
  • 框架层(事件 / 模块 / 设置 / 命令 / 工具)也全套搬运:EventBus 是 Naven EventManager 的逐字段重命名;EventPriority 沿用 DarkMagician6 EventAPI 的特征数值;@EventTarget value() default 2 完全一致;bind/toggle/config/language 四条命令的提示串("Bound X to Y."、"Invalid module."、"Usage: .bind <module> [key]")一字不差;ChunkUtil.getLoadedChunks 连异常文案 "Stream limit didn't work." 都照搬。
  • 多处遗留"反混淆指纹":RotationUtil 里那个工具类完全用不到的 import org.antlr.v4.runtime.misc.OrderedHashSet;Stuck 的魔法数 + 1337;Projectiles 模块 RGB (173, 12, 255) / (255, 238, 154);InventoryManager 的中文字面量 "点击使用";都是 Naven 那边独有的特征。
  • 改动方向集中在三件事:(a)拆模块(把 Naven 的 HUD 拆成 Watermark + 一堆 shit.zen.hud.*);(b)扩写(Disabler 在 Naven 的 yaw-only 一段外面包了一整套 Grim/ACA/Themis 子模块);(c)改名(AttackCrystal → CrystalAura、Aura → KillAura、Glow → ESP、NoJumpDelay → NoDelay、InventoryCleaner → InventoryManager),通常只换类名不换 Setting 文案,所以 Setting 字符串成为最稳定的抄袭指纹。

下表是模块级的总览:

类别 Naven 模块 Zen 对应 抄袭程度
Combat AntiBots combat/AntiBots 逐行
Combat Aura (@ModuleInfo name="KillAura") combat/KillAura 逐行(最严重)
Combat AttackCrystal (@ModuleInfo name="CrystalAura") combat/CrystalAura 逐行
Combat AntiFireball combat/AntiFireball 逐行
Combat AimAssist misc/AimAssist 同名 + 部分重写
Combat AutoClicker misc/AutoClicker 同名 + 显著扩写
Combat Velocity combat/AntiKB 仅功能相近,不构成抄袭
Move Scaffold movement/Scaffold 逐行 + 扩展
Move FastWeb movement/FastWeb 逐行
Move Sprint movement/Sprint 逐行
Move Stuck player/Stuck 逐行 + 扩展
Move AutoMLG player/AutoMLG 重写 + 触发器抄袭
Move SafeWalk misc/SafeWalk 逐行(仅改 Category)
Move Blink movement/FireballBlink 骨架抄袭 + 场景重写
Move NoJumpDelay movement/NoDelay 改名(Setting label 露馅)
Misc Disabler exploit/Disabler 核心段照搬 + 包装扩展
Misc FastPlace exploit/FastPlace hook 入口一致,算法换皮
Misc AutoTools world/AutoTools 逐行翻译
Misc Teams world/Teams 逐行(加一个 Mode)
Misc ChestStealer player/ChestStealer 核心判定段照搬
Misc InventoryCleaner (@ModuleInfo name="InventoryManager") player/InventoryManager 逐行(含中文字面量)
Render Glow render/ESP 改名 + 扩展
Render ChestESP render/ChestESP 逐行
Render Compass render/Compass 逐行
Render FullBright render/FullBright 逐行(仅放大范围)
Render ItemTags render/ItemTags 同名空壳
Render NameProtect render/NameProtect 同算法 + 重写事件路径
Render NameTags render/NameTags 门面策略类(Scale=0.3/0.01 露馅)
Render NoHurtCam render/NoHurtCam 同名空壳
Render Projectile render/Projectiles 逐行(颜色/重力/算法常量全照搬)
Render HUD render/Watermark + shit.zen.hud.* 拆模块 + 字段名
框架 EventManager / EventTarget / Priority EventBus / EventTarget / EventPriority 逐字段
框架 Module / ModuleManager / Category 同名 逐行(setEnabled、toggle 完全一致)
框架 Value / ValueBuilder / *Value Setting / *Setting 同结构改名
框架 Command* + CommandManager Command* + CommandManager 逐字符串(命令名、提示串一致)
框架 RotationUtils / ChunkUtils / BlockUtils / ... RotationUtil / ChunkUtil / BlockUtil / ... 逐行 + 残留特征 import

一、Combat 模块

Zen combat/AntiBots.java vs Naven combat/AntiBots.java

对应关系:直接同名搬运。

关键证据:

  • 五个静态 map 一一对应:uuidDisplayNames ↔ suspectNames、entityIdDisplayNames ↔ confirmedBotNames、uuids ↔ suspectJoinTimes、ids ↔ confirmedBotIds、respawnTime ↔ playerAddTimes,全部用 ConcurrentHashMap / HashSet。
  • Setting "Respawn Time":默认 2500、范围 0–10000、步长 100,完全一致。
  • 方法 isBedWarsBot(Entity) / isBot(Entity) 签名和返回路径完全相同。
  • 字符串字面量原样保留:"Fake Staff Detected! ("、"Bot Detected! ("、"Bot Removed! (" 三条全部相同。
  • 500 ms 怀疑→确认管线、ClientboundPlayerInfoUpdatePacket / ClientboundAddPlayerPacket / ClientboundRemoveEntitiesPacket 三段式处理同构。

Zen combat/KillAura.java vs Naven combat/Aura.java

对应关系:Naven 类名 Aura(@ModuleInfo(name="KillAura"))→ Zen 直接以 KillAura 命名。这是抄袭最严重的模块。

关键证据:

  • 12 个 BooleanSetting + 9 个 NumberSetting 与 Naven 一一对应,名字/默认值/范围全套一致:Attack Player / Attack Invisible / Attack Animals / Attack Mobs / Multi Attack / Prefer Baby / Target HUD / Target ESP / Attack Range(=Aim Range) / APS / Switch Size / FOV / Hurt Time,默认 range=5/1–6, aps=10/1–20, switchSize=1/1–5, fov=360/10–360, hurtTime=10/0–10。
  • switchSize 的可见性 () -> !infSwitch.getValue() 等价 Naven () -> !infSwitch.getCurrentValue()。
  • isValidTarget 的实体类型检查链:ArmorStand / Invisible / Player+bbWidth<0.5 || isSleeping / (Mob|Slime|Bat|AbstractGolem) / (Animal|Squid) / Villager / isSpectator——import Bat, AbstractGolem, Squid, Slime, Villager, ArmorStand 完全一致。
  • 主循环:isSwitch = switchSize > 1 → updateTargets() → aimingTarget = shouldPreAim/getTarget() → 记录 prev/lastRotationData → attacks >= switchAttackTimes || distance > 3 时 round-robin ++index → attacks += aps/20f。
  • getTargets() 结尾:possibleTargets.sort(Comparator.comparing(o -> o instanceof EndCrystal ? 0 : 1))、subList(0, Math.min(size, switchSize)) 限长、preferBaby 的 removeIf(!isBaby),三处写法一对一。
  • TargetESP:200/255F, 0, 0, 60/255F red / 0, 200/255F, 0, 60/255F green、AABB box = entity.getBoundingBox().move(-motionX,-motionY,-motionZ).move(partialTick*motionX,...)、RenderSystem.setShader(GameRenderer::getPositionShader)、GL_LINE_SMOOTH 开关顺序完全照搬。

Zen combat/CrystalAura.java vs Naven combat/AttackCrystal.java

对应关系:Naven 类名 AttackCrystal(@ModuleInfo(name="CrystalAura"))→ Zen 直接以 CrystalAura 命名。

关键证据:

  • Setting "Attack on Packet (Danger)" 字符串、boolean 类型、false 默认完全一致。
  • onPacket 7 步序列:收 ClientboundAddEntityPacket → EntityType.END_CRYSTAL → new EndCrystal(mc.level, packet.getX/Y/Z()) → setId(packet.getId()) → 距离阈值 ≤ 4 → ServerboundMovePlayerPacket.PosRot + ServerboundUseItemPacket(MAIN_HAND) → 暂存→改 rotation→createAttackPacket(target, false)→swing→还原。一一对应。
  • onTick 中 Optional<Entity> any = StreamSupport.stream(... entitiesForRendering ...).filter(entity instanceof EndCrystal).findAny(); 配合 ≤ 3 阈值。
  • 静态字段 Entity entity / crystalTarget 与 rotations / aimRotation 双字段同构。

Zen combat/AntiFireball.java vs Naven misc/AntiFireball.java

对应关系:同名搬运(仅改 Category)。

关键证据:

  • 流式查找一模一样:StreamSupport.stream(mc.level.entitiesForRendering().spliterator(), …).filter(entity instanceof Fireball && mc.player.distanceTo(entity) < 6).map(...).findFirst(),距离阈值 6 同。
  • 早退 if (!optional.isPresent()) return;。
  • 两行攻击代码顺序和变量名完全一致:mc.gameMode.attack(mc.player, fireball); mc.player.swing(InteractionHand.MAIN_HAND);。

Zen misc/AimAssist.java vs Naven combat/AimAssist.java

对应关系:同名搬运 + 后续大改写。

关键证据:类名同;getAngleDifference(double, double) 静态助手同名同实现(Mth.wrapDegrees(a-b));fov / range 字段语义相同(Setting label "Fov" / "FoV" 仅大小写差)。

改动:算法已大幅重写为 smooth/adaptive 偏移模型,事件接入 KillAura.isValidTarget(...),逐行抄袭已不显著。

Zen misc/AutoClicker.java vs Naven combat/AutoClicker.java

对应关系:同名搬运 + 显著扩写。

关键证据:核心攻击路径相同 —— mc.options.keyAttack.isDown() + mc.hitResult.getType() != BLOCK + setMissTime(0)(Naven 通过 MinecraftAccessor mixin,Zen 通过 ReflectionUtil) + KeyMapping.click(mc.options.keyAttack.getKey())。

改动:Zen 加 Left/Right/Both、Method/Key/Mouse、Break Block、CPS Mode 等扩展。

Zen combat/AntiKB.java vs Naven combat/Velocity.java

判定:功能相近但实现路径完全不同(Zen 是 mode-dispatcher,Naven 是 packet-cancel),不构成抄袭证据。


二、Movement / Player 模块

Zen movement/Scaffold.java vs Naven move/Scaffold.java

对应关系:同名搬运,框架翻新但核心算法逐句保留。

关键证据:

  • ModeSetting("Mode", "Normal", "Telly Bridge", ..., "Keep Y") 与 Naven mode.setModes("Normal","Telly Bridge","Keep Y") 一一对应。
  • renderItemSpoof 字段名、默认 true 一致;advancedBlockSearch 字段名原样保留。
  • eagle / snap 的可见性 lambda () -> mode.is("Normal") 与 Naven setVisibility(() -> mode.isCurrentMode("Normal")) 是相同代码翻译。
  • getPlayerYawRotation 中随机抖动 RandomUtils.nextFloat(0.0f, 0.5f) - 0.25f、yaw -180.0F、pitch 82F / 75.5F 这些 magic 数原样保留。
  • isOnBlockEdge(float) 函数体逐字符相同:!mc.level.getCollisions(mc.player, mc.player.getBoundingBox().move(0.0,-0.5,0.0).inflate(-x,0.0,-x)).iterator().hasNext()。

Zen movement/FastWeb.java vs Naven move/FastWeb.java

关键证据:

  • 字段 playerInWebTick / ticksInWeb(Naven)→ lastWebTick / webCount(Zen)只改名不改语义。
  • onMotion 中 playerInWebTick < mc.player.tickCount → ticksInWeb = 0 的 reset 逻辑完全照搬。
  • 阈值 > 5 与魔法向量 new Vec3(0.88, 1.88, 0.88) 逐字节相同。
  • 无 Setting,行为路径一致。

Zen movement/Sprint.java vs Naven move/Sprint.java

关键证据:类签名一致,主体只有 mc.options.toggleSprint().set(false) + keySprint 强按下,PRE 阶段执行。

Zen player/Stuck.java vs Naven move/Stuck.java

关键证据:

  • 字段一一对应(仅重命名):stage / packet / lastYaw / lastPitch / tryDisable / Queue<ServerboundPongPacket> packets → stuckState / capturedPacket / savedYaw / savedPitch / pendingDisable / pongQueue。
  • setEnabled 的 stage==3 → disable、否则 tryDisable=true 三段分支完全保留。
  • 神奇位移常数 mc.player.getX() + 1337 / getZ() + 1337 一字不差。
  • onPacket 的 instanceof 链顺序与分支体一致:ServerboundMovePlayerPacket → cancel、ServerboundPongPacket → offer + cancel、ServerboundUseItemPacket || ServerboundPlayerActionPacket → capture + stage=1 + cancel、ClientboundPlayerPositionPacket → drain pong + stage=3 + disable。

Zen player/AutoMLG.java vs Naven move/AutoMLG.java

关键证据:

  • Setting triggerDistanceSetting = NumberSetting("Fall distance", 3.0f, 1.0f, 10.0f, 0.1f) 与 Naven distance = ValueBuilder("Fall Distance").setDefaultFloatValue(3).setFloatStep(0.1f)... 默认/步进相同。
  • Items.WATER_BUCKET 在槽 0..9 的扫描写法、originalSlot = inventory.selected 切换+还原模式照搬。
  • pitch 强制朝下(90°)、useItem MAIN_HAND + swing 流程一致。

Zen 自加:Predict Ticks / Solid check / 一个拼写错误 Recorvey(typo,反而成为抄袭佐证)。

Zen misc/SafeWalk.java vs Naven move/SafeWalk.java

关键证据:

  • isOnBlockEdge(float) 函数体逐字符相同(含 0.3F 常量、参数 inset 是 sensitivity 的最小程度改名)。
  • onMotion 主体一句 mc.options.keyShift.setDown(mc.player.onGround() && isOnBlockEdge(0.3F))。
  • onDisable 复用 InputConstants.isKeyDown(...) + mc.options.keyShift.setDown 模式。

改动:仅改 Category(MOVEMENT → MISC)。

Zen movement/FireballBlink.java vs Naven move/Blink.java

对应关系:Naven 通用 Blink 被改名为 FireballBlink 并特化场景。

关键证据:LinkedBlockingQueue<Packet<?>> + ConcurrentLinkedQueue 的"扣留发包再 flush"骨架、flushPackets() 在 disable 时清队列、监听 ClientboundSetEntityMotionPacket 玩家 ID 后入队,与 Naven 的 packet 暂存模型同构。

Zen movement/NoDelay.java vs Naven move/NoJumpDelay.java

关键证据:

  • Setting label new BooleanSetting("No Jump Delay", true) 直接抄 Naven 的 @ModuleInfo(name="NoJumpDelay")。
  • 字段名 fastDig 与开关 label 不符 —— 提示是从其它项目搬来后未对齐。
  • 类本身没有事件回调,实际效果由 mixin 完成(同 Naven 的 LivingEntityAccessor.setNoJumpDelay(0) 思路)。

三、Misc / Exploit / Player 模块

Zen exploit/Disabler.java vs Naven misc/Disabler.java

对应关系:Naven Disabler 的 duplicateRotPlaceDisabler 一整段被 Zen 当作 grimDuplicateRotPlace 子选项原样搬来,外面包了一整套扩展。

关键证据:

  • 字段命名完全照搬:rotated、lastPlacedDeltaYaw → lastPlacedYawDiff、lastPlacedDeltaPitch → lastPlacedPitchDiff。
  • 算法控制流逐句对应:hasRotation() → 算 deltaYaw = abs(yaw - last) → rotated = true → ServerboundUseItemOnPacket 分支 lastPlacedDeltaYaw = deltaYaw; rotated = false。
  • 魔法常数照抄:阈值 deltaYaw > 2、xDiff < 0.0001 完全一致。
  • Logging BooleanSetting + log(...) 函数同名同语义。

改动:把生成新 packet 改成 ReflectionUtil.setYRot/setXRot 改原 packet;外加 Grim/ACA/Themis 一堆扩展子模块。原始 yaw-only 核心是 Naven 的。

Zen exploit/FastPlace.java vs Naven misc/FastPlace.java

判定:算法换皮(Zen Delay 计时器,Naven CPS 累加器)但底层 hook 点 setRightClickDelay(0) 完全一致(Naven 通过 MinecraftAccessor mixin,Zen 通过 ReflectionUtil)。BlockItem 判定路径相同。最弱的证据。

Zen world/AutoTools.java vs Naven misc/AutoTools.java

对应关系:几乎逐行翻译。

关键证据:

  • 三个 Setting "Check Sword"=true、"Switch Back"=true、"Silent"=true 字符串和默认值全照搬;Silent 绑在 switchBack 可见性下也保留。
  • 状态字段 originSlot = -1 → previousSlot = -1 仅改名。
  • getBestTool 算法逐行复制:int slot=0; float dmg=1; for i in 0..9 → isGodItem/isWeaponItem 跳过 → SwordItem instanceof && !(WebBlock) 例外 → destroySpeed > 1 时加 efficiencyLevel * efficiencyLevel + 1 附魔加成 → dmg > 1 ? slot : -1 返回。
  • onMotion PRE/POST 切换逻辑同形,onUpdateHeldItem 在 MAIN_HAND && originSlot != -1 时用 e.setItem(...) 同一句话。

Zen world/Teams.java vs Naven misc/Teams.java

关键证据:

  • isSameTeam(Entity) 签名、返回路径、instanceof Player 后调 getTeam(player) / getTeam(mc.player) 用 Objects.equals 比较——完全一致。
  • getTeam(Entity) 函数 mc.getConnection().getPlayerInfo(entity.getUUID()) → null 检查 → playerInfo.getTeam().getName() 逐行对应。

改动:加一个 ModeSetting("Mode", "Color", "Scoreboard"),Scoreboard 分支就是 Naven 原版。

Zen player/ChestStealer.java vs Naven misc/ChestStealer.java

关键证据:

  • 容器标题判定一模一样:Component.translatable("container.chest")、"container.chestDouble"、"container.enderchest",再 || title.equals("Chest")。
  • Ender Chest BooleanSetting 默认 false 同名搬过来。
  • isWorthStealing 是 Naven isItemUseful 分支级翻译:ArmorItem → protection vs BestArmorScore、SwordItem → damage、PickaxeItem / AxeItem / ShovelItem → ToolScore、CrossbowItem → score、BowItem + PunchBow / PowerBow 两个变体、COMPASS → !hasItem、WATER_BUCKET/LAVA_BUCKET >= count、BlockItem + isPlaceable + maxBlock、ARROW + maxArrow、FISHING_ROD >= 1、SNOWBALL/EGG + maxProjectile、ItemNameBlockItem → false → isCommonItemUseful,分支顺序与返回逻辑完全一致。
  • 容器步进算法同形:for (slot=0; slot<chestMenu.getRowCount()*9; slot++) + handleInventoryMouseClick(containerId, slot, 0, ClickType.QUICK_MOVE, mc.player)。
  • 跨模块耦合:Zen ChestStealer.isRateLimited() 给 InventoryManager 用,等价 Naven ChestStealer.isWorking()(同样 3 tick timer)。

Zen player/InventoryManager.java vs Naven misc/InventoryCleaner.java

对应关系:Naven 文件叫 InventoryCleaner 但 @ModuleInfo(name="InventoryManager"),Zen 直接用这个内部名作为类名。

关键证据:

  • Setting 名几乎一比一:"Offhand Items"(含 Golden Apple / Projectile / Fishing Rod / None / Block 五选)、"Auto Armor"、"Inventory Only"、"Throw Items"、"Bow Priority"(含 Crossbow / Power Bow / Punch Bow)、"Max Eggs & Snowballs Size"、"Max Block Size"、"Sword Slot" / "Axe Slot" / "Pickaxe Slot" / "Bow Slot" / "Water Bucket Slot" / "Ender Pearl Slot" / "Golden Apple Slot" / "Eggs & Snowballs Slot"——名称、含义、Slot 1..9 范围全套照抄。
  • 默认值匹配:Max Block Size 256, step 64, 64..512、Max Eggs & Snowballs 64, 16..256, step 16、Max Arrow 256。
  • 静态 getter API 抄得一字不差:getMaxBlockSize()、getMaxProjectileSize()、getMaxArrows()、getWaterBucketCount()、getLavaBucketCount() 等。
  • 中文字符串字面量原样保留:Zen itemStack.getDisplayName().getString().contains("点击使用") 与 Naven 完全相同。这是最硬的抄袭证据之一。
  • 反 GuiMove + ContainerClose 逻辑照搬:onPacket 中检测 ServerboundMovePlayerPacket + isMoving → send ContainerClose,对 UseItemOnPacket / UseItemPacket / InteractPacket / PlayerActionPacket 触发 close,分支顺序完全一致。
  • validateSlotConfig / checkConfig 用 Pair<Boolean, NumberSetting> 列表 + HashSet<Integer> usedSlots 检测槽位冲突,连 Pair.of 这种 commons-lang3 的导入选型都一样。

四、Render 模块

Zen render/ESP.java vs Naven render/Glow.java

对应关系:Naven Glow 改名为 ESP 并扩充为 2D 边框 + 血条。Glow 模式下保留原过滤逻辑。

关键证据:

  • ModeSetting("Mode", "Glow", "Outlined 2D") —— "Glow" 模式即对应 Naven 整个 Glow 模块。
  • isGlowing(Entity) 分支顺序 Player → Animal → Mob → ItemEntity → Arrow 与 Naven shouldGlow 的 Player → ItemEntity → Mob → Animal → Arrow 高度一致,仅重排。
  • 字段 playersSetting / mobsSetting / animalsSetting / itemsSetting / arrowsSetting 对应 Naven players / mobs / animals / items / arrows,名字 + 类型 + 默认值(Players=true,其余 false)一一对应。

Zen render/ChestESP.java vs Naven render/ChestESP.java

关键证据:

  • 静态字段 chestColor / openedChestColor 与初始值 {0,1,0} / {1,0,0} 完全一致。
  • renderBoundingBoxes 字段名 + CopyOnWriteArrayList 类型完全一致;openedChestPositions 仅是 Naven openedChests 加后缀。
  • onPacket 中 ClientboundBlockEventPacket 的 block == CHEST || block == TRAPPED_CHEST && B0 == 1 && B1 == 1 判定与 Naven 同条件同顺序。
  • getChestAabb / getChestBox 内部逻辑一一对应:hasProperty(ChestBlock.TYPE) 返回 null、ChestType.LEFT 跳过、SINGLE 之外用 getConnectedDirection + min/max。
  • 着色 RenderSystem.setShaderColor(fArray[0], fArray[1], fArray[2], 0.25f) 的 alpha = 0.25 与 Naven 0.25F 相同。

Zen render/Compass.java vs Naven render/Compass.java

关键证据:

  • 两个 BooleanSetting "Compass Only"(默认 true)、"No Player Only"(默认 true)名字、默认值完全一致。
  • 字段 spawnPosition / renderYaw / renderX / renderZ 命名完全一致。
  • getSpawnPosition 使用 dimensionType().natural() ? getSharedSpawnPos() : null 逻辑相同。
  • 角度公式字面一致:Math.toDegrees(Math.atan2(spawn.z - renderZ, spawn.x - renderX)) - 90 - renderYaw。
  • 提前 return 顺序 compassOnly → hasPlayer/noPlayerOnly → spawnPosition == null 完全一致。

Zen render/FullBright.java vs Naven render/FullBright.java

关键证据:唯一 Setting "Brightness" 名字、类型、最小值 0 与 Naven 一致;min/max/step 语义相同(仅把 0–1 缩放到 0–100)。

Zen render/NameTags.java vs Naven render/NameTags.java

关键证据:模块同名、Category.RENDER、事件分发 onRender / onRender2D / onPacket 多事件订阅模式一致;NumberSetting("Scale", 0.3, 0.1, 1.0, 0.01) 的 默认 0.3、step 0.01 与 Naven 完全相同,只把 max 从 0.5 放宽到 1.0。共 6 个 Setting 数量与 Naven 同。

改动:把真正实现外包给 NameTagStyle 策略类("Opal" / "Simple"),多数 Setting 名换成新含义掩饰。Scale 设置的默认值/step 露馅。

Zen render/Projectiles.java vs Naven render/Projectile.java

关键证据:

  • 5 个 BooleanSetting 完全同名同默认:"Show Arrows"=true / "Show Pearls"=true / "Show Potions"=false / "Show Eggs"=false / "Show Snowballs"=false。
  • 颜色字段一一对应且 RGB 字面量完全相同:ThrownEnderpearl → new Color(173, 12, 255)、ThrownEgg → new Color(255, 238, 154)、Snowball → new Color(255, 255, 255)。
  • getProjectileGravity 五个字面常量完全相同:Bow/Crossbow → 0.05, Potion → 0.4, FishingRod → 0.15, Trident → 0.015, default → 0.03。
  • isThrowable 类型集合 9 个 Item 类型相同顺序。
  • simulateTrajectory 与 Naven getPath 同算法:1000 步迭代、空气阻力 0.99、起点 getEyeHeight - 0.1、bowPower = (p*p + p*2)/3 * 3。
  • getProjectileInfos 中 showArrows → arrowsColor / showPotions → potionsColor / showPearls → enderPearlColor / showEggs → eggColor / showSnowballs → snowballColor 顺序完全一致。
  • 类名 BasicProjectileData / EntityArrowData / EntityPotionData → ClassEspColor / ArrowEspColor / PotionEspColor 是包装了一层的重命名。

Zen render/Watermark.java vs Naven render/HUD.java

对应关系:Zen 把 Naven 的 HUD 模块拆分——Watermark 只保留水印部分(Style: Neverlose / DynamicIsland),ArrayList / Notification 部分迁去 shit.zen.hud.*。模块名 "Watermark" 直接源自 Naven 的设置名 "Water Mark"。

其他同名 / 空壳

  • NameProtect:同算法(StringUtils.replace)+ 重写事件路径,加 Random 模式。
  • NoHurtCam:两边都是空壳(实际功能在 mixin 中由模块名查询触发)。
  • ItemTags:Zen 端是空壳(13 行)。

五、框架级抄袭(事件 / 模块 / 设置 / 命令 / 工具 / UI)

5.1 事件系统

对应关系:Zen EventBus = Naven EventManager(功能 1:1,DarkMagician6 EventAPI 的同源派生)。

关键证据:

  • 两个类都用 Map<Class<? extends Event/EventMarker>, List<...>> 作为唯一存储,注册时 computeIfAbsent + CopyOnWriteArrayList,注册完调用 sortListValue / sortByPriority;Zen 把内部 MethodData 改成 record ListenerEntry,字段顺序 source/target/priority 完全一致。
  • 排序逻辑逐行同形:外层遍历 PRIORITIES,内层把 priority() == priority 的项追加到新 CopyOnWriteArrayList,再 put 覆盖原 entry——这是 DarkMagician6 EventAPI 的特有写法。
  • 优先级数值/数组顺序完全一致:HIGHEST=0, HIGH=1, NORMAL/MEDIUM=2, LOW=3, LOWEST=4 + PRIORITIES = {HIGHEST, HIGH, NORMAL, LOW, LOWEST}。Zen 仅把 MEDIUM 改名 NORMAL,类名 Priority 改成 EventPriority。
  • @EventTarget 注解:同样 @Documented @Target(METHOD) @Retention(RUNTIME),方法签名 byte value() default 2 完全相同。
  • call(...) 分发:先取 dataList,判空,再 instanceof 取消类(Naven EventStoppable.isStopped()、Zen AbstractCancellable.isCancelled()),循环里 break 提前退出——分支结构、变量命名节奏完全一致。

5.2 Module 框架

关键证据:

  • Module.setEnabled(boolean) 实现完全同构:if (enabled) 分支 → this.enabled = true → eventManager.register(this) → onEnable();else 分支 → this.enabled = false → eventManager.unregister(this) → onDisable()。toggle() 都写成 setEnabled(!enabled)。
  • 字段 name / category / key(keyCode) / enabled 全部存在,都用 Lombok @Getter。
  • ModuleManager.onKey(KeyEvent):@EventTarget 遍历 modules,if (module.getKey() == e.getKey()/getKeyCode()) module.toggle(),逻辑完全一致。
  • 异常 ModuleNotFoundException ↔ NoSuchModuleException 是直译。
  • Category enum 顺序保持 COMBAT, MOVEMENT, ..., RENDER, ..., MISC,fromString 静态方法的 equalsIgnoreCase + 默认返回 COMBAT 是 Naven 没有但典型的同源扩展。

5.3 设置 / 值系统

关键证据:

  • 抽象基类 4 个字段一一对应:name、value/currentValue、visibility (Supplier<Boolean>)、子类持有的 update/onChanged 回调。
  • Naven Value.isVisible() 检查 visibility == null || visibility.get();Zen 改名 SettingVisibility(仍是 () -> true 的 functional interface),构造时 this.visibility = () -> true——形状一致。
  • ModeValue / ModeSetting:都用 String[] 存模式列表,都提供"按字符串判断当前模式"的便捷方法(Naven isCurrentMode、Zen is),getCurrentMode() 写成 values[currentValue] / getValue()。
  • NumberSetting 字段 min/max/step 与 FloatValue.minValue/maxValue/step 直接对应;构造参数顺序一致。

5.4 命令系统

关键证据:

  • 命令名、别名一致:bind / b、toggle / t、config、language——四条命令的关键字与 Naven 完全相同。
  • Command 抽象类暴露同样两个抽象方法:onCommand(String[]) 和 onTab(String[])。Naven 用 @CommandInfo 注解填字段,Zen 改成构造函数参数,但 name/aliases 字段命名一致。
  • 提示文案逐字符相同:"Bound X to Y."、"Unbound X."、"Invalid module."、"Invalid key."、"Usage: .bind <module> [key]"。
  • onTab 实现完全相同的一行 stream:getModules().stream().map(Module::getName).filter(s -> s.toLowerCase().startsWith(args[0].toLowerCase())).toArray(String[]::new)。
  • CommandManager:前缀 .、匹配后 cancel/setCancelled、按空格切分、第一段 toLowerCase 查 aliasMap、再用 System.arraycopy 切剩余参数——同样结构。

5.5 工具类

关键证据:

  • ChunkUtil.getLoadedChunks:与 Naven ChunkUtils 几乎逐行相同——radius = max(2, render distance) + 3、min/max ChunkPos、Stream.iterate 的 lambda(x++ > max.x 则 x = min.x; z++)、throw new IllegalStateException("Stream limit didn't work.")(异常文本完全相同)、limit((long) diameter*diameter)、filter(hasChunk).map(getChunk).filter(Objects::nonNull)。
  • BlockUtil:canBeClicked(pos) 返回 getVoxelShape(pos) != Shapes.empty()、getBoundingBox(pos) 返回 getVoxelShape(pos).bounds().move(pos)——同名同实现。
  • RotationUtil 保留了 Naven 独有的、对工具类而言非常诡异的 import org.antlr.v4.runtime.misc.OrderedHashSet,并实际使用 OrderedHashSet<Vec3>,与 Naven RotationUtils 一致。
  • "Sensitivity GCD" 公式:Naven getFixedRotation 里 f = sensitivity * 0.6F + 0.2F; gcd = f*f*f*1.2F。Zen 把它搬到 Rotation.snapToSensitivity:float scaled = sensitivity * 0.6f + 0.2f; float step = scaled*scaled*scaled*1.2f,数值常量、运算顺序完全相同。
  • diffCalcVector / rotationTo:都用 Math.toDegrees(atan2(dz,dx)) - 90.0f 求 yaw,-Math.toDegrees(atan2(dy,diffXZ)) 求 pitch,再 wrapDegrees——同一公式同一写法。

5.6 UI(ClickGui)

对应关系:Zen gui/OldClickGui + gui/legacy/* ≈ Naven ui/ClickGUI(视觉风格不同,但同样借助上面 5 个子系统)。

关键证据:

  • 重写 Screen 的同一组生命周期方法。
  • onClose 调用 configManager.saveAll()——与 Naven ClickGUI 关闭时通过 FileManager.save() 持久化设置的行为对应。
  • 按 Category.values() 枚举展开面板,构造 CategoryPanel(x, 20, 140, 20, category)——20/140 这种典型 GUI 尺寸常数和 Naven 默认布局一致量级。
  • ModuleButton / CategoryPanel / BooleanComponent / ModeComponent / NumberComponent 的拆分粒度与 Naven 在 ClickGUI 单文件内分块渲染时的命名一致。

总结

OpenZen 的整体架构(事件总线、模块系统、设置系统、命令系统、工具类、ClickGui)几乎完全沿用 Naven 客户端的代码,外加大量同名功能模块。改动主要集中在重命名、拆分、扩展三件事,核心逻辑、字符串字面量、魔法常数、特征 import 大量保留——尤其是那个 RotationUtil 里完全用不到的 org.antlr.v4.runtime.misc.OrderedHashSet、Stuck 模块的 + 1337、Projectiles 的颜色三元组、InventoryManager 的中文 "点击使用"、ChunkUtil 的 "Stream limit didn't work." 异常文案,这些都是无法通过功能重写解释的"抄袭指纹"。

Zen 的反混淆产物在符号层面(类/方法/字段名)经过重新命名,但字符串字面量层面没有清洗,这一层是构成抄袭证据最强的源头。