HyCitizens vs KyuubiSoft Core 1.0.0: Evidence Report

If you are not technical, this report answers one question: did KyuubiSoft Core's citizen system copy HyCitizens? The evidence below shows concrete file-level and code-level matches.

Analysis date: March 1, 2026

HyCitizens source baseline: GitHub commit c7327cb

Kyuubi artifact baseline: CurseForge file 7646202 (KyuubiSoftCore-1.0.0-official.jar)

What was compared: All of Kyuubi's code related to citizens in the "1.0.0 official" release package.

Executive Summary

  • Kyuubi's own shipped UI file directly references HyCitizens by name.
  • 10 citizen role files use the exact same names as HyCitizens, and their code is either byte-identical or effectively identical with one inserted field. Two files are byte-for-byte copies.
  • The interaction system, message system, placeholders, color tags, rotation packets, skin fetching path, and data model structure match HyCitizens behavior in detail.
  • The same unusual nametag architecture (separate hologram entities built on ProjectileComponent) appears in both, and Kyuubi then shipped a next-day fix about nametag entity behavior — strongly indicating they inherited the design flaw from HyCitizens and had to patch it.
  • The PlayerDB skin API is parsed in the exact same 20-field order in both projects. The same backward-compat role-name alias for old HyCitizens names exists in KyuubiSoft's own codebase.
  • Taken together, this is consistent with derivative work, not an independent implementation.

Key Findings

0) Scope Counts (Reviewed Code/Resource Surface)

Project Area
HyCitizens Java (src/main/java)
HyCitizens roles (Server/NPC/Roles)
Kyu citizen Java (com/kyuubisoft/core/citizen)
Kyu CoreAPI Java (com/kyuubisoft/core/api)
Kyu roles (Server/NPC/Roles)

1) Direct HyCitizens Reference in Shipped Kyuubi UI

KyuubiSoft Core 1.0.0 includes the following line in the citizen admin UI resource:

// KyuubiSoft Citizen Admin Panel - Full CRUD with all HyCitizens features

File: Common/UI/Custom/Pages/CitizenAdmin/AdminPanel.ui:1

2) Role Resource Reuse is Extensive

The following 10 role files use the exact same filenames as HyCitizens:

  • Template_Citizen.json
  • Citizen_Interactable_Role.json
  • Citizen_Wander_Passive_R2_Role.json
  • Citizen_Wander_Passive_R2_Interactable_Role.json
  • Citizen_Wander_Passive_R5_Role.json
  • Citizen_Wander_Passive_R5_Interactable_Role.json
  • Citizen_Wander_Passive_R10_Role.json
  • Citizen_Wander_Passive_R10_Interactable_Role.json
  • Citizen_Wander_Passive_R15_Role.json
  • Citizen_Wander_Passive_R15_Interactable_Role.json

Content comparison result:

Metric Result
Overlapping role filenames10
Exact (hash or minified exact) matches2
JSON-equivalent after removing only ApplySeparation10 / 10
Role File Comparison Result
Template_Citizen.jsonExact same code (byte-identical)
Citizen_Interactable_Role.jsonExact same code
Citizen_Wander_Passive_R2_Role.jsonSame code + one inserted field (ApplySeparation: false)
Citizen_Wander_Passive_R2_Interactable_Role.jsonSame code + one inserted field (ApplySeparation: false)
Citizen_Wander_Passive_R5_Role.jsonSame code + one inserted field (ApplySeparation: false)
Citizen_Wander_Passive_R5_Interactable_Role.jsonSame code + one inserted field (ApplySeparation: false)
Citizen_Wander_Passive_R10_Role.jsonSame code + one inserted field (ApplySeparation: false)
Citizen_Wander_Passive_R10_Interactable_Role.jsonSame code + one inserted field (ApplySeparation: false)
Citizen_Wander_Passive_R15_Role.jsonSame code + one inserted field (ApplySeparation: false)
Citizen_Wander_Passive_R15_Interactable_Role.jsonSame code + one inserted field (ApplySeparation: false)

Exact-match examples:

  • Template_Citizen.json is byte-identical in both projects (same SHA-256: 2701671A1A9F7BE72B7425F991FCA99897025CEA1402AA890879978E52501F09).
  • Citizen_Interactable_Role.json is also exact-equivalent.

The other 8 files: same structure and values, with only one inserted property in Kyuubi ("ApplySeparation": false).

3) Interaction Pipeline Mirrors HyCitizens — With Code Evidence

