Skip to content

Commit a249bfb

Browse files
committed
Merge branch 'master' into 2022.2
# Conflicts: # Assets/WebGLTemplates/Release/pretty-console.js.meta
2 parents 2c8840b + cb5e331 commit a249bfb

File tree

15 files changed

+363
-110
lines changed

15 files changed

+363
-110
lines changed

Assets/Plugins/WebGL/WebGLTools/WebGlBridge.Commands.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,15 +123,27 @@ public void ToggleInfoPanel()
123123
}
124124

125125
/// <summary>
126-
/// Log example messages to see if they are rendered and colored correctly
126+
/// Log the user agent of the browser and if this agent is classified as mobile
127+
/// Browser Usage: <code>unityGame.SendMessage("WebGL", "LogUserAgent");</code>
128+
/// </summary>
129+
[WebGlCommand(Description = "Log User Agent and isMobileDevice")]
130+
public void LogUserAgent()
131+
{
132+
string userAgent = WebGlPlugins.GetUserAgent();
133+
bool isMobileDevice = WebGlPlugins.IsMobileDevice();
134+
Debug.Log($"<color=#4D65A4>User Agent:</color> '{userAgent}', <color=#4D65A4>IsMobileDevice:</color> '{isMobileDevice}'");
135+
}
136+
137+
/// <summary>
138+
/// Log example messages to show off unity rich text parsing to html & console styling
127139
/// </summary>
128140
[WebGlCommand(Description = "Log example messages for Log, warning and error")]
129141
[ContextMenu(nameof(LogExampleMessages))]
130142
public void LogExampleMessages()
131143
{
132-
Debug.Log("This is an example <color=#2596be>log</color> message, showing off <color=#ff00ff>rich text support with <color=#ff0000>[nesting (I should be red - not supported yet)]</color></color>!");
133-
Debug.LogWarning("This is an example <color=#e28743>warning</color> message!");
134-
Debug.LogError("This is an example <color=#d36a33>error</color> message!");
144+
Debug.Log("Example unity rich text example with <color=red>red and <color=blue>nested blue</color> color tags</color> and <b>bold</b> + <i>italic</i> tags, and <size=20>custom size with <b><i>bold italic nesting</i></b></size> tag.");
145+
Debug.LogWarning("This is an <b>example <color=#e28743>warning</color></b> message!");
146+
Debug.LogError("This is an <b>example <color=#b50808>error</color></b> message!");
135147
}
136148

137149
/// <summary>

Assets/Plugins/WebGL/WebGLTools/WebGlPlugins.cs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public static class WebGlPlugins
2929
[DllImport("__Internal")]
3030
private static extern void _HideInfoPanel();
3131
[DllImport("__Internal")]
32+
private static extern string _GetUserAgent();
33+
[DllImport("__Internal")]
3234
private static extern uint _GetTotalMemorySize();
3335
[DllImport("__Internal")]
3436
private static extern uint _GetStaticMemorySize();
@@ -51,7 +53,7 @@ public static void SetVariable(string variableName, string value)
5153
#endif
5254
Debug.Log($"<color=#00CCCC>{nameof(WebGlPlugins)}.{nameof(SetVariable)} set {variableName}: {value}</color>");
5355
}
54-
56+
5557
/// <summary>
5658
/// Adds a time marker at the call time to the javascript map "unityTimeTrackers"
5759
/// The mapped value is performance.now() at the time of the call
@@ -65,7 +67,7 @@ public static void AddTimeTrackingEvent(string eventName)
6567
Debug.Log($"{nameof(WebGlPlugins)}.{nameof(AddTimeTrackingEvent)} called with {eventName}");
6668
#endif
6769
}
68-
70+
6971
/// <summary>
7072
/// Show the info panel in the top right corner
7173
/// By default triggered by <see cref="WebGlTimeTracker"/> in Awake
@@ -80,7 +82,7 @@ public static void ShowInfoPanel()
8082
Debug.Log($"{nameof(WebGlPlugins)}.{nameof(ShowInfoPanel)} called");
8183
#endif
8284
}
83-
85+
8486
/// <summary>
8587
/// Hide the info panel in the top right corner
8688
/// By default triggered by <see cref="WebGlTimeTracker"/> in Awake
@@ -111,6 +113,33 @@ public static void ToggleInfoPanel()
111113
}
112114
}
113115

