Local branch for StolenRuby experience changes (#86)

* Experience Tools

Signed-off-by: StolenRuby <26614880+StolenRuby@users.noreply.github.com>

* EEP lsl functions, and updated llTeleport functions

* API Changes in test cases due to experience changes.

* Address some return statements picked up by CodeQL

---------

Signed-off-by: StolenRuby <26614880+StolenRuby@users.noreply.github.com>
Co-authored-by: StolenRuby <26614880+StolenRuby@users.noreply.github.com>
This commit is contained in:
Mike Dickson 2024-08-20 21:19:44 -04:00 committed by GitHub
parent 90d3148f5f
commit 26d3971448
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 6543 additions and 53 deletions

View file

@ -147,6 +147,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenSim.Region.OptionalModu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenSim.Server.MoneyServer", "addon-modules\OpenSim.Server.MoneyServer\OpenSim.Server.MoneyServer\OpenSim.Server.MoneyServer.csproj", "{C3AEE6AC-BE40-4003-A7A3-E8AA039E4451}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSim.Services.ExperienceService", "OpenSim\Services\ExperienceService\OpenSim.Services.ExperienceService.csproj", "{186509B6-EF90-431A-9034-75A1221E4120}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{7F5EC7C6-FD99-4084-8530-5D3F28D6D7C0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenSim.Tests.Common", "Tests\OpenSim.Tests.Common\OpenSim.Tests.Common.csproj", "{4B7616BC-6CCE-4B78-AE40-1F24C92442F5}"
@ -457,6 +459,10 @@ Global
{B120B128-D6C6-40B6-9D83-4F1F7D921109}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B120B128-D6C6-40B6-9D83-4F1F7D921109}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B120B128-D6C6-40B6-9D83-4F1F7D921109}.Release|Any CPU.Build.0 = Release|Any CPU
{186509B6-EF90-431A-9034-75A1221E4120}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{186509B6-EF90-431A-9034-75A1221E4120}.Debug|Any CPU.Build.0 = Debug|Any CPU
{186509B6-EF90-431A-9034-75A1221E4120}.Release|Any CPU.ActiveCfg = Release|Any CPU
{186509B6-EF90-431A-9034-75A1221E4120}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -46,5 +46,10 @@ namespace OpenSim.Framework.Capabilities
/// State of the upload. So far have only even seen this set to "complete"
/// </summary>
public string state;
/// <summary>
/// What experience key should be used with this script
/// </summary>
public UUID experience = UUID.Zero;
}
}

View file

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenSim.Framework;
namespace OpenSim.Data
{
public interface IExperienceData
{
Dictionary<UUID, bool> GetExperiencePermissions(UUID agent_id);
bool ForgetExperiencePermissions(UUID agent_id, UUID experience_id);
bool SetExperiencePermissions(UUID agent_id, UUID experience_id, bool allow);
ExperienceInfoData[] GetExperienceInfos(UUID[] experiences);
ExperienceInfoData[] FindExperiences(string search);
UUID[] GetAgentExperiences(UUID agent_id);
UUID[] GetGroupExperiences(UUID agent_id);
UUID[] GetExperiencesForGroups(UUID[] groups);
bool UpdateExperienceInfo(ExperienceInfoData data);
// KeyValue
string GetKeyValue(UUID experience, string key);
bool SetKeyValue(UUID experience, string key, string val);
bool DeleteKey(UUID experience, string key);
int GetKeyCount(UUID experience);
string[] GetKeys(UUID experience, int start, int count);
int GetKeyValueSize(UUID experience);
}
}

View file

@ -131,6 +131,8 @@ namespace OpenSim.Data.MySQL
es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
es.AllowedExperiences = LoadUUIDList(es.EstateID, "estate_allowed_experiences");
es.KeyExperiences = LoadUUIDList(es.EstateID, "estate_key_experiences");
return es;
}
@ -184,6 +186,8 @@ namespace OpenSim.Data.MySQL
es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
es.AllowedExperiences = LoadUUIDList(es.EstateID, "estate_allowed_experiences");
es.KeyExperiences = LoadUUIDList(es.EstateID, "estate_key_experiences");
return es;
}
@ -278,6 +282,8 @@ namespace OpenSim.Data.MySQL
SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers);
SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess);
SaveUUIDList(es.EstateID, "estate_groups", es.EstateGroups);
SaveUUIDList(es.EstateID, "estate_allowed_experiences", es.AllowedExperiences);
SaveUUIDList(es.EstateID, "estate_key_experiences", es.KeyExperiences);
}
private void LoadBanList(EstateSettings es)

View file

@ -0,0 +1,429 @@
using System.Reflection;
using System.Data;
using MySqlConnector;
using OpenSim.Framework;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
using System.Linq;
using log4net;
namespace OpenSim.Data.MySQL
{
public class MySqlExperienceData : MySqlFramework, IExperienceData
{
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
public MySqlExperienceData(string connectionString)
: base(connectionString)
{
m_connectionString = connectionString;
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
Migration m = new Migration(dbcon, Assembly, "Experience");
m.Update();
dbcon.Close();
}
}
public Dictionary<UUID, bool> GetExperiencePermissions(UUID agent_id)
{
Dictionary<UUID, bool> experiencePermissions = new Dictionary<UUID, bool>();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd
= new MySqlCommand("select * from `experience_permissions` where avatar = ?avatar", dbcon))
{
cmd.Parameters.AddWithValue("?avatar", agent_id.ToString());
using (IDataReader result = cmd.ExecuteReader())
{
while (result.Read())
{
string uuid = result.GetString(0);
bool allow = result.GetBoolean(2);
UUID experience_key;
if(UUID.TryParse(uuid, out experience_key))
{
experiencePermissions.Add(experience_key, allow);
}
}
dbcon.Close();
}
}
}
return experiencePermissions;
}
public bool ForgetExperiencePermissions(UUID agent_id, UUID experience_id)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd
= new MySqlCommand("delete from `experience_permissions` where avatar = ?avatar AND experience = ?experience LIMIT 1", dbcon))
{
cmd.Parameters.AddWithValue("?avatar", agent_id.ToString());
cmd.Parameters.AddWithValue("?experience", experience_id.ToString());
return (cmd.ExecuteNonQuery() > 0);
}
}
}
public bool SetExperiencePermissions(UUID agent_id, UUID experience_id, bool allow)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("replace into `experience_permissions` (avatar, experience, allow) VALUES (?avatar, ?experience, ?allow)", dbcon))
{
cmd.Parameters.AddWithValue("?avatar", agent_id.ToString());
cmd.Parameters.AddWithValue("?experience", experience_id.ToString());
cmd.Parameters.AddWithValue("?allow", allow);
return (cmd.ExecuteNonQuery() > 0);
}
}
}
public ExperienceInfoData[] GetExperienceInfos(UUID[] experiences)
{
List<string> uuids = new List<string>();
foreach (var u in experiences)
uuids.Add("'" + u.ToString() + "'");
string joined = string.Join(",", uuids);
List<ExperienceInfoData> infos = new List<ExperienceInfoData>();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM `experiences` WHERE public_id IN (" + joined + ")", dbcon))
{
using (IDataReader result = cmd.ExecuteReader())
{
while (result.Read())
{
ExperienceInfoData info = new ExperienceInfoData();
info.public_id = UUID.Parse(result["public_id"].ToString());
info.owner_id = UUID.Parse(result["owner_id"].ToString());
info.group_id = UUID.Parse(result["group_id"].ToString());
info.name = result["name"].ToString();
info.description = result["description"].ToString();
info.logo = UUID.Parse(result["logo"].ToString());
info.marketplace = result["marketplace"].ToString();
info.slurl = result["slurl"].ToString();
info.maturity = int.Parse(result["maturity"].ToString());
info.properties = int.Parse(result["properties"].ToString());
infos.Add(info);
}
}
}
dbcon.Close();
}
return infos.ToArray();
}
public UUID[] GetAgentExperiences(UUID agent_id)
{
List<UUID> experiences = new List<UUID>();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM `experiences` WHERE owner_id = ?avatar", dbcon))
{
cmd.Parameters.AddWithValue("?avatar", agent_id.ToString());
using (IDataReader result = cmd.ExecuteReader())
{
while (result.Read())
{
experiences.Add(UUID.Parse(result["public_id"].ToString()));
}
}
}
dbcon.Close();
}
return experiences.ToArray();
}
public bool UpdateExperienceInfo(ExperienceInfoData data)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("replace into `experiences` (public_id, owner_id, name, description, group_id, logo, marketplace, slurl, maturity, properties) VALUES (?public_id, ?owner_id, ?name, ?description, ?group_id, ?logo, ?marketplace, ?slurl, ?maturity, ?properties)", dbcon))
{
cmd.Parameters.AddWithValue("?public_id", data.public_id.ToString());
cmd.Parameters.AddWithValue("?owner_id", data.owner_id.ToString());
cmd.Parameters.AddWithValue("?name", data.name);
cmd.Parameters.AddWithValue("?description", data.description);
cmd.Parameters.AddWithValue("?group_id", data.group_id.ToString());
cmd.Parameters.AddWithValue("?logo", data.logo.ToString());
cmd.Parameters.AddWithValue("?marketplace", data.marketplace);
cmd.Parameters.AddWithValue("?slurl", data.slurl);
cmd.Parameters.AddWithValue("?maturity", data.maturity);
cmd.Parameters.AddWithValue("?properties", data.properties);
return (cmd.ExecuteNonQuery() > 0);
}
}
}
public ExperienceInfoData[] FindExperiences(string search)
{
List<ExperienceInfoData> experiences = new List<ExperienceInfoData>();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM `experiences` WHERE name LIKE ?search", dbcon))
{
cmd.Parameters.AddWithValue("?search", string.Format("%{0}%", search));
using (IDataReader result = cmd.ExecuteReader())
{
while (result.Read())
{
ExperienceInfoData info = new ExperienceInfoData();
info.public_id = UUID.Parse(result["public_id"].ToString());
info.owner_id = UUID.Parse(result["owner_id"].ToString());
info.group_id = UUID.Parse(result["group_id"].ToString());
info.name = result["name"].ToString();
info.description = result["description"].ToString();
info.logo = UUID.Parse(result["logo"].ToString());
info.marketplace = result["marketplace"].ToString();
info.slurl = result["slurl"].ToString();
info.maturity = int.Parse(result["maturity"].ToString());
info.properties = int.Parse(result["properties"].ToString());
experiences.Add(info);
}
}
}
dbcon.Close();
}
return experiences.ToArray();
}
public UUID[] GetGroupExperiences(UUID group_id)
{
List<UUID> experiences = new List<UUID>();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM `experiences` WHERE group_id = ?group", dbcon))
{
cmd.Parameters.AddWithValue("?group", group_id.ToString());
using (IDataReader result = cmd.ExecuteReader())
{
while (result.Read())
{
experiences.Add(UUID.Parse(result["public_id"].ToString()));
}
}
}
dbcon.Close();
}
return experiences.ToArray();
}
public UUID[] GetExperiencesForGroups(UUID[] groups)
{
List<string> uuids = new List<string>();
foreach (var u in groups)
uuids.Add("'" + u.ToString() + "'");
string joined = string.Join(",", uuids);
List<UUID> experiences = new List<UUID>();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM `experiences` WHERE group_id IN (" + joined + ")", dbcon))
{
using (IDataReader result = cmd.ExecuteReader())
{
while (result.Read())
{
experiences.Add(UUID.Parse(result["public_id"].ToString()));
}
}
}
dbcon.Close();
}
return experiences.ToArray();
}
// KeyValue
public bool SetKeyValue(UUID experience, string key, string val)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("REPLACE INTO `experience_kv` (`experience`, `key`, `value`) VALUES (?experience, ?key, ?value)", dbcon))
{
cmd.Parameters.AddWithValue("?experience", experience.ToString());
cmd.Parameters.AddWithValue("?key", key);
cmd.Parameters.AddWithValue("?value", val);
return (cmd.ExecuteNonQuery() > 0);
}
}
}
public string GetKeyValue(UUID experience, string key)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT * FROM `experience_kv` WHERE `experience` = ?experience AND `key` = ?key LIMIT 1", dbcon))
{
cmd.Parameters.AddWithValue("?experience", experience.ToString());
cmd.Parameters.AddWithValue("?key", key);
using (IDataReader result = cmd.ExecuteReader())
{
if (result.Read())
{
return result["value"].ToString();
}
}
}
dbcon.Close();
}
return null;
}
public bool DeleteKey(UUID experience, string key)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("DELETE FROM `experience_kv` WHERE `experience` = ?experience AND `key` = ?key LIMIT 1", dbcon))
{
cmd.Parameters.AddWithValue("?experience", experience.ToString());
cmd.Parameters.AddWithValue("?key", key);
return (cmd.ExecuteNonQuery() > 0);
}
}
}
public int GetKeyCount(UUID experience)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT COUNT(*) AS `count` FROM `experience_kv` WHERE `experience` = ?experience", dbcon))
{
cmd.Parameters.AddWithValue("?experience", experience.ToString());
using (IDataReader result = cmd.ExecuteReader())
{
if (result.Read())
{
return int.Parse(result["count"].ToString());
}
}
}
dbcon.Close();
}
return 0;
}
public string[] GetKeys(UUID experience, int start, int count)
{
List<string> keys = new List<string>();
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT `key` FROM `experience_kv` WHERE `experience` = ?experience LIMIT ?start, ?count;", dbcon))
{
cmd.Parameters.AddWithValue("?experience", experience.ToString());
cmd.Parameters.AddWithValue("?start", start);
cmd.Parameters.AddWithValue("?count", count);
using (IDataReader result = cmd.ExecuteReader())
{
while (result.Read())
{
keys.Add(result["key"].ToString());
}
}
}
dbcon.Close();
}
return keys.ToArray();
}
public int GetKeyValueSize(UUID experience)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT IFNULL(SUM(LENGTH(`key`) + LENGTH(`value`)), 0) AS `size` FROM `experience_kv` WHERE `experience` = ?experience", dbcon))
{
cmd.Parameters.AddWithValue("?experience", experience.ToString());
using (IDataReader result = cmd.ExecuteReader())
{
if (result.Read())
{
return int.Parse(result["size"].ToString());
}
}
}
dbcon.Close();
}
return 0;
}
}
}

View file

@ -171,7 +171,7 @@ namespace OpenSim.Data.MySQL
"PhysicsShapeType, Density, GravityModifier, " +
"Friction, Restitution, Vehicle, PhysInertia, DynAttrs, " +
"RotationAxisLocks, sopanims, sitactrange, pseudocrc, " +
"linksetdata" +
"linksetdata, AllowUnsit, ScriptedSitOnly" +
") values (" + "?UUID, " +
"?CreationDate, ?Name, ?Text, " +
"?Description, ?SitName, ?TouchName, " +
@ -207,7 +207,7 @@ namespace OpenSim.Data.MySQL
"?PhysicsShapeType, ?Density, ?GravityModifier, " +
"?Friction, ?Restitution, ?Vehicle, ?PhysInertia, ?DynAttrs," +
"?RotationAxisLocks, ?sopanims, ?sitactrange, ?pseudocrc, " +
"?linksetdata)";
"?linksetdata, ?AllowUnsit, ?ScriptedSitOnly)";
FillPrimCommand(cmd, prim, obj.UUID, regionUUID);
@ -1191,6 +1191,9 @@ namespace OpenSim.Data.MySQL
prim.LinksetData = LinksetData.DeserializeLinksetData((string)row["linksetdata"]);
}
prim.AllowUnsit = ((sbyte)row["AllowUnsit"] != 0);
prim.ScriptedSitOnly = ((sbyte)row["ScriptedSitOnly"] != 0);
return prim;
}
@ -1624,7 +1627,17 @@ namespace OpenSim.Data.MySQL
else
{
cmd.Parameters.AddWithValue("linksetdata", null);
}
}
if (prim.AllowUnsit)
cmd.Parameters.AddWithValue("AllowUnsit", 1);
else
cmd.Parameters.AddWithValue("AllowUnsit", 0);
if (prim.ScriptedSitOnly)
cmd.Parameters.AddWithValue("ScriptedSitOnly", 1);
else
cmd.Parameters.AddWithValue("ScriptedSitOnly", 0);
}
/// <summary>