Both projects implement the same interaction/message/command behavior in the same style. The actual runtime token names and flow are identical:

  • Message modes: RANDOM, SEQUENTIAL, ALL
  • Placeholder tokens: {PlayerName}, {CitizenName}
  • Command escape token: {SendMessage}
  • Named/hex color token parsing for chat messages using {ColorName} and {#RRGGBB} syntax

The {SendMessage} token: This was the original HyCitizens command-to-message escape, later kept only for backward compatibility when proper message actions were introduced. KyuubiSoft implements this same deprecated-but-preserved behavior with the same substring extraction pattern:

// HyCitizens — CitizenInteraction.java
if (command.startsWith("{SendMessage}")) {
    String messageContent = command.substring("{SendMessage}".length()).trim();
    Message msg = parseColoredMessage(messageContent);
    if (msg != null) { playerRef.sendMessage(msg); }
}

// KyuubiSoft — CitizenService.java
if (resolved.startsWith("{SendMessage}")) {
    String msgText = resolved.substring("{SendMessage}".length()).trim();
    player.sendMessage(parseColoredMessage(msgText, "#aaddff"));
}

The .substring("{SendMessage}".length()).trim() pattern is identical. There is no documentation for {SendMessage} in the Hytale API — it is a HyCitizens-specific invention that KyuubiSoft also has.

The replacePlaceholders() method in both uses the same two placeholders with the same brace syntax:

// HyCitizens — uses {PlayerName} and {CitizenName} (case-insensitive regex)
// KyuubiSoft — text.replace("{PlayerName}", ...).replace("{CitizenName}", ...)

Message selection modes in both are string-compared against "SEQUENTIAL", "ALL", with "RANDOM" as the default case — same three strings, same default, same per-player sequential counter tracked by player UUID.

Hy: interactions/CitizenInteraction.java
Kyu: citizen/CitizenService.java (methods sendCitizenMessages, executeCitizenCommands, replacePlaceholders)

3.1) Color Token System — Kyuubi's Map is a Direct Subset of HyCitizens'

Both implement a custom color token system ({RED}, {#FF0000}, etc.) using a regex pattern and a named-color lookup map. KyuubiSoft's 18 named color entries are every single one a subset of HyCitizens' 47 entries, with identical hex values:

Color Name HyCitizens Hex KyuubiSoft Hex
RED#FF0000#FF0000
GREEN#00FF00#00FF00
BLUE#0000FF#0000FF
YELLOW#FFFF00#FFFF00
ORANGE#FFA500#FFA500
PINK#FFC0CB#FFC0CB
PURPLE#800080#800080
CYAN#00FFFF#00FFFF
GOLD#FFD700#FFD700
GRAY#808080#808080
DARKRED#8B0000#8B0000
DARKGREEN#006400#006400
DARKBLUE#00008B#00008B
LIGHTBLUE#ADD8E6#ADD8E6
LIGHTGREEN#90EE90#90EE90
CORAL#FF7F50#FF7F50
CRIMSON#DC143C#DC143C
WHITE#FFFFFF#FFFFFF

All 18 match exactly. The regex token syntax is also equivalent: HyCitizens uses \{[A-Za-z]+\}|\{#[0-9A-Fa-f]{6}\} and KyuubiSoft uses \{([A-Za-z]+|#[0-9A-Fa-f]{6})\} — structurally the same pattern, with KyuubiSoft's being a condensed single-group rewrite.

This color system is entirely custom — there is no Hytale API or standard library that defines these token names or this regex.

4) Rotation Packet Logic is Structurally the Same

Both implementations use the same yaw/pitch computation and update threshold (0.02), then emit an EntityUpdates packet with look/body orientation.

Shared details include:

  • yaw = atan2(dx, dz) + PI
  • pitch = atan2(dy, horizontalDistance)
  • Ignore tiny movement updates below the same threshold
  • Build the same model transform and send an entity update packet

Hy: managers/CitizensManager.java around lines 1273-1326
Kyu: citizen/CitizenRotationManager.java around lines 83-104

4.1) Class Pair Mapping (Hy -> Kyu)

Beyond "same purpose," several files show measurable structural similarity.

HyCitizens KyuubiSoft Core Observed Relationship Measured Similarity
actions/BuilderActionInteractcitizen/BuilderActionCitizenInteractSame builder role and action wiring pattern71.4% significant-line overlap / 39% token 3-gram overlap
actions/CitizenInteractionActionbasecitizen/ActionCitizenInteractSame action execution skeleton for interaction targets33.3% significant-line overlap / 22.7% token 3-gram overlap
listeners/EntityDamageListenercitizen/CitizenDamageListenerSame damage interception + death/respawn responsibility12.9% significant-line overlap / 11.3% token 3-gram overlap
listeners/ChunkPreLoadListenercitizen/CitizenChunkListenerSame chunk poll/timeout spawn-reattach workflowShared constants and flow (15000, 250, 10000)
util/SkinUtilitiescitizen/CitizenSkinManagerSame PlayerDB endpoint and 20-field skin parsing pathSame API URL and same field order mapping
models/CitizenDatacitizen/CitizenDataHeavy schema overlap with direct field carries19 field-name matches + direct semantic renames
managers/CitizensManagercitizen/CitizenService + managersMonolith split into multiple classes but preserving core behavior modelBehavior-level parity across spawn, interact, rotate, hologram, respawn

Kyu also adds new features (for example quest marker components), but additional code does not erase copied/derived internals.

5) Citizen Data Model Overlap