116+
/// <summary>
117+
/// Get navigator.userAgent from the browser
118+
/// </summary>
119+
/// <returns>navigator.userAgent</returns>
120+
public static string GetUserAgent()
121+
{
122+
#if UNITY_WEBGL && !UNITY_EDITOR
123+
return _GetUserAgent();
124+
#else
125+
Debug.Log($"{nameof(WebGlPlugins)}.{nameof(GetUserAgent)} called");
126+
return "undefined";
127+
#endif
128+
}
129+
130+
/// <summary>
131+
/// Check user agent to determine if the game runs on a mobile device
132+
/// </summary>
133+
/// <returns>true if on phone or tablet</returns>
134+
public static bool IsMobileDevice()
135+
{
136+
string userAgent = GetUserAgent();
137+
return userAgent.Contains("iPhone") ||
138+
userAgent.Contains("iPad") ||
139+
userAgent.Contains("iPod") ||
140+
userAgent.Contains("Android");
141+
}
142+
114143
/// <summary>
115144
/// Get the total memory size used by the application in MB
116145
/// </summary>
@@ -194,7 +223,7 @@ public static float GetManagedMemorySize()
194223
var bytes = (uint) GC.GetTotalMemory(false);
195224
return GetMegaBytes(bytes);
196225
}
197-
226+
198227
/// <summary>
199228
/// Converts bytes (B) to mega bytes (MB)
200229
/// </summary>

