Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

0.7.4.1
Diva Canto 2012-03-10 08:09:43 -08:00
commit 291dc39691
11 changed files with 258 additions and 115 deletions

View File

@ -86,6 +86,7 @@ what it is today.
* Grumly57 * Grumly57
* GuduleLapointe * GuduleLapointe
* Ewe Loon * Ewe Loon
* Fernando Oliveira
* Fly-Man * Fly-Man
* Flyte Xevious * Flyte Xevious
* Imaze Rhiano * Imaze Rhiano
@ -135,6 +136,7 @@ what it is today.
* Ruud Lathorp * Ruud Lathorp
* SachaMagne * SachaMagne
* Salahzar Stenvaag * Salahzar Stenvaag
* satguru p srivastava
* sempuki * sempuki
* SignpostMarv * SignpostMarv
* SpotOn3D * SpotOn3D

View File

@ -28,6 +28,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Xml;
using log4net; using log4net;
using OpenMetaverse; using OpenMetaverse;
@ -39,6 +40,13 @@ namespace OpenSim.Framework
#region SL / file extension / content-type conversions #region SL / file extension / content-type conversions
public static Dictionary<string, UUID> DefaultAvatarAnimations = new Dictionary<string, UUID>();
static SLUtil()
{
DefaultAvatarAnimations = LoadDefaultAvatarAnimations("data/avataranimations.xml");
}
public static string SLAssetTypeToContentType(int assetType) public static string SLAssetTypeToContentType(int assetType)
{ {
switch ((AssetType)assetType) switch ((AssetType)assetType)
@ -374,5 +382,47 @@ namespace OpenSim.Framework
return output; return output;
} }
/// <summary>
/// Load the default SL avatar animations.
/// </summary>
/// <returns></returns>
public static Dictionary<string, UUID> LoadDefaultAvatarAnimations(string path)
{
Dictionary<string, UUID> animations = new Dictionary<string, UUID>();
using (XmlTextReader reader = new XmlTextReader(path))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
if (doc.DocumentElement != null)
{
foreach (XmlNode nod in doc.DocumentElement.ChildNodes)
{
if (nod.Attributes["name"] != null)
{
string name = nod.Attributes["name"].Value.ToLower();
string id = nod.InnerText;
animations.Add(name, (UUID)id);
}
}
}
}
return animations;
}
/// <summary>
/// Get the default SL avatar animation with the given name.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public static UUID GetDefaultAvatarAnimation(string name)
{
if (DefaultAvatarAnimations.ContainsKey(name))
return DefaultAvatarAnimations[name];
return UUID.Zero;
}
} }
} }

View File

