mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-12 08:21:02 +02:00
103 lines
4.6 KiB
Lua
103 lines
4.6 KiB
Lua
-- Parity test: the link fingerprint no longer hashes catchRate, so a
|
|
-- Yellow-shaped dataset that differs from Red/Blue only at
|
|
-- Dragonair/Dragonite's catch rate digests identical and the handshake
|
|
-- reports "full" (#511).
|
|
--
|
|
-- Real cross-version link play (two processes, Red vs Yellow) is outside
|
|
-- what this checkout can assert: it needs both a Red and a Yellow
|
|
-- data/generated/ cache and two live UDP peers. What IS assertable from
|
|
-- one process: (1) catchRate is excluded from the hashed species surface,
|
|
-- so editing only that field never moves the digest, and (2) a synthetic
|
|
-- Yellow stand-in built by copying the real Data and retuning just those
|
|
-- two species' catchRate (the only real R/B vs Yellow link-surface delta,
|
|
-- per data/pokemon/base_stats/dragonair.asm 45 vs 27 and dragonite.asm 45
|
|
-- vs 9) fingerprints identically and clears Handshake.checkCompat as
|
|
-- "full", not "subset".
|
|
--
|
|
-- A human still has to run the actual cross-version check: launch a Red
|
|
-- instance and a Yellow instance (POKEPORT_VERSION=red / =yellow,
|
|
-- distinct POKEPORT_IDENTITY sandboxes), host/join on localhost, and
|
|
-- confirm no "game data is not the same" notice appears and a trade goes
|
|
-- through both ways.
|
|
--
|
|
-- Self-contained; run via `luajit tests/parity_link_fingerprint_yellow.lua`.
|
|
package.path = "./?.lua;./?/init.lua;" .. package.path
|
|
if not _G.love then _G.love = require("tests.love_stub") end
|
|
local S = require("tests.harness").suite("parity link fingerprint yellow")
|
|
local check, eq = S.check, S.eq
|
|
|
|
local Data = require("src.core.Data")
|
|
Data:load()
|
|
|
|
local Fingerprint = require("src.link.Fingerprint")
|
|
local Handshake = require("src.link.Handshake")
|
|
|
|
local function copy(record)
|
|
local out = {}
|
|
for k, v in pairs(record) do out[k] = v end
|
|
return out
|
|
end
|
|
|
|
local function cloneData(base)
|
|
local out = { pokemon = {}, moves = {}, type_chart = base.type_chart,
|
|
constants = base.constants }
|
|
for id, record in pairs(base.pokemon) do out.pokemon[id] = record end
|
|
for id, record in pairs(base.moves) do out.moves[id] = record end
|
|
return out
|
|
end
|
|
|
|
-- (1) catchRate alone must not move the digest: this is the field
|
|
-- allowlist change at src/link/Fingerprint.lua SPECIES_FIELDS.
|
|
local vanilla = cloneData(Data)
|
|
local first = Fingerprint.compute(vanilla, {})
|
|
|
|
local rateOnly = cloneData(Data)
|
|
local pidgeyRate = copy(Data.pokemon.PIDGEY)
|
|
pidgeyRate.catchRate = (pidgeyRate.catchRate or 0) + 1
|
|
rateOnly.pokemon.PIDGEY = pidgeyRate
|
|
eq(Fingerprint.compute(rateOnly, {}), first,
|
|
"a catchRate-only edit does not move the link fingerprint")
|
|
|
|
-- (2) a Yellow stand-in: same records, Dragonair/Dragonite catch rate
|
|
-- retuned to Yellow's values (the only real R/B vs Yellow link delta).
|
|
Fingerprint.forget(vanilla)
|
|
local yellowish = cloneData(Data)
|
|
if Data.pokemon.DRAGONAIR then
|
|
local dragonair = copy(Data.pokemon.DRAGONAIR)
|
|
dragonair.catchRate = 27 -- pokeyellow data/pokemon/base_stats/dragonair.asm
|
|
yellowish.pokemon.DRAGONAIR = dragonair
|
|
end
|
|
if Data.pokemon.DRAGONITE then
|
|
local dragonite = copy(Data.pokemon.DRAGONITE)
|
|
dragonite.catchRate = 9 -- pokeyellow data/pokemon/base_stats/dragonite.asm
|
|
yellowish.pokemon.DRAGONITE = dragonite
|
|
end
|
|
check(Data.pokemon.DRAGONAIR ~= nil and Data.pokemon.DRAGONITE ~= nil,
|
|
"fixture has Dragonair and Dragonite to retune")
|
|
local yellowPrint = Fingerprint.compute(yellowish, {})
|
|
eq(yellowPrint, first,
|
|
"a Yellow-shaped dataset (only Dragonair/Dragonite catch rate differs) " ..
|
|
"fingerprints identically to Red/Blue")
|
|
|
|
-- (3) the handshake actually reads "full" for that pairing, not "subset"
|
|
local redHello = { protocol = 2, engineVersion = "0.1.0", fingerprint = first }
|
|
local yellowHello = { protocol = 2, engineVersion = "0.1.0", fingerprint = yellowPrint }
|
|
local verdict, reason = Handshake.checkCompat(redHello, yellowHello)
|
|
eq(verdict, "full", "Red vs Yellow-shaped peer clears the handshake as full")
|
|
check(reason == nil, "a full verdict carries no mismatch reason")
|
|
|
|
-- control: a real gameplay-affecting edit (base stats) still splits the
|
|
-- two builds, so the fingerprint has not gone toothless
|
|
local buffed = cloneData(Data)
|
|
local strongPidgey = copy(Data.pokemon.PIDGEY)
|
|
strongPidgey.baseStats = copy(Data.pokemon.PIDGEY.baseStats)
|
|
strongPidgey.baseStats.attack = strongPidgey.baseStats.attack + 1
|
|
buffed.pokemon.PIDGEY = strongPidgey
|
|
local buffedPrint = Fingerprint.compute(buffed, {})
|
|
check(buffedPrint ~= first, "a baseStats edit still moves the digest")
|
|
local buffedHello = { protocol = 2, engineVersion = "0.1.0", fingerprint = buffedPrint }
|
|
local verdict2 = Handshake.checkCompat(redHello, buffedHello)
|
|
eq(verdict2, "subset", "a genuinely different dataset still reads subset, not full")
|
|
|
|
S.finish()
|