Skip to content

Fix broken EULA download due to zstd compression level mismatch#296

Open
Copilot wants to merge 3 commits intomainfrom
copilot/fix-eula-download-issue
Open

Fix broken EULA download due to zstd compression level mismatch#296
Copilot wants to merge 3 commits intomainfrom
copilot/fix-eula-download-issue

Conversation

Copy link
Contributor

Copilot AI commented Feb 2, 2026

Fixes the EULA download regression caused by inconsistent zstd compression encoder levels in the StreamJson method.

Root Cause

The DocumentSuccess message (which includes EULA documents) uses StreamJson with ZstdCompression mode. After the recent refactoring that introduced core_stream.go, the StreamJson method was creating a zstd writer with default settings, while StreamJSONRawMessage was using zstd.WithEncoderLevel(1). This inconsistency caused the game client to fail decompression with "Unknown frame descriptor" error.

Changes Made

  • Fix: Updated StreamJson in server/evr/core_stream.go to use zstd.WithEncoderLevel(1) when compressing with ZstdCompression, ensuring consistency with StreamJSONRawMessage
  • Tests: Added comprehensive test coverage for ZstdCompression in both StreamJson and StreamJSONRawMessage methods in server/evr/core_stream_test.go

Testing

  • ✅ All new tests pass successfully
  • ✅ Server builds correctly
  • ✅ Code review passed with no issues
  • ✅ Changes are minimal and surgical (only 1 line changed in the core logic)

Impact

This fix ensures EULA documents are compressed using the correct zstd encoder level that the EchoVR game client expects, resolving the "Error performing zstd decompression: Unknown frame descriptor" issue.

Original prompt

This section details on the original issue you should resolve

<issue_title>EULA download is broken</issue_title>
<issue_description>this is a regression, so something must have been modified recently with the EULA config download.

[01-31-2026] [23:16:34]: config - 0x2FD48A8D4C79448D                                       
  - 0x2FDA8A8C4D75508F: Error performing zstd decompression: Unknown frame descriptor      
  - 0xB4130B7A4AC7E049:                                                                    
  - 0xC8C33E483C7A12B5: d:\projects\rad\dev\src\engine\libs\os\czstdcompression.cpp        
  - 0xC8C33E48367A10B5: 148                                                                
  - 0x5CDBDD908EB88C3B: 0xe8cc523d0fc9e5fe                                                 
```</issue_description>

<agent_instructions>i think this during the eula download</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@thesprockee
Copy link
Member

@copilot retry

Co-authored-by: thesprockee <962164+thesprockee@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 4, 2026

@copilot retry

Fixed in commit 9655ed9. The issue was caused by inconsistent zstd compression encoder levels - StreamJson was using default settings while StreamJSONRawMessage was using level 1. The EULA document now compresses correctly with the encoder level that the game client expects.

Copilot AI changed the title [WIP] Fix broken EULA download due to recent regression Fix broken EULA download due to zstd compression level mismatch Feb 4, 2026
@thesprockee thesprockee marked this pull request as ready for review February 4, 2026 19:39
Copilot AI review requested due to automatic review settings February 4, 2026 19:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a regression where EVR EULA downloads fail to decompress on the client due to inconsistent zstd encoder configuration in StreamJson.

Changes:

  • Align StreamJson zstd writer options with StreamJSONRawMessage by using zstd.WithEncoderLevel(1).
  • Add ZstdCompression round-trip tests for both StreamJSONRawMessage and StreamJson.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
server/evr/core_stream.go Ensures ZstdCompression uses the expected zstd encoder level for JSON streaming.
server/evr/core_stream_test.go Adds ZstdCompression tests for JSON/raw-message streaming paths.

Comment on lines +410 to +455
func TestEasyStream_StreamJson_ZstdCompression(t *testing.T) {
// Test with a struct similar to EULADocument
type TestDoc struct {
Type string `json:"type"`
Lang string `json:"lang"`
Text string `json:"text"`
}

// Test data
original := TestDoc{
Type: "eula",
Lang: "en",
Text: "This is a test EULA document with some content.",
}

// Test with null termination
buf := new(bytes.Buffer)
stream := &EasyStream{
Mode: EncodeMode,
w: buf,
}

if err := stream.StreamJson(original, true, ZstdCompression); err != nil {
t.Fatalf("failed to encode with ZstdCompression: %v", err)
}

encoded := buf.Bytes()
if len(encoded) == 0 {
t.Fatal("encoded data is empty")
}

// Decode and verify
stream = &EasyStream{
Mode: DecodeMode,
r: bytes.NewReader(encoded),
}

var decoded TestDoc
if err := stream.StreamJson(&decoded, true, ZstdCompression); err != nil {
t.Fatalf("failed to decode with ZstdCompression: %v", err)
}

// Compare
if decoded.Type != original.Type || decoded.Lang != original.Lang || decoded.Text != original.Text {
t.Errorf("StreamJson ZstdCompression roundtrip failed: got %+v, want %+v", decoded, original)
}
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new ZstdCompression tests only validate round-trip encode/decode using the same implementation, so they won’t fail if StreamJson accidentally switches back to a different zstd encoder configuration (the regression being fixed). To prevent that drift, add an assertion that StreamJson(ZstdCompression) produces the same encoded bytes as StreamJSONRawMessage(ZstdCompression) for the same JSON payload (including both null-terminated and non-null-terminated cases), or otherwise assert expected zstd frame/header characteristics.

Copilot uses AI. Check for mistakes.
Comment on lines 432 to 438
if err := binary.Write(s.w, binary.LittleEndian, uint32(len(b))); err != nil {
return fmt.Errorf("write error: %w", err)
}
w, err := zstd.NewWriter(s.w)
w, err := zstd.NewWriter(s.w, zstd.WithEncoderLevel(1))
if err != nil {
return err
}
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid future zstd configuration drift between StreamJson and StreamJSONRawMessage (which caused this regression), consider factoring the zstd writer options into a shared helper/constant (e.g., a single function that returns a zstd.Writer with the required options) instead of repeating zstd.WithEncoderLevel(1) in multiple places. This makes it harder for the two methods to become inconsistent again.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

EULA download is broken

2 participants