At least 19 citizen data fields are identical by name (case-insensitive), including uncommon combinations that define behavior/state:

id, name, modelId, scale, attitude, rotateTowardsPlayer, hideNametag, nametagOffset, hideNpc, fKeyInteractionEnabled, messageSelectionMode, takesDamage, respawnOnDeath, createdAt, commandActions, group, isPlayerModel, skinUsername, useLiveSkin

Close semantic renames also map directly, for example:

  • spawnedUUID -> spawnedEntityUUID
  • hologramLineUuids -> hologramEntityUUIDs
  • npcRef -> entityRef

Files: models/CitizenData.java (Hy), citizen/CitizenData.java (Kyu)

5.1) Matching Constants and "Fingerprints"

Several low-level constants and formulas line up exactly, which is harder to explain as coincidence:

  • Chunk spawn logic: 15000ms timeout, 250ms polling, 10000ms minimum age check before processing.
  • Rotation smoothing: 0.02 yaw/pitch threshold before packet send.
  • Nametag math: 1.65 base offset, 0.40 extra-per-scale, 0.25 line spacing.
  • Skin source: both use the exact PlayerDB endpoint https://playerdb.co/api/player/hytale/.
  • Skin parsing: both map the same 20 PlayerSkin fields in the same order.

6) Same Unusual Nametag Architecture + Immediate Follow-Up Patch

Both systems use separate nametag/hologram entities tied to the citizen, including UUID tracking and periodic position sync. This is an unusual design choice compared to embedding text directly in the NPC entity.

Both also share the same core nametag math and constants:

  • Base Y offset: 1.65
  • Extra per scale: 0.40
  • Line spacing: 0.25
  • Separate Projectile + Nameplate hologram entities with UUID tracking

Hy: spawnCitizenHologram() and hologram UUID management in CitizensManager
Kyu: CitizenHologramManager with separate projectile/nameplate entities and UUID tracking

Release timeline from public indexing shows:

  • Feb 18, 2026: KyuubiSoftCore 1.0.0 (file 7646202)
  • Feb 19, 2026: KyuubiSoftCore 1.2.0 changelog includes Nametags are now set directly on the NPC entity

Reference: CurseForge v1.2.0 changelog

6.1) 1.0 Feature Parity Was Already Very High

In Kyuubi 1.0.0, the citizen system already shipped with the same uncommon feature bundle HyCitizens had:

  • F-key interaction toggle (fKeyInteractionEnabled)
  • Hidden nametag option + vertical nametag offset (hideNametag, nametagOffset)
  • Rotate-to-player behavior (rotateTowardsPlayer)
  • Message modes RANDOM/SEQUENTIAL/ALL
  • Color-token and placeholder parsing in interaction messages
  • Command-on-interact flow with {SendMessage} support
  • Damage toggle + respawn behavior (takesDamage, respawnOnDeath)
  • Separate hologram entity UUID tracking for nametags

The overlap is not one or two features; it is the overall design package and implementation style.

7) License/Attribution Signals in Distributed Artifact

In the analyzed Kyuubi 1.0.0 extracted contents, no license/notice attribution files were found (LICENSE, NOTICE, etc.), and no preserved HyCitizens copyright/attribution text appears. Attribution was also not included in Kyuubi's CurseForge page as is required by CurseForge.

Kyu artifact: no license/notice file to be found
HyCitizens license: MIT

8) Side-by-Side Pattern Examples

Rotation math + packet flow:

Hy: yaw = atan2(dx, dz) + PI; pitch = atan2(dy, horizontalDistance);
Kyu: yaw = atan2(dx, dz) + PI; pitch = atan2(dy, horizontalDistance);

Hy: if (yawDiff < 0.02 && pitchDiff < 0.02) return;
Kyu: if (yawDiff < 0.02 && pitchDiff < 0.02) continue;