View file

@ -33,6 +33,7 @@
<EmbeddedResource Include="Resources\Avatar.migrations" />
<EmbeddedResource Include="Resources\EstateStore.migrations" />
<EmbeddedResource Include="Resources\FriendsStore.migrations" />
<EmbeddedResource Include="Resources\Experience.migrations" />
<EmbeddedResource Include="Resources\FSAssetStore.migrations" />
<EmbeddedResource Include="Resources\GridStore.migrations" />
<EmbeddedResource Include="Resources\GridUserStore.migrations" />

View file

@ -81,3 +81,17 @@ BEGIN;
ALTER TABLE `estate_settings`
ADD COLUMN `AllowEnviromentOverride` tinyint(4) NOT NULL DEFAULT '0';
COMMIT;
:VERSION 37
CREATE TABLE IF NOT EXISTS `estate_allowed_experiences` (
`EstateID` int(10) unsigned NOT NULL,
`uuid` char(36) NOT NULL,
KEY `EstateID` (`EstateID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `estate_key_experiences` (
`EstateID` int(10) unsigned NOT NULL,
`uuid` char(36) NOT NULL,
KEY `EstateID` (`EstateID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
COMMIT;

View file

@ -0,0 +1,40 @@
:VERSION 3 # -----------------
BEGIN;
CREATE TABLE IF NOT EXISTS `experiences` (
`public_id` VARCHAR(36) NOT NULL,
`owner_id` VARCHAR(36) NOT NULL,
`name` VARCHAR(42) NOT NULL,
`description` VARCHAR(128) NOT NULL,
`group_id` VARCHAR(36) NOT NULL,
`logo` VARCHAR(36) NOT NULL,
`marketplace` VARCHAR(256) NOT NULL,
`slurl` VARCHAR(256) NOT NULL,
`maturity` INT NOT NULL,
`properties` INT NOT NULL,
PRIMARY KEY (`public_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `experience_permissions` (
`experience` VARCHAR(36) NOT NULL COLLATE 'utf8_unicode_ci',
`avatar` VARCHAR(36) NOT NULL COLLATE 'utf8_unicode_ci',
`allow` BIT(1) NOT NULL,
PRIMARY KEY (`experience`, `avatar`) USING BTREE,
INDEX `avatar` (`avatar`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
COMMIT;
:VERSION 4 # -----------------
BEGIN;
CREATE TABLE IF NOT EXISTS `experience_kv` (
`experience` VARCHAR(36) NOT NULL,
`key` VARCHAR(1011) NOT NULL COLLATE 'latin1_bin',
`value` VARCHAR(4095) NOT NULL COLLATE 'utf8mb4_0900_ai_ci',
PRIMARY KEY(`experience`, `key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
COMMIT;

View file

@ -566,4 +566,12 @@ ALTER TABLE `regionsettings` ADD COLUMN `TerrainPBR1` varchar(36) NOT NULL DEFAU
ALTER TABLE `regionsettings` ADD COLUMN `TerrainPBR2` varchar(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
ALTER TABLE `regionsettings` ADD COLUMN `TerrainPBR3` varchar(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
ALTER TABLE `regionsettings` ADD COLUMN `TerrainPBR4` varchar(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
COMMIT;
COMMIT;
:VERSION 67 #----- Add allow unsit and scripted sit only
BEGIN;
ALTER TABLE `prims`
ADD COLUMN `AllowUnsit` TINYINT(3) NULL DEFAULT '1',
ADD COLUMN `ScriptedSitOnly` TINYINT(3) NULL DEFAULT '0';
COMMIT;

View file

@ -36,6 +36,7 @@
<Compile Remove="MySQL\MySQLAuthenticationData.cs" />
<Compile Remove="MySQL\MySQLAvatarData.cs" />
<Compile Remove="MySQL\MySQLEstateData.cs" />
<Compile Remove="MySQL\MySQLExperienceData.cs" />
<Compile Remove="MySQL\MySQLFramework.cs" />
<Compile Remove="MySQL\MySQLFriendsData.cs" />
<Compile Remove="MySQL\MySQLFSAssetData.cs" />

View file

@ -96,7 +96,9 @@ namespace OpenSim.Framework
AllowedAccess = MaxEstateAccessIds,
AllowedGroups = 63,
EstateBans = 500,
EstateManagers = MaxEstateManagers
EstateManagers = MaxEstateManagers,
AllowedExperiences = 8,
KeyExperiences = 8
}
[Flags]public enum TeleportFlags : uint

View file

@ -278,6 +278,22 @@ namespace OpenSim.Framework
set { l_EstateGroups = new List<UUID>(value); }
}
private List<UUID> l_AllowedExperiences = new List<UUID>();
public UUID[] AllowedExperiences
{
get { return l_AllowedExperiences.ToArray(); }
set { l_AllowedExperiences = new List<UUID>(value); }
}
private List<UUID> l_KeyExperiences = new List<UUID>();
public UUID[] KeyExperiences
{
get { return l_KeyExperiences.ToArray(); }
set { l_KeyExperiences = new List<UUID>(value); }
}
public bool DoDenyMinors = true;
public bool DoDenyAnonymous = true;
@ -449,6 +465,46 @@ namespace OpenSim.Framework
return l_EstateGroups.Contains(groupID);
}
public int AllowedExperiencesCount()
{
return l_AllowedExperiences.Count;
}
public void AddAllowedExperience(UUID experienceKey)
{
if (experienceKey == UUID.Zero)
return;
if (!l_AllowedExperiences.Contains(experienceKey) &&
(l_AllowedExperiences.Count < (int)Constants.EstateAccessLimits.AllowedExperiences))
l_AllowedExperiences.Add(experienceKey);
}
public void RemoveAllowedExperience(UUID experienceKey)
{
if (l_AllowedExperiences.Contains(experienceKey))
l_AllowedExperiences.Remove(experienceKey);
}
public int KeyExperiencesCount()
{
return l_KeyExperiences.Count;
}
public void AddKeyExperience(UUID experienceKey)
{
if (experienceKey == UUID.Zero)
return;
if (!l_KeyExperiences.Contains(experienceKey) &&
(l_KeyExperiences.Count < (int)Constants.EstateAccessLimits.KeyExperiences))
l_KeyExperiences.Add(experienceKey);
}
public void RemoveKeyExperience(UUID experienceKey)
{
if (l_KeyExperiences.Contains(experienceKey))
l_KeyExperiences.Remove(experienceKey);
}
public Dictionary<string, object> ToMap()
{
Dictionary<string, object> map = new();

View file

@ -0,0 +1,36 @@
using OpenMetaverse;
using System.Collections.Generic;
namespace OpenSim.Framework
{
public class ExperienceInfoData
{
public UUID public_id;
public UUID owner_id;
public UUID group_id;
public string name;
public string description;
public UUID logo;
public string marketplace;
public string slurl;
public int maturity;
public int properties;
public Dictionary<string, object> ToDictionary()
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["public_id"] = public_id;
dict["owner_id"] = owner_id;
dict["group_id"] = group_id;
dict["name"] = name;
dict["description"] = description;
dict["logo"] = logo;
dict["marketplace"] = marketplace;
dict["slurl"] = slurl;
dict["maturity"] = maturity;
dict["properties"] = properties;
return dict;
}
}
}

View file

@ -0,0 +1,108 @@
using OpenMetaverse.StructuredData;
using OpenMetaverse;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.TimeZoneInfo;
using System.Security.AccessControl;
namespace OpenSim.Framework
{
public abstract class EnvironmentUpdate
{
public string ObjectName = string.Empty;
public UUID OwnerID = UUID.Zero;
public string ParcelName = string.Empty;
public int Permission = 0;
public string Action = string.Empty;
public float TransitionTime = 0.0f;
public abstract OSDMap ToMap();
}
public class FullEnvironmentUpdate : EnvironmentUpdate
{
public UUID AssetID = UUID.Zero;
public new string Action => "PushFullEnvironment";
public override OSDMap ToMap()
{
OSDMap map = new OSDMap();
map["ObjectName"] = ObjectName;
map["OwnerID"] = OwnerID;
map["ParcelName"] = ParcelName;
map["Permission"] = Permission;
map["action"] = Action;
OSDMap action_data = new OSDMap();
action_data["asset_id"] = AssetID;
action_data["transition_time"] = TransitionTime;
map["action_data"] = action_data;
return map;
}
}
public class PartialEnvironmentUpdate : EnvironmentUpdate
{
public OSDMap water = new OSDMap();
public OSDMap sky = new OSDMap();
public new string Action => "PushPartialEnvironment";
public override OSDMap ToMap()
{
OSDMap map = new OSDMap();
map["ObjectName"] = ObjectName;
map["OwnerID"] = OwnerID;
map["ParcelName"] = ParcelName;
map["Permission"] = Permission;
map["action"] = Action;
OSDMap settings = new OSDMap();
if (water.Count > 0)
settings["water"] = water;
if (sky.Count > 0)
settings["sky"] = sky;
OSDMap action_data = new OSDMap();
action_data["settings"] = settings;
action_data["transition_time"] = TransitionTime;
map["action_data"] = action_data;
return map;
}
}
public class ClearEnvironmentUpdate : EnvironmentUpdate
{
public new string Action => "ClearEnvironment";
public override OSDMap ToMap()
{
OSDMap map = new OSDMap();
map["ObjectName"] = ObjectName;
map["OwnerID"] = OwnerID;
map["ParcelName"] = ParcelName;
map["Permission"] = Permission;
map["action"] = Action;
OSDMap action_data = new OSDMap();
action_data["transition_time"] = TransitionTime;
map["action_data"] = action_data;
return map;
}
}
}

View file

@ -378,6 +378,9 @@ namespace OpenSim.Framework
public delegate void UpdateEstateAccessDeltaRequest(
IClientAPI remote_client, UUID invoice, int estateAccessType, UUID user);
public delegate void UpdateEstateExperienceDeltaRequest(
IClientAPI remote_client, UUID invoice, int estateAccessType, UUID user);
public delegate void SimulatorBlueBoxMessageRequest(
IClientAPI remoteClient, UUID invoice, UUID senderID, UUID sessionID, string senderName, string message);
@ -931,6 +934,7 @@ namespace OpenSim.Framework
event EstateRestartSimRequest OnEstateRestartSimRequest;
event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
event UpdateEstateExperienceDeltaRequest OnUpdateEstateExperienceDeltaRequest;
event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
event EstateDebugRegionRequest OnEstateDebugRegionRequest;
@ -1099,6 +1103,8 @@ namespace OpenSim.Framework
void SendGenericMessage(string method, UUID invoice, List<string> message);
void SendGenericMessage(string method, UUID invoice, List<byte[]> message);
void SendGenericMessageForExperience(UUID experience_id, UUID avatar_id, int action, string obj_name, string parcel, bool is_attachment = false);
bool CanSendLayerData();
void SendLayerData();
@ -1249,7 +1255,7 @@ namespace OpenSim.Framework
void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] membershipType, string flAbout,
uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID);
void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question);
void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question, UUID experience);
void SendHealth(float health);
@ -1263,6 +1269,8 @@ namespace OpenSim.Framework
void SendDetailedEstateData(UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags,
uint sunPosition, UUID covenant, uint covenantChanged, string abuseEmail, UUID estateOwner);
void SendEstateExperiences(UUID invoice, UUID[] allowed, UUID[] key, uint estateID);
/// <summary>
/// Send land properties to the client.
/// </summary>

View file

@ -123,6 +123,7 @@ namespace OpenSim.Framework
public uint NextPermissions { get; set; } = FULL_MASK_PERMISSIONS_GENERAL;
public UUID PermsGranter { get; set; }
public int PermsMask { get; set; }
public UUID ExperienceID { get; set; }
private bool _ownerChanged = false;
public bool OwnerChanged

View file

@ -63,14 +63,14 @@ namespace OpenSim.Region.ClientStack.Linden
int cost, UUID texturesFolder, int nreqtextures, int nreqmeshs, int nreqinstances,
bool IsAtestUpload, ref string error, ref int nextOwnerMask, ref int groupMask, ref int everyoneMask, int[] meshesSides);
public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors);
public delegate void UpdateTaskScript(UUID itemID, UUID primID, bool isScriptRunning, UUID experience, byte[] data, ref ArrayList errors);
public delegate void NewInventoryItem(UUID userID, InventoryItemBase item, uint cost);
public delegate void NewAsset(AssetBase asset);
public delegate ArrayList TaskScriptUpdatedCallback(UUID userID, UUID itemID, UUID primID,
bool isScriptRunning, byte[] data);
bool isScriptRunning, UUID experience, byte[] data);
/// <summary>
/// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that

View file

@ -159,6 +159,7 @@ namespace OpenSim.Region.ClientStack.Linden
UUID itemID = UUID.Zero;
UUID objectID = UUID.Zero;
bool is_script_running = false;
UUID experience_key = UUID.Zero;
OSD tmp;
try
{
@ -168,6 +169,8 @@ namespace OpenSim.Region.ClientStack.Linden
objectID = tmp;
if (map.TryGetValue("is_script_running", out tmp))
is_script_running = tmp;
if (map.TryGetValue("experience", out tmp))
experience_key = tmp;
}
catch { }
@ -215,7 +218,7 @@ namespace OpenSim.Region.ClientStack.Linden
uploadResponse.uploader = uploaderURL;
uploadResponse.state = "upload";
TaskInventoryScriptUpdater uploader = new TaskInventoryScriptUpdater(itemID, objectID, is_script_running,
TaskInventoryScriptUpdater uploader = new TaskInventoryScriptUpdater(itemID, objectID, is_script_running, experience_key,
uploaderPath, m_HostCapsObj.HttpListener, httpRequest.RemoteIPEndPoint.Address, m_dumpAssetsToFile);
uploader.OnUpLoad += TaskScriptUpdated;
@ -243,11 +246,11 @@ namespace OpenSim.Region.ClientStack.Linden
/// <param name="primID">Prim containing item to update</param>
/// <param name="isScriptRunning">Signals whether the script to update is currently running</param>
/// <param name="data">New asset data</param>
public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, byte[] data, ref ArrayList errors)
public void TaskScriptUpdated(UUID itemID, UUID primID, bool isScriptRunning, UUID experience, byte[] data, ref ArrayList errors)
{
if (TaskScriptUpdatedCall != null)
{
ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, data);
ArrayList e = TaskScriptUpdatedCall(m_HostCapsObj.AgentID, itemID, primID, isScriptRunning, experience, data);
foreach (Object item in e)
errors.Add(item);
}
@ -353,10 +356,11 @@ namespace OpenSim.Region.ClientStack.Linden
private UUID m_inventoryItemID;
private UUID m_primID;
private bool m_isScriptRunning;
private UUID m_experienceKey;
private bool m_dumpAssetToFile;
public IPAddress m_remoteAddress;
public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, bool isScriptRunning,
public TaskInventoryScriptUpdater(UUID inventoryItemID, UUID primID, bool isScriptRunning, UUID experience_id,
string path, IHttpServer httpServer, IPAddress address,
bool dumpAssetToFile) : base(httpServer, path)
{
@ -364,6 +368,7 @@ namespace OpenSim.Region.ClientStack.Linden
m_inventoryItemID = inventoryItemID;
m_primID = primID;
m_isScriptRunning = isScriptRunning;
m_experienceKey = experience_id;
m_remoteAddress = address;
Start(30000);
}
@ -405,7 +410,7 @@ namespace OpenSim.Region.ClientStack.Linden
LLSDTaskScriptUploadComplete uploadComplete = new LLSDTaskScriptUploadComplete();
ArrayList errors = new ArrayList();
OnUpLoad?.Invoke(m_inventoryItemID, m_primID, m_isScriptRunning, data, ref errors);
OnUpLoad?.Invoke(m_inventoryItemID, m_primID, m_isScriptRunning, m_experienceKey, data, ref errors);
uploadComplete.new_asset = m_inventoryItemID;
uploadComplete.compiled = errors.Count > 0 ? false : true;