@ -28,6 +28,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@ -67,6 +68,9 @@ namespace OpenSim
private const string PLUGIN_ASSET_CACHE = "/OpenSim/AssetCache"; private const string PLUGIN_ASSET_CACHE = "/OpenSim/AssetCache";
private const string PLUGIN_ASSET_SERVER_CLIENT = "/OpenSim/AssetClient"; private const string PLUGIN_ASSET_SERVER_CLIENT = "/OpenSim/AssetClient";
// OpenSim.ini Section name for ESTATES Settings
public const string ESTATE_SECTION_NAME = "Estates";
protected string proxyUrl; protected string proxyUrl;
protected int proxyOffset = 0; protected int proxyOffset = 0;
@ -445,12 +449,42 @@ namespace OpenSim
{ {
RegionInfo regionInfo = scene.RegionInfo; RegionInfo regionInfo = scene.RegionInfo;
string estateOwnerFirstName = null;
string estateOwnerLastName = null;
string estateOwnerEMail = null;
string estateOwnerPassword = null;
string rawEstateOwnerUuid = null;
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
{
string defaultEstateOwnerName
= m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
string[] ownerNames = defaultEstateOwnerName.Split(' ');
if (ownerNames.Length >= 2)
{
estateOwnerFirstName = ownerNames[0];
estateOwnerLastName = ownerNames[1];
}
// Info to be used only on Standalone Mode
rawEstateOwnerUuid = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerUUID", null);
estateOwnerEMail = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerEMail", null);
estateOwnerPassword = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerPassword", null);
}
MainConsole.Instance.OutputFormat("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName); MainConsole.Instance.OutputFormat("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName);
List<char> excluded = new List<char>(new char[1]{' '}); List<char> excluded = new List<char>(new char[1]{' '});
string first = MainConsole.Instance.CmdPrompt("Estate owner first name", "Test", excluded);
string last = MainConsole.Instance.CmdPrompt("Estate owner last name", "User", excluded);
UserAccount account = scene.UserAccountService.GetUserAccount(regionInfo.ScopeID, first, last);
if (estateOwnerFirstName == null || estateOwnerLastName == null)
{
estateOwnerFirstName = MainConsole.Instance.CmdPrompt("Estate owner first name", "Test", excluded);
estateOwnerLastName = MainConsole.Instance.CmdPrompt("Estate owner last name", "User", excluded);
}
UserAccount account
= scene.UserAccountService.GetUserAccount(regionInfo.ScopeID, estateOwnerFirstName, estateOwnerLastName);
if (account == null) if (account == null)
{ {
@ -469,23 +503,35 @@ namespace OpenSim
if (scene.UserAccountService is UserAccountService) if (scene.UserAccountService is UserAccountService)
{ {
string password = MainConsole.Instance.PasswdPrompt("Password"); if (estateOwnerPassword == null)
string email = MainConsole.Instance.CmdPrompt("Email", ""); estateOwnerPassword = MainConsole.Instance.PasswdPrompt("Password");
string rawPrincipalId = MainConsole.Instance.CmdPrompt("User ID", UUID.Random().ToString()); if (estateOwnerEMail == null)
estateOwnerEMail = MainConsole.Instance.CmdPrompt("Email");
UUID principalId = UUID.Zero; if (rawEstateOwnerUuid == null)
if (!UUID.TryParse(rawPrincipalId, out principalId)) rawEstateOwnerUuid = MainConsole.Instance.CmdPrompt("User ID", UUID.Random().ToString());
UUID estateOwnerUuid = UUID.Zero;
if (!UUID.TryParse(rawEstateOwnerUuid, out estateOwnerUuid))
{ {
m_log.ErrorFormat("[OPENSIM]: ID {0} is not a valid UUID", rawPrincipalId); m_log.ErrorFormat("[OPENSIM]: ID {0} is not a valid UUID", rawEstateOwnerUuid);
return; return;
} }
// If we've been given a zero uuid then this signals that we should use a random user id
if (estateOwnerUuid == UUID.Zero)
estateOwnerUuid = UUID.Random();
account account
= ((UserAccountService)scene.UserAccountService).CreateUser( = ((UserAccountService)scene.UserAccountService).CreateUser(
regionInfo.ScopeID, principalId, first, last, password, email); regionInfo.ScopeID,
estateOwnerUuid,
estateOwnerFirstName,
estateOwnerLastName,
estateOwnerPassword,
estateOwnerEMail);
} }
// }
} }
if (account == null) if (account == null)
@ -885,15 +931,21 @@ namespace OpenSim
/// This method doesn't allow an estate to be created with the same name as existing estates. /// This method doesn't allow an estate to be created with the same name as existing estates.
/// </remarks> /// </remarks>
/// <param name="regInfo"></param> /// <param name="regInfo"></param>
/// <param name="existingName">A list of estate names that already exist.</param> /// <param name="estatesByName">A list of estate names that already exist.</param>
/// <param name="estateName">Estate name to create if already known</param>
/// <returns>true if the estate was created, false otherwise</returns> /// <returns>true if the estate was created, false otherwise</returns>
public bool CreateEstate(RegionInfo regInfo, List<string> existingNames) public bool CreateEstate(RegionInfo regInfo, Dictionary<string, EstateSettings> estatesByName, string estateName)
{ {
// Create a new estate // Create a new estate
regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, true); regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, true);
string newName = MainConsole.Instance.CmdPrompt("New estate name", regInfo.EstateSettings.EstateName);
if (existingNames.Contains(newName)) string newName;
if (estateName != null && estateName != "")
newName = estateName;
else
newName = MainConsole.Instance.CmdPrompt("New estate name", regInfo.EstateSettings.EstateName);
if (estatesByName.ContainsKey(newName))
{ {
MainConsole.Instance.OutputFormat("An estate named {0} already exists. Please try again.", newName); MainConsole.Instance.OutputFormat("An estate named {0} already exists. Please try again.", newName);
return false; return false;
@ -920,22 +972,57 @@ namespace OpenSim
if (EstateDataService != null) if (EstateDataService != null)
regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, false); regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, false);
if (regInfo.EstateSettings.EstateID == 0) // No record at all if (regInfo.EstateSettings.EstateID != 0)
{ return;
m_log.WarnFormat("[ESTATE] Region {0} is not part of an estate.", regInfo.RegionName); m_log.WarnFormat("[ESTATE] Region {0} is not part of an estate.", regInfo.RegionName);
List<EstateSettings> estates = EstateDataService.LoadEstateSettingsAll(); List<EstateSettings> estates = EstateDataService.LoadEstateSettingsAll();
List<string> estateNames = new List<string>(); Dictionary<string, EstateSettings> estatesByName = new Dictionary<string, EstateSettings>();
foreach (EstateSettings estate in estates)
estateNames.Add(estate.EstateName);
foreach (EstateSettings estate in estates)
estatesByName[estate.EstateName] = estate;
string defaultEstateName = null;
if (m_config.Source.Configs[ESTATE_SECTION_NAME] != null)
{
defaultEstateName = m_config.Source.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
if (defaultEstateName != null)
{
EstateSettings defaultEstate;
bool defaultEstateJoined = false;
if (estatesByName.ContainsKey(defaultEstateName))
{
defaultEstate = estatesByName[defaultEstateName];
if (EstateDataService.LinkRegion(regInfo.RegionID, (int)defaultEstate.EstateID))
defaultEstateJoined = true;
}
else
{
if (CreateEstate(regInfo, estatesByName, defaultEstateName))
defaultEstateJoined = true;
}
if (defaultEstateJoined)
return;
else
m_log.ErrorFormat(
"[OPENSIM BASE]: Joining default estate {0} failed", defaultEstateName);
}
}
// If we have no default estate or creation of the default estate failed then ask the user.
while (true) while (true)
{ {
if (estates.Count == 0) if (estates.Count == 0)
{ {
m_log.Info("[ESTATE] No existing estates found. You must create a new one."); m_log.Info("[ESTATE]: No existing estates found. You must create a new one.");
if (CreateEstate(regInfo, estateNames)) if (CreateEstate(regInfo, estatesByName, null))
break; break;
else else
continue; continue;
@ -951,17 +1038,19 @@ namespace OpenSim
if (response == "no") if (response == "no")
{ {
if (CreateEstate(regInfo, estateNames)) if (CreateEstate(regInfo, estatesByName, null))
break; break;
else else
continue; continue;
} }
else else
{ {
string[] estateNames = estatesByName.Keys.ToArray();
response response
= MainConsole.Instance.CmdPrompt( = MainConsole.Instance.CmdPrompt(
string.Format( string.Format(
"Name of estate to join. Existing estate names are ({0})", string.Join(", ", estateNames.ToArray())), "Name of estate to join. Existing estate names are ({0})",
string.Join(", ", estateNames)),
estateNames[0]); estateNames[0]);
List<int> estateIDs = EstateDataService.GetEstates(response); List<int> estateIDs = EstateDataService.GetEstates(response);
@ -984,7 +1073,6 @@ namespace OpenSim
} }
} }
} }
}
public class OpenSimConfigSource public class OpenSimConfigSource
{ {

View File

@ -317,7 +317,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected readonly UUID m_agentId; protected readonly UUID m_agentId;
private readonly uint m_circuitCode; private readonly uint m_circuitCode;
private readonly byte[] m_channelVersion = Utils.EmptyBytes; private readonly byte[] m_channelVersion = Utils.EmptyBytes;
private readonly Dictionary<string, UUID> m_defaultAnimations = new Dictionary<string, UUID>();
private readonly IGroupsModule m_GroupsModule; private readonly IGroupsModule m_GroupsModule;
private int m_cachedTextureSerial; private int m_cachedTextureSerial;
@ -452,10 +451,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
RegisterInterface<IClientChat>(this); RegisterInterface<IClientChat>(this);
RegisterInterface<IClientIPEndpoint>(this); RegisterInterface<IClientIPEndpoint>(this);
InitDefaultAnimations();
m_scene = scene; m_scene = scene;
m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); m_entityUpdates = new PriorityQueue(m_scene.Entities.Count);
m_entityProps = new PriorityQueue(m_scene.Entities.Count); m_entityProps = new PriorityQueue(m_scene.Entities.Count);
m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>(); m_fullUpdateDataBlocksBuilder = new List<ObjectUpdatePacket.ObjectDataBlock>();
@ -11210,30 +11206,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(scriptQuestion, ThrottleOutPacketType.Task); OutPacket(scriptQuestion, ThrottleOutPacketType.Task);
} }
private void InitDefaultAnimations()
{
using (XmlTextReader reader = new XmlTextReader("data/avataranimations.xml"))
{
XmlDocument doc = new XmlDocument();
doc.Load(reader);
if (doc.DocumentElement != null)
foreach (XmlNode nod in doc.DocumentElement.ChildNodes)
{
if (nod.Attributes["name"] != null)
{
string name = nod.Attributes["name"].Value.ToLower();
string id = nod.InnerText;
m_defaultAnimations.Add(name, (UUID)id);
}
}
}
}
public UUID GetDefaultAnimation(string name) public UUID GetDefaultAnimation(string name)
{ {
if (m_defaultAnimations.ContainsKey(name)) return SLUtil.GetDefaultAvatarAnimation(name);
return m_defaultAnimations[name];
return UUID.Zero;
} }
/// <summary> /// <summary>

View File

@ -270,11 +270,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
m_archiveWriter = new TarArchiveWriter(m_saveStream); m_archiveWriter = new TarArchiveWriter(m_saveStream);
m_log.InfoFormat("[INVENTORY ARCHIVER]: Adding control file to archive.");
// Write out control file. This has to be done first so that subsequent loaders will see this file first // Write out control file. This has to be done first so that subsequent loaders will see this file first
// XXX: I know this is a weak way of doing it since external non-OAR aware tar executables will not do this // XXX: I know this is a weak way of doing it since external non-OAR aware tar executables will not do this
// not sure how to fix this though, short of going with a completely different file format. // not sure how to fix this though, short of going with a completely different file format.
m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options)); m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options));
m_log.InfoFormat("[INVENTORY ARCHIVER]: Added control file to archive.");
if (inventoryFolder != null) if (inventoryFolder != null)
{ {

View File

@ -108,12 +108,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
// "[ARCHIVER]: Received {0} of {1} assets requested", // "[ARCHIVER]: Received {0} of {1} assets requested",
// assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count); // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
// Write out region settings // Write out region settings
string settingsPath string settingsPath
= String.Format("{0}{1}.xml", ArchiveConstants.SETTINGS_PATH, m_scene.RegionInfo.RegionName); = String.Format("{0}{1}.xml", ArchiveConstants.SETTINGS_PATH, m_scene.RegionInfo.RegionName);
m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(m_scene.RegionInfo.RegionSettings)); m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(m_scene.RegionInfo.RegionSettings));
m_log.InfoFormat("[ARCHIVER]: Added region settings to archive."); m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
// Write out land data (aka parcel) settings // Write out land data (aka parcel) settings
List<ILandObject>landObjects = m_scene.LandChannel.AllParcels(); List<ILandObject>landObjects = m_scene.LandChannel.AllParcels();
@ -124,7 +126,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
landData.GlobalID.ToString()); landData.GlobalID.ToString());
m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData)); m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData));
} }
m_log.InfoFormat("[ARCHIVER]: Added parcel settings to archive.");
m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
// Write out terrain // Write out terrain
string terrainPath string terrainPath
@ -135,7 +138,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
m_archiveWriter.WriteFile(terrainPath, ms.ToArray()); m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
ms.Close(); ms.Close();
m_log.InfoFormat("[ARCHIVER]: Added terrain information to archive."); m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
// Write out scene object metadata // Write out scene object metadata
foreach (SceneObjectGroup sceneObject in m_sceneObjects) foreach (SceneObjectGroup sceneObject in m_sceneObjects)
@ -145,10 +148,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
string serializedObject = m_serialiser.SerializeGroupToXml2(sceneObject, m_options); string serializedObject = m_serialiser.SerializeGroupToXml2(sceneObject, m_options);
m_archiveWriter.WriteFile(ArchiveHelpers.CreateObjectPath(sceneObject), serializedObject); m_archiveWriter.WriteFile(ArchiveHelpers.CreateObjectPath(sceneObject), serializedObject);
} }
}
m_log.InfoFormat("[ARCHIVER]: Added scene objects to archive.");
}
} }
} }

