fix chase reward
This commit is contained in:
Golumpa 2026-06-17 15:58:52 +01:00
parent b6f60129b0
commit 8102e46b37
6 changed files with 27 additions and 7 deletions

View file

@ -11,7 +11,7 @@ The sanitized JSON export uses:
"capture_source": "npcap", "capture_source": "npcap",
"exporter": { "exporter": {
"name": "nte-history-exporter", "name": "nte-history-exporter",
"version": "0.1.4" "version": "0.1.5"
}, },
"banner": { "banner": {
"id": "Lottery_Permanent", "id": "Lottery_Permanent",

View file

@ -1,6 +1,6 @@
[project] [project]
name = "nte-history-exporter" name = "nte-history-exporter"
version = "0.1.4" version = "0.1.5"
description = "Cross-platform Neverness to Everness pull-history exporter." description = "Cross-platform Neverness to Everness pull-history exporter."
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [] dependencies = []

View file

@ -1 +1 @@
__version__ = "0.1.4" __version__ = "0.1.5"

View file

@ -11,7 +11,7 @@ LIMITED_CHARACTER_BANNER_NAME = "Limited Character Board"
ARC_BANNER_ID = "Arc_MiracleBox" ARC_BANNER_ID = "Arc_MiracleBox"
ARC_BANNER_NAME = "Arc Miracle Box" ARC_BANNER_NAME = "Arc Miracle Box"
EXPORTER_NAME = "nte-history-exporter" EXPORTER_NAME = "nte-history-exporter"
EXPORTER_VERSION = "0.1.4" EXPORTER_VERSION = "0.1.5"
HISTORY_REQUEST_BANNER = 4220 HISTORY_REQUEST_BANNER = 4220
HISTORY_REQUEST_LENGTH = 45 HISTORY_REQUEST_LENGTH = 45

View file

@ -18,6 +18,9 @@ from nte_history_exporter.constants import (
from nte_history_exporter.mappings import REWARDS_BY_ID from nte_history_exporter.mappings import REWARDS_BY_ID
REWARD_ID_CHARS = frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_") REWARD_ID_CHARS = frozenset("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_")
WARP_PIECE_CHASE_PATTERN = bytes.fromhex(
"c4b0ccc00000000000040000003c00000010a58d957dd1a58dad95d17dc1c400"
)
def decode_reward_key(raw: bytes) -> str: def decode_reward_key(raw: bytes) -> str:
@ -141,9 +144,12 @@ def classify_result_type(
chunk_without_marker: bytes, chunk_without_marker: bytes,
dice: int | None, dice: int | None,
dice_offset: int | None, dice_offset: int | None,
reward_id: str = "",
) -> tuple[str, int | None]: ) -> tuple[str, int | None]:
if dice is None or dice_offset is None: if dice is None or dice_offset is None:
return "unknown", None return "unknown", None
if reward_id == "Dice_ticket_01" and WARP_PIECE_CHASE_PATTERN in chunk_without_marker:
return "chase_reward", -4
if dice == 0: if dice == 0:
return "points_gift", 0 return "points_gift", 0
@ -226,15 +232,15 @@ def _decode_aligned_response_records(response_content: bytes) -> list[dict[str,
_, _, _, _, trim, chunk, dice, dice_raw, dice_offset = min(embedded_candidates) _, _, _, _, trim, chunk, dice, dice_raw, dice_offset = min(embedded_candidates)
record_start = prev + trim record_start = prev + trim
full_record = response_content[prev + trim : marker_offset + len(marker) + 8] full_record = response_content[prev + trim : marker_offset + len(marker) + 8]
result_type, result_source_raw = classify_result_type(chunk, dice, dice_offset) key_hex = extract_key(chunk)
reward_id = decode_reward_key(bytes.fromhex(key_hex)) if key_hex else ""
result_type, result_source_raw = classify_result_type(chunk, dice, dice_offset, reward_id)
if result_type == "points_gift": if result_type == "points_gift":
dice = 0 dice = 0
dice_raw = 0 dice_raw = 0
elif result_type == "chase_reward": elif result_type == "chase_reward":
dice = -4 dice = -4
dice_raw = -4 dice_raw = -4
key_hex = extract_key(chunk)
reward_id = decode_reward_key(bytes.fromhex(key_hex)) if key_hex else ""
reward = REWARDS_BY_ID.get(reward_id, {}) reward = REWARDS_BY_ID.get(reward_id, {})
timestamp_raw = response_content[marker_offset + len(marker) : marker_offset + len(marker) + 8] timestamp_raw = response_content[marker_offset + len(marker) : marker_offset + len(marker) + 8]
timestamp_ticks, timestamp_unix, timestamp_decoded = decode_history_timestamp(timestamp_raw) timestamp_ticks, timestamp_unix, timestamp_decoded = decode_history_timestamp(timestamp_raw)

View file

@ -538,6 +538,20 @@ class BoundaryExportTests(unittest.TestCase):
self.assertEqual(decoded["quantity"], 30) self.assertEqual(decoded["quantity"], 30)
self.assertEqual(make_uid(decoded, int(reference["timestamp_group_ordinal"])), "7d035ec098f856f81b403ea538810145") self.assertEqual(make_uid(decoded, int(reference["timestamp_group_ordinal"])), "7d035ec098f856f81b403ea538810145")
def test_warp_piece_chase_subrecord_without_prefix_marker_is_chase_reward(self):
decoded = decode_single_record(
"c1c4b0ccc00000000000040000003c00000010a58d957dd1a58dad95d17dc1c400"
"4c0000000c85c99141bdbdb17d0da185c9858dd195c90140eb2c2dd7227b23"
)
self.assertEqual(decoded["result_type"], "chase_reward")
self.assertEqual(decoded["result_source_raw"], -4)
self.assertEqual(decoded["dice"], -4)
self.assertEqual(decoded["dice_raw_u32"], -4)
self.assertEqual(decoded["reward_id"], "Dice_ticket_01")
self.assertEqual(decoded["reward_name"], "Warp Piece")
self.assertEqual(decoded["quantity"], 30)
def test_batched_monopoly_response_normalizes_embedded_page_header(self): def test_batched_monopoly_response_normalizes_embedded_page_header(self):
page_7 = [load_v7_row("limited_all_04_v7.csv", row) for row in range(31, 36)] page_7 = [load_v7_row("limited_all_04_v7.csv", row) for row in range(31, 36)]
page_8 = [load_v7_row("limited_all_04_v7.csv", row) for row in range(36, 41)] page_8 = [load_v7_row("limited_all_04_v7.csv", row) for row in range(36, 41)]