feat: Upgrade server with HyNB v2.4 modular architecture, minigames, admin GM web panel, companion summons, and car radio

This commit is contained in:
CAtlas0784 committed 2026-10-29 02:44:24 +07:00
1 parent 74e2963a12
commit 3e5adf1dc5
1571 files changed
+336468 -6348

No files matched your search

@@ -185,7 +185,20 @@ internal static class CombatCodec
};
}
private static SceneMethods.WeaponDetail WeaponDetail(CombatWeaponDefinition weapon)
/// <summary>
/// WeaponManager.lua reads OperatorFlags as four independent bytes — GetFlag(flags, n) is
/// (flags >> (n * 8)) &amp; 0xFF, not a bit test. Byte 1 is the discard gate: every consumer in the
/// client reads <c>GetFlag(OperatorFlags, 1) ~= 1</c> as CantDiscard / isNotDiscard, so a weapon
/// is droppable, and the long-press-Q psychokinesis skill is enabled, only when byte 1 is 1.
///
/// Shipping 0 marked every weapon non-discardable. That is why no capture ever contained an
/// AskDiscardWeapon (BackCircleWeaponStore returns before sending one when CantDiscard is true)
/// and why long-press-Q wedged the unit in its absorb animation and slid backwards.
/// Byte 2 is the task-weapon marker (IsTask) and deliberately stays 0.
/// </summary>
internal const uint WeaponOperatorFlagsDiscardable = 1u << 8;
internal static SceneMethods.WeaponDetail WeaponDetail(CombatWeaponDefinition weapon)
=> new()
{
SourceAgentSpoonId = 0,
@@ -198,7 +211,7 @@ internal static class CombatCodec
InstanceId = weapon.InstanceId,
EventId = 0,
ReceivedTimeStamp = 0d,
OperatorFlags = 0,
OperatorFlags = WeaponOperatorFlagsDiscardable,
SpecialLabel = null,
SceneItemHp = 1f,
StackCount = 1,
@@ -209,6 +222,30 @@ internal static class CombatCodec
IsPlayerLocked = false
};
/// <summary>DiscardWeaponReason.Remove — disarm only; unlike Throw/RemoveAndDrop it carries no
/// "and drop it into the world" meaning, so the client will not mint a new ground drop.</summary>
internal const byte DiscardWeaponReasonRemove = 5;
internal static SceneMethods.SpiritRemoveWeaponAction SpiritRemoveWeapon(
uint spiritTemplateId, ulong spiritUnitId, ulong weaponInstanceId)
=> new()
{
SpiritTid = spiritTemplateId,
SpiritUid = spiritUnitId,
WeaponUid = weaponInstanceId,
Reason = DiscardWeaponReasonRemove,
};
internal static SceneMethods.SpiritAddWeaponAction SpiritAddWeapon(
uint spiritTemplateId, ulong spiritUnitId, int slotIndex, CombatWeaponDefinition weapon)
=> new()
{
SpiritTid = spiritTemplateId,
SpiritUid = spiritUnitId,
SlotIndex = slotIndex,
Weapon = WeaponDetail(weapon),
};
internal static SceneMethods.SpiritWeaponDurabilityChangedAction WeaponDurabilityChanged(
uint spiritTemplateId, ulong spiritUnitId, CombatWeaponDefinition weapon, int durability, int magazineAmmo, uint bulletId)
=> new()