View File

@ -219,13 +219,20 @@ namespace OpenSim.Region.CoreModules.World.Archiver
m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
if (SaveAssets) if (SaveAssets)
new AssetsRequest( {
AssetsRequest ar
= new AssetsRequest(
new AssetsArchiver(archiveWriter), assetUuids, new AssetsArchiver(archiveWriter), assetUuids,
m_scene.AssetService, m_scene.UserAccountService, m_scene.AssetService, m_scene.UserAccountService,
m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets).Execute(); m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets);
Util.FireAndForget(o => ar.Execute());
}
else else
{
awre.ReceivedAllAssets(new List<UUID>(), new List<UUID>()); awre.ReceivedAllAssets(new List<UUID>(), new List<UUID>());
} }
}
catch (Exception) catch (Exception)
{ {
m_saveStream.Close(); m_saveStream.Close();

View File

@ -142,12 +142,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
return; return;
} }
m_requestCallbackTimer.Enabled = true;
foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids) foreach (KeyValuePair<UUID, AssetType> kvp in m_uuids)
{ {
m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback); // m_assetService.Get(kvp.Key.ToString(), kvp.Value, PreAssetRequestCallback);
AssetBase asset = m_assetService.Get(kvp.Key.ToString());
PreAssetRequestCallback(kvp.Key.ToString(), kvp.Value, asset);
} }
m_requestCallbackTimer.Enabled = true;
} }
protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args) protected void OnRequestCallbackTimeout(object source, ElapsedEventArgs args)