Nametag/hologram math:

Hy: yOffset = 1.65 * scale + (scale - 1.0) * 0.40 + nametagOffset;
Kyu: yOffset = 1.65 * scale + (scale - 1.0) * 0.40 + nametagOffset;

Hy: lineSpacing = 0.25
Kyu: lineSpacing = 0.25

Chunk spawn constants:

Hy: min age 10000ms, timeout 15000ms, polling 250ms
Kyu: min age 10000ms, timeout 15000ms, polling 250ms

These are not broad feature similarities; these are matching implementation fingerprints. There are also just a few of the many.

10) Hologram Entities Built with ProjectileComponent — An Unusual Non-Obvious Choice

Both plugins create nametag/hologram text lines by spawning a ProjectileComponent entity as an invisible anchor and attaching a Nameplate component to it. This is a non-obvious and non-standard design pattern for adding nametags to NPCs. Most developers would add the Nameplate component directly on the NPC entity instead of creating a separate one.

KyuubiSoft's CitizenHologramManager:

ProjectileComponent projectile = new ProjectileComponent("Projectile");
holder.putComponent(ProjectileComponent.getComponentType(), projectile);
projectile.initialize();
// ...
holder.addComponent(Nameplate.getComponentType(), new Nameplate((String)lines.get(i)));
Ref<EntityStore> ref = store.addEntity(holder, AddReason.SPAWN);

HyCitizens' CitizensManager uses the same approach — as evidenced by ProjectileComponent appearing in its imports, and by the KyuubiSoft team's own internal changelog referencing this exact issue: their next-day 1.2.0 update fixed the nametag by moving it onto the NPC entity directly, acknowledging the "separate entity" approach was problematic. They would have known it was problematic only if they had started from HyCitizens' codebase where this pattern already existed.

11) Identical Lambda Capture Workaround

Java does not allow mutation of local variables captured in lambdas. Both codebases use the same idiomatic workaround: wrapping mutable state in single-element arrays. This appears in the chunk spawn logic of both projects:

// HyCitizens — ChunkPreLoadListener.java
boolean[] spawned = { false };
boolean[] queued = { false };
boolean[] hologramCheckScheduled = { false };
final ScheduledFuture<?>[] futureRef = new ScheduledFuture<?>[1];

// KyuubiSoft — CitizenChunkListener.java
boolean[] done = new boolean[]{false};
boolean[] queued = new boolean[]{false};
ScheduledFuture<?>[] futureRef = new ScheduledFuture[]{null};

The boolean array workaround is a known Java pattern, but the fact that both use it in the same context (a self-cancelling periodic chunk poll), with the same variable names (queued, futureRef) and the same logic flow (cancel future via index-0 reference) is a strong structural fingerprint. The futureRef[0].cancel(false) self-cancellation idiom appears in both.

12) CommandAction Model Class — Identical Fields

Both projects define a CommandAction class (HyCitizens as a standalone model class; KyuubiSoft as an inner class of CitizenData) with the same two fields:

Field HyCitizens Type KyuubiSoft Type
commandStringString
runAsServerbooleanboolean

Both default runAsServer to true. These are non-obvious field naming decisions — nothing in the Hytale API mandates a class with these exact names.

13) PlayerDB Skin Response — 20-Field Parse Order is Identical

Both plugins fetch skins from the same third-party API (https://playerdb.co/api/player/hytale/) and map the response to the same PlayerSkin constructor. The order in which all 20 fields are read is identical in both:

// Both HyCitizens (SkinUtilities) and KyuubiSoft (CitizenSkinManager) parse in this exact order:
new PlayerSkin(
    getStr(skin, "bodyCharacteristic"),
    getStr(skin, "underwear"),
    getStr(skin, "face"),
    getStr(skin, "eyes"),
    getStr(skin, "ears"),
    getStr(skin, "mouth"),
    getStr(skin, "facialHair"),
    getStr(skin, "haircut"),
    getStr(skin, "eyebrows"),
    getStr(skin, "pants"),
    getStr(skin, "overpants"),
    getStr(skin, "undertop"),
    getStr(skin, "overtop"),
    getStr(skin, "shoes"),
    getStr(skin, "headAccessory"),
    getStr(skin, "faceAccessory"),
    getStr(skin, "earAccessory"),
    getStr(skin, "skinFeature"),
    getStr(skin, "gloves"),
    getStr(skin, "cape")
);

The JSON structure traversal is also identical: root → data → player → skin. Neither the PlayerDB docs nor the Hytale API specifies this parse order — a developer would determine it empirically. The same 20-field sequence appearing in the same constructor order in both projects is a near-impossible coincidence for independent implementations.

HyCitizens uses a helper named getJsonString(); KyuubiSoft uses getStr() — different method names, identical logic and sequence.

14) Attitude Enum Values, Defaults, and Field Names are Identical

