mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
feat(scenario): add JSON scenario support and JKR type-3 compressor
Closes #172. Scenario files in bin/scenarios/ can now be authored as .json instead of .bin — the server compiles them to wire format on load, falling back to .bin if no .json is present. - Add ParseScenarioBinary / CompileScenarioJSON in scenario_json.go; supports sub-header format (strings as UTF-8, metadata as base64), inline format, and raw JKR blobs. - Add PackSimple JKR type-3 (LZ77) compressor in jpk_compress.go, ported from ReFrontier JPKEncodeLz.cs; round-trip tested against UnpackSimple. - Fix off-by-one in processDecode (jpk.go): last literal byte was silently dropped for data that does not end on a back-reference. - Wire loadScenarioBinary into handleMsgSysGetFile replacing the inline os.ReadFile call; mirrors the existing loadQuestBinary pattern. - Rewrite docs/scenario-format.md with full container/sub-header spec and JSON schema examples.
This commit is contained in:
78
common/decryption/jpk_compress_test.go
Normal file
78
common/decryption/jpk_compress_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package decryption
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPackSimpleRoundTrip(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
data []byte
|
||||
}{
|
||||
{"single byte", []byte{0x42}},
|
||||
{"ascii text", []byte("hello world")},
|
||||
{"repeated pattern", bytes.Repeat([]byte{0xAB, 0xCD}, 100)},
|
||||
{"all zeros", make([]byte, 256)},
|
||||
{"all 0xFF", bytes.Repeat([]byte{0xFF}, 128)},
|
||||
{"sequential bytes", func() []byte {
|
||||
b := make([]byte, 256)
|
||||
for i := range b {
|
||||
b[i] = byte(i)
|
||||
}
|
||||
return b
|
||||
}()},
|
||||
{"long repeating run", bytes.Repeat([]byte("ABCDEFGH"), 50)},
|
||||
{"mixed", []byte{0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD, 0x80, 0x81}},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
compressed := PackSimple(tc.data)
|
||||
got := UnpackSimple(compressed)
|
||||
if !bytes.Equal(got, tc.data) {
|
||||
t.Errorf("round-trip mismatch\n want len=%d\n got len=%d", len(tc.data), len(got))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackSimpleHeader(t *testing.T) {
|
||||
data := []byte("test data")
|
||||
compressed := PackSimple(data)
|
||||
|
||||
if len(compressed) < 16 {
|
||||
t.Fatalf("output too short: %d bytes", len(compressed))
|
||||
}
|
||||
|
||||
magic := binary.LittleEndian.Uint32(compressed[0:4])
|
||||
if magic != 0x1A524B4A {
|
||||
t.Errorf("wrong magic: got 0x%08X, want 0x1A524B4A", magic)
|
||||
}
|
||||
|
||||
jpkType := binary.LittleEndian.Uint16(compressed[6:8])
|
||||
if jpkType != 3 {
|
||||
t.Errorf("wrong type: got %d, want 3", jpkType)
|
||||
}
|
||||
|
||||
decompSize := binary.LittleEndian.Uint32(compressed[12:16])
|
||||
if decompSize != uint32(len(data)) {
|
||||
t.Errorf("wrong decompressed size: got %d, want %d", decompSize, len(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackSimpleLargeRepeating(t *testing.T) {
|
||||
// 4 KB of repeating pattern — should compress well
|
||||
data := bytes.Repeat([]byte{0xAA, 0xBB, 0xCC, 0xDD}, 1024)
|
||||
compressed := PackSimple(data)
|
||||
|
||||
if len(compressed) >= len(data) {
|
||||
t.Logf("note: compressed (%d) not smaller than original (%d)", len(compressed), len(data))
|
||||
}
|
||||
|
||||
got := UnpackSimple(compressed)
|
||||
if !bytes.Equal(got, data) {
|
||||
t.Errorf("round-trip failed for large repeating data")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user