Skip to content

Commit d0ec759

Browse files
committed
feat(compile-errors): add support for compile error collection and retrieval
- Add Log and LogContainer structs for compile error deserialization - Implement GetCompileErrors message type and handling - Add client methods to request compile errors - Update protocol documentation with new message type details
1 parent 7ee20a6 commit d0ec759

File tree

3 files changed

+101
-3
lines changed

3 files changed

+101
-3
lines changed

docs/UnityPackageMessagingProtocol.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ All available message types:
7878
| `Offline` | 103 | Notifies clients that this package is offline and can not receive messages | Empty string |
7979
| `IsPlaying` | 104 | Notification of current play mode state | "true" (in play mode) / "false" (in edit mode) |
8080
| `CompilationStarted` | 105 | Notification that compilation has started | Empty string |
81+
| `GetCompileErrors` | 106 | Request/response for compile error information | Empty string (request) / JSON serialized LogContainer (response) |
8182

8283
Note:
8384
- Message value greater than or equal to 100 means it does not exist in the official package but was added in this package.
@@ -129,6 +130,51 @@ Detailed value formats for some of the types:
129130
- **Compilation Lifecycle**: This message is sent at the beginning of the compilation process, before any assembly compilation starts
130131
- **Relationship to CompilationFinished**: This message pairs with `CompilationFinished` (Value: 100) to provide complete compilation lifecycle notifications
131132

133+
#### GetCompileErrors (Value: 106)
134+
- **Format**:
135+
- Request: Empty string
136+
- Response: JSON serialized LogContainer object
137+
- **Description**: Requests the collected compile errors that occurred during Unity's compilation process. Unity collects compile errors within a 1-second window after compilation finishes.
138+
139+
- **C# Structure**:
140+
141+
```csharp
142+
[Serializable]
143+
public class LogContainer
144+
{
145+
/// <summary>
146+
/// Array of log entries.
147+
/// </summary>
148+
public Log[] Logs { get; set; }
149+
}
150+
151+
[Serializable]
152+
public class Log
153+
{
154+
/// <summary>
155+
/// The complete log message as logged by Unity.
156+
/// </summary>
157+
public string Message;
158+
159+
/// <summary>
160+
/// The stack trace associated with the log entry, if available.
161+
/// </summary>
162+
public string StackTrace;
163+
164+
/// <summary>
165+
/// The timestamp when the log entry was captured as Unix timestamp (milliseconds since epoch).
166+
/// </summary>
167+
public long Timestamp;
168+
}
169+
```
170+
171+
- **Behavior**:
172+
- **Collection Window**: Compile errors are collected for 1 second after compilation finishes
173+
- **Error Filtering**: Only log messages containing "error CS" are collected
174+
- **Automatic Clearing**: Previous compile errors are cleared when compilation starts
175+
- **Response Format**: Returns JSON with LogContainer containing array of Log objects
176+
- **Usage**: Clients can request this to get structured compile error information for IDE integration, error highlighting, and debugging assistance.
177+
132178
#### RetrieveTestList (Value: 23)
133179
- **Format**: Test mode string ("EditMode" or "PlayMode")
134180
- **Example**: `"EditMode"`

src/unity_messages.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
use serde::{Deserialize, Serialize};
22