Both systems use a string-based attitude/disposition system with the same three values and the same default:

// HyCitizens — CitizenData.java
private String attitude = "PASSIVE";
// Values: "PASSIVE", "NEUTRAL", "AGGRESSIVE"

// KyuubiSoft — CitizenData.java
public String attitude = "PASSIVE";
// enum AttitudeType { PASSIVE, NEUTRAL, AGGRESSIVE }

These strings are not defined by the Hytale engine API — they are application-level design choices. Both use exactly the same three names with the same default.

Similarly, both default respawnDelay / respawnDelaySeconds to 5.0f and default scale to 1.0f.

15) Retained Naming Scheme for NPC Roles

HyCitizens established a specific naming convention for NPC role files: Citizen_ prefix, followed by movement mode (Wander, Idle), attitude (Passive, Neutral, Aggressive), radius suffix (R2, R5, R10, R15), and optionally _Interactable. This convention is entirely invented by HyCitizens — no Hytale API or documentation uses it.

KyuubiSoft 1.0.0 ships roles under this exact same convention (renaming Neutral/Aggressive roles to Generic, but otherwise identical structure). Their code also references the old HyCitizens Citizen_Wander_Passive_R* names directly in resolveRoleName() as a backward-compat alias:

// CitizenData.java (KyuubiSoft)
if (resolved.startsWith("Citizen_Wander_Passive_R") && resolved.endsWith("_Interactable_Role")) {
    resolved = resolved.replace("_Passive_", "_Generic_");
}

16) Animation System — Identical Schema and Application-Invented Type Strings

Both projects implement a timed/proximity/interaction-triggered animation system with the same field schema. HyCitizens defines it as AnimationBehavior; KyuubiSoft defines it as the inner class CitizenData.AnimationConfig. All 8 fields map directly:

HyCitizens Field KyuubiSoft Field Notes
typetypeIdentical
animationNameanimationNameIdentical
animationSlotanimationSlotIdentical
intervalSecondsintervalSemantic rename
proximityRangeproximityRangeIdentical
stopAfterTimestopAfterTimeIdentical
stopAnimationNamestopAnimationSemantic rename
stopTimeSecondsstopTimeSemantic rename

More critically, the four animation trigger type strings are identical in both codebases:

// Both HyCitizens and KyuubiSoft use these exact string values:
"TIMED"         — periodic timer-based animation
"TIMED_RANDOM"  — timer-based with randomized interval
"PROXIMITY"     — triggers when a player is within range
"ON_INTERACT"   — triggers on player F-key interaction

None of these strings are defined by the Hytale API or NPC system — they are application-level string constants invented by HyCitizens. KyuubiSoft's CitizenAnimationManager branches on the same four strings in the same way.

Hy: models/AnimationBehavior.java, managers/CitizensManager.java
Kyu: citizen/CitizenData.java (inner class AnimationConfig), citizen/CitizenAnimationManager.java

Claim-by-Claim Technical Response

  • "Built from the ground up": The citizen subsystem contains clear derivative signals (resource reuse, same internal architecture patterns, mirrored pipeline/token behavior, and direct textual reference to HyCitizens). Two NPC role files are byte-for-byte copies; a third-party API is parsed in exactly the same 20-field order; custom timing constants, naming conventions, and internal tokens match precisely.
  • "No HyCitizens file names or references": Overlapping role file names are present in the shipped artifact, the UI explicitly references "HyCitizens features," and KyuubiSoft's own resolveRoleName() method contains a backward-compat string replacement that maps old HyCitizens role names to new ones — indicating their internal configs already used those names.
  • "Only standard Hytale API usage looks similar": Some APIs are necessarily similar, but the overlap extends well beyond API surface into specific behavior design choices (ProjectileComponent for holograms, boolean-array lambda captures, custom attitude strings, identical timing constants), data schema, deprecated tokens, and content resources. None of these are mandated by the Hytale API.
  • "DamageEventSystem, PlayerDB, and EntityUpdates rotation are standard": The use of these APIs may be standard, but the exact code structure — identical 20-field JSON parse order, yaw/pitch threshold of 0.02, hologram math constants of 1.65/0.40/0.25 — goes far beyond what any common tutorial or documentation would produce. Independent implementations would not converge on all of these values simultaneously.

Source Links