20240422
This commit is contained in:
commit
e0afef912e
1285 files changed
+83219
No files matched your search
@@ -0,0 +1,74 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="MapMatcher.cs" company="Mapbox">
|
||||
// Copyright (c) 2017 Mapbox. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace Mapbox.MapMatching
|
||||
{
|
||||
using System;
|
||||
using System.Text;
|
||||
using Mapbox.Json;
|
||||
using Mapbox.Platform;
|
||||
using Mapbox.Utils.JsonConverters;
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper around the <see href="https://www.mapbox.com/api-documentation/navigation/#map-matching">
|
||||
/// Mapbox Map Matching API</see>.
|
||||
/// </summary>
|
||||
public class MapMatcher
|
||||
{
|
||||
private readonly IFileSource _fileSource;
|
||||
private int _timeout;
|
||||
|
||||
/// <summary> Initializes a new instance of the <see cref="MapMatcher" /> class. </summary>
|
||||
/// <param name="fileSource"> Network access abstraction. </param>
|
||||
public MapMatcher(IFileSource fileSource, int timeout)
|
||||
{
|
||||
_fileSource = fileSource;
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
/// <summary> Performs asynchronously a geocoding lookup. </summary>
|
||||
/// <param name="geocode"> Geocode resource. </param>
|
||||
/// <param name="callback"> Callback to be called after the request is completed. </param>
|
||||
/// <typeparam name="T"> String or LngLat. Should be automatically inferred. </typeparam>
|
||||
/// <returns>
|
||||
/// Returns a <see cref="IAsyncRequest" /> that can be used for canceling a pending
|
||||
/// request. This handle can be completely ignored if there is no intention of ever
|
||||
/// canceling the request.
|
||||
/// </returns>
|
||||
public IAsyncRequest Match(MapMatchingResource match, Action<MapMatchingResponse> callback)
|
||||
{
|
||||
string url = match.GetUrl();
|
||||
return _fileSource.Request(
|
||||
url,
|
||||
(Response response) =>
|
||||
{
|
||||
var str = Encoding.UTF8.GetString(response.Data);
|
||||
var data = Deserialize<MapMatchingResponse>(str);
|
||||
|
||||
if (response.HasError)
|
||||
{
|
||||
data.SetRequestExceptions(response.Exceptions);
|
||||
}
|
||||
|
||||
callback(data);
|
||||
},
|
||||
_timeout
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize the map match response string into a <see cref="MapMatchingResponse"/>.
|
||||
/// </summary>
|
||||
/// <param name="str">JSON String.</param>
|
||||
/// <returns>A <see cref="MapMatchingResponse"/>.</returns>
|
||||
/// <typeparam name="T">Map Matcher. </typeparam>
|
||||
internal T Deserialize<T>(string str)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(str, JsonConverters.Converters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfdfc6d95bc72494e8ae78580d2e6b44
|
||||
timeCreated: 1508239177
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,115 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="MapMatchingParameters.cs" company="Mapbox">
|
||||
// Copyright (c) 2017 Mapbox. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Mapbox.VectorTile.Geometry;
|
||||
|
||||
namespace Mapbox.MapMatching
|
||||
{
|
||||
/// <summary>Directions profile id</summary>
|
||||
public enum Profile
|
||||
{
|
||||
[Description("mapbox/driving")]
|
||||
MapboxDriving,
|
||||
[Description("mapbox/driving-traffic")]
|
||||
MapboxDrivingTraffic,
|
||||
[Description("mapbox/walking")]
|
||||
MapboxWalking,
|
||||
[Description("mapbox/cycling")]
|
||||
MapboxCycling
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Format of the returned geometry. Default value 'Polyline' with precision 5.</summary>
|
||||
public enum Geometries
|
||||
{
|
||||
/// <summary>Default, precision 5.</summary>
|
||||
[Description("polyline")]
|
||||
Polyline,
|
||||
/// <summary>Precision 6.</summary>
|
||||
[Description("polyline6")]
|
||||
Polyline6,
|
||||
/// <summary>Geojson.</summary>
|
||||
[Description("geojson")]
|
||||
GeoJson
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Type of returned overview geometry. </summary>
|
||||
public enum Overview
|
||||
{
|
||||
/// <summary>The most detailed geometry available </summary>
|
||||
[Description("full")]
|
||||
Full,
|
||||
/// <summary>A simplified version of the full geometry</summary>
|
||||
[Description("simplified")]
|
||||
Simplified,
|
||||
/// <summary>No overview geometry </summary>
|
||||
[Description("false")]
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
/// <summary>Whether or not to return additional metadata along the route. Several annotations can be used.</summary>
|
||||
[System.Flags]
|
||||
public enum Annotations
|
||||
{
|
||||
[Description("duration")]
|
||||
Duration,
|
||||
[Description("distance")]
|
||||
Distance,
|
||||
[Description("speed")]
|
||||
Speed,
|
||||
[Description("congestion")]
|
||||
Congestion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// https://www.mapbox.com/api-documentation/navigation/#retrieve-directions
|
||||
/// </summary>
|
||||
public enum InstructionLanguages
|
||||
{
|
||||
[Description("de")]
|
||||
German,
|
||||
[Description("en")]
|
||||
English,
|
||||
[Description("eo")]
|
||||
Esperanto,
|
||||
[Description("es")]
|
||||
Spanish,
|
||||
[Description("es-ES")]
|
||||
SpanishSpain,
|
||||
[Description("fr")]
|
||||
French,
|
||||
[Description("id")]
|
||||
Indonesian,
|
||||
[Description("it")]
|
||||
Italian,
|
||||
[Description("nl")]
|
||||
Dutch,
|
||||
[Description("pl")]
|
||||
Polish,
|
||||
[Description("pt-BR")]
|
||||
PortugueseBrazil,
|
||||
[Description("ro")]
|
||||
Romanian,
|
||||
[Description("ru")]
|
||||
Russian,
|
||||
[Description("sv")]
|
||||
Swedish,
|
||||
[Description("tr")]
|
||||
Turkish,
|
||||
[Description("uk")]
|
||||
Ukrainian,
|
||||
[Description("vi")]
|
||||
Vietnamese,
|
||||
[Description("zh-Hans")]
|
||||
ChineseSimplified
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 991f42eef2c18204cb4a6b79c6f98eed
|
||||
timeCreated: 1508237904
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,209 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="MapMatchingResource.cs" company="Mapbox">
|
||||
// Copyright (c) 2017 Mapbox. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace Mapbox.MapMatching
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Mapbox.Platform;
|
||||
using Mapbox.Utils;
|
||||
using Mapbox.VectorTile.ExtensionMethods;
|
||||
|
||||
/// <summary> Base geocode class. </summary>
|
||||
/// <typeparam name="T"> Type of Query field (either string or LatLng). </typeparam>
|
||||
public class MapMatchingResource : Resource
|
||||
{
|
||||
|
||||
private readonly string _apiEndpoint = "matching/v5/";
|
||||
private Vector2d[] _coordinates;
|
||||
private uint[] _radiuses;
|
||||
private long[] _timestamps;
|
||||
|
||||
|
||||
/// <summary> Gets the API endpoint as a partial URL path. </summary>
|
||||
public override string ApiEndpoint
|
||||
{
|
||||
get { return _apiEndpoint; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>A directions profile ID.</summary>
|
||||
public Profile Profile = Profile.MapboxDriving;
|
||||
|
||||
|
||||
/// <summary> Coordinate to visit in order; there can be between 2 and 100 coordinates. </summary>
|
||||
public Vector2d[] Coordinates
|
||||
{
|
||||
get { return _coordinates; }
|
||||
set
|
||||
{
|
||||
if (null == value)
|
||||
{
|
||||
throw new Exception("Coordinates cannot be null.");
|
||||
}
|
||||
if (value.Length < 2 || value.Length > 100)
|
||||
{
|
||||
throw new Exception("Must be between 2 and 100 elements in coordinates array");
|
||||
}
|
||||
|
||||
_coordinates = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Format of the returned geometry.</para>
|
||||
/// <para>Allowed values are: geojson (as LineString ), polyline with precision 5, polyline6 (polyline with precision 6).</para>
|
||||
/// <para>The default value is polyline.</para>
|
||||
/// </summary>
|
||||
public Nullable<Geometries> Geometries;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>A list of uints in meters indicating the assumed precision of the used tracking device.</para>
|
||||
/// <para>There must be as many radiuses as there are coordinates in the request.</para>
|
||||
/// <para>Values can be a number between 0 and 30.</para>
|
||||
/// <para>Use higher numbers (20-30) for noisy traces and lower numbers (1-10) for clean traces.</para>
|
||||
/// <para>The default value is 5.</para>
|
||||
/// </summary>
|
||||
public uint[] Radiuses
|
||||
{
|
||||
get { return _radiuses; }
|
||||
set
|
||||
{
|
||||
if (null == _coordinates) { throw new Exception("Coordinates not set"); }
|
||||
//allow for nulling radiuses
|
||||
if (null == value)
|
||||
{
|
||||
_radiuses = null;
|
||||
return;
|
||||
}
|
||||
if (value.Length != _coordinates.Length) { throw new Exception("There must be as many radiuses as there are coordinates in the request."); }
|
||||
if (value.Where(r => r == 0).Count() > 0) { throw new Exception("Radius must be greater than 0"); }
|
||||
|
||||
_radiuses = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether to return steps and turn-by-turn instructions.</para>
|
||||
/// <para>Can be true or false.</para>
|
||||
/// <para>The default is false.</para>
|
||||
/// </summary>
|
||||
public bool? Steps;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Type of returned overview geometry.</para>
|
||||
/// <para>Can be full (the most detailed geometry available), simplified (a simplified version of the full geometry), or none (no overview geometry).</para>
|
||||
/// <para>The default is simplified.</para>
|
||||
/// </summary>
|
||||
public Nullable<Overview> Overview;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Timestamps corresponding to each coordinate provided in the request.</para>
|
||||
/// <para>Must be numbers in Unix time (seconds since the Unix epoch).</para>
|
||||
/// <para>There must be as many timestamps as there are coordinates in the request.</para>
|
||||
/// </summary>
|
||||
public long[] Timestamps
|
||||
{
|
||||
get { return _timestamps; }
|
||||
set
|
||||
{
|
||||
if (null == _coordinates) { throw new Exception("Coordinates not set"); }
|
||||
//allow for nulling timestamps
|
||||
if (null == value)
|
||||
{
|
||||
_timestamps = null;
|
||||
return;
|
||||
}
|
||||
if (value.Length != _coordinates.Length) { throw new Exception("There must be as many timestapms as there are coordinates in the request."); }
|
||||
|
||||
_timestamps = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether or not to return additional metadata along the route.</para>
|
||||
/// <para>Possible values are: duration, distance and speed.</para>
|
||||
/// <para>Several annotations can be used.</para>
|
||||
/// <para>Combine via '|'.</para>
|
||||
/// </summary>
|
||||
public Nullable<Annotations> Annotations;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether or not to transparently remove clusters and re-sample traces for improved map matching results.</para>
|
||||
/// <para>Removed tracepoints are set to 'null' in the response!</para>
|
||||
/// <para>Can be true or false.</para>
|
||||
/// <para>The default is false.</para>
|
||||
/// </summary>
|
||||
public bool? Tidy;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Language of returned turn-by-turn text instructions.</para>
|
||||
/// <para>The default is English.</para>
|
||||
/// </summary>
|
||||
public Nullable<InstructionLanguages> Language;
|
||||
|
||||
|
||||
public override string GetUrl()
|
||||
{
|
||||
if (null == _coordinates)
|
||||
{
|
||||
throw new Exception("Coordinates cannot be null.");
|
||||
}
|
||||
|
||||
Dictionary<string, string> options = new Dictionary<string, string>();
|
||||
|
||||
if (Geometries.HasValue) { options.Add("geometries", Geometries.Value.Description()); }
|
||||
if (null != _radiuses) { options.Add("radiuses", GetUrlQueryFromArray(_radiuses, ";")); }
|
||||
if (Steps.HasValue) { options.Add("steps", Steps.ToString().ToLower()); }
|
||||
if (Overview.HasValue) { options.Add("overview", Overview.Value.Description()); }
|
||||
if (null != _timestamps) { options.Add("timestamps", GetUrlQueryFromArray(_timestamps, ";")); }
|
||||
if (Annotations.HasValue) { options.Add("annotations", getUrlQueryFromAnnotations(Annotations.Value, ",")); }
|
||||
if (Tidy.HasValue) { options.Add("tidy", Tidy.Value.ToString().ToLower()); }
|
||||
if (Language.HasValue) { options.Add("language", Language.Value.Description()); }
|
||||
|
||||
return
|
||||
Constants.BaseAPI
|
||||
+ _apiEndpoint
|
||||
+ Profile.Description() + "/"
|
||||
+ GetUrlQueryFromArray<Vector2d>(_coordinates, ";")
|
||||
+ ".json"
|
||||
+ EncodeQueryString(options);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert Annotations (several could be combined) into a string of their descriptions.
|
||||
/// </summary>
|
||||
/// <param name="annotation">Current annotation</param>
|
||||
/// <param name="separator">Character to use for separating items in string.</param>
|
||||
/// <returns></returns>
|
||||
private string getUrlQueryFromAnnotations(Annotations anno, string separator)
|
||||
{
|
||||
List<string> descriptions = new List<string>();
|
||||
|
||||
//iterate through all possible 'Annotations' values
|
||||
foreach (var a in Enum.GetValues(typeof(Annotations)).Cast<Annotations>())
|
||||
{
|
||||
//if current value is set, add its description
|
||||
if (a == (anno & a)) { descriptions.Add(a.Description()); }
|
||||
}
|
||||
|
||||
return string.Join(separator, descriptions.ToArray());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8762d1b8a83c7ba4b91f9a1c64717bee
|
||||
timeCreated: 1508240506
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,72 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="MapMatchingResponse.cs" company="Mapbox">
|
||||
// Copyright (c) 2016 Mapbox. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace Mapbox.MapMatching
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Mapbox.Json;
|
||||
|
||||
/// <summary> Base geocode response. </summary>
|
||||
#if !WINDOWS_UWP
|
||||
//http://stackoverflow.com/a/12903628
|
||||
[Serializable]
|
||||
#endif
|
||||
public class MapMatchingResponse
|
||||
{
|
||||
/// <summary>Simple constructor for deserialization </summary>
|
||||
public MapMatchingResponse() { }
|
||||
|
||||
[JsonProperty("code")]
|
||||
public string Code;
|
||||
[JsonProperty("message")]
|
||||
public string Message;
|
||||
[JsonProperty("tracepoints")]
|
||||
public Tracepoint[] Tracepoints;
|
||||
[JsonProperty("matchings")]
|
||||
public MatchObject[] Matchings;
|
||||
#if !WINDOWS_UWP
|
||||
/// <summary>Error occured during matching</summary>
|
||||
public bool HasMatchingError { get { return !"ok".Equals(Code, StringComparison.InvariantCultureIgnoreCase); } }
|
||||
#else
|
||||
/// <summary>Error occured during matching</summary>
|
||||
public bool HasMatchingError { get { return !"ok".Equals(Code, StringComparison.OrdinalIgnoreCase); } }
|
||||
#endif
|
||||
|
||||
public string MatchingError
|
||||
{
|
||||
get
|
||||
{
|
||||
string matchCode = Code.ToLower();
|
||||
switch (matchCode)
|
||||
{
|
||||
case "ok": return "";
|
||||
case "nomatch": return "The input did not produce any matches. features will be an empty array.";
|
||||
case "toomanycoordinates": return "There are to many points in the request.";
|
||||
case "InvalidInput": return "Invalid input: 'message' will hold an explanation of the invalid input.";
|
||||
case "ProfileNotFound": return "Invalid profile.";
|
||||
case "nosegment": return "Could not find a matching segment for input coordinates.";
|
||||
default:
|
||||
return "Unexpected error: check 'message'";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Errors occured during web request </summary>
|
||||
public bool HasRequestError { get { return _requestExceptions.Count > 0; } }
|
||||
|
||||
private ReadOnlyCollection<Exception> _requestExceptions = new List<Exception>().AsReadOnly();
|
||||
/// <summary>Errors of underlying web request </summary>
|
||||
public ReadOnlyCollection<Exception> RequestExceptions { get { return _requestExceptions; } }
|
||||
/// <summary>Assign errors of underlying web request </summary>
|
||||
public void SetRequestExceptions(ReadOnlyCollection<Exception> exceptions) { _requestExceptions = exceptions; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b0f824b73d2d8f41aeed79f2a15666d
|
||||
timeCreated: 1508247612
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="MatchObject.cs" company="Mapbox">
|
||||
// Copyright (c) 2017 Mapbox. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace Mapbox.MapMatching
|
||||
{
|
||||
using Mapbox.Directions;
|
||||
using Mapbox.Json;
|
||||
|
||||
/// <summary>
|
||||
/// A Match object from a Map Matching API call.
|
||||
/// </summary>
|
||||
public class MatchObject : Route
|
||||
{
|
||||
/// <summary>
|
||||
/// A number between 0 (low) and 1 (high) indicating level of confidence in the returned match
|
||||
/// </summary>
|
||||
[JsonProperty("confidence")]
|
||||
public float Confidence { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6d1f89031e0a60479b516a76cf1a96a
|
||||
timeCreated: 1508309612
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
//-----------------------------------------------------------------------
|
||||
// <copyright file="Tracepoint.cs" company="Mapbox">
|
||||
// Copyright (c) 2017 Mapbox. All rights reserved.
|
||||
// </copyright>
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
namespace Mapbox.MapMatching
|
||||
{
|
||||
using Mapbox.Directions;
|
||||
using Mapbox.Json;
|
||||
using Mapbox.Utils;
|
||||
using Mapbox.Utils.JsonConverters;
|
||||
|
||||
/// <summary>
|
||||
/// A Waypoint from a Directions API call.
|
||||
/// </summary>
|
||||
public class Tracepoint: Waypoint
|
||||
{
|
||||
/// <summary>
|
||||
/// Index of the waypoint inside the matched route.
|
||||
/// </summary>
|
||||
[JsonProperty("waypoint_index")]
|
||||
public int WaypointIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Index to the match object in matchings the sub-trace was matched to.
|
||||
/// </summary>
|
||||
[JsonProperty("matchings_index")]
|
||||
public int MatchingsIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of probable alternative matchings for this trace point. A value of zero indicates that this point was matched unambiguously. Split the trace at these points for incremental map matching.
|
||||
/// </summary>
|
||||
[JsonProperty("alternatives_count")]
|
||||
public int AlternativesCount { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd23eaecbb5aa1947ad2b7a595c2393e
|
||||
timeCreated: 1508251969
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in new issue
Block a user