View file

@ -412,6 +412,12 @@ namespace OpenSim.Region.ClientStack.Linden
Enqueue(EndEventToBytes(sb), avatarID);
}
public void SendEnvironmentUpdate(UUID experience_id, UUID agent_id, EnvironmentUpdate update)
{
string update_message = "<? llsd/notation ?>\n" + OSDParser.SerializeLLSDNotation(update.ToMap());
SendLargeGenericMessage(agent_id, UUID.Zero, UUID.Zero, "PushExpEnvironment", experience_id, new List<string> { update_message });
}
public void SendBulkUpdateInventoryItem(InventoryItemBase item, UUID avatarID, UUID? transationID = null)
{
const uint FULL_MASK_PERMISSIONS = (uint)0x7ffffff;

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Frozen;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime;
@ -52,6 +53,7 @@ using Caps = OpenSim.Framework.Capabilities.Caps;
using PermissionMask = OpenSim.Framework.PermissionMask;
using RegionFlags = OpenMetaverse.RegionFlags;
namespace OpenSim.Region.ClientStack.LindenUDP
{
public delegate void PacketMethod(Packet packet);
@ -215,6 +217,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public event EstateRestartSimRequest OnEstateRestartSimRequest;
public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
public event UpdateEstateExperienceDeltaRequest OnUpdateEstateExperienceDeltaRequest;
public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
@ -1349,6 +1352,92 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
public void SendGenericMessageForExperience(UUID experience_id, UUID avatar_id, int action, string obj_name, string parcel, bool is_attachment)
{
// Todo: Finish decoding this. Stop manaully making the bytes. And use the proper serialiser! And drink some water while you're at it.
// <? LLSD/Binary ?>\n
// {
// 0x00 0x00 0x00 0x02 == number of args
// 'k' key
// 0x00 0x00 0x00 0x07 == Length of the following arg header
// 0x4F 0x77 0x6E 0x65 0x72 0x49 0x44 == "OwnerID"
// 0x75 == 'u' == uuid
// 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 == 16 bytes owner of the script
// 'k' key
// 0x00 0x00 0x00 0x0A == Length of the following arg header
// 0x50 0x65 0x72 0x6D 0x69 0x73 0x73 0x69 0x6F 0x6E == "Permission"
// 0x69 == 'i' == integer
// 0x00, 0x00, 0x00, 0x10 == 4 byte permission int
// }
// 0x00
byte[] header = new byte[18] { 0x3C, 0x3F, 0x20, 0x4C, 0x4C, 0x53, 0x44, 0x2F, 0x42, 0x69, 0x6E, 0x61, 0x72, 0x79, 0x20, 0x3F, 0x3E, 0x0A };
Dictionary<string, object> vals = new Dictionary<string, object>();
vals.Add("OwnerID", avatar_id);
vals.Add("Permission", action);
if (is_attachment)
vals.Add("IsAttachment", 1);
byte[] arg_count = Utils.IntToBytes(vals.Count).Reverse().ToArray();
List<byte> new_body = new List<byte>();
new_body.AddRange(header); // <? LLSD/Binary ?>\n
new_body.Add(0x7B); // {
new_body.AddRange(arg_count); // How many args
foreach (var pair in vals)
{
object o = pair.Value;
new_body.Add(0x6B); // k
byte[] val_name = Util.StringToBytes256(pair.Key);
Array.Resize(ref val_name, val_name.Length - 1); // trim the trailing 0x00
byte[] value_length = Utils.IntToBytes(val_name.Length).Reverse().ToArray();
new_body.AddRange(value_length); // How long is the header name
new_body.AddRange(val_name); // Header name in bytes
if (o is UUID)
{
byte[] uuid_bytes = ((UUID)o).GetBytes();
new_body.Add(0x75); // u Value is a UUID
new_body.AddRange(uuid_bytes); // Owner of the script doigthe action
}
else if (o is int)
{
byte[] int_bytes = Utils.IntToBytes((int)o).Reverse().ToArray();
new_body.Add(0x69); // i Value is an int32
new_body.AddRange(int_bytes); // What permission was used
}
}
new_body.Add(0x7D); // }
new_body.Add(0x00); // 0x00 Null end Parameter
GenericMessagePacket p = new GenericMessagePacket();
p.AgentData = new GenericMessagePacket.AgentDataBlock();
p.AgentData.AgentID = m_agentId;
p.MethodData = new GenericMessagePacket.MethodDataBlock();
p.MethodData.Method = Util.StringToBytes256("ExperienceEvent");
p.MethodData.Invoice = experience_id;
p.ParamList = new GenericMessagePacket.ParamListBlock[3];
p.ParamList[0] = new GenericMessagePacket.ParamListBlock();
p.ParamList[0].Parameter = new_body.ToArray();
p.ParamList[1] = new GenericMessagePacket.ParamListBlock();
p.ParamList[1].Parameter = Util.StringToBytes256(obj_name);
p.ParamList[2] = new GenericMessagePacket.ParamListBlock();
p.ParamList[2].Parameter = Util.StringToBytes256(parcel); // this function seems to add the trailing 0x00
OutPacket(p, ThrottleOutPacketType.Task);
}
public void SendGroupActiveProposals(UUID groupID, UUID transactionID, GroupActiveProposals[] Proposals)
{
/* not in use and broken
@ -6352,6 +6441,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} while (TotalnumberIDs > 0);
}
public void SendEstateExperiences(UUID invoice, UUID[] allowed, UUID[] key, uint estateID)
{
EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket();
packet.AgentData.TransactionID = UUID.Random();
packet.AgentData.AgentID = AgentId;
packet.AgentData.SessionID = SessionId;
packet.MethodData.Invoice = invoice;
packet.MethodData.Method = Utils.StringToBytes("setexperience");
int numberIDs = allowed.Length + key.Length;
EstateOwnerMessagePacket.ParamListBlock[] returnblock = new EstateOwnerMessagePacket.ParamListBlock[5 + numberIDs];
for (int i = 0; i < (5 + numberIDs); i++)
{
returnblock[i] = new EstateOwnerMessagePacket.ParamListBlock();
}
returnblock[0].Parameter = Utils.StringToBytes(estateID.ToString());
returnblock[1].Parameter = Utils.StringToBytes("0");
returnblock[2].Parameter = Utils.StringToBytes("0");
returnblock[3].Parameter = Utils.StringToBytes(key.Length.ToString());
returnblock[4].Parameter = Utils.StringToBytes(allowed.Length.ToString());
int j = 5;
for (int i = 0; i < key.Length; i++)
{
returnblock[j].Parameter = key[i].GetBytes();
j++;
}
for (int i = 0; i < allowed.Length; i++)
{
returnblock[j].Parameter = allowed[i].GetBytes();
j++;
}
packet.ParamList = returnblock;
packet.Header.Reliable = true;
OutPacket(packet, ThrottleOutPacketType.Task);
}
public void SendBannedUserList(UUID invoice, EstateBan[] bl, uint estateID)
{
List<UUID> BannedUsers = new();
@ -10869,6 +11002,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
c.OnUpdateEstateAccessDeltaRequest?.Invoke(c, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)));
}
return;
case "estateexperiencedelta":
if (((Scene)c.m_scene).Permissions.CanIssueEstateCommand(c.m_agentId, false))
{
int estateAccessType = Convert.ToInt16(Utils.BytesToString(messagePacket.ParamList[1].Parameter));
c.OnUpdateEstateExperienceDeltaRequest(c, messagePacket.MethodData.Invoice, estateAccessType, new UUID(Utils.BytesToString(messagePacket.ParamList[2].Parameter)));
}
return;
case "simulatormessage":
@ -12179,7 +12321,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Packet Handlers
public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question)
public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question, UUID experience)
{
ScriptQuestionPacket scriptQuestion = (ScriptQuestionPacket)PacketPool.Instance.GetPacket(PacketType.ScriptQuestion);
scriptQuestion.Data.TaskID = taskID;
@ -12187,6 +12329,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
scriptQuestion.Data.Questions = question;
scriptQuestion.Data.ObjectName = Util.StringToBytes256(taskName);
scriptQuestion.Data.ObjectOwner = Util.StringToBytes256(ownerName);
if (experience != UUID.Zero)
{
scriptQuestion.Experience = new ScriptQuestionPacket.ExperienceBlock
{
ExperienceID = experience
};
}
OutPacket(scriptQuestion, ThrottleOutPacketType.Task);
}

View file

@ -575,12 +575,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
}
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent,
bool addToInventory, bool append)
bool addToInventory, bool append, UUID experience)
{
if (!Enabled)
return false;
return AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append);
return AttachObjectInternal(sp, group, attachmentPt, silent, addToInventory, false, append, experience);
}
/// <summary>
@ -594,7 +594,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
/// <param name='addToInventory'>If true then add object to user inventory.</param>
/// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt,
bool silent, bool addToInventory, bool resumeScripts, bool append)
bool silent, bool addToInventory, bool resumeScripts, bool append, UUID experience)
{
//m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
@ -708,7 +708,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (addToInventory && sp.PresenceType != PresenceType.Npc)
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, append);
AttachToAgent(sp, group, attachmentPt, attachPos, silent);
AttachToAgent(sp, group, attachmentPt, attachPos, silent, experience);
if (resumeScripts)
{
@ -1089,7 +1089,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
/// <param name="attachmentpoint"></param>
/// <param name="attachOffset"></param>
/// <param name="silent"></param>
private void AttachToAgent(IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
private void AttachToAgent(IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent, UUID experience)
{
if (DebugLevel > 0)
m_log.DebugFormat(
@ -1117,6 +1117,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
so.RootPart.AttachedPos = attachOffset;
so.RootPart.GroupPosition = attachOffset; // can not set absolutepos
so.IsAttachment = true;
so.AttachedExperienceID = experience;
sp.AddAttachment(so);
@ -1325,7 +1326,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
objatt.ResetOwnerChangeFlag();
}
doneAttach = AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, append);
doneAttach = AttachObjectInternal(sp, objatt, attachmentPt, false, true, true, append, UUID.Zero);
}
catch (Exception e)
{
@ -1455,7 +1456,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
AttachmentPt &= 0x7f;
// Calls attach with a Zero position
if (AttachObject(sp, group , AttachmentPt, false, true, append))
if (AttachObject(sp, group , AttachmentPt, false, true, append, UUID.Zero))
{
if (DebugLevel > 0)
m_log.Debug(

View file

@ -0,0 +1,207 @@
using log4net;
using Mono.Addins;
using Nini.Config;
using System;
using System.Collections.Generic;
using System.Reflection;
using OpenSim.Framework;
using OpenSim.Server.Base;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
using OpenSim.Data;
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Experience
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LocalExperienceServicesConnector")]
public class LocalExperienceServicesConnector : ISharedRegionModule, IExperienceService
{
private static readonly ILog m_log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
private List<Scene> m_Scenes = new List<Scene>();
protected IExperienceService m_service = null;
private bool m_Enabled = false;
#region ISharedRegionModule
public Type ReplaceableInterface
{
get { return null; }
}
public string Name
{
get { return "LocalExperienceServicesConnector"; }
}
public void Initialise(IConfigSource source)
{
IConfig moduleConfig = source.Configs["Modules"];
if (moduleConfig == null)
return;
string name = moduleConfig.GetString("ExperienceService", "");
if(name != Name)
return;
IConfig userConfig = source.Configs["ExperienceService"];
if (userConfig == null)
{
m_log.Error("[EXPERIENCE LOCALCONNECTOR]: ExperienceService missing from configuration");
return;
}
string serviceDll = userConfig.GetString("LocalServiceModule",
String.Empty);
if (serviceDll == String.Empty)
{
m_log.Error("[EXPERIENCE LOCALCONNECTOR]: No ExperienceModule named in section ExperienceService");
return;
}
Object[] args = new Object[] { source };
try
{
m_service = ServerUtils.LoadPlugin<IExperienceService>(serviceDll, args);
}
catch
{
m_log.Error("[EXPERIENCE LOCALCONNECTOR]: Failed to load experience service");
return;
}
if (m_service == null)
{
m_log.Error("[EXPERIENCE LOCALCONNECTOR]: Can't load experience service");
return;
}
m_Enabled = true;
m_log.Info("[EXPERIENCE LOCALCONNECTOR]: Enabled!");
}
public void Close()
{
}
public void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
lock(m_Scenes)
{
m_Scenes.Add(scene);
scene.RegisterModuleInterface<IExperienceService>(this);
}
}
public void RegionLoaded(Scene scene)
{
}
public void PostInitialise()
{
}
public void RemoveRegion(Scene scene)
{
if (!m_Enabled)
return;
lock(m_Scenes)
{
if (m_Scenes.Contains(scene))
{
m_Scenes.Remove(scene);
scene.UnregisterModuleInterface<IExperienceService>(this);
}
}
}
#endregion ISharedRegionModule
#region IExperienceService
public Dictionary<UUID, bool> FetchExperiencePermissions(UUID agent_id)
{
return m_service.FetchExperiencePermissions(agent_id);
}
public bool UpdateExperiencePermissions(UUID agent_id, UUID experience, ExperiencePermission perm)
{
return m_service.UpdateExperiencePermissions(agent_id, experience, perm);
}
public ExperienceInfo[] GetExperienceInfos(UUID[] experiences)
{
return m_service.GetExperienceInfos(experiences);
}
public UUID[] GetAgentExperiences(UUID agent_id)
{
return m_service.GetAgentExperiences(agent_id);
}
public ExperienceInfo UpdateExpereienceInfo(ExperienceInfo info)
{
return m_service.UpdateExpereienceInfo(info);
}
public ExperienceInfo[] FindExperiencesByName(string search)
{
return m_service.FindExperiencesByName(search);
}
public UUID[] GetGroupExperiences(UUID group_id)
{
return m_service.GetGroupExperiences(group_id);
}
public UUID[] GetExperiencesForGroups(UUID[] groups)
{
return m_service.GetExperiencesForGroups(groups);
}
public string GetKeyValue(UUID experience, string key)
{
return m_service.GetKeyValue(experience, key);
}
public string CreateKeyValue(UUID experience, string key, string value)
{
return m_service.CreateKeyValue(experience, key, value);
}
public string UpdateKeyValue(UUID experience, string key, string val, bool check, string original)
{
return m_service.UpdateKeyValue(experience, key, val, check, original);
}
public string DeleteKey(UUID experience, string key)
{
return m_service.DeleteKey(experience, key);
}
public int GetKeyCount(UUID experience)
{
return m_service.GetKeyCount(experience);
}
public string[] GetKeys(UUID experience, int start, int count)
{
return m_service.GetKeys(experience, start, count);
}
public int GetSize(UUID experience)
{
return m_service.GetSize(experience);
}
#endregion IExperienceService
}
}

View file

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Connectors;
using OpenMetaverse;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenSim.Data;
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Experience
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RemoteExperienceServicesConnector")]
public class RemoteExperienceServicesConnector : ISharedRegionModule, IExperienceService
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#region ISharedRegionModule
private bool m_Enabled = false;
private IExperienceService m_remoteConnector;
public Type ReplaceableInterface
{
get { return null; }
}
public string Name
{
get { return "RemoteExperienceServicesConnector"; }
}
public void Initialise(IConfigSource source)
{
IConfig moduleConfig = source.Configs["Modules"];
if (moduleConfig != null)
{
string name = moduleConfig.GetString("InventoryServices", "");
if (name == Name)
{
m_remoteConnector = new ExperienceServicesConnector(source);
m_Enabled = true;
m_log.Info("[XINVENTORY CONNECTOR]: Remote ExperienceService enabled");
}
}
}
public void PostInitialise()
{
}
public void Close()
{
}
public void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
scene.RegisterModuleInterface<IExperienceService>(this);
m_log.InfoFormat("[EXPERIENCE CONNECTOR]: Enabled for region {0}", scene.RegionInfo.RegionName);
}
public void RemoveRegion(Scene scene)
{
if (!m_Enabled)
return;
}
public void RegionLoaded(Scene scene)
{
if (!m_Enabled)
return;
}
#endregion
#region IExperienceService
public Dictionary<UUID, bool> FetchExperiencePermissions(UUID agent_id)
{
return m_remoteConnector.FetchExperiencePermissions(agent_id);
}
public bool UpdateExperiencePermissions(UUID agent_id, UUID experience, ExperiencePermission perm)
{
return m_remoteConnector.UpdateExperiencePermissions(agent_id, experience, perm);
}
public ExperienceInfo[] GetExperienceInfos(UUID[] experiences)
{
return m_remoteConnector.GetExperienceInfos(experiences);
}
public UUID[] GetAgentExperiences(UUID agent_id)
{
return m_remoteConnector.GetAgentExperiences(agent_id);
}
public ExperienceInfo UpdateExpereienceInfo(ExperienceInfo info)
{
return m_remoteConnector.UpdateExpereienceInfo(info);
}
public ExperienceInfo[] FindExperiencesByName(string search)
{
return m_remoteConnector.FindExperiencesByName(search);
}
public UUID[] GetGroupExperiences(UUID group_id)
{
return m_remoteConnector.GetGroupExperiences(group_id);
}
public UUID[] GetExperiencesForGroups(UUID[] groups)
{
return m_remoteConnector.GetExperiencesForGroups(groups);
}
public string GetKeyValue(UUID experience, string key)
{
return m_remoteConnector.GetKeyValue(experience, key);
}
public string CreateKeyValue(UUID experience, string key, string value)
{
return m_remoteConnector.CreateKeyValue(experience, key, value);
}
public string UpdateKeyValue(UUID experience, string key, string val, bool check, string original)
{
return m_remoteConnector.UpdateKeyValue(experience, key, val, check, original);
}
public string DeleteKey(UUID experience, string key)
{
return m_remoteConnector.DeleteKey(experience, key);
}
public int GetKeyCount(UUID experience)
{
return m_remoteConnector.GetKeyCount(experience);
}
public string[] GetKeys(UUID experience, int start, int count)
{
return m_remoteConnector.GetKeys(experience, start, count);
}
public int GetSize(UUID experience)
{
return m_remoteConnector.GetSize(experience);
}
#endregion IExperienceService
}
}

View file

@ -1165,6 +1165,249 @@ namespace OpenSim.Region.CoreModules.World.Estate
runnigDeltaExec = false;
}
private object expdeltareqLock = new object();
private bool runnigExpDeltaExec = false;
private class EstateExperienceDeltaRequest
{
public IClientAPI remote_client;
public UUID invoice;
public int estateAccessType;
public UUID experience;
}
private BlockingCollection<EstateExperienceDeltaRequest> experienceDeltaRequests = new BlockingCollection<EstateExperienceDeltaRequest>();
private void handleEstateExperienceDeltaRequest(IClientAPI _remote_client, UUID _invoice, int _estateAccessType, UUID _experience)
{
EstateExperienceDeltaRequest newreq = new EstateExperienceDeltaRequest();
newreq.remote_client = _remote_client;
newreq.invoice = _invoice;
newreq.estateAccessType = _estateAccessType;
newreq.experience = _experience;
experienceDeltaRequests.Add(newreq);
lock (expdeltareqLock)
{
if (!runnigExpDeltaExec)
{
runnigExpDeltaExec = true;
WorkManager.RunInThreadPool(execExpDeltaRequests, null, "execExpDeltaRequests");
}
}
}
private void execExpDeltaRequests(object o)
{
IClientAPI remote_client;
UUID invoice;
int estateAccessType;
UUID experience;
Dictionary<int, EstateSettings> changed = new Dictionary<int, EstateSettings>();
Dictionary<IClientAPI, UUID> sendExperienceLists = new Dictionary<IClientAPI, UUID>();
List<EstateSettings> otherEstates = new List<EstateSettings>();
bool sentAllowedFull = false;
EstateExperienceDeltaRequest req;
while (Scene.IsRunning)
{
req = null;
experienceDeltaRequests.TryTake(out req, 500);
if (!Scene.IsRunning)
break;
if (req == null)
{
if (changed.Count > 0)
{
foreach (EstateSettings est in changed.Values)
Scene.EstateDataService.StoreEstateSettings(est);
TriggerEstateInfoChange();
}
EstateSettings es = Scene.RegionInfo.EstateSettings;
foreach (KeyValuePair<IClientAPI, UUID> kvp in sendExperienceLists)
{
IClientAPI cli = kvp.Key;
UUID invoive = kvp.Value;
cli.SendEstateExperiences(invoive, es.AllowedExperiences, es.KeyExperiences, es.EstateID);
}
sendExperienceLists.Clear();
otherEstates.Clear();
changed.Clear();
lock (expdeltareqLock)
{
if (experienceDeltaRequests.Count != 0)
continue;
runnigExpDeltaExec = false;
return;
}
}
remote_client = req.remote_client;
if (!remote_client.IsActive)
continue;
invoice = req.invoice;
experience = req.experience;
estateAccessType = req.estateAccessType;
bool needReply = ((estateAccessType & 1024) == 0);
bool doOtherEstates = ((estateAccessType & 3) != 0);
EstateSettings thisSettings = Scene.RegionInfo.EstateSettings;
int thisEstateID = (int)thisSettings.EstateID;
UUID agentID = remote_client.AgentId;
bool isadmin = Scene.Permissions.IsAdministrator(agentID);
// just in case recheck rights
if (!isadmin && !Scene.Permissions.IsEstateManager(agentID))
{
remote_client.SendAlertMessage("Method EstateAccess Failed, you don't have permissions");
continue;
}
otherEstates.Clear();
if (doOtherEstates)
{
UUID thisOwner = Scene.RegionInfo.EstateSettings.EstateOwner;
List<int> estateIDs = Scene.EstateDataService.GetEstatesByOwner(thisOwner);
foreach (int estateID in estateIDs)
{
if (estateID == thisEstateID)
continue;
EstateSettings estateSettings;
if (changed.ContainsKey(estateID))
estateSettings = changed[estateID];
else
estateSettings = Scene.EstateDataService.LoadEstateSettings(estateID);
if (!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID))
continue;
otherEstates.Add(estateSettings);
}
estateIDs.Clear();
}
if ((estateAccessType & 4) != 0) // add key experience
{
if (thisSettings.KeyExperiencesCount() >= (int)Constants.EstateAccessLimits.KeyExperiences)
{
if (!sentAllowedFull)
{
sentAllowedFull = true;
remote_client.SendAlertMessage("Estate Allowed Experiences list is full");
}
}
else
{
if (doOtherEstates)
{
foreach (EstateSettings estateSettings in otherEstates)
{
if (!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID))
continue;
if (estateSettings.KeyExperiencesCount() >= (int)Constants.EstateAccessLimits.KeyExperiences)
continue;
estateSettings.AddKeyExperience(experience);
changed[(int)estateSettings.EstateID] = estateSettings;
}
}
thisSettings.AddKeyExperience(experience);
changed[thisEstateID] = thisSettings;
if (needReply)
sendExperienceLists[remote_client] = invoice;
}
}
if ((estateAccessType & 8) != 0) // remove key experience
{
if (doOtherEstates) // All estates
{
foreach (EstateSettings estateSettings in otherEstates)
{
if (!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID))
continue;
estateSettings.RemoveKeyExperience(experience);
changed[(int)estateSettings.EstateID] = estateSettings;
}
}
thisSettings.RemoveKeyExperience(experience);
changed[thisEstateID] = thisSettings;
if (needReply)
sendExperienceLists[remote_client] = invoice;
}
if ((estateAccessType & 16) != 0) // add allowed experience
{
if (thisSettings.AllowedExperiencesCount() >= (int)Constants.EstateAccessLimits.AllowedExperiences)
{
if (!sentAllowedFull)
{
sentAllowedFull = true;
remote_client.SendAlertMessage("Estate Allowed Experiences list is full");
}
}
else
{
if (doOtherEstates)
{
foreach (EstateSettings estateSettings in otherEstates)
{
if (!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID))
continue;
if (estateSettings.AllowedExperiencesCount() >= (int)Constants.EstateAccessLimits.AllowedExperiences)
continue;
estateSettings.AddAllowedExperience(experience);
changed[(int)estateSettings.EstateID] = estateSettings;
}
}
thisSettings.AddAllowedExperience(experience);
changed[thisEstateID] = thisSettings;
if (needReply)
sendExperienceLists[remote_client] = invoice;
}
}
if ((estateAccessType & 32) != 0) // remove allowed experience
{
if (doOtherEstates) // All estates
{
foreach (EstateSettings estateSettings in otherEstates)
{
if (!isadmin && !estateSettings.IsEstateManagerOrOwner(agentID))
continue;
estateSettings.RemoveAllowedExperience(experience);
changed[(int)estateSettings.EstateID] = estateSettings;
}
}
thisSettings.RemoveAllowedExperience(experience);
changed[thisEstateID] = thisSettings;
if (needReply)
sendExperienceLists[remote_client] = invoice;
}
}
lock (deltareqLock)
runnigDeltaExec = false;
}
public void HandleOnEstateManageTelehub(IClientAPI client, UUID invoice, UUID senderID, string cmd, uint param1)
{
SceneObjectPart part;
@ -1856,6 +2099,7 @@ namespace OpenSim.Region.CoreModules.World.Estate
client.OnEstateChangeInfo += HandleEstateChangeInfo;
client.OnEstateManageTelehub += HandleOnEstateManageTelehub;
client.OnUpdateEstateAccessDeltaRequest += HandleEstateAccessDeltaRequest;
client.OnUpdateEstateExperienceDeltaRequest += handleEstateExperienceDeltaRequest;
client.OnSimulatorBlueBoxMessageRequest += SendSimulatorBlueBoxMessage;
client.OnEstateBlueBoxMessageRequest += SendEstateBlueBoxMessage;
client.OnEstateDebugRegionRequest += HandleEstateDebugRegionRequest;

View file

@ -690,7 +690,9 @@ namespace OpenSim.Region.CoreModules.World.Land
uint flags, UUID transactionID, int landLocalID, List<LandAccessEntry> entries,
IClientAPI remote_client)
{
if ((flags & 0x03) == 0)
// Todo: update the actual AccessList enum!
if ((flags & (uint)0x1Bu) == 0)
return; // we only have access and ban
if(m_scene.RegionInfo.EstateSettings.TaxFree)
@ -709,8 +711,12 @@ namespace OpenSim.Region.CoreModules.World.Land
requiredPowers |= GroupPowers.LandManageAllowed;
if ((flags & (uint)AccessList.Ban) != 0)
requiredPowers |= GroupPowers.LandManageBanned;
if ((flags & (uint)8u) != 0)
requiredPowers |= GroupPowers.LandManageAllowed;
if ((flags & (uint)0x10u) != 0)
requiredPowers |= GroupPowers.LandManageBanned;
if(requiredPowers == GroupPowers.None)
if (requiredPowers == GroupPowers.None)
return;
if (m_scene.Permissions.CanEditParcelProperties(agentID,

View file

@ -1016,6 +1016,8 @@ namespace OpenSim.Region.CoreModules.World.Land
int now = Util.UnixTimeSinceEpoch();
List<LandAccessEntry> accesslist = new();
List<LandAccessEntry> banlist = new();
List<LandAccessEntry> allowed = new();
List<LandAccessEntry> blocked = new();
foreach (LandAccessEntry entry in LandData.ParcelAccessList)
{
if(entry.Expires > now || entry.Expires == 0)
@ -1024,6 +1026,10 @@ namespace OpenSim.Region.CoreModules.World.Land
accesslist.Add(entry);
else if (entry.Flags == AccessList.Ban)
banlist.Add(entry);
else if((uint)entry.Flags == 8u) // Todo: Update to AccessList.Allowed
allowed.Add(entry);
else if((uint)entry.Flags == 0x10u) // Todo: Update to AccessList.Blocked
blocked.Add(entry);
}
}
@ -1046,7 +1052,7 @@ namespace OpenSim.Region.CoreModules.World.Land
public void UpdateAccessList(uint flags, UUID transactionID, List<LandAccessEntry> entries)
{
flags &= 0x03;
flags &= 0x1Bu; // Todo: Update to AccessList.All
if (flags == 0)
return; // we only have access and ban

View file

@ -91,7 +91,7 @@ namespace OpenSim.Region.Framework.Interfaces
/// <param name="append">Append to attachment point rather than replace.</param>
/// <returns>true if the object was successfully attached, false otherwise</returns>
bool AttachObject(IScenePresence sp, SceneObjectGroup grp, uint AttachmentPt, bool silent,
bool addToInventory, bool append);
bool addToInventory, bool append, UUID experience);
/// <summary>
/// Rez an attachment from user inventory and change inventory status to match.

View file

@ -106,6 +106,7 @@ namespace OpenSim.Region.Framework.Interfaces
byte[] BuildEvent(string eventName, OSD eventBody);
void partPhysicsProperties(uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID);
void WindlightRefreshEvent(int interpolate, UUID avatarID);
void SendEnvironmentUpdate(UUID experience_id, UUID agent_id, EnvironmentUpdate update);
void SendBulkUpdateInventoryItem(InventoryItemBase item, UUID avatarID, UUID? transationID = null);
osUTF8 StartEvent(string eventName);
osUTF8 StartEvent(string eventName, int cap);

View file

@ -0,0 +1,45 @@
using OpenMetaverse;
using OpenSim.Services.Interfaces;
namespace OpenSim.Region.Framework.Interfaces
{
public interface IExperienceModule
{
ExperiencePermission GetExperiencePermission(UUID avatar_id, UUID experience_id);
bool SetExperiencePermission(UUID avatar_id, UUID experience_id, ExperiencePermission perm);
bool SetExperiencePermissions(UUID avatar_id, UUID experience_id, bool allow);
bool ForgetExperiencePermissions(UUID avatar_id, UUID experience_id);
UUID[] GetAllowedExperiences(UUID avatar_id);
UUID[] GetBlockedExperiences(UUID avatar_id);
UUID[] GetAgentExperiences(UUID agent_id);
UUID[] GetAdminExperiences(UUID agent_id);
UUID[] GetConributorExperiences(UUID agent_id);
ExperienceInfo GetExperienceInfo(UUID experience_id, bool fetch = false);
ExperienceInfo[] GetExperienceInfos(UUID[] experience_ids, bool fetch = false);
ExperienceInfo[] FindExperiencesByName(string query);
UUID[] GetGroupExperiences(UUID group_id);
ExperienceInfo UpdateExperienceInfo(ExperienceInfo info);
bool IsExperienceAdmin(UUID agent_id, UUID experience_id);
bool IsExperienceContributor(UUID agent_id, UUID experience_id);
UUID[] GetEstateAllowedExperiences();
UUID[] GetEstateKeyExperiences();
bool IsExperienceEnabled(UUID experience_id);
string GetKeyValue(UUID experience, string key);
string CreateKeyValue(UUID experience, string key, string value);
string UpdateKeyValue(UUID experience, string key, string val, bool check, string original);
string DeleteKey(UUID experience, string key);
int GetKeyCount(UUID experience);
string[] GetKeys(UUID experience, int start, int count);
int GetSize(UUID experience);
}
}

View file

@ -354,7 +354,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="isScriptRunning">Indicates whether the script to update is currently running</param>
/// <param name="data"></param>
public ArrayList CapsUpdateTaskInventoryScriptAsset(IClientAPI remoteClient, UUID itemId,
UUID primId, bool isScriptRunning, byte[] data)
UUID primId, bool isScriptRunning, UUID experience, byte[] data)
{
if (!Permissions.CanEditScript(itemId, primId, remoteClient.AgentId))
{
@ -391,16 +391,36 @@ namespace OpenSim.Region.Framework.Scenes
part.Inventory.RemoveScriptInstance(item.ItemID, false);
ArrayList errors = new ArrayList();
bool allowed_to_contribute = true;
if (experience != UUID.Zero)
{
allowed_to_contribute = ExperienceModule.IsExperienceContributor(remoteClient.AgentId, experience);
if (!allowed_to_contribute)
{
experience = UUID.Zero;
errors = new ArrayList(1);
errors.Add("Access denied to experience!");
}
}
// Update item with new asset
item.AssetID = asset.FullID;
item.ExperienceID = experience;
group.UpdateInventoryItem(item);
group.InvalidateEffectivePerms();
part.SendPropertiesToClient(remoteClient);
// Trigger rerunning of script (use TriggerRezScript event, see RezScript)
// Needs to determine which engine was running it and use that
ArrayList errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 1);
if (allowed_to_contribute)
{
// Trigger rerunning of script (use TriggerRezScript event, see RezScript)
// Needs to determine which engine was running it and use that
errors = part.Inventory.CreateScriptInstanceEr(item.ItemID, 0, false, DefaultScriptEngine, 1);
}
// Tell anyone managing scripts that a script has been reloaded/changed
EventManager.TriggerUpdateScript(remoteClient.AgentId, itemId, primId, isScriptRunning, item.AssetID);
@ -413,12 +433,12 @@ namespace OpenSim.Region.Framework.Scenes
/// <see>CapsUpdateTaskInventoryScriptAsset(IClientAPI, UUID, UUID, bool, byte[])</see>
/// </summary>
public ArrayList CapsUpdateTaskInventoryScriptAsset(UUID avatarId, UUID itemId,
UUID primId, bool isScriptRunning, byte[] data)
UUID primId, bool isScriptRunning, UUID experience, byte[] data)
{
if (TryGetScenePresence(avatarId, out ScenePresence avatar))
{
return CapsUpdateTaskInventoryScriptAsset(
avatar.ControllingClient, itemId, primId, isScriptRunning, data);
avatar.ControllingClient, itemId, primId, isScriptRunning, experience, data);
}
else
{

View file

@ -311,6 +311,7 @@ namespace OpenSim.Region.Framework.Scenes
protected IAuthorizationService m_AuthorizationService;
protected IInventoryService m_InventoryService;
protected IGridService m_GridService;
protected IExperienceModule m_ExperienceModule;
protected ILibraryService m_LibraryService;
protected ISimulationService m_simulationService;
protected IAuthenticationService m_AuthenticationService;
@ -634,6 +635,27 @@ namespace OpenSim.Region.Framework.Scenes
}
}
public IExperienceModule ExperienceModule
{
get
{
m_ExperienceModule ??= RequestModuleInterface<IExperienceModule>();
return m_ExperienceModule;
//if (m_ExperienceModule == null)
//{
// m_ExperienceModule = RequestModuleInterface<IExperienceModule>();
// if (m_ExperienceModule == null)
// {
// throw new Exception("No IExperienceModule available. This could happen if the config_include folder doesn't exist or if the OpenSim.ini [Architecture] section isn't set.");
// }
//}
//return m_ExperienceModule;
}
}
public ILibraryService LibraryService
{
get
@ -3057,7 +3079,7 @@ namespace OpenSim.Region.Framework.Scenes
// We currently do this in Scene.MakeRootAgent() instead.
bool attached = false;
if (AttachmentsModule is not null)
attached = AttachmentsModule.AttachObject(sp, grp, 0, false, false, true);
attached = AttachmentsModule.AttachObject(sp, grp, 0, false, false, true, UUID.Zero);
if (attached)
RootPrim.RemFlag(PrimFlags.TemporaryOnRez);

View file

@ -89,9 +89,11 @@ namespace OpenSim.Region.Framework.Scenes
path_update = 40,
linkset_data = 41,
experience_permissions = 42,
experience_permissions_denied = 43,
// marks highest numbered event
Size = 42
Size = 44
}
// this is not the right place for this
@ -143,6 +145,8 @@ namespace OpenSim.Region.Framework.Scenes
path_update = 1UL << 40,
linkset_data = 1UL << 41,
experience_permissions = 1UL << 42,
experience_permissions_denied = 1UL << 43,
anytouch = touch | touch_end | touch_start,
anyTarget = at_target | not_at_target | at_rot_target | not_at_rot_target,
@ -312,6 +316,12 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
public bool IsAttachment { get; set; }
/// <summary>
/// What experience temp attached this item
/// This will not be set if the object wasn't temp attached
/// </summary>
public UUID AttachedExperienceID { get; set; }
/// <summary>
/// The avatar to which this scene object is attached.
/// </summary>

View file

@ -303,6 +303,9 @@ namespace OpenSim.Region.Framework.Scenes
private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
private Quaternion m_sitTargetOrientation = Quaternion.Identity;
private Vector3 m_sitTargetPosition;
private bool m_scriptedSitOnly = false;
private bool m_allowUnsit = true;
private UUID m_experienceUsedForSit = UUID.Zero;
private string m_sitAnimation = "SIT";
private UndoRedoState m_UndoRedo = null;
private readonly object m_UndoLock = new object();
@ -1264,8 +1267,44 @@ namespace OpenSim.Region.Framework.Scenes
set { m_sitTargetOrientation = value; }
}
public float SitActiveRange { get; set; }
public Vector3 StandOffset { get; set; }
[XmlIgnore]
public bool AllowUnsit
{
get { return m_allowUnsit; }
set
{
m_allowUnsit = value;
if (ParentGroup != null)
ParentGroup.HasGroupChanged = true;
}
}
[XmlIgnore]
public bool ScriptedSitOnly
{
get { return m_scriptedSitOnly; }
set
{
m_scriptedSitOnly = value;
if (ParentGroup != null)
ParentGroup.HasGroupChanged = true;
}
}
[XmlIgnore]
public UUID ExperienceUsedForSit
{
get { return m_experienceUsedForSit; }
set
{
m_experienceUsedForSit = value;
}
}
public float SitActiveRange { get; set;}
public Vector3 StandOffset { get; set;}
public bool Stopped
{

View file

@ -2645,7 +2645,19 @@ namespace OpenSim.Region.Framework.Scenes
// SendAgentTerseUpdate(this);
if ((allFlags & ACFlags.AGENT_CONTROL_STAND_UP) != 0)
{
if (ParentPart != null && !ParentPart.AllowUnsit)
{
// Check that the experience still has permission to keep the user seated
if(Scene.ExperienceModule.GetExperiencePermission(remoteClient.AgentId, ParentPart.ExperienceUsedForSit) == ExperiencePermission.Allowed)
{
ControllingClient.SendAgentAlertMessage(string.Format("'{0}' will not allow you to stand at this time.", ParentPart.Name), false);
return;
}
}
StandUp();
}
if ((allFlags & ACFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0)
HandleAgentSitOnGround();
@ -3374,10 +3386,31 @@ namespace OpenSim.Region.Framework.Scenes
if (IsChildAgent)
return;
SceneObjectPart part = Scene.GetSceneObjectPart(targetID);
if (part == null)
return;
if(part.ScriptedSitOnly)
{
ControllingClient.SendAgentAlertMessage("There is no suitable surface to sit on, try another spot.", false);
return;
}
if (ParentID != 0)
{
if (targetID.Equals(ParentPart.UUID))
return; // already sitting here, ignore
if (!ParentPart.AllowUnsit)
{
if (Scene.ExperienceModule.GetExperiencePermission(this.UUID, ParentPart.ExperienceUsedForSit) == ExperiencePermission.Allowed)
{
ControllingClient.SendAgentAlertMessage(string.Format("'{0}' will not allow you to change your seat at this time.", ParentPart.Name), false);
return;
}
}
StandUp();
}
else if (SitGround)
@ -3386,6 +3419,26 @@ namespace OpenSim.Region.Framework.Scenes
SendSitResponse(targetID, offset, Quaternion.Identity);
}
public void ScriptedSit(SceneObjectPart part, UUID agent_id, UUID experience_id)
{
// todo: come back to this!
if (IsChildAgent)
return;
if (ParentID != 0)
{
if (agent_id.Equals(ParentPart.UUID))
return; // already sitting here, ignore
StandUp();
}
else if (SitGround)
StandUp();
SendSitResponse(part.UUID, part.SitTargetPositionLL, part.SitTargetOrientationLL);
}
// returns false if does not suport so older sit can be tried
public bool PhysicsSit(SceneObjectPart part, Vector3 offset)
{

View file

@ -515,7 +515,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
{"SOPAnims", ProcessSOPAnims },
{"SitActRange", ProcessSitActRange },
{"LinksetData", ProcessLinksetData}
{"LinksetData", ProcessLinksetData },
{"AllowUnsit", ProcessAllowUnsit },
{"ScriptedSitOnly", ProcessScriptedSitOnly }
}.ToFrozenDictionary();
private static readonly FrozenDictionary<string, Action<TaskInventoryItem, XmlReader>> m_TaskInventoryXmlProcessors = new Dictionary<string, Action<TaskInventoryItem, XmlReader>>()
@ -815,6 +817,16 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
obj.SitActiveRange = reader.ReadElementContentAsFloat("SitActRange", string.Empty);
}
private static void ProcessAllowUnsit(SceneObjectPart obj, XmlReader reader)
{
obj.AllowUnsit = Util.ReadBoolean(reader);
}
private static void ProcessScriptedSitOnly(SceneObjectPart obj, XmlReader reader)
{
obj.ScriptedSitOnly = Util.ReadBoolean(reader);
}
private static void ProcessLinksetData(SceneObjectPart obj, XmlReader reader)
{
try
@ -1683,7 +1695,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
var lsd = sop.SerializeLinksetData();
if (string.IsNullOrWhiteSpace(lsd) is false)
writer.WriteElementString("LinksetData", lsd);
writer.WriteElementString("AllowUnsit", sop.AllowUnsit.ToString().ToLower());
writer.WriteElementString("ScriptedSitOnly", sop.ScriptedSitOnly.ToString().ToLower());
writer.WriteEndElement();
}

View file

@ -827,6 +827,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
public event EstateRestartSimRequest OnEstateRestartSimRequest;
public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
public event UpdateEstateExperienceDeltaRequest OnUpdateEstateExperienceDeltaRequest;
public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
@ -1250,7 +1251,12 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
}
public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question)
public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question, UUID experience)
{
}
public void SendEstateExperiences(UUID invoice, UUID[] allowed, UUID[] key, uint estateID)
{
}
@ -1778,5 +1784,8 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
return 0;
}
public void SendGenericMessageForExperience(UUID experience_id, UUID avatar_id, int action, string obj_name, string parcel, bool is_attachment)
{
}
}
}

View file

@ -458,6 +458,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
public event EstateRestartSimRequest OnEstateRestartSimRequest;
public event EstateChangeCovenantRequest OnEstateChangeCovenantRequest;
public event UpdateEstateAccessDeltaRequest OnUpdateEstateAccessDeltaRequest;
public event UpdateEstateExperienceDeltaRequest OnUpdateEstateExperienceDeltaRequest;
public event SimulatorBlueBoxMessageRequest OnSimulatorBlueBoxMessageRequest;
public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest;
public event EstateDebugRegionRequest OnEstateDebugRegionRequest;
@ -1085,13 +1086,17 @@ namespace OpenSim.Region.OptionalModules.World.NPC
{
}
public void SendScriptQuestion(UUID objectID, string taskName, string ownerName, UUID itemID, int question)
public void SendScriptQuestion(UUID objectID, string taskName, string ownerName, UUID itemID, int question, UUID experience)
{
}
public void SendHealth(float health)
{
}
public void SendEstateExperiences(UUID invoice, UUID[] allowed, UUID[] key, uint estateID)
{
}
public void SendEstateList(UUID invoice, int code, UUID[] Data, uint estateID)
{
}
@ -1401,5 +1406,8 @@ namespace OpenSim.Region.OptionalModules.World.NPC
return 0;
}
public void SendGenericMessageForExperience(UUID experience_id, UUID avatar_id, int action, string obj_name, string parcel, bool is_attachment)
{
}
}
}

View file

@ -523,6 +523,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
LSL_Integer llLinksetDataDeleteProtected(LSL_String name, LSL_String pass);
LSL_Integer llIsFriend(LSL_Key agent_id);
LSL_Integer llDerezObject(LSL_Key objectUUID, LSL_Integer flag);
}
LSL_Integer llDerezObject(LSL_Key objectUUID, LSL_Integer flag);
void llRequestExperiencePermissions(string agent_id, string unused);
LSL_Integer llAgentInExperience(string agent_id);
LSL_List llGetExperienceDetails(string experience_key);
LSL_String llGetExperienceErrorMessage(LSL_Integer error);
LSL_Integer llSitOnLink(string agent_id, LSL_Integer link);
LSL_Key llCreateKeyValue(string key, string value);
LSL_Key llDeleteKeyValue(string key);
LSL_Key llReadKeyValue(string key);
LSL_Key llUpdateKeyValue(string key, string value, LSL_Integer check, string original);
LSL_Key llKeyCountKeyValue();
LSL_Key llKeysKeyValue(LSL_Integer first, LSL_Integer count);
LSL_Key llDataSizeKeyValue();
LSL_Integer llSetAgentEnvironment(LSL_Key agent_id, LSL_Float transition, LSL_List param_list);
LSL_Integer llReplaceAgentEnvironment(LSL_Key agent_id, LSL_Float transition, LSL_String environment);
}
}

View file

@ -1015,6 +1015,73 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
public const int TARGETED_EMAIL_ROOT_CREATOR = 1;
public const int TARGETED_EMAIL_OBJECT_OWNER = 2;
// Experience
public const int XP_ERROR_NONE = 0;
public const int XP_ERROR_THROTTLED = 1;
public const int XP_ERROR_EXPERIENCES_DISABLED = 2;
public const int XP_ERROR_INVALID_PARAMETERS = 3;
public const int XP_ERROR_NOT_PERMITTED = 4;
public const int XP_ERROR_NO_EXPERIENCE = 5;
public const int XP_ERROR_NOT_FOUND = 6;
public const int XP_ERROR_INVALID_EXPERIENCE = 7;
public const int XP_ERROR_EXPERIENCE_DISABLED = 8;
public const int XP_ERROR_EXPERIENCE_SUSPENDED = 9;
public const int XP_ERROR_UNKNOWN_ERROR = 10;
public const int XP_ERROR_QUOTA_EXCEEDED = 11;
public const int XP_ERROR_STORE_DISABLED = 12;
public const int XP_ERROR_STORAGE_EXCEPTION = 13;
public const int XP_ERROR_KEY_NOT_FOUND = 14;
public const int XP_ERROR_RETRY_UPDATE = 15;
public const int XP_ERROR_MATURITY_EXCEEDED = 16;
public const int XP_ERROR_NOT_PERMITTED_LAND = 17;
public const int XP_ERROR_REQUEST_PERM_TIMEOUT = 18;
// llSitOnLink
public const int SIT_NOT_EXPERIENCE = -1;
public const int SIT_NO_EXPERIENCE_PERMISSION = -2;
public const int SIT_NO_SIT_TARGET = -3;
public const int SIT_INVALID_AGENT = -4;
public const int SIT_INVALID_LINK = -5;
public const int SIT_NO_ACCESS = -6;
public const int SIT_INVALID_OBJECT = -7;
// EEP
public const int ENV_NOT_EXPERIENCE = -1;
public const int ENV_NO_EXPERIENCE_PERMISSION = -2;
public const int ENV_NO_ENVIRONMENT = -3;
public const int ENV_INVALID_AGENT = -4;
public const int ENV_INVALID_RULE = -5;
public const int ENV_VALIDATION_FAIL = -6;
public const int ENV_NO_EXPERIENCE_LAND = -7;
public const int ENV_THROTTLE = -8;
public const int SKY_CLOUDS = 2;
public const int SKY_CLOUD_TEXTURE = 19;
public const int SKY_DOME = 4;
public const int SKY_GAMMA = 5;
public const int SKY_GLOW = 6;
public const int SKY_MOON = 9;
public const int SKY_MOON_TEXTURE = 20;
public const int SKY_STAR_BRIGHTNESS = 13;
public const int SKY_SUN = 14;
public const int SKY_SUN_TEXTURE = 21;
public const int SKY_PLANET = 10;
public const int SKY_REFRACTION = 11;
public const int WATER_BLUR_MULTIPLIER = 100;
public const int WATER_FOG = 101;
public const int WATER_FRESNEL = 102;
public const int WATER_NORMAL_TEXTURE = 107;
public const int WATER_NORMAL_SCALE = 104;
public const int WATER_REFRACTION = 105;
public const int WATER_WAVE_DIRECTION = 106;
public const int SKY_AMBIENT = 0;
public const int SKY_BLUE = 22;
public const int SKY_HAZE = 23;
public const int SKY_REFLECTION_PROBE_AMBIANCE = 24;
public const int NPCLOOKAT_NONE = 0;
public const int NPCLOOKAT_IDLE = 1;
public const int NPCLOOKAT_LISTEN = 2;

View file

@ -75,5 +75,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine
void path_update(int type, LSL_List data);
void region_cross(LSL_Vector newpos, LSL_Vector oldpos);
void linkset_data(LSL_Integer action, string name, string value);
void experience_permissions(LSL_Key agent_id);
void experience_permissions_denied(LSL_Key agent_id, LSL_Integer reason);
}
}

View file

@ -85,7 +85,10 @@ namespace OpenSim.Region.ScriptEngine.Yengine
path_update = 40,
linkset_data = 41,
experience_permissions = 42,
experience_permissions_denied = 43,
// marks highest numbered event
Size = 42
Size = 44
}
}

View file

@ -184,6 +184,12 @@ namespace OpenSim.Region.ScriptEngine.Yengine
scriptStateN.AppendChild(plugins);
//m_RunOnePhase = "GetExecutionState H";
XmlElement experienceN = doc.CreateElement("", "ExperienceKey", "");
experienceN.AppendChild(doc.CreateTextNode(m_Item.ExperienceID.ToString()));
scriptStateN.AppendChild(experienceN);
//m_RunOnePhase = "GetExecutionState I";
//CheckRunLockInvariants(true);
// Let script run again.
suspendOnCheckRunHold = false;

View file

@ -544,6 +544,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine
MigrateInEventHandler(ms);
}
XmlElement experienceKey = (XmlElement)scriptStateN.SelectSingleNode("ExperienceKey");
m_Item.ExperienceID = UUID.Parse(experienceKey.InnerText);
XmlElement permissionsN = (XmlElement)scriptStateN.SelectSingleNode("Permissions");
m_Item.PermsGranter = new UUID(permissionsN.GetAttribute("granter"));
m_Item.PermsMask = Convert.ToInt32(permissionsN.GetAttribute("mask"));
@ -593,6 +596,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine
int permsMask = 0;
double minEventDelay = 0.0;
Object[] pluginData = new Object[0];
UUID experienceKey = UUID.Zero;
LinkedList<EventParams> eventQueue = new LinkedList<EventParams>();
@ -661,6 +665,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine
case "Running":
running = bool.Parse(part.InnerText);
break;
case "ExperienceKey":
experienceKey = UUID.Parse(part.InnerText);
break;
case "Variables":
int indx;
XmlNodeList varL = part.ChildNodes;
@ -880,6 +887,7 @@ namespace OpenSim.Region.ScriptEngine.Yengine
m_Item.PermsGranter = permsGranter;
m_Item.PermsMask = permsMask;
m_Item.ExperienceID = experienceKey;
m_Part.Inventory.UpdateInventoryItem(m_Item, false, false);
lock (m_RunLock)

View file

@ -242,7 +242,9 @@ namespace OpenSim.Region.ScriptEngine.Yengine
{"sensor", ScriptEventCode.sensor},
{"http_request", ScriptEventCode.http_request},
{"path_update", ScriptEventCode.path_update},
{"linkset_data", ScriptEventCode.linkset_data}
{"linkset_data", ScriptEventCode.linkset_data},
{"experience_permissions", ScriptEventCode.experience_permissions},
{"experience_permissions_denied", ScriptEventCode.experience_permissions_denied},
};
}
}

View file

@ -0,0 +1,36 @@
using System;
using Nini.Config;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.ServiceAuth;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base;
namespace OpenSim.Server.Handlers.Experience
{
public class ExperienceServiceConnector : ServiceConnector
{
private IExperienceService m_ExperienceService;
private string m_ConfigName = "ExperienceService";
public ExperienceServiceConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
IConfig serverConfig = config.Configs[m_ConfigName];
if (serverConfig == null)
throw new Exception(String.Format("No section {0} in config file", m_ConfigName));
string service = serverConfig.GetString("LocalServiceModule", String.Empty);
if (service == String.Empty)
throw new Exception("LocalServiceModule not present in ExperienceService config file ExperienceService section");
Object[] args = new Object[] { config };
m_ExperienceService = ServerUtils.LoadPlugin<IExperienceService>(service, args);
IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName);
server.AddStreamHandler(new ExperienceServerPostHandler(m_ExperienceService, auth));
}
}
}

View file

@ -0,0 +1,456 @@
using Nini.Config;
using log4net;
using System;
using System.Reflection;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework;
using OpenSim.Framework.ServiceAuth;
using OpenSim.Framework.Servers.HttpServer;
using OpenMetaverse;
using System.Linq;
namespace OpenSim.Server.Handlers.Experience
{
public class ExperienceServerPostHandler : BaseStreamHandler
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IExperienceService m_service;
public ExperienceServerPostHandler(IExperienceService service, IServiceAuth auth) :
base("POST", "/experience", auth)
{
m_service = service;
}
protected override byte[] ProcessRequest(string path, Stream requestData,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
string body;
using(StreamReader sr = new StreamReader(requestData))
body = sr.ReadToEnd();
body = body.Trim();
//m_log.InfoFormat("[EXPERIENCE POST HANDLER]: {0}", body);
string method = string.Empty;
try
{
Dictionary<string, object> request = ServerUtils.ParseQueryString(body);
if (!request.ContainsKey("METHOD"))
return FailureResult();
method = request["METHOD"].ToString();
switch (method)
{
case "getpermissions":
return GetPermissions(request);
case "updatepermission":
return UpdatePermission(request);
case "getexperienceinfos":
return GetExperienceInfos(request);
case "getagentexperiences":
return GetAgentExperiences(request);
case "updateexperienceinfo":
return UpdateExperienceInfo(request);
case "findexperiences":
return FindExperiences(request);
case "getgroupexperiences":
return GetGroupExperiences(request);
case "getexperiencesforgroups":
return GetExperiencesForGroups(request);
case "accesskvdatabase":
return AccessKeyValueDatabase(request);
}
m_log.DebugFormat("[EXPERIENCE HANDLER]: unknown method request: {0}", method);
}
catch (Exception e)
{
m_log.DebugFormat("[EXPERIENCE HANDLER]: Exception in method {0}: {1}", method, e);
}
return FailureResult();
}
private byte[] GetExperiencesForGroups(Dictionary<string, object> request)
{
List<UUID> groups = new List<UUID>();
int i = 0;
while (true)
{
string key = string.Format("id_{0}", i);
if (request.ContainsKey(key) == false)
break;
UUID group_id;
if (!UUID.TryParse(request[key].ToString(), out group_id))
break;
groups.Add(group_id);
i++;
}
Dictionary<string, object> result = new Dictionary<string, object>();
UUID[] experiences = m_service.GetExperiencesForGroups(groups.ToArray());
i = 0;
foreach (var id in experiences)
result.Add("id_" + i++, id.ToString());
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
private byte[] GetGroupExperiences(Dictionary<string, object> request)
{
UUID group_id;
if (!UUID.TryParse(request["GROUP"].ToString(), out group_id))
return FailureResult();
UUID[] experiences = m_service.GetGroupExperiences(group_id);
Dictionary<string, object> result = new Dictionary<string, object>();
int i = 0;
foreach (var id in experiences)
result.Add("id_" + i++, id.ToString());
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
private byte[] FindExperiences(Dictionary<string, object> request)
{
if (!request.ContainsKey("SEARCH"))
return FailureResult();
string search = request["SEARCH"].ToString();
ExperienceInfo[] infos = m_service.FindExperiencesByName(search);
Dictionary<string, object> result = new Dictionary<string, object>();
if ((infos == null) || ((infos != null) && (infos.Length == 0)))
{
result["result"] = "null";
}
else
{
int n = 0;
foreach (ExperienceInfo ex in infos)
{
if (ex == null)
continue;
Dictionary<string, object> rinfoDict = ex.ToDictionary();
result["experience_" + n] = rinfoDict;
n++;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] GetPermissions(Dictionary<string, object> request)
{
UUID agent_id;
if( !UUID.TryParse(request["agent_id"].ToString(), out agent_id))
return FailureResult();
Dictionary<UUID, bool> reply_data = m_service.FetchExperiencePermissions(agent_id);
XmlDocument doc = new XmlDocument();
XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, "", "");
doc.AppendChild(xmlnode);
XmlElement rootElement = doc.CreateElement("", "ServerResponse", "");
doc.AppendChild(rootElement);
int i = 0;
foreach(var pair in reply_data)
{
XmlElement key = doc.CreateElement("", string.Format("uuid_{0}", i), "");
key.AppendChild(doc.CreateTextNode(pair.Key.ToString()));
rootElement.AppendChild(key);
XmlElement perm = doc.CreateElement("", string.Format("perm_{0}", i), "");
perm.AppendChild(doc.CreateTextNode(pair.Value.ToString()));
rootElement.AppendChild(perm);
i++;
}
return Util.DocToBytes(doc);
}
byte[] GetAgentExperiences(Dictionary<string, object> request)
{
UUID agent_id;
if (!UUID.TryParse(request["AGENT"].ToString(), out agent_id))
return FailureResult();
UUID[] experiences = m_service.GetAgentExperiences(agent_id);
Dictionary<string, object> result = new Dictionary<string, object>();
int i = 0;
foreach (var id in experiences)
result.Add("id_" + i++, id.ToString());
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] UpdatePermission(Dictionary<string, object> request)
{
UUID agent_id;
UUID experience;
if (!UUID.TryParse(request["agent_id"].ToString(), out agent_id))
return FailureResult();
if (!UUID.TryParse(request["experience"].ToString(), out experience))
return FailureResult();
string perm = request["permission"].ToString();
ExperiencePermission permissions = ExperiencePermission.None;
if (perm == "allow") permissions = ExperiencePermission.Allowed;
else if (perm == "block") permissions = ExperiencePermission.Blocked;
return m_service.UpdateExperiencePermissions(agent_id, experience, permissions) ? SuccessResult() : FailureResult();
}
byte[] GetExperienceInfos(Dictionary<string, object> request)
{
List<UUID> experiences = new List<UUID>();
int i = 0;
while(true)
{
string key = string.Format("id_{0}", i);
if (request.ContainsKey(key) == false)
break;
UUID experience_id;
if (!UUID.TryParse(request[key].ToString(), out experience_id))
break;
experiences.Add(experience_id);
i++;
}
ExperienceInfo[] infos = m_service.GetExperienceInfos(experiences.ToArray());
Dictionary<string, object> result = new Dictionary<string, object>();
if ((infos == null) || ((infos != null) && (infos.Length == 0)))
{
result["result"] = "null";
}
else
{
int n = 0;
foreach (ExperienceInfo ex in infos)
{
if (ex == null)
continue;
Dictionary<string, object> rinfoDict = ex.ToDictionary();
result["experience_" + n] = rinfoDict;
n++;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] UpdateExperienceInfo(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (request.ContainsKey("public_id"))
{
ExperienceInfo info = new ExperienceInfo(request);
var updated = m_service.UpdateExpereienceInfo(info);
if(updated != null)
{
result = updated.ToDictionary();
}
else result["result"] = "failed";
}
else result["result"] = "failed";
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
private byte[] AccessKeyValueDatabase(Dictionary<string, object> request)
{
UUID experience_id;
if (!UUID.TryParse(request["EXPERIENCE"].ToString(), out experience_id))
return FailureResult();
if (request.ContainsKey("ACTION") == false)
return FailureResult();
string action = request["ACTION"].ToString();
Dictionary<string, object> result = new Dictionary<string, object>();
if (action == "GET")
{
if (request.ContainsKey("KEY") == false)
return FailureResult();
string key = request["KEY"].ToString();
string get = m_service.GetKeyValue(experience_id, key);
if(get != null)
{
result.Add("result", "success");
result.Add("value", get);
}
else
{
result.Add("result", "missing");
}
}
else if (action == "CREATE")
{
if (request.ContainsKey("KEY") == false || request.ContainsKey("VALUE") == false)
return FailureResult();
string key = request["KEY"].ToString();
string val = request["VALUE"].ToString();
string get = m_service.GetKeyValue(experience_id, key);
if (get == null)
{
result.Add("result", m_service.CreateKeyValue(experience_id, key, val));
}
else
{
result.Add("result", "exists");
}
}
else if (action == "UPDATE")
{
if (request.ContainsKey("KEY") == false || request.ContainsKey("VALUE") == false || request.ContainsKey("CHECK") == false)
return FailureResult();
string key = request["KEY"].ToString();
string val = request["VALUE"].ToString();
bool check = request["CHECK"].ToString() == "TRUE";
string original = string.Empty;
if (check)
{
if (request.ContainsKey("ORIGINAL") == false)
return FailureResult();
else
original = request["ORIGINAL"].ToString();
}
result.Add("result", m_service.UpdateKeyValue(experience_id, key, val, check, original));
}
else if (action == "DELETE")
{
if (request.ContainsKey("KEY") == false)
return FailureResult();
string key = request["KEY"].ToString();
result.Add("result", m_service.DeleteKey(experience_id, key));
}
else if (action == "COUNT")
{
int count = m_service.GetKeyCount(experience_id);
result.Add("result", "success");
result.Add("count", count);
}
else if (action == "GETKEYS")
{
if (request.ContainsKey("START") == false || request.ContainsKey("COUNT") == false)
return FailureResult();
int start = int.Parse(request["START"].ToString());
int count = int.Parse(request["COUNT"].ToString());
string[] keys = m_service.GetKeys(experience_id, start, count);
int i = 0;
foreach (var str in keys)
result.Add("key_" + i++, str);
}
else if(action == "SIZE")
{
int size = m_service.GetSize(experience_id);
result.Add("result", "success");
result.Add("count", size);
}
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
private byte[] SuccessResult()
{
XmlDocument doc = new XmlDocument();
XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, "", "");
doc.AppendChild(xmlnode);
XmlElement rootElement = doc.CreateElement("", "ServerResponse", "");
doc.AppendChild(rootElement);
XmlElement result = doc.CreateElement("", "result", "");
result.AppendChild(doc.CreateTextNode("Success"));
rootElement.AppendChild(result);
return Util.DocToBytes(doc);
}
private byte[] FailureResult()
{
XmlDocument doc = new XmlDocument();
XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, "", "");
doc.AppendChild(xmlnode);
XmlElement rootElement = doc.CreateElement("", "ServerResponse", "");
doc.AppendChild(rootElement);
XmlElement result = doc.CreateElement("", "result", "");
result.AppendChild(doc.CreateTextNode("Failure"));
rootElement.AppendChild(result);
return Util.DocToBytes(doc);
}
}
}

View file

@ -0,0 +1,528 @@
using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.ServiceAuth;
using OpenSim.Services.Interfaces;
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
using OpenSim.Server.Base;
using OpenMetaverse;
using System.Security.AccessControl;
using OpenSim.Data;
using System.Linq;
namespace OpenSim.Services.Connectors
{
public class ExperienceServicesConnector : BaseServiceConnector, IExperienceService
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string m_ServerURI = String.Empty;
public ExperienceServicesConnector()
{
}
public ExperienceServicesConnector(string serverURI)
{
m_ServerURI = serverURI.TrimEnd('/') + "/experience";
}
public ExperienceServicesConnector(IConfigSource source)
{
Initialise(source);
}
public virtual void Initialise(IConfigSource source)
{
IConfig gridConfig = source.Configs["ExperienceService"];
if (gridConfig == null)
{
m_log.Error("[EXPERIENCE CONNECTOR]: ExperienceService missing from configuration");
throw new Exception("Experience connector init error");
}
string serviceURI = gridConfig.GetString("ExperienceServerURI",
String.Empty);
if (serviceURI == String.Empty)
{
m_log.Error("[EXPERIENCE CONNECTOR]: No Server URI named in section GridUserService");
throw new Exception("Experience connector init error");
}
m_ServerURI = serviceURI + "/experience";
base.Initialise(source, "ExperienceService");
}
#region IExperienceService
public Dictionary<UUID, bool> FetchExperiencePermissions(UUID agent_id)
{
//m_log.InfoFormat("[ExperienceServiceConnector]: FetchExperiencePermissions for {0}", agent_id);
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "getpermissions";
sendData["agent_id"] = agent_id.ToString();
string request_str = ServerUtils.BuildQueryString(sendData);
Dictionary<UUID, bool> experiences = new Dictionary<UUID, bool>();
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
int iter = 0;
while(true)
{
string key = string.Format("uuid_{0}", iter);
string perm = string.Format("perm_{0}", iter);
if (replyData.ContainsKey(key) && replyData.ContainsKey(perm))
{
UUID experience_id;
if (UUID.TryParse(replyData[key].ToString(), out experience_id))
{
bool allow = bool.Parse(replyData[perm].ToString());
experiences.Add(experience_id, allow);
//m_log.InfoFormat("[EXPERIENCE SERVICE CONNECTOR]: {0} = {1}", experience_id, allow);
}
}
else break;
iter++;
}
}
return experiences;
}
public bool UpdateExperiencePermissions(UUID agent_id, UUID experience, ExperiencePermission perm)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "updatepermission";
sendData["agent_id"] = agent_id.ToString();
sendData["experience"] = experience.ToString();
sendData["permission"] = perm == ExperiencePermission.None ? "forget" : perm == ExperiencePermission.Allowed ? "allow" : "block";
string request_str = ServerUtils.BuildQueryString(sendData);
return doSimplePost(request_str, "updatepermission");
}
public ExperienceInfo[] GetExperienceInfos(UUID[] experiences)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "getexperienceinfos";
int i = 0;
foreach(UUID id in experiences)
{
sendData[string.Format("id_{0}", i)] = id.ToString();
i++;
}
string request_str = ServerUtils.BuildQueryString(sendData);
List<ExperienceInfo> infos = new List<ExperienceInfo>();
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
//m_log.InfoFormat("[EXPERIENCE SERVICE CONNECTOR]: Reply: {0}", reply);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
Dictionary<string, object>.ValueCollection experienceList = replyData.Values;
foreach (object ex in experienceList)
{
if (ex is Dictionary<string, object>)
{
Dictionary<string, object> experience = (Dictionary<string, object>)ex;
infos.Add(new ExperienceInfo(experience));
}
}
}
return infos.ToArray();
}
#endregion IExperienceService
private bool doSimplePost(string reqString, string meth)
{
try
{
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, reqString, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData.ContainsKey("result"))
{
if (replyData["result"].ToString().ToLower() == "success")
return true;
else
return false;
}
else
m_log.DebugFormat("[EXPERIENCE CONNECTOR]: {0} reply data does not contain result field", meth);
}
else
m_log.DebugFormat("[EXPERIENCE CONNECTOR]: {0} received empty reply", meth);
}
catch (Exception e)
{
m_log.DebugFormat("[EXPERIENCE CONNECTOR]: Exception when contacting server at {0}: {1}", m_ServerURI, e.Message);
}
return false;
}
public UUID[] GetAgentExperiences(UUID agent_id)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "getagentexperiences";
sendData["AGENT"] = agent_id.ToString();
string request_str = ServerUtils.BuildQueryString(sendData);
List<ExperienceInfo> infos = new List<ExperienceInfo>();
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
//m_log.InfoFormat("[EXPERIENCE SERVICE CONNECTOR]: Reply: {0}", reply);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if(replyData != null)
{
Dictionary<string, object>.ValueCollection experienceList = replyData.Values;
return experienceList.Select(x => UUID.Parse(x.ToString())).ToArray();
}
}
return new UUID[0];
}
public ExperienceInfo UpdateExpereienceInfo(ExperienceInfo info)
{
// let's just pray they never add a parameter named "method"
Dictionary<string, object> sendData = info.ToDictionary();
sendData["METHOD"] = "updateexperienceinfo";
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
//m_log.InfoFormat("[EXPERIENCE SERVICE CONNECTOR]: UpdateExpereienceInfo Reply: {0}", reply);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
ExperienceInfo responseInfo = new ExperienceInfo(replyData);
return responseInfo;
}
return null;
}
public ExperienceInfo[] FindExperiencesByName(string search)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "findexperiences";
sendData["SEARCH"] = search;
string request_str = ServerUtils.BuildQueryString(sendData);
List<ExperienceInfo> infos = new List<ExperienceInfo>();
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
Dictionary<string, object>.ValueCollection experienceList = replyData.Values;
foreach (object ex in experienceList)
{
if (ex is Dictionary<string, object>)
{
Dictionary<string, object> experience = (Dictionary<string, object>)ex;
infos.Add(new ExperienceInfo(experience));
}
}
}
return infos.ToArray();
}
public UUID[] GetGroupExperiences(UUID group_id)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "getgroupexperiences";
sendData["GROUP"] = group_id.ToString();
string request_str = ServerUtils.BuildQueryString(sendData);
List<ExperienceInfo> infos = new List<ExperienceInfo>();
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
Dictionary<string, object>.ValueCollection experienceList = replyData.Values;
return experienceList.Select(x => UUID.Parse(x.ToString())).ToArray();
}
}
return new UUID[0];
}
public UUID[] GetExperiencesForGroups(UUID[] groups)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "getexperiencesforgroups";
int i = 0;
foreach(var id in groups)
{
sendData["id_" + i] = id.ToString();
i++;
}
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
Dictionary<string, object>.ValueCollection experienceList = replyData.Values;
return experienceList.Select(x => UUID.Parse(x.ToString())).ToArray();
}
}
return new UUID[0];
}
public string GetKeyValue(UUID experience, string key)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "accesskvdatabase";
sendData["ACTION"] = "GET";
sendData["EXPERIENCE"] = experience.ToString();
sendData["KEY"] = key;
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
if(replyData.ContainsKey("result"))
{
if(replyData["result"].ToString() == "success")
{
if (replyData.ContainsKey("value"))
{
return replyData["value"].ToString();
}
}
}
}
}
return null;
}
public string CreateKeyValue(UUID experience, string key, string value)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "accesskvdatabase";
sendData["ACTION"] = "CREATE";
sendData["EXPERIENCE"] = experience.ToString();
sendData["KEY"] = key;
sendData["VALUE"] = value;
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
if (replyData.ContainsKey("result"))
{
return replyData["result"].ToString();
}
}
}
return "error";
}
public string UpdateKeyValue(UUID experience, string key, string val, bool check, string original)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "accesskvdatabase";
sendData["ACTION"] = "UPDATE";
sendData["EXPERIENCE"] = experience.ToString();
sendData["KEY"] = key;
sendData["VALUE"] = val;
sendData["CHECK"] = check ? "TRUE" : "FALSE";
sendData["ORIGINAL"] = check ? original : string.Empty;
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
if (replyData.ContainsKey("result"))
{
return replyData["result"].ToString();
}
}
}
return "error";
}
public string DeleteKey(UUID experience, string key)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "accesskvdatabase";
sendData["ACTION"] = "DELETE";
sendData["EXPERIENCE"] = experience.ToString();
sendData["KEY"] = key;
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
if (replyData.ContainsKey("result"))
{
return replyData["result"].ToString();
}
}
}
return "error";
}
public int GetKeyCount(UUID experience)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "accesskvdatabase";
sendData["ACTION"] = "COUNT";
sendData["EXPERIENCE"] = experience.ToString();
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
if (replyData.ContainsKey("result"))
{
if(replyData["result"].ToString() == "success")
{
if (replyData.ContainsKey("count"))
{
return int.Parse(replyData["count"].ToString());
}
}
}
}
}
return 0;
}
public string[] GetKeys(UUID experience, int start, int count)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "accesskvdatabase";
sendData["ACTION"] = "GETKEYS";
sendData["EXPERIENCE"] = experience.ToString();
sendData["START"] = start.ToString();
sendData["COUNT"] = count.ToString();
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
Dictionary<string, object>.ValueCollection keyList = replyData.Values;
return keyList.Select(x => x.ToString()).ToArray();
}
}
return new string[0];
}
public int GetSize(UUID experience)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["METHOD"] = "accesskvdatabase";
sendData["ACTION"] = "SIZE";
sendData["EXPERIENCE"] = experience.ToString();
string request_str = ServerUtils.BuildQueryString(sendData);
string reply = SynchronousRestFormsRequester.MakeRequest("POST", m_ServerURI, request_str, m_Auth);
if (reply != string.Empty)
{
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply);
if (replyData != null)
{
if (replyData.ContainsKey("result"))
{
if (replyData["result"].ToString() == "success")
{
if (replyData.ContainsKey("count"))
{
return int.Parse(replyData["count"].ToString());
}
}
}
}
}
return 0;
}
}
}

View file

@ -0,0 +1,332 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using Nini.Config;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Data;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
namespace OpenSim.Services.ExperienceService
{
public class ExperienceService : ExperienceServiceBase, IExperienceService
{
private static readonly ILog m_log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
private IUserAccountService m_UserService = null;
private const int MAX_QUOTA = 1024 * 1024 * 16;
public ExperienceService(IConfigSource config)
: base(config)
{
m_log.Debug("[EXPERIENCE SERVICE]: Starting experience service");
IConfig userConfig = config.Configs["ExperienceService"];
if (userConfig == null)
throw new Exception("No ExperienceService configuration");
string userServiceDll = userConfig.GetString("UserAccountService", string.Empty);
if (userServiceDll != string.Empty)
m_UserService = LoadPlugin<IUserAccountService>(userServiceDll, new Object[] { config });
if (MainConsole.Instance != null)
{
MainConsole.Instance.Commands.AddCommand("Experience", false,
"create experience",
"create experience <first> <last>",
"Create a new experience owned by a user.", HandleCreateNewExperience);
MainConsole.Instance.Commands.AddCommand("Experience", false,
"suspend experience",
"suspend experience <key> <true/false>",
"Suspend/unsuspend an experience by its key.", HandleSuspendExperience);
}
}
private void HandleCreateNewExperience(string module, string[] cmdparams)
{
string firstName;
string lastName;
string experienceKey;
if (cmdparams.Length < 3)
firstName = MainConsole.Instance.Prompt("Experience owner first name", "Test");
else firstName = cmdparams[2];
if (cmdparams.Length < 4)
lastName = MainConsole.Instance.Prompt("Experience owner last name", "Resident");
else lastName = cmdparams[3];
if (cmdparams.Length < 5)
experienceKey = MainConsole.Instance.Prompt("Experience Key (leave blank for random)", "");
else experienceKey = cmdparams[4];
UUID newExperienceKey;
if (experienceKey == "")
newExperienceKey = UUID.Random();
else
{
if(!UUID.TryParse(experienceKey, out newExperienceKey))
{
MainConsole.Instance.Output("Invalid UUID");
return;
}
}
UserAccount account = m_UserService.GetUserAccount(UUID.Zero, firstName, lastName);
if (account == null)
{
MainConsole.Instance.Output("No such user as {0} {1}", firstName, lastName);
return;
}
var existing = GetExperienceInfos(new UUID[] { newExperienceKey });
if(existing.Length > 0)
{
MainConsole.Instance.Output("Experience already exists!");
return;
}
ExperienceInfo new_info = new ExperienceInfo
{
public_id = newExperienceKey,
owner_id = account.PrincipalID
};
var stored_info = UpdateExpereienceInfo(new_info);
if (stored_info == null)
MainConsole.Instance.Output("Unable to create experience!");
else
{
MainConsole.Instance.Output("Experience created!");
}
}
private void HandleSuspendExperience(string module, string[] cmdparams)
{
string experience_key;
string enabled_str;
if (cmdparams.Length < 3)
experience_key = MainConsole.Instance.Prompt("Experience Key");
else experience_key = cmdparams[2];
UUID experienceID;
if(!UUID.TryParse(experience_key, out experienceID))
{
MainConsole.Instance.Output("Invalid key!");
return;
}
if (cmdparams.Length < 4)
enabled_str = MainConsole.Instance.Prompt("Suspended:", "false");
else enabled_str = cmdparams[3];
bool suspend = enabled_str == "true";
var infos = GetExperienceInfos(new UUID[] { experienceID });
if(infos.Length != 1)
{
MainConsole.Instance.Output("Experience not found!");
return;
}
ExperienceInfo info = infos[0];
bool is_suspended = (info.properties & (int)ExperienceFlags.Suspended) != 0;
string message = "";
bool update = false;
if (suspend && !is_suspended)
{
info.properties |= (int)ExperienceFlags.Suspended;
message = "Experience has been suspended";
update = true;
}
else if(!suspend && is_suspended)
{
info.properties &= ~(int)ExperienceFlags.Suspended;
message = "Experience has been unsuspended";
update = true;
}
else if(suspend && is_suspended)
{
message = "Experience is already suspended";
}
else if (!suspend && !is_suspended)
{
message = "Experience is not suspended";
}
if(update)
{
var updated = UpdateExpereienceInfo(info);
if (updated != null)
{
MainConsole.Instance.Output(message);
}
else
MainConsole.Instance.Output("Error updating experience!");
}
else
{
MainConsole.Instance.Output(message);
}
}
public Dictionary<UUID, bool> FetchExperiencePermissions(UUID agent_id)
{
return m_Database.GetExperiencePermissions(agent_id);
}
public ExperienceInfo[] FindExperiencesByName(string search)
{
List<ExperienceInfo> infos = new List<ExperienceInfo>();
ExperienceInfoData[] datas = m_Database.FindExperiences(search);
foreach (var data in datas)
{
ExperienceInfo info = new ExperienceInfo(data.ToDictionary());
infos.Add(info);
}
return infos.ToArray();
}
public UUID[] GetAgentExperiences(UUID agent_id)
{
return m_Database.GetAgentExperiences(agent_id);
}
public ExperienceInfo[] GetExperienceInfos(UUID[] experiences)
{
ExperienceInfoData[] datas = m_Database.GetExperienceInfos(experiences);
List<ExperienceInfo> infos = new List<ExperienceInfo>();
foreach (var data in datas)
{
infos.Add(new ExperienceInfo(data.ToDictionary()));
}
return infos.ToArray();
}
public UUID[] GetExperiencesForGroups(UUID[] groups)
{
return m_Database.GetExperiencesForGroups(groups);
}
public UUID[] GetGroupExperiences(UUID group_id)
{
return m_Database.GetGroupExperiences(group_id);
}
public ExperienceInfo UpdateExpereienceInfo(ExperienceInfo info)
{
ExperienceInfoData data = new ExperienceInfoData();
data.public_id = info.public_id;
data.owner_id = info.owner_id;
data.name = info.name;
data.description = info.description;
data.group_id = info.group_id;
data.slurl = info.slurl;
data.logo = info.logo;
data.marketplace = info.marketplace;
data.maturity = info.maturity;
data.properties = info.properties;
if (m_Database.UpdateExperienceInfo(data))
{
var find = GetExperienceInfos(new UUID[] { data.public_id });
if(find.Length == 1)
{
return new ExperienceInfo(find[0].ToDictionary());
}
}
return null;
}
public bool UpdateExperiencePermissions(UUID agent_id, UUID experience, ExperiencePermission perm)
{
if (perm == ExperiencePermission.None)
return m_Database.ForgetExperiencePermissions(agent_id, experience);
else return m_Database.SetExperiencePermissions(agent_id, experience, perm == ExperiencePermission.Allowed);
}
public string GetKeyValue(UUID experience, string key)
{
return m_Database.GetKeyValue(experience, key);
}
public string CreateKeyValue(UUID experience, string key, string value)
{
int current_size = m_Database.GetKeyValueSize(experience);
if (current_size + key.Length + value.Length > MAX_QUOTA)
return "full";
string get = m_Database.GetKeyValue(experience, key);
if (get == null)
{
if (m_Database.SetKeyValue(experience, key, value))
return "success";
else return "error";
}
else return "exists";
}
public string UpdateKeyValue(UUID experience, string key, string val, bool check, string original)
{
string get = m_Database.GetKeyValue(experience, key);
if (get != null)
{
if (check && get != original)
return "mismatch";
int current_size = m_Database.GetKeyValueSize(experience);
if ((current_size - get.Length) + val.Length > MAX_QUOTA)
return "full";
if (m_Database.SetKeyValue(experience, key, val))
return "success";
else return "error";
}
else return "missing";
}
public string DeleteKey(UUID experience, string key)
{
string get = m_Database.GetKeyValue(experience, key);
if (get != null)
{
return m_Database.DeleteKey(experience, key) ? "success" : "failed";
}
return "missing";
}
public int GetKeyCount(UUID experience)
{
return m_Database.GetKeyCount(experience);
}
public string[] GetKeys(UUID experience, int start, int count)
{
return m_Database.GetKeys(experience, start, count);
}
public int GetSize(UUID experience)
{
return m_Database.GetKeyValueSize(experience);
}
}
}

View file

@ -0,0 +1,55 @@
using System;
using System.Reflection;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Data;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Base;
namespace OpenSim.Services.ExperienceService
{
public class ExperienceServiceBase : ServiceBase
{
protected IExperienceData m_Database = null;
public ExperienceServiceBase(IConfigSource config)
: base(config)
{
string dllName = string.Empty;
string connString = string.Empty;
//
// Try reading the [DatabaseService] section, if it exists
//
IConfig dbConfig = config.Configs["DatabaseService"];
if (dbConfig != null)
{
if (dllName == string.Empty)
dllName = dbConfig.GetString("StorageProvider", string.Empty);
if (connString == string.Empty)
connString = dbConfig.GetString("ConnectionString", string.Empty);
}
//
// [ExperienceService] section overrides [DatabaseService], if it exists
//
IConfig presenceConfig = config.Configs["ExperienceService"];
if (presenceConfig != null)
{
dllName = presenceConfig.GetString("StorageProvider", dllName);
connString = presenceConfig.GetString("ConnectionString", connString);
}
//
// We tried, but this doesn't exist. We can't proceed.
//
if (dllName.Equals(string.Empty))
throw new Exception("No StorageProvider configured");
m_Database = LoadPlugin<IExperienceData>(dllName, new object[] { connString });
if (m_Database == null)
throw new Exception("Could not find a storage interface in the given module " + dllName);
}
}
}

View file

@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\Data\OpenSim.Data.csproj" />
<ProjectReference Include="..\..\Framework\Console\OpenSim.Framework.Console.csproj" />
<ProjectReference Include="..\..\Framework\OpenSim.Framework.csproj" />
<ProjectReference Include="..\Base\OpenSim.Services.Base.csproj" />
<ProjectReference Include="..\Connectors\OpenSim.Services.Connectors.csproj" />
<ProjectReference Include="..\Interfaces\OpenSim.Services.Interfaces.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Nini">
<HintPath>..\..\..\bin\Nini.dll</HintPath>
</Reference>
<Reference Include="OpenMetaverse">
<HintPath>..\..\..\bin\OpenMetaverse.dll</HintPath>
</Reference>
<Reference Include="OpenMetaverseTypes">
<HintPath>..\..\..\bin\OpenMetaverseTypes.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using OpenSim.Framework;
using OpenMetaverse;
namespace OpenSim.Services.Interfaces
{
public enum ExperiencePermission
{
None,
Allowed,
Blocked
}
public enum ExperienceFlags
{
None = 0,
Invalid = 1 << 0,
Privileged = 1 << 3,
Grid = 1 << 4,
Private = 1 << 5,
Disabled = 1 << 6,
Suspended = 1 << 7
}
public class ExperienceInfo
{
public UUID public_id = UUID.Zero;
public UUID owner_id = UUID.Zero;
public string name = string.Empty;
public string description = string.Empty;
public UUID group_id = UUID.Zero;
// extended
public UUID logo = UUID.Zero;
public string marketplace = string.Empty;
public string slurl = string.Empty;
public int properties = 0;
public int maturity = 0;
public DateTime CachedTime = DateTime.Now;
public int quota = 16;
public Dictionary<string, object> ToDictionary()
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["public_id"] = public_id;
dict["owner_id"] = owner_id;
dict["group_id"] = group_id;
dict["name"] = name;
dict["description"] = description;
dict["logo"] = logo;
dict["marketplace"] = marketplace;
dict["slurl"] = slurl;
dict["properties"] = properties;
dict["maturity"] = maturity;
return dict;
}
public ExperienceInfo()
{
}
public ExperienceInfo(Dictionary<string, object> data)
{
if (data.ContainsKey("public_id"))
public_id = UUID.Parse(data["public_id"].ToString());
if (data.ContainsKey("owner_id"))
owner_id = UUID.Parse(data["owner_id"].ToString());
if (data.ContainsKey("group_id"))
group_id = UUID.Parse(data["group_id"].ToString());
if (data.ContainsKey("name"))
name = data["name"].ToString();
if (data.ContainsKey("description"))
description = data["description"].ToString();
if (data.ContainsKey("logo"))
logo = UUID.Parse(data["logo"].ToString());
if (data.ContainsKey("marketplace"))
marketplace = data["marketplace"].ToString();
if (data.ContainsKey("slurl"))
slurl = data["slurl"].ToString();
if (data.ContainsKey("properties"))
properties = int.Parse(data["properties"].ToString());
if (data.ContainsKey("maturity"))
maturity = int.Parse(data["maturity"].ToString());
}
}
public interface IExperienceService
{
Dictionary<UUID, bool> FetchExperiencePermissions(UUID agent_id);
bool UpdateExperiencePermissions(UUID agent_id, UUID experience, ExperiencePermission perm);
ExperienceInfo[] GetExperienceInfos(UUID[] experiences);
UUID[] GetAgentExperiences(UUID agent_id);
ExperienceInfo UpdateExpereienceInfo(ExperienceInfo info);
ExperienceInfo[] FindExperiencesByName(string search);
UUID[] GetGroupExperiences(UUID group_id);
UUID[] GetExperiencesForGroups(UUID[] groups);
string GetKeyValue(UUID experience, string key);
string CreateKeyValue(UUID experience, string key, string value);
string UpdateKeyValue(UUID experience, string key, string val, bool check, string original);
string DeleteKey(UUID experience, string key);
int GetKeyCount(UUID experience);
string[] GetKeys(UUID experience, int start, int count);
int GetSize(UUID experience);
}
}

View file

@ -339,6 +339,7 @@ namespace OpenSim.Tests.Common
public event GodUpdateRegionInfoUpdate OnGodUpdateRegionInfoUpdate;
public event GenericCall2 OnUpdateThrottles;
public event AgentFOV OnAgentFOV;
public event UpdateEstateExperienceDeltaRequest OnUpdateEstateExperienceDeltaRequest;
#pragma warning restore 67
@ -1406,5 +1407,19 @@ namespace OpenSim.Tests.Common
return 0x1000;
}
public void SendGenericMessageForExperience(UUID experience_id, UUID avatar_id, int action, string obj_name, string parcel, bool is_attachment = false)
{
throw new NotImplementedException();
}
public void SendScriptQuestion(UUID taskID, string taskName, string ownerName, UUID itemID, int question, UUID experience)
{
throw new NotImplementedException();
}
public void SendEstateExperiences(UUID invoice, UUID[] allowed, UUID[] key, uint estateID)
{
throw new NotImplementedException();
}
}
}

View file

@ -224,5 +224,10 @@ namespace OpenSim.Tests.Common
{
throw new NotImplementedException();
}
public void SendEnvironmentUpdate(UUID experience_id, UUID agent_id, EnvironmentUpdate update)
{
throw new NotImplementedException();
}
}
}

View file

@ -1322,6 +1322,10 @@
; FullNames = "Test User, Foo Bar"
; Surnames = "Kryztlsk"
[Experience]
;# {Enabled} {} {Use Experience Tools on this region} {true false} false
; Enabled = true
[Architecture]
;# {Include-Architecture} {} {Choose one of the following architectures} {config-include/Standalone.ini config-include/StandaloneHypergrid.ini config-include/Grid.ini config-include/GridHypergrid.ini} config-include/Standalone.ini
;; Uncomment one of the following includes as required. For instance, to create a standalone OpenSim,

View file

@ -100,6 +100,8 @@
FriendsServiceConnector = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:FriendsServiceConnector"
MapAddServiceConnector = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:MapAddServiceConnector"
MapGetServiceConnector = "${Const|PublicPort}/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
;; Uncomment this if you want experience tools to work
; ExperienceServiceConnector = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:ExperienceServiceConnector"
;; Uncomment this if you want offline IM to work
; OfflineIMServiceConnector = "${Const|PrivatePort}/OpenSim.Addons.OfflineIM.dll:OfflineIMServiceRobustConnector"
;; Uncomment this if you want Groups V2 to work
@ -856,3 +858,10 @@
[MuteListService]
LocalServiceModule = "OpenSim.Services.MuteListService.dll:MuteListService"
[ExperienceService]
LocalServiceModule = "OpenSim.Services.ExperienceService.dll:ExperienceService"
;; ConnectionString = "Data Source=localhost;Database=robust;User ID=robust;Password=*****;Old Guids=true;CharSet=utf8mb4;"
UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"

View file

@ -91,6 +91,8 @@
FriendsServiceConnector = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:FriendsServiceConnector"
MapAddServiceConnector = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:MapAddServiceConnector"
MapGetServiceConnector = "${Const|PublicPort}/OpenSim.Server.Handlers.dll:MapGetServiceConnector"
;; Uncomment this if you want experience tools to work
; ExperienceServiceConnector = "${Const|PrivatePort}/OpenSim.Server.Handlers.dll:ExperienceServiceConnector"
;; Uncomment this if you want offline IM to work
; OfflineIMServiceConnector = "${Const|PrivatePort}/OpenSim.Addons.OfflineIM.dll:OfflineIMServiceRobustConnector"
;; Uncomment this if you want Groups V2 to work
@ -605,3 +607,10 @@
[MuteListService]
LocalServiceModule = "OpenSim.Services.MuteListService.dll:MuteListService"
[ExperienceService]
LocalServiceModule = "OpenSim.Services.ExperienceService.dll:ExperienceService"
;; ConnectionString = "Data Source=localhost;Database=robust;User ID=robust;Password=*****;Old Guids=true;CharSet=utf8mb4;"
UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"

View file

@ -234,3 +234,11 @@
[MuteListService]
MuteListServerURI = "${Const|PrivURL}:${Const|PrivatePort}"
[ExperienceService]
LocalServiceModule = "OpenSim.Services.Connectors.dll:RemoteExperienceServiceConnector"
;
; Change this to your grid-wide experience server
;
ExperienceServerURI = "${Const|BaseURL}:${Const|PrivatePort}"

View file

@ -23,6 +23,7 @@
MapImageService = "MapImageServiceModule"
SearchModule = "BasicSearchModule"
MuteListService = "LocalMuteListServicesConnector"
ExperienceService = "LocalExperienceServicesConnector"
LibraryModule = true
LLLoginServiceInConnector = true
@ -119,6 +120,9 @@
[MuteListService]
LocalServiceModule = "OpenSim.Services.MuteListService.dll:MuteListService"
[ExperienceService]
LocalServiceModule = "OpenSim.Services.ExperienceService.dll:ExperienceService"
;; This should always be the very last thing on this file
[Includes]
Include-Common = "config-include/StandaloneCommon.ini"

View file

@ -28,6 +28,7 @@
UserManagementModule = "HGUserManagementModule"
SearchModule = "BasicSearchModule"
MuteListService = "LocalMuteListServicesConnector"
ExperienceService = "LocalExperienceServicesConnector"
InventoryServiceInConnector = true
AssetServiceInConnector = true
@ -192,6 +193,12 @@
[MuteListService]
LocalServiceModule = "OpenSim.Services.MuteListService.dll:MuteListService"
[ExperienceService]
LocalServiceModule = "OpenSim.Services.ExperienceService.dll:ExperienceService"
UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
GridUserService = "OpenSim.Services.UserAccountService.dll:GridUserService"
;; This should always be the very last thing on this file
[Includes]
Include-Common = "config-include/StandaloneCommon.ini"