fix: sync current handlers, repair relic data and restore visible launcher consoles
This commit is contained in:
1 parent
163d4433e6
commit
74f3c4411b
46 files changed
+4599
-1402
No files matched your search
@@ -31,3 +31,26 @@
|
||||
- ใน `GetCurBattleInfo` ตัด fallback ปลอมออก หากไม่มี Token ใน `CURRENT_BATTLE` ให้ตอบ `RET_BATTLE_STAGE_NOT_MATCH` (2000) ป้องกัน NRE
|
||||
- ใน `StartCocoonStage` และ `StartQuickCocoonStage` ส่ง `battleInfo` ที่สมบูรณ์พร้อมเวฟที่ถูกต้อง และเพิ่ม Log แสดงค่า `CocoonId`, `Wave`, `WorldLevel`
|
||||
4. คอมไพล์ `gameserver-go.exe` ใหม่และรีสตาร์ทกระบวนการ
|
||||
|
||||
## Codex battle investigation correction — main affix (2026-10-16)
|
||||
- Client stack RVA 0xc4eb77c is the return address after the throw call at 0xc4eb777, reached when main-affix lookup returns null (branch at 0xc4eb2b3). It does NOT prove a null sub-affix array; that throw call would return to 0xc4eb781. Earlier interpretation is withdrawn.
|
||||
- Captured Calyx/SceneCastSkill payload and inventory UID 483: avatar 1213, relic 63095, main_affix_id 11. Reference relic main group 55 contains IDs 1–10, with 10=ImaginaryAddedRatio. Local AvatarConfig confirms Imaginary for 1213.
|
||||
- Repaired only this inventory field in freesr-data.json: 11 -> 10. No converter ID override. All 24 relic main affixes in the captured team validate against reference data. Reference lacks new relics 63295/63296, so whole inventory is not fully validated.
|
||||
- Source: Mar-7th/StarRailRes commit dbe8cdfcfb0bf657b9fe1cf92d5537f118ccb487, index_new/en/relics.json and relic_main_affixes.json.
|
||||
- Backup: ignored battle_diagnostics/main-affix-repair/. Build completed; root gameserver-go.exe/sdkserver-go.exe updated. In-game battle success still requires a new client run.
|
||||
- First readback probe reported parser property not found. V2 includes non-public fields and CodedInputStream fallback, but local diagnostic probe is disabled for the repair verification. V2 is not yet verified in client.
|
||||
|
||||
## Handler/dispatch update against PearlSR 4.6.53 reference
|
||||
- Synced 2,690 current command names/IDs from upstream revision 005d2c12db4781071f4b5b68e8f364587886a710; generated table preserves verified old Go type aliases and fails on conflicts.
|
||||
- Source audit: all 865 existing request/response pairs and 4,435 shared message field-number sets match. This does not validate all field types/defaults or client behavior. Include oneof members (including enum-valued wrappers) when auditing; ignoring oneof produces false missing-field reports.
|
||||
- Replaced numeric raw registrations/old alias ranges with current named bindings. Removed multi-response guesses. Added missing typed Tierce lineup request8992/response8979, fields4/5; fixed cumulative reward request1747/response1748, group10 -> group12/retcode9.
|
||||
- Current schema statistics fields1/3/11 are a oneof; do not claim they are absent. Updated Go schema to oneof; statistics handler now echoes group without fabricated past scores, matching upstream.
|
||||
- Added ReplaceLineupScRsp field14; regenerated protobuf. Peak start/leave bindings restored; empty current Peak response no longer fabricates PeakID1. Challenge leave uses saved overworld scene rather than fixed destination.
|
||||
- Tutorial handlers load IDs from installed TutorialData/TutorialGuideGroup resources, removing the embedded old list. Removed unused generated activity list.
|
||||
- ClientDownloadData version51 remains because current upstream still uses51 for Lua payloads; do not infer53 from client patch. Avatar command400 response pairing remains semantically obfuscated; current adjacent schema response is used instead of spraying5 candidates, still requires client verification.
|
||||
- Added reproducible offline source sync/audit tools and docs/protocol-update.md; README/AGENTS updated. Final run.bat build completed, both root executables updated at22:16 local time. No in-game success claimed; no test suite run in this turn.
|
||||
|
||||
## Launcher visibility preference
|
||||
- User explicitly requested visible SDK/game server consoles and launcher menu closure after5 seconds.
|
||||
- run.ps1 now launches both root server executables with WindowStyle Normal and no stdout/stderr redirection; each server console remains independent when run.bat exits.
|
||||
- Interactive menu waits5 seconds after the selected action finishes, preserving exit codes. Argument-based build/check/stop returns immediately. README/AGENTS updated. No binary rebuild needed for this script-only change; did not launch or stop running servers.
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Compare command IDs and message field numbers with a local PearlSR checkout.
|
||||
|
||||
This is a source audit, not a client compatibility test. It does not verify
|
||||
field types, default values, assets, or gameplay behavior.
|
||||
"""
|
||||
import argparse
|
||||
import pathlib
|
||||
import re
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("upstream", type=pathlib.Path)
|
||||
args = parser.parse_args()
|
||||
root = pathlib.Path(__file__).resolve().parents[1]
|
||||
upstream = args.upstream / "protocol/src"
|
||||
command_source = (upstream / "root.zig").read_text(encoding="utf-8")
|
||||
commands = {n: int(v) for n, v in re.findall(r"\bCmd(\w+)\s*=\s*(\d+)", command_source)}
|
||||
go_commands = {}
|
||||
command_conflicts = []
|
||||
for filename in ("cmdid.go", "upstream_cmdids.go"):
|
||||
source = (root / "protocol/proto" / filename).read_text(encoding="utf-8")
|
||||
for name, value in re.findall(r'^\s*"(\w+)":\s*(\d+),', source, re.M):
|
||||
number = int(value)
|
||||
if name in go_commands and go_commands[name] != number:
|
||||
command_conflicts.append((name, go_commands[name], number))
|
||||
go_commands[name] = number
|
||||
command_differences = [(n, go_commands.get(n), v) for n, v in commands.items() if go_commands.get(n) != v]
|
||||
command_differences.extend(command_conflicts)
|
||||
|
||||
zig_messages = {}
|
||||
source = (upstream / "protocol.pb.zig").read_text(encoding="utf-8")
|
||||
for name, body in re.findall(r"^pub const (\w+) = struct \{\n(.*?)^};", source, re.M | re.S):
|
||||
descriptor = re.search(r"^ pub const _desc_table = .\{\n(.*?)^ };", body, re.M | re.S)
|
||||
if descriptor is None:
|
||||
continue
|
||||
numbers = {int(v) for v in re.findall(r"^ \.\w+ = fd\((\d+),", descriptor[1], re.M)}
|
||||
for union in re.findall(r"pub const _union_desc = .\{(.*?)\n };", body, re.S):
|
||||
numbers.update(int(v) for v in re.findall(r"\.\w+ = fd\((\d+),", union))
|
||||
zig_messages[name] = numbers
|
||||
|
||||
go_messages, wrappers = {}, {}
|
||||
for path in (root / "protocol/proto").glob("*.pb.go"):
|
||||
for name, body in re.findall(r"^type (\w+) struct \{\n(.*?)^}", path.read_text(encoding="utf-8"), re.M | re.S):
|
||||
numbers = {int(v) for v in re.findall(r'protobuf:"[^,]+,(\d+),', body)}
|
||||
go_messages[name] = numbers
|
||||
if ',oneof"' in body and "_" in name:
|
||||
wrappers.setdefault(name.split("_", 1)[0], set()).update(numbers)
|
||||
for name, numbers in wrappers.items():
|
||||
go_messages[name].update(numbers)
|
||||
shared = go_messages.keys() & zig_messages.keys()
|
||||
field_differences = [(n, sorted(go_messages[n]), sorted(zig_messages[n])) for n in sorted(shared)
|
||||
if go_messages[n] != zig_messages[n]]
|
||||
|
||||
current_pairs = {}
|
||||
for name, number in commands.items():
|
||||
for suffix in ("CsReq", "CSReq", "Req"):
|
||||
if name.endswith(suffix):
|
||||
stem = name[:-len(suffix)]
|
||||
candidates = [commands[n] for n in (stem + "ScRsp", stem + "CSScRsp", stem + "Rsp") if n in commands]
|
||||
if len(candidates) == 1:
|
||||
current_pairs[number] = candidates[0]
|
||||
break
|
||||
source = (root / "protocol/proto/cmdpairs.go").read_text(encoding="utf-8")
|
||||
pairs = {int(a): int(b) for a, b in re.findall(r"^\s*(\d+):\s*(\d+),", source, re.M)}
|
||||
pair_differences = [(a, b, current_pairs.get(a)) for a, b in pairs.items() if current_pairs.get(a) != b]
|
||||
print(f"Command IDs: {len(commands)} compared, {len(command_differences)} differences")
|
||||
print(f"Existing request/response pairs: {len(pairs)} compared, {len(pair_differences)} differences")
|
||||
print(f"Shared message field-number sets: {len(shared)} compared, {len(field_differences)} differences")
|
||||
for difference in command_differences + pair_differences + field_differences:
|
||||
print(difference)
|
||||
raise SystemExit(bool(command_differences or pair_differences or field_differences))
|
||||
@@ -0,0 +1,45 @@
|
||||
"""Generate current command names from a local PearlSR checkout; no network I/O."""
|
||||
import argparse
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("upstream", type=pathlib.Path)
|
||||
args = parser.parse_args()
|
||||
checkout = args.upstream.resolve()
|
||||
revision = subprocess.check_output(
|
||||
["git", "-C", str(checkout), "rev-parse", "HEAD"], text=True
|
||||
).strip()
|
||||
source = (checkout / "protocol/src/root.zig").read_text(encoding="utf-8")
|
||||
enum = source.split("pub const CmdID = enum(u16) {", 1)[1].split("};", 1)[0]
|
||||
commands = re.findall(r"\bCmd(\w+)\s*=\s*(\d+)\s*,", enum)
|
||||
if not commands or len({name for name, _ in commands}) != len(commands):
|
||||
raise SystemExit("Missing or duplicate upstream command names")
|
||||
if len({int(value) for _, value in commands}) != len(commands):
|
||||
raise SystemExit("Duplicate upstream command IDs")
|
||||
lines = [
|
||||
"// Code generated by tools/sync_protocol_commands.py. DO NOT EDIT.",
|
||||
"// Source: https://git.xeondev.com/HonkaiSlopRail/pearl-sr protocol/src/root.zig",
|
||||
"// Revision: " + revision,
|
||||
"package proto", "",
|
||||
'const CommandSourceRevision = "' + revision + '"', "",
|
||||
"var upstreamCmdIDByName = map[string]uint16{",
|
||||
]
|
||||
lines += [f'\t"{name}": {value},' for name, value in commands]
|
||||
lines += ["}", "", "func init() {",
|
||||
"\tfor name, id := range upstreamCmdIDByName {",
|
||||
"\t\tif previous, ok := CmdIDByName[name]; ok && previous != id {",
|
||||
'\t\t\tpanic("command ID conflict between schema and upstream: " + name)',
|
||||
"\t\t}", "\t\tCmdIDByName[name] = id", "\t\tNameByCmdID[id] = name",
|
||||
"\t}", "}", ""]
|
||||
root = pathlib.Path(__file__).resolve().parents[1]
|
||||
base_source = (root / "protocol/proto/cmdid.go").read_text(encoding="utf-8")
|
||||
base_commands = {n: int(v) for n, v in re.findall(r'^\s*"(\w+)":\s*(\d+),', base_source, re.M)}
|
||||
conflicts = [n for n, v in commands if n in base_commands and base_commands[n] != int(v)]
|
||||
if conflicts:
|
||||
raise SystemExit("Update the base schema command IDs first: " + ", ".join(conflicts))
|
||||
target = root / "protocol/proto/upstream_cmdids.go"
|
||||
target.write_text("\n".join(lines), encoding="utf-8")
|
||||
subprocess.run(["gofmt", "-w", str(target)], check=True)
|
||||
print(f"Generated {len(commands)} commands from {revision}")
|
||||
Reference in new issue
Block a user