Assets/Plugins/WebGL/WebGLTools/WebGlPlugins.jslib

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,26 @@ var WebGlPlugins =
6060
setInfoPanelVisible(false);
6161
}
6262
},
63-
63+
64+
_GetUserAgent: function () {
65+
var userAgent = navigator.userAgent;
66+
67+
//Get size of the string
68+
var bufferSize = lengthBytesUTF8(userAgent) + 1;
69+
//Allocate memory space
70+
var buffer = _malloc(bufferSize);
71+
72+
//Copy old data to the new one then return it
73+
if(typeof stringToUTF8 !== 'undefined') {
74+
stringToUTF8(userAgent, buffer, bufferSize);
75+
}
76+
else if(typeof writeStringToMemory !== 'undefined') {
77+
writeStringToMemory(userAgent, buffer);
78+
}
79+
80+
return buffer;
81+
},
82+
6483
_GetTotalMemorySize: function()
6584
{
6685
if(typeof TOTAL_MEMORY !== 'undefined') {

Assets/WebGLTemplates/Develop/debug-console.js

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,33 @@ function setupConsoleLogPipe() {
270270
let defaultConsoleError = console.error;
271271

272272
// Overwrite log functions to parse and pipe to debug html console
273-
console.log = (message) => { parseMessageAndLog(message, 'log', defaultConsoleLog); };
274-
console.info = (message) => { parseMessageAndLog(message, 'info', defaultConsoleInfo); };
275-
console.debug = (message) => { parseMessageAndLog(message, 'debug', defaultConsoleDebug); };
276-
console.warn = (message) => { parseMessageAndLog(message, 'warn', defaultConsoleWarn); };
277-
console.error = (message) => { parseMessageAndLog(message, 'error', defaultConsoleError); errorReceived(); };
273+
console.log = (message) => { handleLog(message, 'log', defaultConsoleLog); };
274+
console.info = (message) => { handleLog(message, 'info', defaultConsoleInfo); };
275+
console.debug = (message) => { handleLog(message, 'debug', defaultConsoleDebug); };
276+
console.warn = (message) => { handleLog(message, 'warn', defaultConsoleWarn); };
277+
console.error = (message) => { handleLog(message, 'error', defaultConsoleError); errorReceived(); };
278278

279279

280-
parseMessageAndLog = (message, logLevel, consoleLogFunction) => {
280+
handleLog = (message, logLevel, consoleLogFunction) => {
281281
updateLogCounter(logLevel);
282+
if (typeof message === 'string') {
283+
// Only parse messages that are actual strings
284+
parseMessageAndLog(message, logLevel, consoleLogFunction);
285+
}
286+
else {
287+
consoleLogFunction(message);
288+
// Try to also log the object to the html console (does not always work in a meaningful manner)
289+
var htmlMessage;
290+
try {
291+
htmlMessage = JSON.stringify(message);
292+
} catch (error) {
293+
htmlMessage = `Can't convert message to JSON: ${error}`;
294+
}
295+
htmlLog(htmlMessage, logLevel);
296+
}
297+
};
298+
299+
parseMessageAndLog = (message, logLevel, consoleLogFunction) => {
282300
let styledTextParts = parseUnityRichText(message);
283301

284302
let consoleText = '';
@@ -301,16 +319,17 @@ class StyledTextPart {
301319
}
302320

303321
toHTML() {
304-
if(this.styles.length > 0) {
322+
if (this.styles.length > 0) {
305323
return `<span style="${this.styles.join(';')}">${this.text}</span>`;
306324
}
307325
return this.text;
308326
}
309327

310328
toConsoleStyleString() {
311-
if(this.styles.length > 0) {
329+
if (this.styles.length > 0) {
312330
return this.styles.join(';');
313331
}
332+
// Return some styling that does not change anything to support unstyled text
314333
return 'color:inherit';
315334
}
316335

@@ -321,11 +340,12 @@ class StyledTextPart {
321340

322341
function parseUnityRichText(message) {
323342
// Mapping for unity tags to css style tags
343+
// Unity rich text tags, see https://docs.unity3d.com/Packages/com.unity.ugui@1.0/manual/StyledText.html
324344
const tagMap = {
325-
'color': {startTag: '<color=', closeTag: '</color>', styleTag: 'color:', postfix: '', hasParameter: true},
326-
'size': {startTag: '<size=', closeTag: '</size>', styleTag: 'font-size:', postfix: 'px', hasParameter: true},
327-
'bold': {startTag: '<b', closeTag: '</b>', styleTag: 'font-weight:', styleValue: 'bold', hasParameter: false},
328-
'italic': {startTag: '<i', closeTag: '</i>', styleTag: 'font-style:', styleValue: 'italic', hasParameter: false}
345+
'color': { startTag: '<color=', closeTag: '</color>', styleTag: 'color:', postfix: '', hasParameter: true },
346+
'size': { startTag: '<size=', closeTag: '</size>', styleTag: 'font-size:', postfix: 'px', hasParameter: true },
347+
'bold': { startTag: '<b', closeTag: '</b>', styleTag: 'font-weight:', styleValue: 'bold', hasParameter: false },
348+
'italic': { startTag: '<i', closeTag: '</i>', styleTag: 'font-style:', styleValue: 'italic', hasParameter: false }
329349
};
330350

331351
let index = 0;
@@ -338,7 +358,7 @@ function parseUnityRichText(message) {
338358
// next end index for each tag
339359
let nextEndIndex = [];
340360
Object.keys(tagMap).forEach(key => {
341-
nextStartIndex[key] = message.indexOf(tagMap[key].startTag, index);
361+
nextStartIndex[key] = message.indexOf(tagMap[key].startTag, index);
342362
nextEndIndex[key] = message.indexOf(tagMap[key].closeTag, index);
343363
});
344364

@@ -350,14 +370,14 @@ function parseUnityRichText(message) {
350370

351371
// find the next tag start or end
352372
Object.keys(tagMap).forEach(key => {
353-
if(nextStartIndex[key] >= 0 && nextStartIndex[key] < nextIndex) {
373+
if (nextStartIndex[key] >= 0 && nextStartIndex[key] < nextIndex) {
354374
nextIndex = nextStartIndex[key];
355375
nextKey = key;
356376
fromArray = nextStartIndex;
357377
nextTagFound = true;
358378
}
359379

360-
if(nextEndIndex[key] >= 0 && nextEndIndex[key] < nextIndex) {
380+
if (nextEndIndex[key] >= 0 && nextEndIndex[key] < nextIndex) {
361381
nextIndex = nextEndIndex[key];
362382
nextKey = key;
363383
fromArray = nextEndIndex;
@@ -366,39 +386,44 @@ function parseUnityRichText(message) {
366386
});
367387

368388
// write the text in before the next tag to our style text part array
369-
if(nextIndex > index) {
389+
if (nextIndex > index) {
370390
let messageToNextTag = message.substring(index, nextIndex);
371391
let styles = [...styleStack];
372392
styledTextParts.push(new StyledTextPart(messageToNextTag, styles));
373393
}
374394

375395
// end if no more tags exist
376-
if(nextTagFound === false) {
396+
if (nextTagFound === false) {
377397
index = message.length;
378398
break;
379399
}
380400

401+
let closeTagIndex = message.indexOf('>', nextIndex + 1);
402+
381403
// Process start tag
382-
if(fromArray === nextStartIndex) {
383-
nextStartIndex[nextKey] = message.indexOf(tagMap[nextKey].startTag, nextIndex+1);
384-
let closeTagIndex = message.indexOf('>', nextIndex+1);
404+
if (fromArray === nextStartIndex) {
385405
let styleValue;
386-
if(tagMap[nextKey].hasParameter) {
406+
if (tagMap[nextKey].hasParameter) {
387407
styleValue = message.substring(nextIndex + tagMap[nextKey].startTag.length, closeTagIndex);
388-
styleValue+=tagMap[nextKey].postfix;
408+
styleValue += tagMap[nextKey].postfix;
389409
} else {
390410
styleValue = tagMap[nextKey].styleValue;
391411
}
392412
styleStack.push(`${tagMap[nextKey].styleTag}${styleValue}`);
393-
index = closeTagIndex+1;
413+
414+
// Update list entry to next unprocessed start tag of type nextKey
415+
nextStartIndex[nextKey] = message.indexOf(tagMap[nextKey].startTag, nextIndex + 1);
394416
}
395417
// process end tag
396-
else if(fromArray === nextEndIndex) {
397-
nextEndIndex[nextKey] = message.indexOf(tagMap[nextKey].closeTag, nextIndex+1);
398-
let closeTagIndex = message.indexOf('>', nextIndex+1);
418+
else if (fromArray === nextEndIndex) {
399419
styleStack.pop();
400-
index = closeTagIndex+1;
420+
421+
// Update list entry to next unprocessed end tag of type nextKey
422+
nextEndIndex[nextKey] = message.indexOf(tagMap[nextKey].closeTag, nextIndex + 1);
401423
}
424+
425+
// Update index to position after the tag closes
426+
index = closeTagIndex + 1;
402427
}
403428
return styledTextParts;
404429
}

0 commit comments

Comments
 (0)