3+
/// Unity compile error structures for proper deserialization
4+
#[derive(Debug, Clone, Deserialize, Serialize)]
5+
pub struct LogContainer {
6+
#[serde(rename = "Logs")]
7+
pub logs: Vec<Log>,
8+
}
9+
10+
#[derive(Debug, Clone, Deserialize, Serialize)]
11+
pub struct Log {
12+
#[serde(rename = "Message")]
13+
pub message: String,
14+
#[serde(rename = "StackTrace")]
15+
pub stack_trace: String,
16+
#[serde(rename = "Timestamp")]
17+
pub timestamp: i64,
18+
}
19+
320
/// Unity test result structures for proper deserialization
421
#[derive(Debug, Clone, Deserialize, Serialize)]
522
pub struct TestResultAdaptorContainer {
@@ -135,6 +152,8 @@ pub enum UnityEvent {
135152
Offline,
136153
/// Unity play mode changed
137154
IsPlaying(bool),
155+
/// Compile errors received from Unity
156+
CompileErrors(LogContainer),
138157
}
139158

140159
/// Message types as defined in the Unity Package Messaging Protocol
@@ -169,6 +188,7 @@ pub enum MessageType {
169188
Offline = 103,
170189
IsPlaying = 104,
171190
CompilationStarted = 105,
191+
GetCompileErrors = 106,
172192
}
173193

174194
impl From<i32> for MessageType {
@@ -202,6 +222,7 @@ impl From<i32> for MessageType {
202222
103 => MessageType::Offline,
203223
104 => MessageType::IsPlaying,
204224
105 => MessageType::CompilationStarted,
225+
106 => MessageType::GetCompileErrors,
205226
_ => MessageType::None,
206227
}
207228
}

src/unity_messaging_client.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use crate::unity_messages::{
2-
LogLevel, Message, MessageType, TestAdaptorContainer, TestFilter, TestResultAdaptorContainer,
2+
LogContainer, LogLevel, Message, MessageType, TestAdaptorContainer, TestFilter, TestResultAdaptorContainer,
33
UnityEvent, UnityMessagingError,
44
};
55
use crate::{debug_log, error_log, info_log};
66
use serde::{Deserialize, Serialize};
77
use std::net::SocketAddr;
88
use std::sync::Arc;
99
use std::sync::Mutex;
10-
use std::time::{Duration, Instant};
10+
use std::time::{Duration, Instant, SystemTime};
1111
use tokio::io::AsyncReadExt;
1212
use tokio::net::{TcpStream, UdpSocket};
1313
use tokio::sync::broadcast;
@@ -27,6 +27,10 @@ pub struct UnityMessagingClient {
2727
current_test_run_id: Arc<Mutex<Option<String>>>,
2828
/// Whether Unity Editor is currently in play mode
2929
is_in_play_mode: Arc<Mutex<bool>>,
30+
/// Timestamp of the last compilation finished event
31+
last_compilation_finished: Arc<Mutex<Option<SystemTime>>>,
32+
/// Compile errors collected after compilation finishes
33+
last_compile_errors: Arc<Mutex<Vec<String>>>,
3034
}
3135

3236
impl UnityMessagingClient {
@@ -60,6 +64,8 @@ impl UnityMessagingClient {
6064
is_online: Arc::new(Mutex::new(false)),
6165
current_test_run_id: Arc::new(Mutex::new(None)),
6266
is_in_play_mode: Arc::new(Mutex::new(false)),
67+
last_compilation_finished: Arc::new(Mutex::new(None)),
68+
last_compile_errors: Arc::new(Mutex::new(Vec::new())),
6369
})
6470
}
6571

@@ -85,6 +91,8 @@ impl UnityMessagingClient {
8591
let is_online = self.is_online.clone();
8692
let current_test_run_id = self.current_test_run_id.clone();
8793
let is_in_play_mode = self.is_in_play_mode.clone();
94+
let last_compilation_finished = self.last_compilation_finished.clone();
95+
let last_compile_errors = self.last_compile_errors.clone();
8896

8997
// Spawn background task for message listening
9098
let task = tokio::spawn(async move {
@@ -95,7 +103,7 @@ impl UnityMessagingClient {
95103
last_response_time,
96104
is_online,
97105
current_test_run_id,
98-
is_in_play_mode,
106+
is_in_play_mode
99107
)
100108
.await;
101109
});
@@ -366,6 +374,16 @@ impl UnityMessagingClient {
366374
// Compilation messages
367375
MessageType::CompilationFinished => Some(UnityEvent::CompilationFinished),
368376
MessageType::CompilationStarted => Some(UnityEvent::CompilationStarted),
377+
MessageType::GetCompileErrors => {
378+
match serde_json::from_str::<LogContainer>(&message.value) {
379+
Ok(container) => Some(UnityEvent::CompileErrors(container)),
380+
Err(e) => {
381+
error_log!("Failed to deserialize GetCompileErrors data: {}", e);
382+
debug_log!("Raw GetCompileErrors data: {}", message.value);
383+
None
384+
}
385+
}
386+
}
369387

370388
// Refresh messages
371389
MessageType::Refresh => Some(UnityEvent::RefreshCompleted(message.value.clone())),
@@ -498,6 +516,19 @@ impl UnityMessagingClient {
498516
self.send_message(&refresh_message, timeout_seconds).await
499517
}
500518

519+
/// Requests compile errors from Unity
520+
///
521+
/// This method sends a compile errors request to Unity. The response will be available
522+
/// through the event system as a CompileErrors event.
523+
///
524+
/// # Returns
525+
///
526+
/// Returns `Ok(())` if the request was sent successfully
527+
pub async fn get_compile_errors(&self) -> Result<(), UnityMessagingError> {
528+
let compile_errors_message = Message::new(MessageType::GetCompileErrors, String::new());
529+
self.send_message(&compile_errors_message, None).await
530+
}
531+
501532
/// Executes tests based on the specified filter
502533
///
503534
/// This method sends a test execution request to Unity. Test events will be available

0 commit comments

Comments
 (0)