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>
31 KiB
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是 NavenEventManager的逐字段重命名;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——importBat, 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/255Fred /0, 200/255F, 0, 60/255Fgreen、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默认完全一致。 onPacket7 步序列:收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")与 Navenmode.setModes("Normal","Telly Bridge","Keep Y")一一对应。renderItemSpoof字段名、默认true一致;advancedBlockSearch字段名原样保留。eagle/snap的可见性 lambda() -> mode.is("Normal")与 NavensetVisibility(() -> mode.isCurrentMode("Normal"))是相同代码翻译。getPlayerYawRotation中随机抖动RandomUtils.nextFloat(0.0f, 0.5f) - 0.25f、yaw-180.0F、pitch82F / 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)与 Navendistance = 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完全一致。 LoggingBooleanSetting +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返回。onMotionPRE/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 ChestBooleanSetting 默认false同名搬过来。isWorthStealing是 NavenisItemUseful分支级翻译: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用,等价 NavenChestStealer.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与 NavenshouldGlow的Player → ItemEntity → Mob → Animal → Arrow高度一致,仅重排。- 字段
playersSetting / mobsSetting / animalsSetting / itemsSetting / arrowsSetting对应 Navenplayers / 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仅是 NavenopenedChests加后缀。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 与 Naven0.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与 NavengetPath同算法: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改成 recordListenerEntry,字段顺序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取消类(NavenEventStoppable.isStopped()、ZenAbstractCancellable.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是直译。 Categoryenum 顺序保持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[]存模式列表,都提供"按字符串判断当前模式"的便捷方法(NavenisCurrentMode、Zenis),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:与 NavenChunkUtils几乎逐行相同——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>,与 NavenRotationUtils一致。- "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()——与 NavenClickGUI关闭时通过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 的反混淆产物在符号层面(类/方法/字段名)经过重新命名,但字符串字面量层面没有清洗,这一层是构成抄袭证据最强的源头。