feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: gdc demo - #7

Open
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo
Open

feat: gdc demo#7
JoshuaMoelans wants to merge 16 commits into
mainfrom
gdc-demo

Conversation

@JoshuaMoelans

@JoshuaMoelansJoshuaMoelans commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Adds a bunch of QoL and fixes for us to be able to demo at GDC 2026 using our handhelds


ℹ️ This PR is not necessarily meant to be merged into main in full; there is some pure QoL, but the GDC specific 'DLC' changes could be left on this branch. We might split this up into a separate PR that brings only the relevant stuff over into main


⚠️ there are some changes we have locally (e.g., DSN setup, Nintendo input package, leaderboard login) that are not pushed to remote, but are necessary to build the demo properly. These changes live in DemoConfig.asset (_apiUrl, user.Username and user.Password), packages-lock.json , SentryOptions.asset (<Dsn>k__BackingField))

Overview

fixes

  • fixes HTTP requests on Switch by changing to UnityWebRequest instead of httpClient.
  • update scorePoster to provide controller support; now on game over, we pop in the elements one by one, automatically selecting the enter name field once everything is loaded. This will trigger the built-in keyboards on our handhelds. When deselecting the field, we navigate to the 'submit' button, so users just confirm by X/A to send their score.
  • fixes double-score-sending which could happen if spamming the confirm key on the Submit button.
  • adds a 'crash' trigger button (pressing down the right joystick) that is active during gameplay. This uses a null pointer dereference instead of Utils.ForceCrash, since the latter did not work on Switch.
  • fixed aim snapping back to default angle when letting go of right joystick.

cosmetic changes

  • update splash screen icon to Sentry glyph
  • change DLC icon to be GDC edition
  • add score to game over screen

co-authored by Claude

@JoshuaMoelans
JoshuaMoelans marked this pull request as ready for review March 3, 2026 07:35
Comment on lines +252 to +257
// WARNING, this also crashes in the Editor (on purpose, to easily test)
forceCrashAction.performed += _ =>
{
Debug.Log("ForceCrash triggered via input.");
Marshal.ReadInt32(IntPtr.Zero); // null pointer dereference — works on all platforms
};

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

our other 'crash on game over' does not trigger in the Editor, which makes sense since this also does crash the Editor itself... we could add the same safeguard here, I just kept it like this to make testing slightly easier.

@JoshuaMoelans

Copy link
Copy Markdown
ContributorAuthor

@sentry review

false, // multiline
false, // secure
false, // alert
_nameField.placeholder.GetComponent<TextMeshProUGUI>().text // placeholder text

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: A potential NullReferenceException exists when opening the on-screen keyboard. The code accesses _nameField.placeholder without checking if it's null, which can cause a crash.
Severity: HIGH

Suggested Fix

Use the null-conditional operator (?.) and null-coalescing operator (??) to safely access the placeholder text and provide an empty string as a fallback: _nameField.placeholder?.GetComponent<TextMeshProUGUI>()?.text ?? "".

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L192
Potential issue: The code at `ScorePoster.cs:192` attempts to get the placeholder text
for the on-screen keyboard using
`_nameField.placeholder.GetComponent<TextMeshProUGUI>().text`. However, the
`_nameField.placeholder` property can be null if it's not assigned in the Unity editor.
This will cause a `NullReferenceException` when `GetComponent` is called on a null
object. A second `NullReferenceException` can occur if the placeholder exists but lacks
a `TextMeshProUGUI` component, as `.text` would be accessed on a null result. This will
crash the application on touch-supported devices when the user tries to enter their
name.

Did we get this right? 👍 / 👎 to inform future reviews.

_buttonText.text = "Retry";
uploadTransaction.Finish(SpanStatus.InternalError);
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: An HttpClient instance is created in Start() but is never disposed in OnDestroy(), causing a resource leak every time the scene is reloaded on non-Switch platforms.
Severity: MEDIUM

Suggested Fix

Implement the IDisposable interface on the ScorePoster class and call _httpClient?.Dispose() within the Dispose method. Then, call this Dispose method from OnDestroy() to ensure the HttpClient is properly cleaned up when the object is destroyed.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: Assets/Scripts/UI/ScorePoster.cs#L142
Potential issue: On non-Switch platforms, an `HttpClient` instance is created in the
`Start()` method of the `ScorePoster` component but is never disposed. Because the
`ScorePoster` is destroyed and recreated every time the scene is reloaded (e.g., when
the player clicks "Try Again"), a new `HttpClient` is leaked with each playthrough. This
consumes system resources like connection sockets, which can lead to performance
degradation, connection failures, or crashes over extended sessions, particularly in a
demo environment.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for freeto 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.

1 participant

@JoshuaMoelans