Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions com.unity.netcode.gameobjects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Additional documentation and release notes are available at [Multiplayer Documen

### Added

- Clicking on the Help icon in the inspector will now redirect to the relevant documentation. (#3663)

### Changed

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Unity.Mathematics;
using Unity.Netcode.Runtime;
using UnityEngine;

namespace Unity.Netcode.Components
Expand Down Expand Up @@ -43,6 +44,7 @@ namespace Unity.Netcode.Components
#pragma warning restore IDE0001
[DisallowMultipleComponent]
[AddComponentMenu("Netcode/Anticipated Network Transform")]
[HelpURL(HelpUrls.AnticipatedNetworkTransform)]
public class AnticipatedNetworkTransform : NetworkTransform
{

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Collections.Generic;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Netcode.Runtime;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor.Animations;
Expand Down Expand Up @@ -186,6 +187,7 @@ internal NetworkAnimatorStateChangeHandler(NetworkAnimator networkAnimator)
/// NetworkAnimator enables remote synchronization of <see cref="UnityEngine.Animator"/> state for on network objects.
/// </summary>
[AddComponentMenu("Netcode/Network Animator")]
[HelpURL(HelpUrls.NetworkAnimator)]
public class NetworkAnimator : NetworkBehaviour, ISerializationCallbackReceiver
{
[Serializable]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#if COM_UNITY_MODULES_PHYSICS
using Unity.Netcode.Runtime;
using UnityEngine;

namespace Unity.Netcode.Components
Expand All @@ -10,6 +11,7 @@ namespace Unity.Netcode.Components
[RequireComponent(typeof(NetworkTransform))]
[RequireComponent(typeof(Rigidbody))]
[AddComponentMenu("Netcode/Network Rigidbody")]
[HelpURL(HelpUrls.NetworkRigidbody)]
public class NetworkRigidbody : NetworkRigidbodyBase
{

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#if COM_UNITY_MODULES_PHYSICS2D
using Unity.Netcode.Runtime;
using UnityEngine;

namespace Unity.Netcode.Components
Expand All @@ -10,6 +11,7 @@ namespace Unity.Netcode.Components
[RequireComponent(typeof(NetworkTransform))]
[RequireComponent(typeof(Rigidbody2D))]
[AddComponentMenu("Netcode/Network Rigidbody 2D")]
[HelpURL(HelpUrls.NetworkRigidbody2D)]
public class NetworkRigidbody2D : NetworkRigidbodyBase
{
public Rigidbody2D Rigidbody2D => m_InternalRigidbody2D;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Runtime.CompilerServices;
using System.Text;
using Unity.Mathematics;
using Unity.Netcode.Runtime;
using UnityEngine;

namespace Unity.Netcode.Components
Expand All @@ -14,6 +15,7 @@ namespace Unity.Netcode.Components
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("Netcode/Network Transform")]
[HelpURL(HelpUrls.NetworkTransform)]
public class NetworkTransform : NetworkBehaviour
{
#if UNITY_EDITOR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using Unity.Netcode.Runtime;
using UnityEngine;

namespace Unity.Netcode.Components
Expand Down Expand Up @@ -71,6 +72,7 @@ public interface IContactEventHandlerWithInfo : IContactEventHandler
/// <see cref="ContactEventHandlerInfo"/><br />
/// </summary>
[AddComponentMenu("Netcode/Rigidbody Contact Event Manager")]
[HelpURL(HelpUrls.RigidbodyContactEventManager)]
public class RigidbodyContactEventManager : MonoBehaviour
{
public static RigidbodyContactEventManager Instance { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
using UnityEngine.SceneManagement;
using Debug = UnityEngine.Debug;
using Unity.Netcode.Components;
using Unity.Netcode.Runtime;

namespace Unity.Netcode
{
/// <summary>
/// The main component of the library
/// </summary>
[AddComponentMenu("Netcode/Network Manager", -100)]
[HelpURL(HelpUrls.NetworkManager)]
public class NetworkManager : MonoBehaviour, INetworkUpdateSystem
{
/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Runtime.CompilerServices;
using System.Text;
using Unity.Netcode.Components;
using Unity.Netcode.Runtime;
#if UNITY_EDITOR
using UnityEditor;
#if UNITY_2021_2_OR_NEWER
Expand All @@ -24,6 +25,7 @@ namespace Unity.Netcode
/// </summary>
[AddComponentMenu("Netcode/Network Object", -99)]
[DisallowMultipleComponent]
[HelpURL(HelpUrls.NetworkObject)]
public sealed class NetworkObject : MonoBehaviour
{
[HideInInspector]
Expand Down
22 changes: 22 additions & 0 deletions com.unity.netcode.gameobjects/Runtime/HelpUrls.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Unity.Netcode.Runtime
{
internal static class HelpUrls
{
private const string k_BaseUrl = "https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest/?subfolder=/";
private const string k_BaseManualUrl = k_BaseUrl + "manual/";
private const string k_BaseApiUrl = k_BaseUrl + "api/Unity.Netcode";

// The HelpUrls have to be defined as public for the test to work
public const string NetworkManager = k_BaseManualUrl + "components/core/networkmanager.html";
public const string NetworkObject = k_BaseManualUrl + "components/core/networkobject.html";
public const string NetworkAnimator = k_BaseManualUrl + "components/helper/networkanimator.html";
public const string NetworkRigidbody = k_BaseManualUrl + "advanced-topics/physics.html#networkrigidbody";
public const string NetworkRigidbody2D = k_BaseManualUrl + "advanced-topics/physics.html#networkrigidbody2d";
public const string RigidbodyContactEventManager = k_BaseApiUrl + ".Components.RigidbodyContactEventManager.html";
public const string NetworkTransform = k_BaseManualUrl + "components/helper/networktransform.html";
public const string AnticipatedNetworkTransform = k_BaseManualUrl + "advanced-topics/client-anticipation.html";
public const string UnityTransport = k_BaseApiUrl + ".Transports.UTP.UnityTransport.html";
public const string SecretsLoaderHelper = k_BaseApiUrl + ".Transports.UTP.SecretsLoaderHelper.html";
public const string SinglePlayerTransport = k_BaseApiUrl + ".Transports.SinglePlayer.SinglePlayerTransport.html";
}
}
3 changes: 3 additions & 0 deletions com.unity.netcode.gameobjects/Runtime/HelpUrls.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using Unity.Netcode.Runtime;
using UnityEngine;

namespace Unity.Netcode.Transports.SinglePlayer
{
Expand All @@ -11,6 +13,8 @@ namespace Unity.Netcode.Transports.SinglePlayer
/// <remarks>
/// You can only start as a host when using this transport.
/// </remarks>
[AddComponentMenu("Netcode/Single Player Transport")]
[HelpURL(HelpUrls.SinglePlayerTransport)]
public class SinglePlayerTransport : NetworkTransport
{
/// <inheritdoc/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using Unity.Netcode.Runtime;
using UnityEngine;

namespace Unity.Netcode.Transports.UTP
Expand All @@ -13,6 +14,7 @@ namespace Unity.Netcode.Transports.UTP
/// - SetClientSecrets
/// directly, instead of relying on this.
/// </summary>
[HelpURL(HelpUrls.SecretsLoaderHelper)]
public class SecretsLoaderHelper : MonoBehaviour
{
internal struct ServerSecrets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Netcode.Runtime;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Networking.Transport.TLS;
Expand All @@ -28,6 +29,7 @@ namespace Unity.Netcode.Transports.UTP
/// Note: This is highly recommended to use over UNet.
/// </summary>
[AddComponentMenu("Netcode/Unity Transport")]
[HelpURL(HelpUrls.UnityTransport)]
public partial class UnityTransport : NetworkTransport, INetworkStreamDriverConstructor
{
/// <summary>
Expand Down
165 changes: 165 additions & 0 deletions com.unity.netcode.gameobjects/Tests/Runtime/HelpUrlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NUnit.Framework;
using Unity.Netcode.Runtime;
using UnityEngine;
using UnityEngine.TestTools;

namespace Unity.Netcode.RuntimeTests
{
internal class HelpUrlTests
{
private const string k_PackageName = "com.unity.netcode.gameobjects";
private static readonly HttpClient k_HttpClient = new();

private bool m_VerboseLogging = false;

[UnityTest]
public IEnumerator ValidateUrlsAreValid()
{
var names = new List<string>();
var allUrls = new List<string>();

// GetFields() can only see public strings. Ensure each HelpUrl is public.
foreach (var constant in typeof(HelpUrls).GetFields())
{
if (constant.IsLiteral && !constant.IsInitOnly)
{
names.Add(constant.Name);
allUrls.Add((string)constant.GetValue(null));
}
}

VerboseLog($"Found {allUrls.Count} URLs");

var tasks = new List<Task<bool>>();
foreach (var url in allUrls)
{
tasks.Add(AreUnityDocsAvailableAt(url));
}

while (tasks.Any(task => !task.IsCompleted))
{
yield return new WaitForSeconds(0.01f);
}

for (int i = 0; i < allUrls.Count; i++)
{
Assert.IsTrue(tasks[i].Result, $"HelpUrls.{names[i]} has an invalid path! Path: {allUrls[i]}");
}
}

private async Task<bool> AreUnityDocsAvailableAt(string url)
{
try
{
var split = url.Split('#');
url = split[0];

var stream = await GetContentFromRemoteFile(url);

var redirectUrl = CalculateRedirectURl(url, stream);
VerboseLog($"Calculated Redirect URL: {redirectUrl}");

var content = await GetContentFromRemoteFile(redirectUrl);

// If original url had an anchor part (e.g. some/url.html#anchor)
if (split.Length > 1)
{
var anchorString = split[1];

// All headings will have an id with the anchorstring (e.g. <h2 id="anchor">)
if (!content.Contains($"id=\"{anchorString}\">"))
{
return false;
}
}

return true;
}
catch (Exception e)
{
VerboseLog(e.Message);
return false;
}
}

/// <summary>
/// Checks if a remote file at the <paramref name="url"/> exists, and if access is not restricted.
/// </summary>
/// <param name="url">URL to a remote file.</param>
/// <returns>True if the file at the <paramref name="url"/> is able to be downloaded, false if the file does not exist, or if the file is restricted.</returns>
private async Task<string> GetContentFromRemoteFile(string url)
{
//Checking if URI is well formed is optional
var uri = new Uri(url);
if (!uri.IsWellFormedOriginalString())
{
throw new Exception($"URL {url} is not well formed");
}

try
{
using var request = new HttpRequestMessage(HttpMethod.Get, uri);
using var response = await k_HttpClient.SendAsync(request);
if (!response.IsSuccessStatusCode || response.Content.Headers.ContentLength <= 0)
{
throw new Exception($"Failed to get remote file from URL {url}");
}

return await response.Content.ReadAsStringAsync();
}
catch
{
throw new Exception($"URL {url} request failed");
}
}

private string CalculateRedirectURl(string originalRequest, string content)
{
var uri = new Uri(originalRequest);
var baseRequest = $"{uri.Scheme}://{uri.Host}";
foreach (var segment in uri.Segments)
{
if (segment.Contains(k_PackageName))
{
break;
}
baseRequest += segment;
}

var subfolderRegex = new Regex(@"[?&](\w[\w.]*)=([^?&]+)").Match(uri.Query);
var subfolder = "";
foreach (Group match in subfolderRegex.Groups)
{
subfolder = match.Value;
}

string pattern = @"com.unity.netcode.gameobjects\@(\d+.\d+)";
var targetDestination = "";
foreach (Match match in Regex.Matches(content, pattern))
{
targetDestination = match.Value;
break;
}

return baseRequest + targetDestination + subfolder;
}

private void VerboseLog(string message)
{
if (m_VerboseLogging)
{
Debug.unityLogger.Log(message);
}
}

}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.