View File

@ -34,6 +34,9 @@ using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.CoreModules.World.Estate; using OpenSim.Region.CoreModules.World.Estate;
using log4net;
using System.Reflection;
using System.Xml;
namespace OpenSim.Region.OptionalModules.World.NPC namespace OpenSim.Region.OptionalModules.World.NPC
{ {
@ -132,7 +135,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
public UUID GetDefaultAnimation(string name) public UUID GetDefaultAnimation(string name)
{ {
return UUID.Zero; return SLUtil.GetDefaultAvatarAnimation(name);
} }
public Vector3 Position public Vector3 Position

View File

@ -36,7 +36,6 @@
[Startup] [Startup]
;# {ConsolePrompt} {} {ConsolePrompt} {} "Region (\R) " ;# {ConsolePrompt} {} {ConsolePrompt} {} "Region (\R) "
;; Console prompt ;; Console prompt
;; Certain special characters can be used to customize the prompt ;; Certain special characters can be used to customize the prompt
@ -232,6 +231,24 @@
;; server to send mail through. ;; server to send mail through.
; emailmodule = DefaultEmailModule ; emailmodule = DefaultEmailModule
[Estates]
; If these values are commented out then the user will be asked for estate details when required (this is the normal case).
; If these values are uncommented then they will be used to create a default estate as necessary.
; New regions will be automatically assigned to that default estate.
; DefaultEstateName = My Estate
; DefaultEstateOwnerName = FirstName LastName
; The following parameters will only be used on a standalone system to create an estate owner that does not already exist
; If DefaultEstateOwnerUUID is left at UUID.Zero (as below) then a random UUID will be assigned.
; This is normally what you want
; DefaultEstateOwnerUUID = 00000000-0000-0000-0000-000000000000
; DefaultEstateOwnerEMail = owner@domain.com
; DefaultEstateOwnerPassword = password
[SMTP] [SMTP]
;; The SMTP server enabled the email module to send email to external ;; The SMTP server enabled the email module to send email to external
;; destinations. ;; destinations.
@ -754,7 +771,6 @@
; XmlRpcServiceReadKey = 1234 ; XmlRpcServiceReadKey = 1234
; XmlRpcServiceWriteKey = 1234 ; XmlRpcServiceWriteKey = 1234
[InterestManagement] [InterestManagement]
;# {UpdatePrioritizationScheme} {} {Update prioritization scheme?} {BestAvatarResponsiveness Time Distance SimpleAngularDistance FrontBack} BestAvatarResponsiveness ;# {UpdatePrioritizationScheme} {} {Update prioritization scheme?} {BestAvatarResponsiveness Time Distance SimpleAngularDistance FrontBack} BestAvatarResponsiveness
;; This section controls how state updates are prioritized for each client ;; This section controls how state updates are prioritized for each client