Compare commits
343 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc33afddd3 | ||
|
|
eaccfa6d99 | ||
|
|
fd7a097849 | ||
|
|
f7dcd33008 | ||
|
|
6ba42e9e75 | ||
|
|
71b73d6dc3 | ||
|
|
af5383e479 | ||
|
|
645e3171b4 | ||
|
|
597df51f91 | ||
|
|
ec044537d5 | ||
|
|
32171708c3 | ||
|
|
28483150e2 | ||
|
|
0f70460a32 | ||
|
|
9417176389 | ||
|
|
38e96afa38 | ||
|
|
b058ba5859 | ||
|
|
845228b35e | ||
|
|
75f5e66d1c | ||
|
|
1f3c9db2b9 | ||
|
|
8aa43e72e5 | ||
|
|
a960273e91 | ||
|
|
a2c93133be | ||
|
|
afab5f5cd1 | ||
|
|
7ab83f9eb2 | ||
|
|
de44e93aa2 | ||
|
|
1e7fb2dc36 | ||
|
|
991151250d | ||
|
|
0811f3d28d | ||
|
|
1de80cdafe | ||
|
|
3ec2923022 | ||
|
|
faf6b56839 | ||
|
|
2ed59ad8ac | ||
|
|
f35826eb31 | ||
|
|
4e5b2346a5 | ||
|
|
fc861c7904 | ||
|
|
db4ca57590 | ||
|
|
8459b98f68 | ||
|
|
ab0294f010 | ||
|
|
0eb457442d | ||
|
|
d469bde849 | ||
|
|
3ac6a423f7 | ||
|
|
8c2564c05c | ||
|
|
dc460579fd | ||
|
|
946c2e7e7c | ||
|
|
330b976a62 | ||
|
|
f6e166cd0b | ||
|
|
8c40215834 | ||
|
|
fba59d905c | ||
|
|
b9c2a1508e | ||
|
|
ab7b7c5d3d | ||
|
|
b5a3c74a5c | ||
|
|
b7e75d467c | ||
|
|
8873a4a8fc | ||
|
|
1e86c58822 | ||
|
|
21d0cbf703 | ||
|
|
87a87ebb9a | ||
|
|
3af2095cbc | ||
|
|
59a17ad676 | ||
|
|
8a402850dd | ||
|
|
387ce8ef35 | ||
|
|
2e9ef015f7 | ||
|
|
f5f5f2e3fb | ||
|
|
1f2472d0fc | ||
|
|
b63134764f | ||
|
|
b24190ec98 | ||
|
|
5b82f18d64 | ||
|
|
a86fedd25f | ||
|
|
3a458e2a36 | ||
|
|
919569f6ec | ||
|
|
a791620622 | ||
|
|
68698975f1 | ||
|
|
87825b0abe | ||
|
|
311a03befa | ||
|
|
b768c35f6f | ||
|
|
efd9791506 | ||
|
|
756ac4f321 | ||
|
|
11d8119a21 | ||
|
|
528085adef | ||
|
|
e76b01a201 | ||
|
|
a3c0e3ed26 | ||
|
|
785671e242 | ||
|
|
40bf789ad7 | ||
|
|
7e90ea3551 | ||
|
|
764270a0d8 | ||
|
|
ef3cc2e507 | ||
|
|
a0d047413b | ||
|
|
73c9abf5f2 | ||
|
|
d342adaa87 | ||
|
|
f65218f826 | ||
|
|
839aa57b42 | ||
|
|
ff92330523 | ||
|
|
90a39379f0 | ||
|
|
13c4fd7271 | ||
|
|
9de991301c | ||
|
|
16c9c1dff7 | ||
|
|
91ca3117cb | ||
|
|
6f220a8679 | ||
|
|
1fb53e7103 | ||
|
|
22f6fa49e3 | ||
|
|
16feed456a | ||
|
|
68859af3f8 | ||
|
|
633e1ed62c | ||
|
|
130768b16a | ||
|
|
8cd1dc8d60 | ||
|
|
d87813a194 | ||
|
|
046113c137 | ||
|
|
03136df1a7 | ||
|
|
7c7cdf3431 | ||
|
|
4832ed6960 | ||
|
|
f0178a6a41 | ||
|
|
276fdbc1b3 | ||
|
|
5b90f5bb17 | ||
|
|
d98af79f77 | ||
|
|
b977f962fa | ||
|
|
aa52c8b20f | ||
|
|
3d36a6d55c | ||
|
|
e717398f6c | ||
|
|
a2ab3b88de | ||
|
|
b9baab5521 | ||
|
|
653a98e891 | ||
|
|
e56ef2720e | ||
|
|
df3d1d1301 | ||
|
|
a5b8359b8e | ||
|
|
ca5c0814f4 | ||
|
|
f1886c449c | ||
|
|
a1679517d3 | ||
|
|
f555febdb7 | ||
|
|
ce7694c108 | ||
|
|
c677c04f10 | ||
|
|
35b7c80e0b | ||
|
|
e81e19a3b4 | ||
|
|
210f227fe6 | ||
|
|
ce47d0c454 | ||
|
|
d8a786870b | ||
|
|
ce97ebdc88 | ||
|
|
b6b505163c | ||
|
|
1e5869dcf6 | ||
|
|
f2c78281ce | ||
|
|
33617e09a1 | ||
|
|
c1740a2903 | ||
|
|
5221f2421e | ||
|
|
54ec8b197b | ||
|
|
14b659e550 | ||
|
|
402128bb53 | ||
|
|
0b9bf236dd | ||
|
|
503ce70f74 | ||
|
|
060d6fe8f4 | ||
|
|
7cc89cdadc | ||
|
|
f8a4b61954 | ||
|
|
91a5c602e3 | ||
|
|
531edd51d8 | ||
|
|
14a4b146bf | ||
|
|
5b69872655 | ||
|
|
4e9509dafa | ||
|
|
f457952755 | ||
|
|
818379ba14 | ||
|
|
fae869c4ca | ||
|
|
d588467d5b | ||
|
|
e3d6d36c72 | ||
|
|
7f96bb601a | ||
|
|
76e9cc41bd | ||
|
|
6f89975526 | ||
|
|
74dea4cfd5 | ||
|
|
7b65985047 | ||
|
|
5781d4d52d | ||
|
|
f82b903dee | ||
|
|
4589bc84a3 | ||
|
|
735d89e369 | ||
|
|
d016051fa0 | ||
|
|
42802669dd | ||
|
|
22290ef35a | ||
|
|
a27e4ce6cb | ||
|
|
91efccabdc | ||
|
|
ee7cda261c | ||
|
|
d26fbf727a | ||
|
|
b5af17c8e3 | ||
|
|
3db10fdbef | ||
|
|
6511c3b5c6 | ||
|
|
7a50705188 | ||
|
|
0e5d3d051b | ||
|
|
f5fac2c916 | ||
|
|
581e76942f | ||
|
|
2bf42f30af | ||
|
|
b9934fc4db | ||
|
|
31c636f1e4 | ||
|
|
36e3123069 | ||
|
|
327320d1a7 | ||
|
|
21f30a1b5f | ||
|
|
90dd5844d6 | ||
|
|
3c77b8f463 | ||
|
|
80133f9ebe | ||
|
|
2f61763923 | ||
|
|
7d2cd0d935 | ||
|
|
ae58cf4224 | ||
|
|
495a3e7daf | ||
|
|
92afa6aa44 | ||
|
|
ddd9384b39 | ||
|
|
4dc27aa91f | ||
|
|
b96a53962b | ||
|
|
3c2fb77133 | ||
|
|
eb5bec96e4 | ||
|
|
2f795e4fa6 | ||
|
|
4fc0cfba3c | ||
|
|
77355295da | ||
|
|
4ec2fc4cc2 | ||
|
|
020103c51e | ||
|
|
ac02cadbdb | ||
|
|
1cfd63d0b4 | ||
|
|
1c42337381 | ||
|
|
87d810217e | ||
|
|
772aedc731 | ||
|
|
fb6d6e5cca | ||
|
|
48f4b32d7f | ||
|
|
ebd99c9e3e | ||
|
|
21a6ef5bb6 | ||
|
|
a6f7328216 | ||
|
|
b36ef60aca | ||
|
|
8d7b1f8aa0 | ||
|
|
b0da4b8d13 | ||
|
|
cfa022700d | ||
|
|
9ab5c5040d | ||
|
|
5df3944607 | ||
|
|
fb2ace6fff | ||
|
|
f931c0a868 | ||
|
|
f4cc19968c | ||
|
|
b542622b3a | ||
|
|
5f97b3e1d9 | ||
|
|
e379566e6e | ||
|
|
80f486c778 | ||
|
|
632a42e2b1 | ||
|
|
bceef401fa | ||
|
|
1b0abf8f0c | ||
|
|
e29d563557 | ||
|
|
33aa6d172f | ||
|
|
3089b6d824 | ||
|
|
a5b3989e5d | ||
|
|
387a1bb283 | ||
|
|
b481a78234 | ||
|
|
d667f9d260 | ||
|
|
696b3f66c4 | ||
|
|
49e2872f9e | ||
|
|
61f4523e01 | ||
|
|
a74167bb06 | ||
|
|
f2a9d26118 | ||
|
|
e50b6b5334 | ||
|
|
967d42d393 | ||
|
|
e50155ebca | ||
|
|
f99278c956 | ||
|
|
95809cabd9 | ||
|
|
9d973ec3b3 | ||
|
|
d29fc53052 | ||
|
|
91312daeb2 | ||
|
|
0e5f5538bc | ||
|
|
f9721573d9 | ||
|
|
c7948a669a | ||
|
|
5e626ce55d | ||
|
|
380962d359 | ||
|
|
daa4745fb7 | ||
|
|
de69a24574 | ||
|
|
b602b476ad | ||
|
|
c77be802d2 | ||
|
|
1826b2b18e | ||
|
|
f35bd6eb7d | ||
|
|
dcb94b8a24 | ||
|
|
6632eb7c05 | ||
|
|
f0a098924e | ||
|
|
7c347f4c5c | ||
|
|
d86cbe6379 | ||
|
|
c0fec70b1a | ||
|
|
2c5ff93990 | ||
|
|
1ec84ac8b1 | ||
|
|
d5c8c6bc12 | ||
|
|
5dd2569bf7 | ||
|
|
d7e6fe488d | ||
|
|
ce468215d5 | ||
|
|
6f7825e310 | ||
|
|
dd0a89a0e6 | ||
|
|
190f9c258b | ||
|
|
46d8405229 | ||
|
|
9598c1af9e | ||
|
|
82487549f7 | ||
|
|
cdc3781f42 | ||
|
|
7df7b86ec5 | ||
|
|
81fda6f947 | ||
|
|
e9322b0bf7 | ||
|
|
96f889b20e | ||
|
|
224efe7b76 | ||
|
|
ebb394bbda | ||
|
|
c17965eec4 | ||
|
|
4ead48f09f | ||
|
|
41f3f2400e | ||
|
|
f06394f195 | ||
|
|
d53a53d4c5 | ||
|
|
757d9163fa | ||
|
|
25111e703f | ||
|
|
ad1b9bbba6 | ||
|
|
97b8739c1d | ||
|
|
0760121eb9 | ||
|
|
0a22e78f59 | ||
|
|
5e51f16ceb | ||
|
|
fd8a7e64b9 | ||
|
|
ed5f574356 | ||
|
|
44349f742e | ||
|
|
e3993eefa5 | ||
|
|
8db5d79f4b | ||
|
|
bf56b30024 | ||
|
|
8321ecb7a2 | ||
|
|
783ee949ea | ||
|
|
e041f09750 | ||
|
|
fa3edcf55c | ||
|
|
874bde366a | ||
|
|
d8df2d6bed | ||
|
|
126eae7100 | ||
|
|
3c097cb7a9 | ||
|
|
189f51233e | ||
|
|
76dc29dc37 | ||
|
|
df3914c7cd | ||
|
|
740eac192b | ||
|
|
783ecd01f4 | ||
|
|
a0e3e23aa9 | ||
|
|
1acee36822 | ||
|
|
ac90322f1b | ||
|
|
2ca93cb144 | ||
|
|
4e2805496c | ||
|
|
46af3a3d92 | ||
|
|
717b11856e | ||
|
|
0199abd625 | ||
|
|
550f6c4ad2 | ||
|
|
2b506cffb1 | ||
|
|
33469a0d2b | ||
|
|
1f18ce516f | ||
|
|
2ec34580ce | ||
|
|
288baaecaf | ||
|
|
d2b00749ef | ||
|
|
8f02fd926e | ||
|
|
9f914327c6 | ||
|
|
4215877b48 | ||
|
|
d2e79e26d7 | ||
|
|
3f6c6eed33 | ||
|
|
0a71e3ab39 | ||
|
|
8fe8fdb0c9 | ||
|
|
fbfd28a61b | ||
|
|
a0d0c9f751 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -66,6 +66,7 @@ Examples/*.dll
|
||||
OpenSim.build
|
||||
OpenSim.sln
|
||||
OpenSim.suo
|
||||
OpenSim.userprefs
|
||||
Prebuild/Prebuild.build
|
||||
Prebuild/Prebuild.sln
|
||||
TestResult.xml
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
==== Building OpenSim ====
|
||||
|
||||
=== Building on Windows ===
|
||||
# Building on Windows
|
||||
|
||||
Steps:
|
||||
* runprebuild.bat
|
||||
@@ -9,16 +7,15 @@ Steps:
|
||||
* copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include
|
||||
* run OpenSim.exe
|
||||
|
||||
=== Building on Linux ===
|
||||
# Building on Linux
|
||||
|
||||
Prereqs:
|
||||
* Mono >= 2.4.3
|
||||
* Nant >= 0.85
|
||||
* On some Linux distributions you may need to install additional packages.
|
||||
See http://opensimulator.org/wiki/Dependencies for more information.
|
||||
|
||||
* May also use xbuild (included in mono distributions)
|
||||
* May use Monodevelop, a cross-platform IDE
|
||||
* Mono >= 2.4.3
|
||||
* Nant >= 0.85
|
||||
* On some Linux distributions you may need to install additional packages.
|
||||
See http://opensimulator.org/wiki/Dependencies for more information.
|
||||
* May also use xbuild (included in mono distributions)
|
||||
* May use Monodevelop, a cross-platform IDE
|
||||
|
||||
From the distribution type:
|
||||
* ./runprebuild.sh
|
||||
@@ -27,13 +24,13 @@ From the distribution type:
|
||||
* copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include
|
||||
* run mono OpenSim.exe
|
||||
|
||||
=== Using Monodevelop ===
|
||||
# Using Monodevelop
|
||||
|
||||
From the distribution type:
|
||||
* ./runprebuild.sh
|
||||
* type monodevelop OpenSim.sln
|
||||
|
||||
=== References ===
|
||||
# References
|
||||
|
||||
Helpful resources:
|
||||
* http://opensimulator.org/wiki/Build_Instructions
|
||||
@@ -1,5 +1,5 @@
|
||||
<<<>>>>The following people have contributed to OpenSim (Thank you
|
||||
for your effort!)
|
||||
for your effort!)
|
||||
|
||||
= Current OpenSim Developers (in very rough order of appearance) =
|
||||
These folks represent the current core team for OpenSim, and are the
|
||||
@@ -16,7 +16,7 @@ people that make the day to day of OpenSim happen.
|
||||
* BlueWall (James Hughes)
|
||||
* Nebadon Izumi (Michael Cerquoni, OSgrid)
|
||||
* Snoopy Pfeffer
|
||||
* Richard Adams (Intel)
|
||||
* Robert Adams (Intel)
|
||||
|
||||
= Core Developers Following the White Rabbit =
|
||||
Core developers who have temporarily (we hope) gone chasing the white rabbit.
|
||||
@@ -209,3 +209,4 @@ In addition, we would like to thank:
|
||||
* The NANT Developers
|
||||
* Microsoft (.NET, MSSQL-Adapters)
|
||||
*x
|
||||
|
||||
|
||||
@@ -572,7 +572,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
|
||||
region.ExternalHostName = (string) requestData["external_address"];
|
||||
|
||||
bool persist = Convert.ToBoolean((string) requestData["persist"]);
|
||||
bool persist = Convert.ToBoolean(requestData["persist"]);
|
||||
if (persist)
|
||||
{
|
||||
// default place for region configuration files is in the
|
||||
@@ -728,7 +728,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
responseData["success"] = true;
|
||||
responseData["region_name"] = region.RegionName;
|
||||
responseData["region_id"] = region.RegionID.ToString();
|
||||
responseData["region_uuid"] = region.RegionID.ToString(); //Deprecate July 2012
|
||||
|
||||
m_log.Info("[RADMIN]: CreateRegion: request complete");
|
||||
}
|
||||
@@ -982,8 +981,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
string lastName = (string) requestData["user_lastname"];
|
||||
string password = (string) requestData["user_password"];
|
||||
|
||||
uint regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
|
||||
uint regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
|
||||
uint regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
|
||||
uint regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
|
||||
|
||||
string email = ""; // empty string for email
|
||||
if (requestData.Contains("user_email"))
|
||||
@@ -1180,9 +1179,9 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
|
||||
if (requestData.ContainsKey("user_password")) password = (string) requestData["user_password"];
|
||||
if (requestData.ContainsKey("start_region_x"))
|
||||
regionXLocation = Convert.ToUInt32((Int32) requestData["start_region_x"]);
|
||||
regionXLocation = Convert.ToUInt32(requestData["start_region_x"]);
|
||||
if (requestData.ContainsKey("start_region_y"))
|
||||
regionYLocation = Convert.ToUInt32((Int32) requestData["start_region_y"]);
|
||||
regionYLocation = Convert.ToUInt32(requestData["start_region_y"]);
|
||||
|
||||
// if (requestData.ContainsKey("start_lookat_x"))
|
||||
// ulaX = Convert.ToUInt32((Int32) requestData["start_lookat_x"]);
|
||||
@@ -1369,6 +1368,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
/// <description>profile url</description></item>
|
||||
/// <item><term>noassets</term>
|
||||
/// <description>true if no assets should be saved</description></item>
|
||||
/// <item><term>all</term>
|
||||
/// <description>true to save all the regions in the simulator</description></item>
|
||||
/// <item><term>perm</term>
|
||||
/// <description>C and/or T</description></item>
|
||||
/// </list>
|
||||
@@ -1425,6 +1426,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
options["checkPermissions"] = (string)requestData["perm"];
|
||||
}
|
||||
|
||||
if ((string)requestData["all"] == "true")
|
||||
{
|
||||
options["all"] = (string)requestData["all"];
|
||||
}
|
||||
|
||||
IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>();
|
||||
|
||||
if (archiver != null)
|
||||
@@ -1874,29 +1880,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
{
|
||||
return;
|
||||
}
|
||||
#region Deprecate July 2012
|
||||
//region_ID, regionid, region_uuid will be deprecated in July 2012!!!!!!
|
||||
else if (requestData.ContainsKey("regionid") &&
|
||||
!String.IsNullOrEmpty((string)requestData["regionid"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
|
||||
}
|
||||
else if (requestData.ContainsKey("region_ID") &&
|
||||
!String.IsNullOrEmpty((string)requestData["region_ID"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
|
||||
}
|
||||
else if (requestData.ContainsKey("regionID") &&
|
||||
!String.IsNullOrEmpty((string)requestData["regionID"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
|
||||
}
|
||||
else if (requestData.ContainsKey("region_uuid") &&
|
||||
!String.IsNullOrEmpty((string)requestData["region_uuid"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
|
||||
}
|
||||
#endregion
|
||||
else
|
||||
{
|
||||
responseData["accepted"] = false;
|
||||
@@ -1918,56 +1901,6 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
throw new Exception(String.Format("Region ID {0} not found", regionID));
|
||||
}
|
||||
}
|
||||
#region Deprecate July 2012
|
||||
else if (requestData.ContainsKey("regionid") &&
|
||||
!String.IsNullOrEmpty((string)requestData["regionid"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter regionid will be deprecated as of July 2012. Use region_id instead");
|
||||
|
||||
UUID regionID = (UUID)(string)requestData["regionid"];
|
||||
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
|
||||
{
|
||||
responseData["error"] = String.Format("Region ID {0} not found", regionID);
|
||||
throw new Exception(String.Format("Region ID {0} not found", regionID));
|
||||
}
|
||||
}
|
||||
else if (requestData.ContainsKey("region_ID") &&
|
||||
!String.IsNullOrEmpty((string)requestData["region_ID"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter region_ID will be deprecated as of July 2012. Use region_id instead");
|
||||
|
||||
UUID regionID = (UUID)(string)requestData["region_ID"];
|
||||
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
|
||||
{
|
||||
responseData["error"] = String.Format("Region ID {0} not found", regionID);
|
||||
throw new Exception(String.Format("Region ID {0} not found", regionID));
|
||||
}
|
||||
}
|
||||
else if (requestData.ContainsKey("regionID") &&
|
||||
!String.IsNullOrEmpty((string)requestData["regionID"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter regionID will be deprecated as of July 2012. Use region_id instead");
|
||||
|
||||
UUID regionID = (UUID)(string)requestData["regionID"];
|
||||
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
|
||||
{
|
||||
responseData["error"] = String.Format("Region ID {0} not found", regionID);
|
||||
throw new Exception(String.Format("Region ID {0} not found", regionID));
|
||||
}
|
||||
}
|
||||
else if (requestData.ContainsKey("region_uuid") &&
|
||||
!String.IsNullOrEmpty((string)requestData["region_uuid"]))
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Use of parameter region_uuid will be deprecated as of July 2012. Use region_id instead");
|
||||
|
||||
UUID regionID = (UUID)(string)requestData["region_uuid"];
|
||||
if (!m_application.SceneManager.TryGetScene(regionID, out scene))
|
||||
{
|
||||
responseData["error"] = String.Format("Region ID {0} not found", regionID);
|
||||
throw new Exception(String.Format("Region ID {0} not found", regionID));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
else if (requestData.ContainsKey("region_name") &&
|
||||
!String.IsNullOrEmpty((string)requestData["region_name"]))
|
||||
{
|
||||
|
||||
@@ -312,14 +312,16 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
// Now that everything is setup we can proceed to
|
||||
// add THIS agent to the HTTP server's handler list
|
||||
|
||||
if (!AddAgentHandler(Rest.Name,this))
|
||||
{
|
||||
Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
|
||||
foreach (IRest handler in handlers)
|
||||
{
|
||||
handler.Close();
|
||||
}
|
||||
}
|
||||
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
|
||||
// have to be handled through the AddHttpHandler interface.
|
||||
// if (!AddAgentHandler(Rest.Name,this))
|
||||
// {
|
||||
// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
|
||||
// foreach (IRest handler in handlers)
|
||||
// {
|
||||
// handler.Close();
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -342,11 +344,13 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
|
||||
|
||||
try
|
||||
{
|
||||
RemoveAgentHandler(Rest.Name, this);
|
||||
}
|
||||
catch (KeyNotFoundException){}
|
||||
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
|
||||
// have to be handled through the AddHttpHandler interface.
|
||||
// try
|
||||
// {
|
||||
// RemoveAgentHandler(Rest.Name, this);
|
||||
// }
|
||||
// catch (KeyNotFoundException){}
|
||||
|
||||
foreach (IRest handler in handlers)
|
||||
{
|
||||
|
||||
@@ -297,7 +297,9 @@ namespace OpenSim.ApplicationPlugins.Rest
|
||||
{
|
||||
if (!IsEnabled) return false;
|
||||
_agents.Add(agentName, handler);
|
||||
return _httpd.AddAgentHandler(agentName, handler);
|
||||
// return _httpd.AddAgentHandler(agentName, handler);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -316,7 +318,7 @@ namespace OpenSim.ApplicationPlugins.Rest
|
||||
if (_agents[agentName] == handler)
|
||||
{
|
||||
_agents.Remove(agentName);
|
||||
return _httpd.RemoveAgentHandler(agentName, handler);
|
||||
// return _httpd.RemoveAgentHandler(agentName, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -358,10 +360,10 @@ namespace OpenSim.ApplicationPlugins.Rest
|
||||
_httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
|
||||
}
|
||||
_handlers = null;
|
||||
foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
|
||||
{
|
||||
_httpd.RemoveAgentHandler(h.Key, h.Value);
|
||||
}
|
||||
// foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
|
||||
// {
|
||||
// _httpd.RemoveAgentHandler(h.Key, h.Value);
|
||||
// }
|
||||
_agents = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
|
||||
if (texture == null)
|
||||
{
|
||||
//m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
|
||||
// m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
|
||||
|
||||
// Fetch locally or remotely. Misses return a 404
|
||||
texture = m_assetService.Get(textureID.ToString());
|
||||
@@ -197,7 +197,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
}
|
||||
else // it was on the cache
|
||||
{
|
||||
//m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
|
||||
// m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
|
||||
WriteTextureData(httpRequest, httpResponse, texture, format);
|
||||
return true;
|
||||
}
|
||||
@@ -219,12 +219,30 @@ namespace OpenSim.Capabilities.Handlers
|
||||
int start, end;
|
||||
if (TryParseRange(range, out start, out end))
|
||||
{
|
||||
|
||||
// Before clamping start make sure we can satisfy it in order to avoid
|
||||
// sending back the last byte instead of an error status
|
||||
if (start >= texture.Data.Length)
|
||||
{
|
||||
response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
|
||||
// m_log.DebugFormat(
|
||||
// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
|
||||
// texture.ID, start, texture.Data.Length);
|
||||
|
||||
// Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
|
||||
// Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
|
||||
// of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
|
||||
// received a very small texture may attempt to fetch bytes from the server past the
|
||||
// range of data that it received originally. Whether this happens appears to depend on whether
|
||||
// the viewer's estimation of how large a request it needs to make for certain discard levels
|
||||
// (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard
|
||||
// level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
|
||||
// here will cause the viewer to treat the texture as bad and never display the full resolution
|
||||
// However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
|
||||
|
||||
// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
|
||||
// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length));
|
||||
// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
|
||||
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
|
||||
response.ContentType = texture.Metadata.ContentType;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -232,12 +250,18 @@ namespace OpenSim.Capabilities.Handlers
|
||||
start = Utils.Clamp(start, 0, end);
|
||||
int len = end - start + 1;
|
||||
|
||||
//m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
|
||||
// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
|
||||
|
||||
// Always return PartialContent, even if the range covered the entire data length
|
||||
// We were accidentally sending back 404 before in this situation
|
||||
// https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the
|
||||
// entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this.
|
||||
//
|
||||
// We also do not want to send back OK even if the whole range was satisfiable since this causes
|
||||
// HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality.
|
||||
// if (end > maxEnd)
|
||||
// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
|
||||
// else
|
||||
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
|
||||
|
||||
response.ContentLength = len;
|
||||
|
||||
@@ -85,21 +85,6 @@ namespace OpenSim.Data
|
||||
List<RegionData> GetHyperlinks(UUID scopeID);
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RegionFlags : int
|
||||
{
|
||||
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
|
||||
FallbackRegion = 2, // Regions we redirect to when the destination is down
|
||||
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
|
||||
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
|
||||
Persistent = 16, // Don't remove on unregister
|
||||
LockedOut = 32, // Don't allow registration
|
||||
NoMove = 64, // Don't allow moving this region
|
||||
Reservation = 128, // This is an inactive reservation
|
||||
Authenticate = 256, // Require authentication
|
||||
Hyperlink = 512 // Record represents a HG link
|
||||
}
|
||||
|
||||
public class RegionDataDistanceCompare : IComparer<RegionData>
|
||||
{
|
||||
private Vector2 m_origin;
|
||||
|
||||
@@ -37,6 +37,7 @@ using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using RegionFlags = OpenSim.Framework.RegionFlags;
|
||||
|
||||
namespace OpenSim.Data.MSSQL
|
||||
{
|
||||
|
||||
@@ -30,11 +30,11 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
|
||||
using MySql.Data.MySqlClient;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Data;
|
||||
using MySql.Data.MySqlClient;
|
||||
using RegionFlags = OpenSim.Framework.RegionFlags;
|
||||
|
||||
namespace OpenSim.Data.MySQL
|
||||
{
|
||||
|
||||
@@ -17,3 +17,8 @@ CREATE TABLE `GridUser` (
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
COMMIT;
|
||||
|
||||
:VERSION 2 # --------------------------
|
||||
BEGIN;
|
||||
|
||||
COMMIT;
|
||||
|
||||
@@ -33,6 +33,7 @@ using OpenSim.Framework;
|
||||
using OpenSim.Data;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using RegionFlags = OpenSim.Framework.RegionFlags;
|
||||
|
||||
namespace OpenSim.Data.Null
|
||||
{
|
||||
|
||||
84
OpenSim/Framework/AssetPermissions.cs
Normal file
84
OpenSim/Framework/AssetPermissions.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using Nini.Config;
|
||||
using log4net;
|
||||
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
public class AssetPermissions
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(
|
||||
MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private bool[] m_DisallowExport, m_DisallowImport;
|
||||
private string[] m_AssetTypeNames;
|
||||
|
||||
public AssetPermissions(IConfig config)
|
||||
{
|
||||
Type enumType = typeof(AssetType);
|
||||
m_AssetTypeNames = Enum.GetNames(enumType);
|
||||
for (int i = 0; i < m_AssetTypeNames.Length; i++)
|
||||
m_AssetTypeNames[i] = m_AssetTypeNames[i].ToLower();
|
||||
int n = Enum.GetValues(enumType).Length;
|
||||
m_DisallowExport = new bool[n];
|
||||
m_DisallowImport = new bool[n];
|
||||
|
||||
LoadPermsFromConfig(config, "DisallowExport", m_DisallowExport);
|
||||
LoadPermsFromConfig(config, "DisallowImport", m_DisallowImport);
|
||||
|
||||
}
|
||||
|
||||
private void LoadPermsFromConfig(IConfig assetConfig, string variable, bool[] bitArray)
|
||||
{
|
||||
if (assetConfig == null)
|
||||
return;
|
||||
|
||||
string perms = assetConfig.GetString(variable, String.Empty);
|
||||
string[] parts = perms.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string s in parts)
|
||||
{
|
||||
int index = Array.IndexOf(m_AssetTypeNames, s.Trim().ToLower());
|
||||
if (index >= 0)
|
||||
bitArray[index] = true;
|
||||
else
|
||||
m_log.WarnFormat("[Asset Permissions]: Invalid AssetType {0}", s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool AllowedExport(sbyte type)
|
||||
{
|
||||
string assetTypeName = ((AssetType)type).ToString();
|
||||
|
||||
int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
|
||||
if (index >= 0 && m_DisallowExport[index])
|
||||
{
|
||||
m_log.DebugFormat("[Asset Permissions]: Export denied: configuration does not allow export of AssetType {0}", assetTypeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool AllowedImport(sbyte type)
|
||||
{
|
||||
string assetTypeName = ((AssetType)type).ToString();
|
||||
|
||||
int index = Array.IndexOf(m_AssetTypeNames, assetTypeName.ToLower());
|
||||
if (index >= 0 && m_DisallowImport[index])
|
||||
{
|
||||
m_log.DebugFormat("[Asset Permissions]: Import denied: configuration does not allow import of AssetType {0}", assetTypeName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
114
OpenSim/Framework/Console/ConsoleUtil.cs
Normal file
114
OpenSim/Framework/Console/ConsoleUtil.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
|
||||
public class ConsoleUtil
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public const string MinRawConsoleVectorValue = "-~";
|
||||
public const string MaxRawConsoleVectorValue = "~";
|
||||
|
||||
public const string VectorSeparator = ",";
|
||||
public static char[] VectorSeparatorChars = VectorSeparator.ToCharArray();
|
||||
|
||||
/// <summary>
|
||||
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
|
||||
/// </summary>
|
||||
/// <param name='rawConsoleVector'>/param>
|
||||
/// <param name='vector'></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryParseConsoleMinVector(string rawConsoleVector, out Vector3 vector)
|
||||
{
|
||||
return TryParseConsoleVector(rawConsoleVector, c => float.MinValue.ToString(), out vector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a maximum vector input from the console to an OpenMetaverse.Vector3
|
||||
/// </summary>
|
||||
/// <param name='rawConsoleVector'>/param>
|
||||
/// <param name='vector'></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryParseConsoleMaxVector(string rawConsoleVector, out Vector3 vector)
|
||||
{
|
||||
return TryParseConsoleVector(rawConsoleVector, c => float.MaxValue.ToString(), out vector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a vector input from the console to an OpenMetaverse.Vector3
|
||||
/// </summary>
|
||||
/// <param name='rawConsoleVector'>
|
||||
/// A string in the form <x>,<y>,<z> where there is no space between values.
|
||||
/// Any component can be missing (e.g. ,,40). blankComponentFunc is invoked to replace the blank with a suitable value
|
||||
/// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40,30 or 40)
|
||||
/// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
|
||||
/// Other than that, component values must be numeric.
|
||||
/// </param>
|
||||
/// <param name='blankComponentFunc'></param>
|
||||
/// <param name='vector'></param>
|
||||
/// <returns></returns>
|
||||
public static bool TryParseConsoleVector(
|
||||
string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
|
||||
{
|
||||
List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
|
||||
|
||||
if (components.Count < 1 || components.Count > 3)
|
||||
{
|
||||
vector = Vector3.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = components.Count; i < 3; i++)
|
||||
components.Add("");
|
||||
|
||||
List<string> semiDigestedComponents
|
||||
= components.ConvertAll<string>(
|
||||
c =>
|
||||
{
|
||||
if (c == "")
|
||||
return blankComponentFunc.Invoke(c);
|
||||
else if (c == MaxRawConsoleVectorValue)
|
||||
return float.MaxValue.ToString();
|
||||
else if (c == MinRawConsoleVectorValue)
|
||||
return float.MinValue.ToString();
|
||||
else
|
||||
return c;
|
||||
});
|
||||
|
||||
string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
|
||||
|
||||
// m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
|
||||
|
||||
return Vector3.TryParse(semiDigestedConsoleVector, out vector);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ namespace OpenSim.Framework
|
||||
public class Constants
|
||||
{
|
||||
public const uint RegionSize = 256;
|
||||
public const uint RegionHeight = 4096;
|
||||
public const byte TerrainPatchSize = 16;
|
||||
public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ namespace OpenSim.Framework
|
||||
public Vector3 Position;
|
||||
public byte[] binaryBucket;
|
||||
|
||||
|
||||
public uint ParentEstateID;
|
||||
public Guid RegionID;
|
||||
public uint timestamp;
|
||||
@@ -58,7 +57,7 @@ namespace OpenSim.Framework
|
||||
string _fromAgentName, UUID _toAgentID,
|
||||
byte _dialog, bool _fromGroup, string _message,
|
||||
UUID _imSessionID, bool _offline, Vector3 _position,
|
||||
byte[] _binaryBucket)
|
||||
byte[] _binaryBucket, bool addTimestamp)
|
||||
{
|
||||
fromAgentID = _fromAgentID.Guid;
|
||||
fromAgentName = _fromAgentName;
|
||||
@@ -79,7 +78,9 @@ namespace OpenSim.Framework
|
||||
ParentEstateID = scene.RegionInfo.EstateSettings.ParentEstateID;
|
||||
RegionID = scene.RegionInfo.RegionSettings.RegionUUID.Guid;
|
||||
}
|
||||
timestamp = (uint)Util.UnixTimeSinceEpoch();
|
||||
|
||||
if (addTimestamp)
|
||||
timestamp = (uint)Util.UnixTimeSinceEpoch();
|
||||
}
|
||||
|
||||
public GridInstantMessage(IScene scene, UUID _fromAgentID,
|
||||
@@ -87,7 +88,7 @@ namespace OpenSim.Framework
|
||||
string _message, bool _offline,
|
||||
Vector3 _position) : this(scene, _fromAgentID, _fromAgentName,
|
||||
_toAgentID, _dialog, false, _message,
|
||||
_fromAgentID ^ _toAgentID, _offline, _position, new byte[0])
|
||||
_fromAgentID ^ _toAgentID, _offline, _position, new byte[0], true)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -805,8 +805,23 @@ namespace OpenSim.Framework
|
||||
event Action<IClientAPI> OnRegionHandShakeReply;
|
||||
event GenericCall1 OnRequestWearables;
|
||||
event Action<IClientAPI, bool> OnCompleteMovementToRegion;
|
||||
|
||||
/// <summary>
|
||||
/// Called when an AgentUpdate message is received and before OnAgentUpdate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Listeners must not retain a reference to AgentUpdateArgs since this object may be reused for subsequent AgentUpdates.
|
||||
/// </remarks>
|
||||
event UpdateAgent OnPreAgentUpdate;
|
||||
|
||||
/// <summary>
|
||||
/// Called when an AgentUpdate message is received and after OnPreAgentUpdate.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Listeners must not retain a reference to AgentUpdateArgs since this object may be reused for subsequent AgentUpdates.
|
||||
/// </remarks>
|
||||
event UpdateAgent OnAgentUpdate;
|
||||
|
||||
event AgentRequestSit OnAgentRequestSit;
|
||||
event AgentSit OnAgentSit;
|
||||
event AvatarPickerRequest OnAvatarPickerRequest;
|
||||
|
||||
@@ -49,7 +49,11 @@ namespace OpenSim.Framework.Monitoring
|
||||
Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
|
||||
|
||||
sb.AppendFormat(
|
||||
"OpenSim object memory churn : {0} MB/s\n",
|
||||
"OpenSim last object memory churn : {0} MB/s\n",
|
||||
Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3));
|
||||
|
||||
sb.AppendFormat(
|
||||
"OpenSim average object memory churn : {0} MB/s\n",
|
||||
Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3));
|
||||
|
||||
sb.AppendFormat(
|
||||
|
||||
@@ -60,13 +60,21 @@ namespace OpenSim.Framework.Monitoring
|
||||
private static bool m_enabled;
|
||||
|
||||
/// <summary>
|
||||
/// Average memory churn in bytes per millisecond.
|
||||
/// Last memory churn in bytes per millisecond.
|
||||
/// </summary>
|
||||
public static double AverageMemoryChurn
|
||||
{
|
||||
get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Average memory churn in bytes per millisecond.
|
||||
/// </summary>
|
||||
public static double LastMemoryChurn
|
||||
{
|
||||
get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of statistical samples.
|
||||
/// </summary>
|
||||
|
||||
@@ -355,10 +355,25 @@ Asset service request failures: {3}" + Environment.NewLine,
|
||||
sb.Append(Environment.NewLine);
|
||||
sb.Append(
|
||||
string.Format(
|
||||
"{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}",
|
||||
"{0,6:0} {1,6:0} {2,6:0} {3,6:0} {4,6:0} {5,6:0.0} {6,6:0.0} {7,6:0.0} {8,6:0.0} {9,6:0.0} {10,6:0.0}\n\n",
|
||||
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
|
||||
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
|
||||
sb.Append(Environment.NewLine);
|
||||
|
||||
Dictionary<string, Dictionary<string, Stat>> sceneStats;
|
||||
|
||||
if (StatsManager.TryGetStats("scene", out sceneStats))
|
||||
{
|
||||
foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats)
|
||||
{
|
||||
foreach (Stat stat in kvp.Value.Values)
|
||||
{
|
||||
if (stat.Verbosity == StatVerbosity.Info)
|
||||
{
|
||||
sb.AppendFormat("{0} ({1}): {2}{3}\n", stat.Name, stat.Container, stat.Value, stat.UnitName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
sb.Append(Environment.NewLine);
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
/// <summary>
|
||||
@@ -32,6 +35,24 @@ namespace OpenSim.Framework.Monitoring
|
||||
/// </summary>
|
||||
public class StatsManager
|
||||
{
|
||||
// Subcommand used to list other stats.
|
||||
public const string AllSubCommand = "all";
|
||||
|
||||
// Subcommand used to list other stats.
|
||||
public const string ListSubCommand = "list";
|
||||
|
||||
// All subcommands
|
||||
public static HashSet<string> SubCommands = new HashSet<string> { AllSubCommand, ListSubCommand };
|
||||
|
||||
/// <summary>
|
||||
/// Registered stats categorized by category/container/shortname
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Do not add or remove directly from this dictionary.
|
||||
/// </remarks>
|
||||
public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats
|
||||
= new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>();
|
||||
|
||||
private static AssetStatsCollector assetStats;
|
||||
private static UserStatsCollector userStats;
|
||||
private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
|
||||
@@ -40,6 +61,75 @@ namespace OpenSim.Framework.Monitoring
|
||||
public static UserStatsCollector UserStats { get { return userStats; } }
|
||||
public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
|
||||
|
||||
public static void RegisterConsoleCommands(ICommandConsole console)
|
||||
{
|
||||
console.Commands.AddCommand(
|
||||
"General",
|
||||
false,
|
||||
"show stats",
|
||||
"show stats [list|all|<category>]",
|
||||
"Show statistical information for this server",
|
||||
"If no final argument is specified then legacy statistics information is currently shown.\n"
|
||||
+ "If list is specified then statistic categories are shown.\n"
|
||||
+ "If all is specified then all registered statistics are shown.\n"
|
||||
+ "If a category name is specified then only statistics from that category are shown.\n"
|
||||
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
|
||||
HandleShowStatsCommand);
|
||||
}
|
||||
|
||||
public static void HandleShowStatsCommand(string module, string[] cmd)
|
||||
{
|
||||
ICommandConsole con = MainConsole.Instance;
|
||||
|
||||
if (cmd.Length > 2)
|
||||
{
|
||||
var categoryName = cmd[2];
|
||||
|
||||
if (categoryName == AllSubCommand)
|
||||
{
|
||||
foreach (var category in RegisteredStats.Values)
|
||||
{
|
||||
OutputCategoryStatsToConsole(con, category);
|
||||
}
|
||||
}
|
||||
else if (categoryName == ListSubCommand)
|
||||
{
|
||||
con.Output("Statistic categories available are:");
|
||||
foreach (string category in RegisteredStats.Keys)
|
||||
con.OutputFormat(" {0}", category);
|
||||
}
|
||||
else
|
||||
{
|
||||
Dictionary<string, Dictionary<string, Stat>> category;
|
||||
if (!RegisteredStats.TryGetValue(categoryName, out category))
|
||||
{
|
||||
con.OutputFormat("No such category as {0}", categoryName);
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputCategoryStatsToConsole(con, category);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Legacy
|
||||
con.Output(SimExtraStats.Report());
|
||||
}
|
||||
}
|
||||
|
||||
private static void OutputCategoryStatsToConsole(
|
||||
ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category)
|
||||
{
|
||||
foreach (var container in category.Values)
|
||||
{
|
||||
foreach (Stat stat in container.Values)
|
||||
{
|
||||
con.Output(stat.ToConsoleString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start collecting statistics related to assets.
|
||||
/// Should only be called once.
|
||||
@@ -61,5 +151,224 @@ namespace OpenSim.Framework.Monitoring
|
||||
|
||||
return userStats;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers a statistic.
|
||||
/// </summary>
|
||||
/// <param name='stat'></param>
|
||||
/// <returns></returns>
|
||||
public static bool RegisterStat(Stat stat)
|
||||
{
|
||||
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
|
||||
Dictionary<string, Stat> container = null, newContainer;
|
||||
|
||||
lock (RegisteredStats)
|
||||
{
|
||||
// Stat name is not unique across category/container/shortname key.
|
||||
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
|
||||
// in a class are run in the same instance of the VM.
|
||||
if (TryGetStat(stat, out category, out container))
|
||||
return false;
|
||||
|
||||
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
|
||||
// This means that we don't need to lock or copy them on iteration, which will be a much more
|
||||
// common operation after startup.
|
||||
if (container != null)
|
||||
newContainer = new Dictionary<string, Stat>(container);
|
||||
else
|
||||
newContainer = new Dictionary<string, Stat>();
|
||||
|
||||
if (category != null)
|
||||
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
|
||||
else
|
||||
newCategory = new Dictionary<string, Dictionary<string, Stat>>();
|
||||
|
||||
newContainer[stat.ShortName] = stat;
|
||||
newCategory[stat.Container] = newContainer;
|
||||
RegisteredStats[stat.Category] = newCategory;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deregister a statistic
|
||||
/// </summary>>
|
||||
/// <param name='stat'></param>
|
||||
/// <returns></returns
|
||||
public static bool DeregisterStat(Stat stat)
|
||||
{
|
||||
Dictionary<string, Dictionary<string, Stat>> category = null, newCategory;
|
||||
Dictionary<string, Stat> container = null, newContainer;
|
||||
|
||||
lock (RegisteredStats)
|
||||
{
|
||||
if (!TryGetStat(stat, out category, out container))
|
||||
return false;
|
||||
|
||||
newContainer = new Dictionary<string, Stat>(container);
|
||||
newContainer.Remove(stat.UniqueName);
|
||||
|
||||
newCategory = new Dictionary<string, Dictionary<string, Stat>>(category);
|
||||
newCategory.Remove(stat.Container);
|
||||
|
||||
newCategory[stat.Container] = newContainer;
|
||||
RegisteredStats[stat.Category] = newCategory;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats)
|
||||
{
|
||||
return RegisteredStats.TryGetValue(category, out stats);
|
||||
}
|
||||
|
||||
public static bool TryGetStat(
|
||||
Stat stat,
|
||||
out Dictionary<string, Dictionary<string, Stat>> category,
|
||||
out Dictionary<string, Stat> container)
|
||||
{
|
||||
category = null;
|
||||
container = null;
|
||||
|
||||
lock (RegisteredStats)
|
||||
{
|
||||
if (RegisteredStats.TryGetValue(stat.Category, out category))
|
||||
{
|
||||
if (category.TryGetValue(stat.Container, out container))
|
||||
{
|
||||
if (container.ContainsKey(stat.ShortName))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verbosity of stat.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Info will always be displayed.
|
||||
/// </remarks>
|
||||
public enum StatVerbosity
|
||||
{
|
||||
Debug,
|
||||
Info
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds individual static details
|
||||
/// </summary>
|
||||
public class Stat
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique stat name used for indexing. Each ShortName in a Category must be unique.
|
||||
/// </summary>
|
||||
public string UniqueName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Category of this stat (e.g. cache, scene, etc).
|
||||
/// </summary>
|
||||
public string Category { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Containing name for this stat.
|
||||
/// FIXME: In the case of a scene, this is currently the scene name (though this leaves
|
||||
/// us with a to-be-resolved problem of non-unique region names).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The container.
|
||||
/// </value>
|
||||
public string Container { get; private set; }
|
||||
|
||||
public StatVerbosity Verbosity { get; private set; }
|
||||
public string ShortName { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string Description { get; private set; }
|
||||
public virtual string UnitName { get; private set; }
|
||||
|
||||
public virtual double Value { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name='shortName'>Short name for the stat. Must not contain spaces. e.g. "LongFrames"</param>
|
||||
/// <param name='name'>Human readable name for the stat. e.g. "Long frames"</param>
|
||||
/// <param name='unitName'>
|
||||
/// Unit name for the stat. Should be preceeded by a space if the unit name isn't normally appeneded immediately to the value.
|
||||
/// e.g. " frames"
|
||||
/// </param>
|
||||
/// <param name='category'>Category under which this stat should appear, e.g. "scene". Do not capitalize.</param>
|
||||
/// <param name='container'>Entity to which this stat relates. e.g. scene name if this is a per scene stat.</param>
|
||||
/// <param name='verbosity'>Verbosity of stat. Controls whether it will appear in short stat display or only full display.</param>
|
||||
/// <param name='description'>Description of stat</param>
|
||||
public Stat(
|
||||
string shortName, string name, string unitName, string category, string container, StatVerbosity verbosity, string description)
|
||||
{
|
||||
if (StatsManager.SubCommands.Contains(category))
|
||||
throw new Exception(
|
||||
string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
|
||||
|
||||
ShortName = shortName;
|
||||
Name = name;
|
||||
UnitName = unitName;
|
||||
Category = category;
|
||||
Container = container;
|
||||
Verbosity = verbosity;
|
||||
Description = description;
|
||||
|
||||
UniqueName = GenUniqueName(Container, Category, ShortName);
|
||||
}
|
||||
|
||||
public static string GenUniqueName(string container, string category, string shortName)
|
||||
{
|
||||
return string.Format("{0}+{1}+{2}", container, category, shortName);
|
||||
}
|
||||
|
||||
public virtual string ToConsoleString()
|
||||
{
|
||||
return string.Format(
|
||||
"{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
|
||||
}
|
||||
}
|
||||
|
||||
public class PercentageStat : Stat
|
||||
{
|
||||
public int Antecedent { get; set; }
|
||||
public int Consequent { get; set; }
|
||||
|
||||
public override double Value
|
||||
{
|
||||
get
|
||||
{
|
||||
int c = Consequent;
|
||||
|
||||
// Avoid any chance of a multi-threaded divide-by-zero
|
||||
if (c == 0)
|
||||
return 0;
|
||||
|
||||
return (double)Antecedent / c * 100;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new Exception("Cannot set value on a PercentageStat");
|
||||
}
|
||||
}
|
||||
|
||||
public PercentageStat(
|
||||
string shortName, string name, string category, string container, StatVerbosity verbosity, string description)
|
||||
: base(shortName, name, "%", category, container, verbosity, description) {}
|
||||
|
||||
public override string ToConsoleString()
|
||||
{
|
||||
return string.Format(
|
||||
"{0}.{1}.{2} : {3:0.##}{4} ({5}/{6})",
|
||||
Category, Container, ShortName, Value, UnitName, Antecedent, Consequent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,25 @@ namespace OpenSim.Framework.Monitoring
|
||||
private static bool RemoveThread(int threadID)
|
||||
{
|
||||
lock (m_threads)
|
||||
return m_threads.Remove(threadID);
|
||||
{
|
||||
ThreadWatchdogInfo twi;
|
||||
if (m_threads.TryGetValue(threadID, out twi))
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
|
||||
|
||||
m_threads.Remove(threadID);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[WATCHDOG]: Requested to remove thread with ID {0} but this is not being monitored", threadID);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AbortThread(int threadID)
|
||||
|
||||
@@ -28,30 +28,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
public class HGUuidGatherer : UuidGatherer
|
||||
/// <summary>
|
||||
/// Naive pool implementation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently assumes that objects are in a useable state when returned.
|
||||
/// </remarks>
|
||||
public class Pool<T>
|
||||
{
|
||||
protected string m_assetServerURL;
|
||||
protected HGAssetMapper m_assetMapper;
|
||||
private Stack<T> m_pool;
|
||||
|
||||
public HGUuidGatherer(HGAssetMapper assMap, IAssetService assetCache, string assetServerURL) : base(assetCache)
|
||||
private int m_maxPoolSize;
|
||||
|
||||
private Func<T> m_createFunction;
|
||||
|
||||
public Pool(Func<T> createFunction, int maxSize)
|
||||
{
|
||||
m_assetMapper = assMap;
|
||||
m_assetServerURL = assetServerURL;
|
||||
m_maxPoolSize = maxSize;
|
||||
m_createFunction = createFunction;
|
||||
m_pool = new Stack<T>(m_maxPoolSize);
|
||||
}
|
||||
|
||||
protected override AssetBase GetAsset(UUID uuid)
|
||||
public T GetObject()
|
||||
{
|
||||
if (string.Empty == m_assetServerURL)
|
||||
return m_assetCache.Get(uuid.ToString());
|
||||
else
|
||||
return m_assetMapper.FetchAsset(m_assetServerURL, uuid);
|
||||
lock (m_pool)
|
||||
{
|
||||
if (m_pool.Count > 0)
|
||||
return m_pool.Pop();
|
||||
else
|
||||
return m_createFunction();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReturnObject(T obj)
|
||||
{
|
||||
lock (m_pool)
|
||||
{
|
||||
if (m_pool.Count >= m_maxPoolSize)
|
||||
return;
|
||||
else
|
||||
m_pool.Push(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
OpenSim/Framework/RegionFlags.cs
Normal file
53
OpenSim/Framework/RegionFlags.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
/// <summary>
|
||||
/// Region flags used internally by OpenSimulator to store installation specific information about regions.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Don't confuse with OpenMetaverse.RegionFlags which are client facing flags (i.e. they go over the wire).
|
||||
/// Returned by IGridService.GetRegionFlags()
|
||||
/// </remarks>
|
||||
[Flags]
|
||||
public enum RegionFlags : int
|
||||
{
|
||||
DefaultRegion = 1, // Used for new Rez. Random if multiple defined
|
||||
FallbackRegion = 2, // Regions we redirect to when the destination is down
|
||||
RegionOnline = 4, // Set when a region comes online, unset when it unregisters and DeleteOnUnregister is false
|
||||
NoDirectLogin = 8, // Region unavailable for direct logins (by name)
|
||||
Persistent = 16, // Don't remove on unregister
|
||||
LockedOut = 32, // Don't allow registration
|
||||
NoMove = 64, // Don't allow moving this region
|
||||
Reservation = 128, // This is an inactive reservation
|
||||
Authenticate = 256, // Require authentication
|
||||
Hyperlink = 512 // Record represents a HG link
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,7 @@ namespace OpenSim.Framework
|
||||
private int m_physPrimMax = 0;
|
||||
private bool m_clampPrimSize = false;
|
||||
private int m_objectCapacity = 0;
|
||||
private int m_linksetCapacity = 0;
|
||||
private int m_agentCapacity = 0;
|
||||
private string m_regionType = String.Empty;
|
||||
private RegionLightShareData m_windlight = new RegionLightShareData();
|
||||
@@ -317,6 +318,11 @@ namespace OpenSim.Framework
|
||||
get { return m_objectCapacity; }
|
||||
}
|
||||
|
||||
public int LinksetCapacity
|
||||
{
|
||||
get { return m_linksetCapacity; }
|
||||
}
|
||||
|
||||
public int AgentCapacity
|
||||
{
|
||||
get { return m_agentCapacity; }
|
||||
@@ -637,11 +643,11 @@ namespace OpenSim.Framework
|
||||
|
||||
#region Prim stuff
|
||||
|
||||
m_nonphysPrimMin = config.GetFloat("NonphysicalPrimMin", 0);
|
||||
allKeys.Remove("NonphysicalPrimMin");
|
||||
m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
|
||||
allKeys.Remove("NonPhysicalPrimMin");
|
||||
|
||||
m_nonphysPrimMax = config.GetInt("NonphysicalPrimMax", 0);
|
||||
allKeys.Remove("NonphysicalPrimMax");
|
||||
m_nonphysPrimMax = config.GetInt("NonPhysicalPrimMax", 0);
|
||||
allKeys.Remove("NonPhysicalPrimMax");
|
||||
|
||||
m_physPrimMin = config.GetFloat("PhysicalPrimMin", 0);
|
||||
allKeys.Remove("PhysicalPrimMin");
|
||||
@@ -654,6 +660,9 @@ namespace OpenSim.Framework
|
||||
|
||||
m_objectCapacity = config.GetInt("MaxPrims", 15000);
|
||||
allKeys.Remove("MaxPrims");
|
||||
|
||||
m_linksetCapacity = config.GetInt("LinksetPrims", 0);
|
||||
allKeys.Remove("LinksetPrims");
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -692,24 +701,27 @@ namespace OpenSim.Framework
|
||||
|
||||
config.Set("ExternalHostName", m_externalHostName);
|
||||
|
||||
if (m_nonphysPrimMin != 0)
|
||||
if (m_nonphysPrimMin > 0)
|
||||
config.Set("NonphysicalPrimMax", m_nonphysPrimMin);
|
||||
|
||||
if (m_nonphysPrimMax != 0)
|
||||
if (m_nonphysPrimMax > 0)
|
||||
config.Set("NonphysicalPrimMax", m_nonphysPrimMax);
|
||||
|
||||
if (m_physPrimMin != 0)
|
||||
if (m_physPrimMin > 0)
|
||||
config.Set("PhysicalPrimMax", m_physPrimMin);
|
||||
|
||||
if (m_physPrimMax != 0)
|
||||
if (m_physPrimMax > 0)
|
||||
config.Set("PhysicalPrimMax", m_physPrimMax);
|
||||
|
||||
config.Set("ClampPrimSize", m_clampPrimSize.ToString());
|
||||
|
||||
if (m_objectCapacity != 0)
|
||||
if (m_objectCapacity > 0)
|
||||
config.Set("MaxPrims", m_objectCapacity);
|
||||
|
||||
if (m_agentCapacity != 0)
|
||||
if (m_linksetCapacity > 0)
|
||||
config.Set("LinksetPrims", m_linksetCapacity);
|
||||
|
||||
if (m_agentCapacity > 0)
|
||||
config.Set("MaxAgents", m_agentCapacity);
|
||||
|
||||
if (ScopeID != UUID.Zero)
|
||||
@@ -804,6 +816,9 @@ namespace OpenSim.Framework
|
||||
configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
|
||||
"Max objects this sim will hold", m_objectCapacity.ToString(), true);
|
||||
|
||||
configMember.addConfigurationOption("linkset_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
|
||||
"Max prims an object will hold", m_linksetCapacity.ToString(), true);
|
||||
|
||||
configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
|
||||
"Max avatars this sim will hold", m_agentCapacity.ToString(), true);
|
||||
|
||||
@@ -922,6 +937,9 @@ namespace OpenSim.Framework
|
||||
case "object_capacity":
|
||||
m_objectCapacity = (int)configuration_result;
|
||||
break;
|
||||
case "linkset_capacity":
|
||||
m_linksetCapacity = (int)configuration_result;
|
||||
break;
|
||||
case "agent_capacity":
|
||||
m_agentCapacity = (int)configuration_result;
|
||||
break;
|
||||
@@ -1052,4 +1070,4 @@ namespace OpenSim.Framework
|
||||
return kvp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,11 @@ namespace OpenSim.Framework.Serialization
|
||||
/// </value>
|
||||
public const string INVENTORY_PATH = "inventory/";
|
||||
|
||||
/// <value>
|
||||
/// Path for regions in a multi-region archive
|
||||
/// </value>
|
||||
public const string REGIONS_PATH = "regions/";
|
||||
|
||||
/// <value>
|
||||
/// Path for the prims file
|
||||
/// </value>
|
||||
|
||||
@@ -96,11 +96,6 @@ namespace OpenSim.Framework.Servers
|
||||
get { return m_httpServer; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Holds the non-viewer statistics collection object for this service/server
|
||||
/// </summary>
|
||||
protected IStatsCollector m_stats;
|
||||
|
||||
public BaseOpenSimServer()
|
||||
{
|
||||
m_startuptime = DateTime.Now;
|
||||
@@ -177,10 +172,6 @@ namespace OpenSim.Framework.Servers
|
||||
"show info",
|
||||
"Show general information about the server", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("General", false, "show stats",
|
||||
"show stats",
|
||||
"Show statistics", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("General", false, "show threads",
|
||||
"show threads",
|
||||
"Show thread status", HandleShow);
|
||||
@@ -226,12 +217,7 @@ namespace OpenSim.Framework.Servers
|
||||
{
|
||||
StringBuilder sb = new StringBuilder("DIAGNOSTICS\n\n");
|
||||
sb.Append(GetUptimeReport());
|
||||
|
||||
if (m_stats != null)
|
||||
{
|
||||
sb.Append(m_stats.Report());
|
||||
}
|
||||
|
||||
sb.Append(StatsManager.SimExtraStats.Report());
|
||||
sb.Append(Environment.NewLine);
|
||||
sb.Append(GetThreadsReport());
|
||||
|
||||
@@ -382,10 +368,6 @@ namespace OpenSim.Framework.Servers
|
||||
{
|
||||
Notice("set log level [level] - change the console logging level only. For example, off or debug.");
|
||||
Notice("show info - show server information (e.g. startup path).");
|
||||
|
||||
if (m_stats != null)
|
||||
Notice("show stats - show statistical information for this server");
|
||||
|
||||
Notice("show threads - list tracked threads");
|
||||
Notice("show uptime - show server startup time and uptime.");
|
||||
Notice("show version - show server version.");
|
||||
@@ -409,11 +391,6 @@ namespace OpenSim.Framework.Servers
|
||||
ShowInfo();
|
||||
break;
|
||||
|
||||
case "stats":
|
||||
if (m_stats != null)
|
||||
Notice(m_stats.Report());
|
||||
break;
|
||||
|
||||
case "threads":
|
||||
Notice(GetThreadsReport());
|
||||
break;
|
||||
@@ -604,8 +581,7 @@ namespace OpenSim.Framework.Servers
|
||||
|
||||
public string osSecret {
|
||||
// Secret uuid for the simulator
|
||||
get { return m_osSecret; }
|
||||
|
||||
get { return m_osSecret; }
|
||||
}
|
||||
|
||||
public string StatReport(IOSHttpRequest httpRequest)
|
||||
@@ -613,11 +589,11 @@ namespace OpenSim.Framework.Servers
|
||||
// If we catch a request for "callback", wrap the response in the value for jsonp
|
||||
if (httpRequest.Query.ContainsKey("callback"))
|
||||
{
|
||||
return httpRequest.Query["callback"].ToString() + "(" + m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
|
||||
return httpRequest.Query["callback"].ToString() + "(" + StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version) + ");";
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_stats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
|
||||
return StatsManager.SimExtraStats.XReport((DateTime.Now - m_startuptime).ToString() , m_version);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,23 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the debug level.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// See MainServer.DebugLevel.
|
||||
/// </value>
|
||||
public int DebugLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Request number for diagnostic purposes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is an internal number. In some debug situations an external number may also be supplied in the
|
||||
/// opensim-request-id header but we are not currently logging this.
|
||||
/// </remarks>
|
||||
public int RequestNumber { get; private set; }
|
||||
|
||||
private volatile int NotSocketErrors = 0;
|
||||
public volatile bool HTTPDRunning = false;
|
||||
|
||||
@@ -67,7 +82,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
|
||||
protected Dictionary<string, IRequestHandler> m_streamHandlers = new Dictionary<string, IRequestHandler>();
|
||||
protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers = new Dictionary<string, GenericHTTPMethod>();
|
||||
protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
|
||||
// protected Dictionary<string, IHttpAgentHandler> m_agentHandlers = new Dictionary<string, IHttpAgentHandler>();
|
||||
protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
|
||||
new Dictionary<string, PollServiceEventArgs>();
|
||||
|
||||
@@ -245,29 +260,29 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
return new List<string>(m_pollHandlers.Keys);
|
||||
}
|
||||
|
||||
// Note that the agent string is provided simply to differentiate
|
||||
// the handlers - it is NOT required to be an actual agent header
|
||||
// value.
|
||||
public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
|
||||
{
|
||||
lock (m_agentHandlers)
|
||||
{
|
||||
if (!m_agentHandlers.ContainsKey(agent))
|
||||
{
|
||||
m_agentHandlers.Add(agent, handler);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//must already have a handler for that path so return false
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<string> GetAgentHandlerKeys()
|
||||
{
|
||||
lock (m_agentHandlers)
|
||||
return new List<string>(m_agentHandlers.Keys);
|
||||
}
|
||||
// // Note that the agent string is provided simply to differentiate
|
||||
// // the handlers - it is NOT required to be an actual agent header
|
||||
// // value.
|
||||
// public bool AddAgentHandler(string agent, IHttpAgentHandler handler)
|
||||
// {
|
||||
// lock (m_agentHandlers)
|
||||
// {
|
||||
// if (!m_agentHandlers.ContainsKey(agent))
|
||||
// {
|
||||
// m_agentHandlers.Add(agent, handler);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //must already have a handler for that path so return false
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// public List<string> GetAgentHandlerKeys()
|
||||
// {
|
||||
// lock (m_agentHandlers)
|
||||
// return new List<string>(m_agentHandlers.Keys);
|
||||
// }
|
||||
|
||||
public bool AddLLSDHandler(string path, LLSDMethod handler)
|
||||
{
|
||||
@@ -296,6 +311,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
private void OnRequest(object source, RequestEventArgs args)
|
||||
{
|
||||
RequestNumber++;
|
||||
|
||||
try
|
||||
{
|
||||
IHttpClientContext context = (IHttpClientContext)source;
|
||||
@@ -405,7 +422,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
string requestMethod = request.HttpMethod;
|
||||
string uriString = request.RawUrl;
|
||||
|
||||
// string reqnum = "unknown";
|
||||
int requestStartTick = Environment.TickCount;
|
||||
|
||||
// Will be adjusted later on.
|
||||
@@ -422,22 +438,22 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true);
|
||||
|
||||
// This is the REST agent interface. We require an agent to properly identify
|
||||
// itself. If the REST handler recognizes the prefix it will attempt to
|
||||
// satisfy the request. If it is not recognizable, and no damage has occurred
|
||||
// the request can be passed through to the other handlers. This is a low
|
||||
// probability event; if a request is matched it is normally expected to be
|
||||
// handled
|
||||
IHttpAgentHandler agentHandler;
|
||||
|
||||
if (TryGetAgentHandler(request, response, out agentHandler))
|
||||
{
|
||||
if (HandleAgentRequest(agentHandler, request, response))
|
||||
{
|
||||
requestEndTick = Environment.TickCount;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// // This is the REST agent interface. We require an agent to properly identify
|
||||
// // itself. If the REST handler recognizes the prefix it will attempt to
|
||||
// // satisfy the request. If it is not recognizable, and no damage has occurred
|
||||
// // the request can be passed through to the other handlers. This is a low
|
||||
// // probability event; if a request is matched it is normally expected to be
|
||||
// // handled
|
||||
// IHttpAgentHandler agentHandler;
|
||||
//
|
||||
// if (TryGetAgentHandler(request, response, out agentHandler))
|
||||
// {
|
||||
// if (HandleAgentRequest(agentHandler, request, response))
|
||||
// {
|
||||
// requestEndTick = Environment.TickCount;
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
//response.KeepAlive = true;
|
||||
response.SendChunked = false;
|
||||
@@ -449,9 +465,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
if (TryGetStreamHandler(handlerKey, out requestHandler))
|
||||
{
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}",
|
||||
request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description);
|
||||
LogIncomingToStreamHandler(request, requestHandler);
|
||||
|
||||
response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
|
||||
|
||||
@@ -531,8 +545,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
|
||||
RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
|
||||
|
||||
buffer = HandleHTTPRequest(request, response);
|
||||
break;
|
||||
@@ -543,8 +557,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
|
||||
RequestNumber, Port, request.ContentType, request.HttpMethod, request.Url.PathAndQuery, request.RemoteIPEndPoint);
|
||||
|
||||
buffer = HandleLLSDRequests(request, response);
|
||||
break;
|
||||
@@ -563,9 +577,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
if (DoWeHaveALLSDHandler(request.RawUrl))
|
||||
{
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
LogIncomingToContentTypeHandler(request);
|
||||
|
||||
buffer = HandleLLSDRequests(request, response);
|
||||
}
|
||||
@@ -573,18 +585,14 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
else if (DoWeHaveAHTTPHandler(request.RawUrl))
|
||||
{
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
LogIncomingToContentTypeHandler(request);
|
||||
|
||||
buffer = HandleHTTPRequest(request, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
|
||||
request.HttpMethod, request.Url.PathAndQuery);
|
||||
LogIncomingToXmlRpcHandler(request);
|
||||
|
||||
// generic login request.
|
||||
buffer = HandleXmlRpcRequests(request, response);
|
||||
@@ -628,11 +636,11 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e);
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e);
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
|
||||
SendHTML500(response);
|
||||
}
|
||||
finally
|
||||
@@ -640,17 +648,93 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
// Every month or so this will wrap and give bad numbers, not really a problem
|
||||
// since its just for reporting
|
||||
int tickdiff = requestEndTick - requestStartTick;
|
||||
if (tickdiff > 3000)
|
||||
if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture")
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms",
|
||||
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
|
||||
RequestNumber,
|
||||
requestMethod,
|
||||
uriString,
|
||||
requestHandler != null ? requestHandler.Name : "",
|
||||
requestHandler != null ? requestHandler.Description : "",
|
||||
request.RemoteIPEndPoint.ToString(),
|
||||
request.RemoteIPEndPoint,
|
||||
tickdiff);
|
||||
}
|
||||
else if (DebugLevel >= 4)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms",
|
||||
RequestNumber,
|
||||
Port,
|
||||
tickdiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
|
||||
RequestNumber,
|
||||
Port,
|
||||
request.HttpMethod,
|
||||
request.Url.PathAndQuery,
|
||||
requestHandler.Name,
|
||||
requestHandler.Description,
|
||||
request.RemoteIPEndPoint);
|
||||
|
||||
if (DebugLevel >= 5)
|
||||
LogIncomingInDetail(request);
|
||||
}
|
||||
|
||||
private void LogIncomingToContentTypeHandler(OSHttpRequest request)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
|
||||
RequestNumber,
|
||||
Port,
|
||||
request.ContentType,
|
||||
request.HttpMethod,
|
||||
request.Url.PathAndQuery,
|
||||
request.RemoteIPEndPoint);
|
||||
|
||||
if (DebugLevel >= 5)
|
||||
LogIncomingInDetail(request);
|
||||
}
|
||||
|
||||
private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
|
||||
RequestNumber,
|
||||
Port,
|
||||
request.HttpMethod,
|
||||
request.Url.PathAndQuery,
|
||||
request.RemoteIPEndPoint);
|
||||
|
||||
if (DebugLevel >= 5)
|
||||
LogIncomingInDetail(request);
|
||||
}
|
||||
|
||||
private void LogIncomingInDetail(OSHttpRequest request)
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8))
|
||||
{
|
||||
string output;
|
||||
|
||||
if (DebugLevel == 5)
|
||||
{
|
||||
const int sampleLength = 80;
|
||||
char[] sampleChars = new char[sampleLength];
|
||||
reader.Read(sampleChars, 0, sampleLength);
|
||||
output = new string(sampleChars);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = reader.ReadToEnd();
|
||||
}
|
||||
|
||||
m_log.DebugFormat("[BASE HTTP SERVER]: {0}...", output.Replace("\n", @"\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,24 +830,24 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
|
||||
{
|
||||
agentHandler = null;
|
||||
|
||||
lock (m_agentHandlers)
|
||||
{
|
||||
foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
|
||||
{
|
||||
if (handler.Match(request, response))
|
||||
{
|
||||
agentHandler = handler;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// private bool TryGetAgentHandler(OSHttpRequest request, OSHttpResponse response, out IHttpAgentHandler agentHandler)
|
||||
// {
|
||||
// agentHandler = null;
|
||||
//
|
||||
// lock (m_agentHandlers)
|
||||
// {
|
||||
// foreach (IHttpAgentHandler handler in m_agentHandlers.Values)
|
||||
// {
|
||||
// if (handler.Match(request, response))
|
||||
// {
|
||||
// agentHandler = handler;
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Try all the registered xmlrpc handlers when an xmlrpc request is received.
|
||||
@@ -1688,21 +1772,21 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_pollHandlers.Remove(path);
|
||||
}
|
||||
|
||||
public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
|
||||
{
|
||||
lock (m_agentHandlers)
|
||||
{
|
||||
IHttpAgentHandler foundHandler;
|
||||
|
||||
if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
|
||||
{
|
||||
m_agentHandlers.Remove(agent);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler)
|
||||
// {
|
||||
// lock (m_agentHandlers)
|
||||
// {
|
||||
// IHttpAgentHandler foundHandler;
|
||||
//
|
||||
// if (m_agentHandlers.TryGetValue(agent, out foundHandler) && foundHandler == handler)
|
||||
// {
|
||||
// m_agentHandlers.Remove(agent);
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
|
||||
public void RemoveXmlRPCHandler(string method)
|
||||
{
|
||||
|
||||
@@ -41,10 +41,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
uint Port { get; }
|
||||
bool UseSSL { get; }
|
||||
|
||||
// Note that the agent string is provided simply to differentiate
|
||||
// the handlers - it is NOT required to be an actual agent header
|
||||
// value.
|
||||
bool AddAgentHandler(string agent, IHttpAgentHandler handler);
|
||||
// // Note that the agent string is provided simply to differentiate
|
||||
// // the handlers - it is NOT required to be an actual agent header
|
||||
// // value.
|
||||
// bool AddAgentHandler(string agent, IHttpAgentHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// Add a handler for an HTTP request.
|
||||
@@ -106,13 +106,13 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
bool SetDefaultLLSDHandler(DefaultLLSDMethod handler);
|
||||
|
||||
/// <summary>
|
||||
/// Remove the agent if it is registered.
|
||||
/// </summary>
|
||||
/// <param name="agent"></param>
|
||||
/// <param name="handler"></param>
|
||||
/// <returns></returns>
|
||||
bool RemoveAgentHandler(string agent, IHttpAgentHandler handler);
|
||||
// /// <summary>
|
||||
// /// Remove the agent if it is registered.
|
||||
// /// </summary>
|
||||
// /// <param name="agent"></param>
|
||||
// /// <param name="handler"></param>
|
||||
// /// <returns></returns>
|
||||
// bool RemoveAgentHandler(string agent, IHttpAgentHandler handler);
|
||||
|
||||
/// <summary>
|
||||
/// Remove an HTTP handler
|
||||
|
||||
@@ -29,6 +29,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using log4net;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
@@ -47,9 +48,12 @@ namespace OpenSim.Framework.Servers
|
||||
/// Control the printing of certain debug messages.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If DebugLevel >= 1, then short warnings are logged when receiving bad input data.
|
||||
/// If DebugLevel >= 2, then long warnings are logged when receiving bad input data.
|
||||
/// If DebugLevel >= 3, then short notices about all incoming non-poll HTTP requests are logged.
|
||||
/// If DebugLevel >= 1 then short warnings are logged when receiving bad input data.
|
||||
/// If DebugLevel >= 2 then long warnings are logged when receiving bad input data.
|
||||
/// If DebugLevel >= 3 then short notices about all incoming non-poll HTTP requests are logged.
|
||||
/// If DebugLevel >= 4 then the time taken to fulfill the request is logged.
|
||||
/// If DebugLevel >= 5 then the start of the body of incoming non-poll HTTP requests will be logged.
|
||||
/// If DebugLevel >= 6 then the entire body of incoming non-poll HTTP requests will be logged.
|
||||
/// </remarks>
|
||||
public static int DebugLevel
|
||||
{
|
||||
@@ -101,17 +105,28 @@ namespace OpenSim.Framework.Servers
|
||||
get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
|
||||
}
|
||||
|
||||
|
||||
public static void RegisterHttpConsoleCommands(ICommandConsole console)
|
||||
{
|
||||
console.Commands.AddCommand(
|
||||
"Debug", false, "debug http", "debug http [<level>]",
|
||||
"Turn on inbound non-poll http request debugging.",
|
||||
"If level <= 0, then no extra logging is done.\n"
|
||||
+ "If level >= 1, then short warnings are logged when receiving bad input data.\n"
|
||||
+ "If level >= 2, then long warnings are logged when receiving bad input data.\n"
|
||||
+ "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n"
|
||||
+ "If no level is specified then the current level is returned.",
|
||||
"Comms", false, "show http-handlers",
|
||||
"show http-handlers",
|
||||
"Show all registered http handlers", HandleShowHttpHandlersCommand);
|
||||
|
||||
console.Commands.AddCommand(
|
||||
"Debug", false, "debug http", "debug http <in|out|all> [<level>]",
|
||||
"Turn on http request logging.",
|
||||
"If in or all and\n"
|
||||
+ " level <= 0 then no extra logging is done.\n"
|
||||
+ " level >= 1 then short warnings are logged when receiving bad input data.\n"
|
||||
+ " level >= 2 then long warnings are logged when receiving bad input data.\n"
|
||||
+ " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
|
||||
+ " level >= 4 then the time taken to fulfill the request is logged.\n"
|
||||
+ " level >= 5 then a sample from the beginning of the incoming data is logged.\n"
|
||||
+ " level >= 6 then the entire incoming data is logged.\n"
|
||||
+ " no level is specified then the current level is returned.\n\n"
|
||||
+ "If out or all and\n"
|
||||
+ " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
|
||||
+ " level >= 4 then the time taken to fulfill the request is logged.\n",
|
||||
HandleDebugHttpCommand);
|
||||
}
|
||||
|
||||
@@ -119,25 +134,120 @@ namespace OpenSim.Framework.Servers
|
||||
/// Turn on some debugging values for OpenSim.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private static void HandleDebugHttpCommand(string module, string[] args)
|
||||
private static void HandleDebugHttpCommand(string module, string[] cmdparams)
|
||||
{
|
||||
if (args.Length == 3)
|
||||
if (cmdparams.Length < 3)
|
||||
{
|
||||
int newDebug;
|
||||
if (int.TryParse(args[2], out newDebug))
|
||||
{
|
||||
MainServer.DebugLevel = newDebug;
|
||||
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
|
||||
}
|
||||
MainConsole.Instance.Output("Usage: debug http <in|out|all> 0..6");
|
||||
return;
|
||||
}
|
||||
else if (args.Length == 2)
|
||||
|
||||
bool inReqs = false;
|
||||
bool outReqs = false;
|
||||
bool allReqs = false;
|
||||
|
||||
string subCommand = cmdparams[2];
|
||||
|
||||
if (subCommand.ToLower() == "in")
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel);
|
||||
inReqs = true;
|
||||
}
|
||||
else if (subCommand.ToLower() == "out")
|
||||
{
|
||||
outReqs = true;
|
||||
}
|
||||
else if (subCommand.ToLower() == "all")
|
||||
{
|
||||
allReqs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug http 0..3");
|
||||
MainConsole.Instance.Output("You must specify in, out or all");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmdparams.Length >= 4)
|
||||
{
|
||||
string rawNewDebug = cmdparams[3];
|
||||
int newDebug;
|
||||
|
||||
if (!int.TryParse(rawNewDebug, out newDebug))
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawNewDebug);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newDebug < 0 || newDebug > 6)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0..6", newDebug);
|
||||
return;
|
||||
}
|
||||
|
||||
if (allReqs || inReqs)
|
||||
{
|
||||
MainServer.DebugLevel = newDebug;
|
||||
MainConsole.Instance.OutputFormat("IN debug level set to {0}", newDebug);
|
||||
}
|
||||
|
||||
if (allReqs || outReqs)
|
||||
{
|
||||
WebUtil.DebugLevel = newDebug;
|
||||
MainConsole.Instance.OutputFormat("OUT debug level set to {0}", newDebug);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (allReqs || inReqs)
|
||||
MainConsole.Instance.OutputFormat("Current IN debug level is {0}", MainServer.DebugLevel);
|
||||
|
||||
if (allReqs || outReqs)
|
||||
MainConsole.Instance.OutputFormat("Current OUT debug level is {0}", WebUtil.DebugLevel);
|
||||
}
|
||||
}
|
||||
|
||||
private static void HandleShowHttpHandlersCommand(string module, string[] args)
|
||||
{
|
||||
if (args.Length != 2)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: show http-handlers");
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder handlers = new StringBuilder();
|
||||
|
||||
lock (m_Servers)
|
||||
{
|
||||
foreach (BaseHttpServer httpServer in m_Servers.Values)
|
||||
{
|
||||
handlers.AppendFormat(
|
||||
"Registered HTTP Handlers for server at {0}:{1}\n", httpServer.ListenIPAddress, httpServer.Port);
|
||||
|
||||
handlers.AppendFormat("* XMLRPC:\n");
|
||||
foreach (String s in httpServer.GetXmlRpcHandlerKeys())
|
||||
handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
handlers.AppendFormat("* HTTP:\n");
|
||||
List<String> poll = httpServer.GetPollServiceHandlerKeys();
|
||||
foreach (String s in httpServer.GetHTTPHandlerKeys())
|
||||
handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
|
||||
|
||||
// handlers.AppendFormat("* Agent:\n");
|
||||
// foreach (String s in httpServer.GetAgentHandlerKeys())
|
||||
// handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
handlers.AppendFormat("* LLSD:\n");
|
||||
foreach (String s in httpServer.GetLLSDHandlerKeys())
|
||||
handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
handlers.AppendFormat("* StreamHandlers ({0}):\n", httpServer.GetStreamHandlerKeys().Count);
|
||||
foreach (String s in httpServer.GetStreamHandlerKeys())
|
||||
handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
handlers.Append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
MainConsole.Instance.Output(handlers.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -533,6 +533,19 @@ namespace OpenSim.Framework
|
||||
return (x + y - (min >> 1) - (min >> 2) + (min >> 4));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a point is inside a bounding box.
|
||||
/// </summary>
|
||||
/// <param name='v'>/param>
|
||||
/// <param name='min'></param>
|
||||
/// <param name='max'></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsInsideBox(Vector3 v, Vector3 min, Vector3 max)
|
||||
{
|
||||
return v.X >= min.X & v.Y >= min.Y && v.Z >= min.Z
|
||||
&& v.X <= max.X && v.Y <= max.Y && v.Z <= max.Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Are the co-ordinates of the new region visible from the old region?
|
||||
/// </summary>
|
||||
@@ -1007,6 +1020,38 @@ namespace OpenSim.Framework
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy data from one stream to another, leaving the read position of both streams at the beginning.
|
||||
/// </summary>
|
||||
/// <param name='inputStream'>
|
||||
/// Input stream. Must be seekable.
|
||||
/// </param>
|
||||
/// <exception cref='ArgumentException'>
|
||||
/// Thrown if the input stream is not seekable.
|
||||
/// </exception>
|
||||
public static Stream Copy(Stream inputStream)
|
||||
{
|
||||
if (!inputStream.CanSeek)
|
||||
throw new ArgumentException("Util.Copy(Stream inputStream) must receive an inputStream that can seek");
|
||||
|
||||
const int readSize = 256;
|
||||
byte[] buffer = new byte[readSize];
|
||||
MemoryStream ms = new MemoryStream();
|
||||
|
||||
int count = inputStream.Read(buffer, 0, readSize);
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
ms.Write(buffer, 0, count);
|
||||
count = inputStream.Read(buffer, 0, readSize);
|
||||
}
|
||||
|
||||
ms.Position = 0;
|
||||
inputStream.Position = 0;
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args)
|
||||
{
|
||||
return SendXmlRpcCommand(url, methodName, args);
|
||||
|
||||
@@ -53,10 +53,18 @@ namespace OpenSim.Framework
|
||||
LogManager.GetLogger(
|
||||
MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// Control the printing of certain debug messages.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If DebugLevel >= 3 then short notices about outgoing HTTP requests are logged.
|
||||
/// </remarks>
|
||||
public static int DebugLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Request number for diagnostic purposes.
|
||||
/// </summary>
|
||||
public static int RequestNumber = 0;
|
||||
public static int RequestNumber { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// this is the header field used to communicate the local request id
|
||||
@@ -146,7 +154,11 @@ namespace OpenSim.Framework
|
||||
private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed)
|
||||
{
|
||||
int reqnum = RequestNumber++;
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})",
|
||||
reqnum, method, url, timeout, compressed);
|
||||
|
||||
string errorMessage = "unknown error";
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
@@ -229,7 +241,7 @@ namespace OpenSim.Framework
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > LongCallTime)
|
||||
m_log.InfoFormat(
|
||||
"[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
"[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
method,
|
||||
url,
|
||||
@@ -238,10 +250,14 @@ namespace OpenSim.Framework
|
||||
strBuffer != null
|
||||
? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
|
||||
: "");
|
||||
else if (DebugLevel >= 4)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
|
||||
reqnum, tickdiff, tickdata);
|
||||
}
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage);
|
||||
"[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage);
|
||||
|
||||
return ErrorResponseMap(errorMessage);
|
||||
}
|
||||
@@ -317,7 +333,11 @@ namespace OpenSim.Framework
|
||||
{
|
||||
int reqnum = RequestNumber++;
|
||||
string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})",
|
||||
reqnum, method, url, timeout);
|
||||
|
||||
string errorMessage = "unknown error";
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
@@ -380,7 +400,7 @@ namespace OpenSim.Framework
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > LongCallTime)
|
||||
m_log.InfoFormat(
|
||||
"[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
"[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
method,
|
||||
url,
|
||||
@@ -389,9 +409,13 @@ namespace OpenSim.Framework
|
||||
queryString != null
|
||||
? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
|
||||
: "");
|
||||
else if (DebugLevel >= 4)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
|
||||
reqnum, tickdiff, tickdata);
|
||||
}
|
||||
|
||||
m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage);
|
||||
m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage);
|
||||
|
||||
return ErrorResponseMap(errorMessage);
|
||||
}
|
||||
@@ -643,7 +667,6 @@ namespace OpenSim.Framework
|
||||
/// <returns></returns>
|
||||
public static string[] GetPreferredImageTypes(string accept)
|
||||
{
|
||||
|
||||
if (accept == null || accept == string.Empty)
|
||||
return new string[0];
|
||||
|
||||
@@ -693,18 +716,31 @@ namespace OpenSim.Framework
|
||||
//
|
||||
public static void MakeRequest<TRequest, TResponse>(string verb,
|
||||
string requestUrl, TRequest obj, Action<TResponse> action)
|
||||
{
|
||||
MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, action, 0);
|
||||
}
|
||||
|
||||
public static void MakeRequest<TRequest, TResponse>(string verb,
|
||||
string requestUrl, TRequest obj, Action<TResponse> action,
|
||||
int maxConnections)
|
||||
{
|
||||
int reqnum = WebUtil.RequestNumber++;
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
if (WebUtil.DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
|
||||
reqnum, verb, requestUrl);
|
||||
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
|
||||
// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
|
||||
|
||||
Type type = typeof(TRequest);
|
||||
|
||||
WebRequest request = WebRequest.Create(requestUrl);
|
||||
HttpWebRequest ht = (HttpWebRequest)request;
|
||||
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
|
||||
ht.ServicePoint.ConnectionLimit = maxConnections;
|
||||
|
||||
WebResponse response = null;
|
||||
TResponse deserial = default(TResponse);
|
||||
XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
|
||||
@@ -854,7 +890,7 @@ namespace OpenSim.Framework
|
||||
}
|
||||
|
||||
m_log.InfoFormat(
|
||||
"[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
"[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
verb,
|
||||
requestUrl,
|
||||
@@ -862,6 +898,12 @@ namespace OpenSim.Framework
|
||||
tickdata,
|
||||
originalRequest);
|
||||
}
|
||||
else if (WebUtil.DebugLevel >= 4)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
|
||||
reqnum, tickdiff, tickdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -882,7 +924,11 @@ namespace OpenSim.Framework
|
||||
public static string MakeRequest(string verb, string requestUrl, string obj)
|
||||
{
|
||||
int reqnum = WebUtil.RequestNumber++;
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
if (WebUtil.DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
|
||||
reqnum, verb, requestUrl);
|
||||
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
@@ -967,13 +1013,17 @@ namespace OpenSim.Framework
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > WebUtil.LongCallTime)
|
||||
m_log.InfoFormat(
|
||||
"[FORMS]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
"[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
verb,
|
||||
requestUrl,
|
||||
tickdiff,
|
||||
tickdata,
|
||||
obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
|
||||
else if (WebUtil.DebugLevel >= 4)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
|
||||
reqnum, tickdiff, tickdata);
|
||||
|
||||
return respstring;
|
||||
}
|
||||
@@ -996,9 +1046,23 @@ namespace OpenSim.Framework
|
||||
/// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting
|
||||
/// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
|
||||
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
|
||||
{
|
||||
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0);
|
||||
}
|
||||
|
||||
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
|
||||
{
|
||||
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0);
|
||||
}
|
||||
|
||||
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
|
||||
{
|
||||
int reqnum = WebUtil.RequestNumber++;
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
if (WebUtil.DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
|
||||
reqnum, verb, requestUrl);
|
||||
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
@@ -1007,6 +1071,10 @@ namespace OpenSim.Framework
|
||||
TResponse deserial = default(TResponse);
|
||||
|
||||
WebRequest request = WebRequest.Create(requestUrl);
|
||||
HttpWebRequest ht = (HttpWebRequest)request;
|
||||
if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
|
||||
ht.ServicePoint.ConnectionLimit = maxConnections;
|
||||
|
||||
request.Method = verb;
|
||||
MemoryStream buffer = null;
|
||||
|
||||
@@ -1111,7 +1179,7 @@ namespace OpenSim.Framework
|
||||
}
|
||||
|
||||
m_log.InfoFormat(
|
||||
"[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
"[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
verb,
|
||||
requestUrl,
|
||||
@@ -1119,8 +1187,14 @@ namespace OpenSim.Framework
|
||||
tickdata,
|
||||
originalRequest);
|
||||
}
|
||||
else if (WebUtil.DebugLevel >= 4)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing",
|
||||
reqnum, tickdiff, tickdata);
|
||||
}
|
||||
|
||||
return deserial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using log4net.Config;
|
||||
@@ -73,6 +74,7 @@ namespace OpenSim
|
||||
AppDomain.CurrentDomain.UnhandledException +=
|
||||
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
|
||||
|
||||
ServicePointManager.DefaultConnectionLimit = 12;
|
||||
|
||||
// Add the arguments supplied when running the application to the configuration
|
||||
ArgvConfigSource configSource = new ArgvConfigSource(args);
|
||||
|
||||
@@ -254,8 +254,14 @@ namespace OpenSim
|
||||
m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
|
||||
|
||||
m_console.Commands.AddCommand("Debug", false, "debug scene",
|
||||
"debug scene <scripting> <collisions> <physics>",
|
||||
"Turn on scene debugging", Debug);
|
||||
"debug scene active|collisions|physics|scripting|teleport true|false",
|
||||
"Turn on scene debugging.",
|
||||
"If active is false then main scene update and maintenance loops are suspended.\n"
|
||||
+ "If collisions is false then collisions with other objects are turned off.\n"
|
||||
+ "If physics is false then all physics objects are non-physical.\n"
|
||||
+ "If scripting is false then no scripting operations happen.\n"
|
||||
+ "If teleport is true then some extra teleport debug information is logged.",
|
||||
Debug);
|
||||
|
||||
m_console.Commands.AddCommand("General", false, "change region",
|
||||
"change region <region name>",
|
||||
@@ -292,7 +298,7 @@ namespace OpenSim
|
||||
|
||||
m_console.Commands.AddCommand("Archiving", false, "save oar",
|
||||
//"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]",
|
||||
"save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]",
|
||||
"save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [--all] [<OAR path>]",
|
||||
"Save a region's data to an OAR archive.",
|
||||
// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
|
||||
"-h|--home=<url> adds the url of the profile service to the saved user information.\n"
|
||||
@@ -302,6 +308,7 @@ namespace OpenSim
|
||||
+ " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n"
|
||||
+ "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n"
|
||||
+ " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n"
|
||||
+ "--all saves all the regions in the simulator, instead of just the current region.\n"
|
||||
+ "The OAR path must be a filesystem path."
|
||||
+ " If this is not given then the oar is saved to region.oar in the current directory.",
|
||||
SaveOar);
|
||||
@@ -332,10 +339,6 @@ namespace OpenSim
|
||||
"show circuits",
|
||||
"Show agent circuit data", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("Comms", false, "show http-handlers",
|
||||
"show http-handlers",
|
||||
"Show all registered http handlers", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("Comms", false, "show pending-objects",
|
||||
"show pending-objects",
|
||||
"Show # of objects on the pending queues of all scene viewers", HandleShow);
|
||||
@@ -933,7 +936,8 @@ namespace OpenSim
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false");
|
||||
MainConsole.Instance.Output(
|
||||
"Usage: debug scene active|scripting|collisions|physics|teleport true|false");
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1013,33 +1017,6 @@ namespace OpenSim
|
||||
HandleShowCircuits();
|
||||
break;
|
||||
|
||||
case "http-handlers":
|
||||
System.Text.StringBuilder handlers = new System.Text.StringBuilder("Registered HTTP Handlers:\n");
|
||||
|
||||
handlers.AppendFormat("* XMLRPC:\n");
|
||||
foreach (String s in HttpServer.GetXmlRpcHandlerKeys())
|
||||
handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
handlers.AppendFormat("* HTTP:\n");
|
||||
List<String> poll = HttpServer.GetPollServiceHandlerKeys();
|
||||
foreach (String s in HttpServer.GetHTTPHandlerKeys())
|
||||
handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
|
||||
|
||||
handlers.AppendFormat("* Agent:\n");
|
||||
foreach (String s in HttpServer.GetAgentHandlerKeys())
|
||||
handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
handlers.AppendFormat("* LLSD:\n");
|
||||
foreach (String s in HttpServer.GetLLSDHandlerKeys())
|
||||
handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
handlers.AppendFormat("* StreamHandlers ({0}):\n", HttpServer.GetStreamHandlerKeys().Count);
|
||||
foreach (String s in HttpServer.GetStreamHandlerKeys())
|
||||
handlers.AppendFormat("\t{0}\n", s);
|
||||
|
||||
MainConsole.Instance.Output(handlers.ToString());
|
||||
break;
|
||||
|
||||
case "modules":
|
||||
MainConsole.Instance.Output("The currently loaded shared modules are:");
|
||||
foreach (IRegionModule module in m_moduleLoader.GetLoadedSharedModules)
|
||||
|
||||
@@ -223,8 +223,6 @@ namespace OpenSim
|
||||
|
||||
base.StartupSpecific();
|
||||
|
||||
m_stats = StatsManager.SimExtraStats;
|
||||
|
||||
// Create a ModuleLoader instance
|
||||
m_moduleLoader = new ModuleLoader(m_config.Source);
|
||||
|
||||
@@ -234,51 +232,51 @@ namespace OpenSim
|
||||
plugin.PostInitialise();
|
||||
}
|
||||
|
||||
AddPluginCommands();
|
||||
}
|
||||
|
||||
protected virtual void AddPluginCommands()
|
||||
{
|
||||
// If console exists add plugin commands.
|
||||
if (m_console != null)
|
||||
{
|
||||
List<string> topics = GetHelpTopics();
|
||||
StatsManager.RegisterConsoleCommands(m_console);
|
||||
AddPluginCommands(m_console);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string topic in topics)
|
||||
protected virtual void AddPluginCommands(CommandConsole console)
|
||||
{
|
||||
List<string> topics = GetHelpTopics();
|
||||
|
||||
foreach (string topic in topics)
|
||||
{
|
||||
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
|
||||
|
||||
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
|
||||
// away at some point.
|
||||
console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
|
||||
"help " + capitalizedTopic,
|
||||
"Get help on plugin command '" + topic + "'",
|
||||
HandleCommanderHelp);
|
||||
console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
|
||||
"help " + capitalizedTopic,
|
||||
"Get help on plugin command '" + topic + "'",
|
||||
HandleCommanderHelp);
|
||||
|
||||
ICommander commander = null;
|
||||
|
||||
Scene s = SceneManager.CurrentOrFirstScene;
|
||||
|
||||
if (s != null && s.GetCommanders() != null)
|
||||
{
|
||||
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
|
||||
if (s.GetCommanders().ContainsKey(topic))
|
||||
commander = s.GetCommanders()[topic];
|
||||
}
|
||||
|
||||
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
|
||||
// away at some point.
|
||||
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
|
||||
"help " + capitalizedTopic,
|
||||
"Get help on plugin command '" + topic + "'",
|
||||
HandleCommanderHelp);
|
||||
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
|
||||
"help " + capitalizedTopic,
|
||||
"Get help on plugin command '" + topic + "'",
|
||||
HandleCommanderHelp);
|
||||
if (commander == null)
|
||||
continue;
|
||||
|
||||
ICommander commander = null;
|
||||
|
||||
Scene s = SceneManager.CurrentOrFirstScene;
|
||||
|
||||
if (s != null && s.GetCommanders() != null)
|
||||
{
|
||||
if (s.GetCommanders().ContainsKey(topic))
|
||||
commander = s.GetCommanders()[topic];
|
||||
}
|
||||
|
||||
if (commander == null)
|
||||
continue;
|
||||
|
||||
foreach (string command in commander.Commands.Keys)
|
||||
{
|
||||
m_console.Commands.AddCommand(capitalizedTopic, false,
|
||||
topic + " " + command,
|
||||
topic + " " + commander.Commands[command].ShortHelp(),
|
||||
String.Empty, HandleCommanderCommand);
|
||||
}
|
||||
foreach (string command in commander.Commands.Keys)
|
||||
{
|
||||
console.Commands.AddCommand(capitalizedTopic, false,
|
||||
topic + " " + command,
|
||||
topic + " " + commander.Commands[command].ShortHelp(),
|
||||
String.Empty, HandleCommanderCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,8 +163,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
m_HostCapsObj.RegisterHandler(
|
||||
"SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
|
||||
// m_log.DebugFormat(
|
||||
// "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
|
||||
|
||||
//m_capsHandlers["MapLayer"] =
|
||||
// new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
|
||||
@@ -254,11 +254,12 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
public string SeedCapRequest(string request, string path, string param,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
// m_log.Debug("[CAPS]: Seed Caps Request in region: " + m_regionName);
|
||||
m_log.DebugFormat(
|
||||
"[CAPS]: Received SEED caps request in {0} for agent {1}", m_regionName, m_HostCapsObj.AgentID);
|
||||
|
||||
if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
m_log.WarnFormat(
|
||||
"[CAPS]: Unauthorized CAPS client {0} from {1}",
|
||||
m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
//scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack);
|
||||
|
||||
scene.EventManager.OnNewClient += OnNewClient;
|
||||
// scene.EventManager.OnNewClient += OnNewClient;
|
||||
|
||||
// TODO: Leaving these open, or closing them when we
|
||||
// become a child is incorrect. It messes up TP in a big
|
||||
@@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
// circuit is there.
|
||||
|
||||
scene.EventManager.OnClientClosed += ClientClosed;
|
||||
|
||||
scene.EventManager.OnMakeChildAgent += MakeChildAgent;
|
||||
scene.EventManager.OnRegisterCaps += OnRegisterCaps;
|
||||
|
||||
@@ -110,10 +111,10 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
false,
|
||||
"debug eq",
|
||||
"debug eq [0|1|2]",
|
||||
"Turn on event queue debugging"
|
||||
+ "<= 0 - turns off all event queue logging"
|
||||
+ ">= 1 - turns on outgoing event logging"
|
||||
+ ">= 2 - turns on poll notification",
|
||||
"Turn on event queue debugging\n"
|
||||
+ " <= 0 - turns off all event queue logging\n"
|
||||
+ " >= 1 - turns on outgoing event logging\n"
|
||||
+ " >= 2 - turns on poll notification",
|
||||
HandleDebugEq);
|
||||
}
|
||||
else
|
||||
@@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnNewClient(IClientAPI client)
|
||||
{
|
||||
//client.OnLogout += ClientClosed;
|
||||
}
|
||||
|
||||
// private void ClientClosed(IClientAPI client)
|
||||
// {
|
||||
// ClientClosed(client.AgentId);
|
||||
// }
|
||||
|
||||
private void ClientClosed(UUID agentID, Scene scene)
|
||||
{
|
||||
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
UUID capID = UUID.Random();
|
||||
|
||||
m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
|
||||
// m_log.DebugFormat("[REGION CONSOLE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
|
||||
caps.RegisterHandler(
|
||||
"SimConsoleAsync",
|
||||
new ConsoleHandler("/CAPS/" + capID + "/", "SimConsoleAsync", agentID, this, m_scene));
|
||||
|
||||
@@ -45,7 +45,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
public Packet Packet;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// No arg constructor.
|
||||
/// </summary>
|
||||
public IncomingPacket() {}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="client">Reference to the client this packet came from</param>
|
||||
/// <param name="packet">Packet data</param>
|
||||
|
||||
@@ -47,6 +47,7 @@ using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Timer = System.Timers.Timer;
|
||||
using AssetLandmark = OpenSim.Framework.AssetLandmark;
|
||||
using RegionFlags = OpenMetaverse.RegionFlags;
|
||||
using Nini.Config;
|
||||
|
||||
using System.IO;
|
||||
@@ -346,7 +347,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
private int m_moneyBalance;
|
||||
private int m_animationSequenceNumber = 1;
|
||||
private bool m_SendLogoutPacketWhenClosing = true;
|
||||
private AgentUpdateArgs lastarg;
|
||||
|
||||
/// <summary>
|
||||
/// We retain a single AgentUpdateArgs so that we can constantly reuse it rather than construct a new one for
|
||||
/// every single incoming AgentUpdate. Every client sends 10 AgentUpdate UDP messages per second, even if it
|
||||
/// is doing absolutely nothing.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This does mean that agent updates must be processed synchronously, at least for each client, and called methods
|
||||
/// cannot retain a reference to it outside of that method.
|
||||
/// </remarks>
|
||||
private AgentUpdateArgs m_lastAgentUpdateArgs;
|
||||
|
||||
protected Dictionary<PacketType, PacketProcessor> m_packetHandlers = new Dictionary<PacketType, PacketProcessor>();
|
||||
protected Dictionary<string, GenericMessage> m_genericPacketHandlers = new Dictionary<string, GenericMessage>(); //PauPaw:Local Generic Message handlers
|
||||
@@ -3921,7 +3932,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
|
||||
|
||||
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
|
||||
ImprovedTerseObjectUpdatePacket packet
|
||||
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate);
|
||||
|
||||
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
|
||||
packet.RegionData.TimeDilation = timeDilation;
|
||||
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
|
||||
@@ -3966,7 +3979,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
|
||||
|
||||
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
|
||||
ImprovedTerseObjectUpdatePacket packet
|
||||
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
|
||||
PacketType.ImprovedTerseObjectUpdate);
|
||||
|
||||
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
|
||||
packet.RegionData.TimeDilation = timeDilation;
|
||||
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
|
||||
@@ -4958,7 +4974,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Y, -64.0f, 64.0f), data, pos); pos += 2;
|
||||
Utils.UInt16ToBytes(Utils.FloatToUInt16(angularVelocity.Z, -64.0f, 64.0f), data, pos); pos += 2;
|
||||
|
||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock();
|
||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock block
|
||||
= PacketPool.Instance.GetDataBlock<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>();
|
||||
|
||||
block.Data = data;
|
||||
|
||||
if (textureEntry != null && textureEntry.Length > 0)
|
||||
@@ -5190,7 +5208,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
protected virtual void RegisterLocalPacketHandlers()
|
||||
{
|
||||
AddLocalPacketHandler(PacketType.LogoutRequest, HandleLogout);
|
||||
|
||||
// If AgentUpdate is ever handled asynchronously, then we will also need to construct a new AgentUpdateArgs
|
||||
// for each AgentUpdate packet.
|
||||
AddLocalPacketHandler(PacketType.AgentUpdate, HandleAgentUpdate, false);
|
||||
|
||||
AddLocalPacketHandler(PacketType.ViewerEffect, HandleViewerEffect, false);
|
||||
AddLocalPacketHandler(PacketType.AgentCachedTexture, HandleAgentTextureCached, false);
|
||||
AddLocalPacketHandler(PacketType.MultipleObjectUpdate, HandleMultipleObjUpdate, false);
|
||||
@@ -5417,80 +5439,83 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
#region Scene/Avatar
|
||||
|
||||
private bool HandleAgentUpdate(IClientAPI sener, Packet Pack)
|
||||
private bool HandleAgentUpdate(IClientAPI sener, Packet packet)
|
||||
{
|
||||
if (OnAgentUpdate != null)
|
||||
{
|
||||
bool update = false;
|
||||
AgentUpdatePacket agenUpdate = (AgentUpdatePacket)Pack;
|
||||
AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
|
||||
|
||||
#region Packet Session and User Check
|
||||
if (agenUpdate.AgentData.SessionID != SessionId || agenUpdate.AgentData.AgentID != AgentId)
|
||||
if (agentUpdate.AgentData.SessionID != SessionId || agentUpdate.AgentData.AgentID != AgentId)
|
||||
{
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
AgentUpdatePacket.AgentDataBlock x = agenUpdate.AgentData;
|
||||
bool update = false;
|
||||
AgentUpdatePacket.AgentDataBlock x = agentUpdate.AgentData;
|
||||
|
||||
// We can only check when we have something to check
|
||||
// against.
|
||||
|
||||
if (lastarg != null)
|
||||
if (m_lastAgentUpdateArgs != null)
|
||||
{
|
||||
// These should be ordered from most-likely to
|
||||
// least likely to change. I've made an initial
|
||||
// guess at that.
|
||||
update =
|
||||
(
|
||||
(x.BodyRotation != lastarg.BodyRotation) ||
|
||||
(x.CameraAtAxis != lastarg.CameraAtAxis) ||
|
||||
(x.CameraCenter != lastarg.CameraCenter) ||
|
||||
(x.CameraLeftAxis != lastarg.CameraLeftAxis) ||
|
||||
(x.CameraUpAxis != lastarg.CameraUpAxis) ||
|
||||
(x.ControlFlags != lastarg.ControlFlags) ||
|
||||
(x.Far != lastarg.Far) ||
|
||||
(x.Flags != lastarg.Flags) ||
|
||||
(x.State != lastarg.State) ||
|
||||
(x.HeadRotation != lastarg.HeadRotation) ||
|
||||
(x.SessionID != lastarg.SessionID) ||
|
||||
(x.AgentID != lastarg.AgentID)
|
||||
(x.BodyRotation != m_lastAgentUpdateArgs.BodyRotation) ||
|
||||
(x.CameraAtAxis != m_lastAgentUpdateArgs.CameraAtAxis) ||
|
||||
(x.CameraCenter != m_lastAgentUpdateArgs.CameraCenter) ||
|
||||
(x.CameraLeftAxis != m_lastAgentUpdateArgs.CameraLeftAxis) ||
|
||||
(x.CameraUpAxis != m_lastAgentUpdateArgs.CameraUpAxis) ||
|
||||
(x.ControlFlags != m_lastAgentUpdateArgs.ControlFlags) ||
|
||||
(x.Far != m_lastAgentUpdateArgs.Far) ||
|
||||
(x.Flags != m_lastAgentUpdateArgs.Flags) ||
|
||||
(x.State != m_lastAgentUpdateArgs.State) ||
|
||||
(x.HeadRotation != m_lastAgentUpdateArgs.HeadRotation) ||
|
||||
(x.SessionID != m_lastAgentUpdateArgs.SessionID) ||
|
||||
(x.AgentID != m_lastAgentUpdateArgs.AgentID)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lastAgentUpdateArgs = new AgentUpdateArgs();
|
||||
update = true;
|
||||
}
|
||||
|
||||
// These should be ordered from most-likely to
|
||||
// least likely to change. I've made an initial
|
||||
// guess at that.
|
||||
|
||||
if (update)
|
||||
{
|
||||
// m_log.DebugFormat("[LLCLIENTVIEW]: Triggered AgentUpdate for {0}", sener.Name);
|
||||
|
||||
AgentUpdateArgs arg = new AgentUpdateArgs();
|
||||
arg.AgentID = x.AgentID;
|
||||
arg.BodyRotation = x.BodyRotation;
|
||||
arg.CameraAtAxis = x.CameraAtAxis;
|
||||
arg.CameraCenter = x.CameraCenter;
|
||||
arg.CameraLeftAxis = x.CameraLeftAxis;
|
||||
arg.CameraUpAxis = x.CameraUpAxis;
|
||||
arg.ControlFlags = x.ControlFlags;
|
||||
arg.Far = x.Far;
|
||||
arg.Flags = x.Flags;
|
||||
arg.HeadRotation = x.HeadRotation;
|
||||
arg.SessionID = x.SessionID;
|
||||
arg.State = x.State;
|
||||
m_lastAgentUpdateArgs.AgentID = x.AgentID;
|
||||
m_lastAgentUpdateArgs.BodyRotation = x.BodyRotation;
|
||||
m_lastAgentUpdateArgs.CameraAtAxis = x.CameraAtAxis;
|
||||
m_lastAgentUpdateArgs.CameraCenter = x.CameraCenter;
|
||||
m_lastAgentUpdateArgs.CameraLeftAxis = x.CameraLeftAxis;
|
||||
m_lastAgentUpdateArgs.CameraUpAxis = x.CameraUpAxis;
|
||||
m_lastAgentUpdateArgs.ControlFlags = x.ControlFlags;
|
||||
m_lastAgentUpdateArgs.Far = x.Far;
|
||||
m_lastAgentUpdateArgs.Flags = x.Flags;
|
||||
m_lastAgentUpdateArgs.HeadRotation = x.HeadRotation;
|
||||
m_lastAgentUpdateArgs.SessionID = x.SessionID;
|
||||
m_lastAgentUpdateArgs.State = x.State;
|
||||
|
||||
UpdateAgent handlerAgentUpdate = OnAgentUpdate;
|
||||
UpdateAgent handlerPreAgentUpdate = OnPreAgentUpdate;
|
||||
lastarg = arg; // save this set of arguments for nexttime
|
||||
|
||||
if (handlerPreAgentUpdate != null)
|
||||
OnPreAgentUpdate(this, arg);
|
||||
OnPreAgentUpdate(this, m_lastAgentUpdateArgs);
|
||||
|
||||
if (handlerAgentUpdate != null)
|
||||
OnAgentUpdate(this, arg);
|
||||
OnAgentUpdate(this, m_lastAgentUpdateArgs);
|
||||
|
||||
handlerAgentUpdate = null;
|
||||
handlerPreAgentUpdate = null;
|
||||
}
|
||||
}
|
||||
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5862,7 +5887,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
msgpack.MessageBlock.ID,
|
||||
msgpack.MessageBlock.Offline != 0 ? true : false,
|
||||
msgpack.MessageBlock.Position,
|
||||
msgpack.MessageBlock.BinaryBucket);
|
||||
msgpack.MessageBlock.BinaryBucket,
|
||||
true);
|
||||
|
||||
handlerInstantMessage(this, im);
|
||||
}
|
||||
@@ -9054,7 +9080,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
#endregion
|
||||
|
||||
switch (Utils.BytesToString(messagePacket.MethodData.Method))
|
||||
string method = Utils.BytesToString(messagePacket.MethodData.Method);
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case "getinfo":
|
||||
if (((Scene)m_scene).Permissions.CanIssueEstateCommand(AgentId, false))
|
||||
@@ -9370,7 +9398,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return true;
|
||||
|
||||
default:
|
||||
m_log.Error("EstateOwnerMessage: Unknown method requested\n" + messagePacket);
|
||||
m_log.WarnFormat(
|
||||
"[LLCLIENTVIEW]: EstateOwnerMessage: Unknown method {0} requested for {1} in {2}",
|
||||
method, Name, Scene.Name);
|
||||
|
||||
for (int i = 0; i < messagePacket.ParamList.Length; i++)
|
||||
{
|
||||
EstateOwnerMessagePacket.ParamListBlock block = messagePacket.ParamList[i];
|
||||
string data = (string)Utils.BytesToString(block.Parameter);
|
||||
m_log.DebugFormat("[LLCLIENTVIEW]: Param {0}={1}", i, data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11756,7 +11794,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
logPacket = false;
|
||||
|
||||
if (DebugPacketLevel <= 50
|
||||
& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
|
||||
&& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
|
||||
logPacket = false;
|
||||
|
||||
if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
|
||||
@@ -11830,8 +11868,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
if (!ProcessPacketMethod(packet))
|
||||
m_log.Warn("[CLIENT]: unhandled packet " + packet.Type);
|
||||
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
}
|
||||
|
||||
private static PrimitiveBaseShape GetShapeFromAddPacket(ObjectAddPacket addPacket)
|
||||
@@ -12284,7 +12320,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
ushort timeDilation = Utils.FloatToUInt16(TIME_DILATION, 0.0f, 1.0f);
|
||||
|
||||
|
||||
ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
|
||||
ImprovedTerseObjectUpdatePacket packet
|
||||
= (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(
|
||||
PacketType.ImprovedTerseObjectUpdate);
|
||||
|
||||
packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
|
||||
packet.RegionData.TimeDilation = timeDilation;
|
||||
packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[1];
|
||||
|
||||
@@ -37,6 +37,7 @@ using log4net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse.Packets;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenMetaverse;
|
||||
@@ -100,9 +101,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
/// <summary>The measured resolution of Environment.TickCount</summary>
|
||||
public readonly float TickCountResolution;
|
||||
|
||||
/// <summary>Number of prim updates to put on the queue each time the
|
||||
/// OnQueueEmpty event is triggered for updates</summary>
|
||||
public readonly int PrimUpdatesPerCallback;
|
||||
|
||||
/// <summary>Number of texture packets to put on the queue each time the
|
||||
/// OnQueueEmpty event is triggered for textures</summary>
|
||||
public readonly int TextureSendLimit;
|
||||
@@ -111,6 +114,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
//PacketEventDictionary packetEvents = new PacketEventDictionary();
|
||||
/// <summary>Incoming packets that are awaiting handling</summary>
|
||||
private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
|
||||
|
||||
/// <summary></summary>
|
||||
//private UDPClientCollection m_clients = new UDPClientCollection();
|
||||
/// <summary>Bandwidth throttle for this UDP server</summary>
|
||||
@@ -121,28 +125,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
/// <summary>Manages authentication for agent circuits</summary>
|
||||
private AgentCircuitManager m_circuitManager;
|
||||
|
||||
/// <summary>Reference to the scene this UDP server is attached to</summary>
|
||||
protected Scene m_scene;
|
||||
|
||||
/// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
|
||||
private Location m_location;
|
||||
|
||||
/// <summary>The size of the receive buffer for the UDP socket. This value
|
||||
/// is passed up to the operating system and used in the system networking
|
||||
/// stack. Use zero to leave this value as the default</summary>
|
||||
private int m_recvBufferSize;
|
||||
|
||||
/// <summary>Flag to process packets asynchronously or synchronously</summary>
|
||||
private bool m_asyncPacketHandling;
|
||||
|
||||
/// <summary>Tracks whether or not a packet was sent each round so we know
|
||||
/// whether or not to sleep</summary>
|
||||
private bool m_packetSent;
|
||||
|
||||
/// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
|
||||
private int m_elapsedMSSinceLastStatReport = 0;
|
||||
|
||||
/// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
|
||||
private int m_tickLastOutgoingPacketHandler;
|
||||
|
||||
/// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
|
||||
private int m_elapsedMSOutgoingPacketHandler;
|
||||
|
||||
/// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
|
||||
private int m_elapsed100MSOutgoingPacketHandler;
|
||||
|
||||
/// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
|
||||
private int m_elapsed500MSOutgoingPacketHandler;
|
||||
|
||||
@@ -155,6 +168,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <summary>Flag to signal when clients should send pings</summary>
|
||||
protected bool m_sendPing;
|
||||
|
||||
private Pool<IncomingPacket> m_incomingPacketPool;
|
||||
|
||||
private int m_defaultRTO = 0;
|
||||
private int m_maxRTO = 0;
|
||||
private int m_ackTimeout = 0;
|
||||
@@ -175,7 +190,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// </summary>
|
||||
private IClientAPI m_currentIncomingClient;
|
||||
|
||||
public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
|
||||
public LLUDPServer(
|
||||
IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
|
||||
IConfigSource configSource, AgentCircuitManager circuitManager)
|
||||
: base(listenIP, (int)port)
|
||||
{
|
||||
#region Environment.TickCount Measurement
|
||||
@@ -222,6 +239,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_pausedAckTimeout = 1000 * 300; // 5 minutes
|
||||
}
|
||||
|
||||
// FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
|
||||
// However, there is no harm in temporarily doing it multiple times.
|
||||
IConfig packetConfig = configSource.Configs["PacketPool"];
|
||||
if (packetConfig != null)
|
||||
{
|
||||
PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
|
||||
PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
|
||||
UsePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", false);
|
||||
}
|
||||
|
||||
#region BinaryStats
|
||||
config = configSource.Configs["Statistics.Binary"];
|
||||
m_shouldCollectStats = false;
|
||||
@@ -249,20 +276,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
m_throttle = new TokenBucket(null, sceneThrottleBps);
|
||||
ThrottleRates = new ThrottleRates(configSource);
|
||||
|
||||
if (UsePools)
|
||||
m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (m_scene == null)
|
||||
throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
|
||||
StartInbound();
|
||||
StartOutbound();
|
||||
|
||||
m_elapsedMSSinceLastStatReport = Environment.TickCount;
|
||||
}
|
||||
|
||||
private void StartInbound()
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[LLUDPSERVER]: Starting the LLUDP server in {0} mode",
|
||||
m_asyncPacketHandling ? "asynchronous" : "synchronous");
|
||||
"[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
|
||||
m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
|
||||
|
||||
base.Start(m_recvBufferSize, m_asyncPacketHandling);
|
||||
base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
|
||||
|
||||
// Start the packet processing threads
|
||||
// This thread will process the packets received that are placed on the packetInbox
|
||||
Watchdog.StartThread(
|
||||
IncomingPacketHandler,
|
||||
string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
|
||||
@@ -271,6 +306,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
true,
|
||||
GetWatchdogIncomingAlarmData,
|
||||
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
private new void StartOutbound()
|
||||
{
|
||||
m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
|
||||
|
||||
base.StartOutbound();
|
||||
|
||||
Watchdog.StartThread(
|
||||
OutgoingPacketHandler,
|
||||
@@ -280,8 +322,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
true,
|
||||
GetWatchdogOutgoingAlarmData,
|
||||
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
m_elapsedMSSinceLastStatReport = Environment.TickCount;
|
||||
public void Stop()
|
||||
{
|
||||
m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
|
||||
base.StopOutbound();
|
||||
base.StopInbound();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -306,12 +353,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
|
||||
}
|
||||
|
||||
public new void Stop()
|
||||
{
|
||||
m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
|
||||
base.Stop();
|
||||
}
|
||||
|
||||
public void AddScene(IScene scene)
|
||||
{
|
||||
if (m_scene != null)
|
||||
@@ -328,6 +369,81 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
m_scene = (Scene)scene;
|
||||
m_location = new Location(m_scene.RegionInfo.RegionHandle);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp start",
|
||||
"debug lludp start <in|out|all>",
|
||||
"Control LLUDP packet processing.",
|
||||
"No effect if packet processing has already started.\n"
|
||||
+ "in - start inbound processing.\n"
|
||||
+ "out - start outbound processing.\n"
|
||||
+ "all - start in and outbound processing.\n",
|
||||
HandleStartCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp stop",
|
||||
"debug lludp stop <in|out|all>",
|
||||
"Stop LLUDP packet processing.",
|
||||
"No effect if packet processing has already stopped.\n"
|
||||
+ "in - stop inbound processing.\n"
|
||||
+ "out - stop outbound processing.\n"
|
||||
+ "all - stop in and outbound processing.\n",
|
||||
HandleStopCommand);
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"Debug",
|
||||
false,
|
||||
"debug lludp status",
|
||||
"debug lludp status",
|
||||
"Return status of LLUDP packet processing.",
|
||||
HandleStatusCommand);
|
||||
}
|
||||
|
||||
private void HandleStartCommand(string module, string[] args)
|
||||
{
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
|
||||
return;
|
||||
}
|
||||
|
||||
string subCommand = args[3];
|
||||
|
||||
if (subCommand == "in" || subCommand == "all")
|
||||
StartInbound();
|
||||
|
||||
if (subCommand == "out" || subCommand == "all")
|
||||
StartOutbound();
|
||||
}
|
||||
|
||||
private void HandleStopCommand(string module, string[] args)
|
||||
{
|
||||
if (args.Length != 4)
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
|
||||
return;
|
||||
}
|
||||
|
||||
string subCommand = args[3];
|
||||
|
||||
if (subCommand == "in" || subCommand == "all")
|
||||
StopInbound();
|
||||
|
||||
if (subCommand == "out" || subCommand == "all")
|
||||
StopOutbound();
|
||||
}
|
||||
|
||||
private void HandleStatusCommand(string module, string[] args)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
public bool HandlesRegion(Location x)
|
||||
@@ -411,6 +527,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
byte[] data = packet.ToBytes();
|
||||
SendPacketData(udpClient, data, packet.Type, category, method);
|
||||
}
|
||||
|
||||
PacketPool.Instance.ReturnPacket(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -695,7 +813,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
LLUDPClient udpClient = null;
|
||||
Packet packet = null;
|
||||
int packetEnd = buffer.DataLength - 1;
|
||||
IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
|
||||
IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
|
||||
|
||||
#region Decoding
|
||||
|
||||
@@ -705,7 +823,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
|
||||
// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
|
||||
|
||||
return; // Drop undersizd packet
|
||||
return; // Drop undersized packet
|
||||
}
|
||||
|
||||
int headerLen = 7;
|
||||
@@ -728,7 +846,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
try
|
||||
{
|
||||
packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
|
||||
// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
|
||||
// // Only allocate a buffer for zerodecoding if the packet is zerocoded
|
||||
// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
|
||||
// If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
|
||||
// assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
|
||||
// bytes are copied out).
|
||||
packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
|
||||
// Only allocate a buffer for zerodecoding if the packet is zerocoded
|
||||
((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
|
||||
}
|
||||
@@ -743,11 +867,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
return; // Drop short packet
|
||||
}
|
||||
catch(Exception e)
|
||||
catch (Exception e)
|
||||
{
|
||||
if (m_malformedCount < 100)
|
||||
m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
|
||||
|
||||
m_malformedCount++;
|
||||
|
||||
if ((m_malformedCount % 100000) == 0)
|
||||
m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
|
||||
}
|
||||
@@ -768,7 +894,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// UseCircuitCode handling
|
||||
if (packet.Type == PacketType.UseCircuitCode)
|
||||
{
|
||||
object[] array = new object[] { buffer, packet };
|
||||
// We need to copy the endpoint so that it doesn't get changed when another thread reuses the
|
||||
// buffer.
|
||||
object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
|
||||
|
||||
Util.FireAndForget(HandleUseCircuitCode, array);
|
||||
|
||||
@@ -777,7 +905,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
// Determine which agent this packet came from
|
||||
IClientAPI client;
|
||||
if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView))
|
||||
if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
|
||||
{
|
||||
//m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
|
||||
return;
|
||||
@@ -801,6 +929,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Handle appended ACKs
|
||||
if (packet.Header.AppendedAcks && packet.Header.AckList != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
|
||||
// packet.Header.AckList.Length, client.Name, m_scene.Name);
|
||||
|
||||
for (int i = 0; i < packet.Header.AckList.Length; i++)
|
||||
udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
|
||||
}
|
||||
@@ -810,6 +942,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
PacketAckPacket ackPacket = (PacketAckPacket)packet;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
|
||||
// ackPacket.Packets.Length, client.Name, m_scene.Name);
|
||||
|
||||
for (int i = 0; i < ackPacket.Packets.Length; i++)
|
||||
udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
|
||||
|
||||
@@ -823,6 +959,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
if (packet.Header.Reliable)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
|
||||
// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
|
||||
|
||||
udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
|
||||
|
||||
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
|
||||
@@ -869,6 +1009,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
if (packet.Type == PacketType.StartPingCheck)
|
||||
{
|
||||
// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
|
||||
|
||||
// We don't need to do anything else with ping checks
|
||||
StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
|
||||
CompletePing(udpClient, startPing.PingID.PingID);
|
||||
@@ -888,8 +1030,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
#endregion Ping Check Handling
|
||||
|
||||
IncomingPacket incomingPacket;
|
||||
|
||||
// Inbox insertion
|
||||
packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet));
|
||||
if (UsePools)
|
||||
{
|
||||
incomingPacket = m_incomingPacketPool.GetObject();
|
||||
incomingPacket.Client = (LLClientView)client;
|
||||
incomingPacket.Packet = packet;
|
||||
}
|
||||
else
|
||||
{
|
||||
incomingPacket = new IncomingPacket((LLClientView)client, packet);
|
||||
}
|
||||
|
||||
packetInbox.Enqueue(incomingPacket);
|
||||
}
|
||||
|
||||
#region BinaryStats
|
||||
@@ -975,21 +1130,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
private void HandleUseCircuitCode(object o)
|
||||
{
|
||||
IPEndPoint remoteEndPoint = null;
|
||||
IPEndPoint endPoint = null;
|
||||
IClientAPI client = null;
|
||||
|
||||
try
|
||||
{
|
||||
// DateTime startTime = DateTime.Now;
|
||||
object[] array = (object[])o;
|
||||
UDPPacketBuffer buffer = (UDPPacketBuffer)array[0];
|
||||
endPoint = (IPEndPoint)array[0];
|
||||
UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
|
||||
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint);
|
||||
|
||||
remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
|
||||
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
|
||||
|
||||
AuthenticateResponse sessionInfo;
|
||||
if (IsClientAuthorized(uccp, out sessionInfo))
|
||||
@@ -1000,13 +1153,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
uccp.CircuitCode.Code,
|
||||
uccp.CircuitCode.ID,
|
||||
uccp.CircuitCode.SessionID,
|
||||
remoteEndPoint,
|
||||
endPoint,
|
||||
sessionInfo);
|
||||
|
||||
// Send ack straight away to let the viewer know that the connection is active.
|
||||
// The client will be null if it already exists (e.g. if on a region crossing the client sends a use
|
||||
// circuit code to the existing child agent. This is not particularly obvious.
|
||||
SendAckImmediate(remoteEndPoint, uccp.Header.Sequence);
|
||||
SendAckImmediate(endPoint, uccp.Header.Sequence);
|
||||
|
||||
// We only want to send initial data to new clients, not ones which are being converted from child to root.
|
||||
if (client != null)
|
||||
@@ -1017,7 +1170,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Don't create clients for unauthorized requesters.
|
||||
m_log.WarnFormat(
|
||||
"[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
|
||||
uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint);
|
||||
uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat(
|
||||
@@ -1029,7 +1182,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
|
||||
remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a",
|
||||
endPoint != null ? endPoint.ToString() : "n/a",
|
||||
client != null ? client.Name : "unknown",
|
||||
client != null ? client.AgentId.ToString() : "unknown",
|
||||
e.Message,
|
||||
@@ -1094,20 +1247,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
IClientAPI client = null;
|
||||
|
||||
// In priciple there shouldn't be more than one thread here, ever.
|
||||
// But in case that happens, we need to synchronize this piece of code
|
||||
// because it's too important
|
||||
lock (this)
|
||||
// We currently synchronize this code across the whole scene to avoid issues such as
|
||||
// http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
|
||||
// consistently, this lock could probably be removed.
|
||||
lock (this)
|
||||
{
|
||||
if (!m_scene.TryGetClient(agentID, out client))
|
||||
{
|
||||
LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
|
||||
|
||||
|
||||
client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
|
||||
client.OnLogout += LogoutHandler;
|
||||
|
||||
|
||||
((LLClientView)client).DisableFacelights = m_disableFacelights;
|
||||
|
||||
|
||||
client.Start();
|
||||
}
|
||||
}
|
||||
@@ -1146,7 +1299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// on to en-US to avoid number parsing issues
|
||||
Culture.SetCurrentCulture();
|
||||
|
||||
while (base.IsRunning)
|
||||
while (IsRunningInbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -1161,7 +1314,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
|
||||
if (packetInbox.Dequeue(100, ref incomingPacket))
|
||||
{
|
||||
ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
|
||||
|
||||
if (UsePools)
|
||||
m_incomingPacketPool.ReturnObject(incomingPacket);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1188,7 +1346,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// Action generic every round
|
||||
Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
|
||||
|
||||
while (base.IsRunning)
|
||||
while (base.IsRunningOutbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@ using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenMetaverse
|
||||
{
|
||||
@@ -58,17 +59,29 @@ namespace OpenMetaverse
|
||||
/// <summary>Flag to process packets asynchronously or synchronously</summary>
|
||||
private bool m_asyncPacketHandling;
|
||||
|
||||
/// <summary>The all important shutdown flag</summary>
|
||||
private volatile bool m_shutdownFlag = true;
|
||||
/// <summary>
|
||||
/// Pool to use for handling data. May be null if UsePools = false;
|
||||
/// </summary>
|
||||
protected OpenSim.Framework.Pool<UDPPacketBuffer> m_pool;
|
||||
|
||||
/// <summary>Returns true if the server is currently listening, otherwise false</summary>
|
||||
public bool IsRunning { get { return !m_shutdownFlag; } }
|
||||
/// <summary>
|
||||
/// Are we to use object pool(s) to reduce memory churn when receiving data?
|
||||
/// </summary>
|
||||
public bool UsePools { get; protected set; }
|
||||
|
||||
/// <summary>Returns true if the server is currently listening for inbound packets, otherwise false</summary>
|
||||
public bool IsRunningInbound { get; private set; }
|
||||
|
||||
/// <summary>Returns true if the server is currently sending outbound packets, otherwise false</summary>
|
||||
/// <remarks>If IsRunningOut = false, then any request to send a packet is simply dropped.</remarks>
|
||||
public bool IsRunningOutbound { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
/// <param name="bindAddress">Local IP address to bind the server to</param>
|
||||
/// <param name="port">Port to listening for incoming UDP packets on</param>
|
||||
/// /// <param name="usePool">Are we to use an object pool to get objects for handing inbound data?</param>
|
||||
public OpenSimUDPBase(IPAddress bindAddress, int port)
|
||||
{
|
||||
m_localBindAddress = bindAddress;
|
||||
@@ -76,7 +89,7 @@ namespace OpenMetaverse
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start the UDP server
|
||||
/// Start inbound UDP packet handling.
|
||||
/// </summary>
|
||||
/// <param name="recvBufferSize">The size of the receive buffer for
|
||||
/// the UDP socket. This value is passed up to the operating system
|
||||
@@ -91,11 +104,16 @@ namespace OpenMetaverse
|
||||
/// manner (not throwing an exception when the remote side resets the
|
||||
/// connection). This call is ignored on Mono where the flag is not
|
||||
/// necessary</remarks>
|
||||
public void Start(int recvBufferSize, bool asyncPacketHandling)
|
||||
public void StartInbound(int recvBufferSize, bool asyncPacketHandling)
|
||||
{
|
||||
if (UsePools)
|
||||
m_pool = new Pool<UDPPacketBuffer>(() => new UDPPacketBuffer(), 500);
|
||||
else
|
||||
m_pool = null;
|
||||
|
||||
m_asyncPacketHandling = asyncPacketHandling;
|
||||
|
||||
if (m_shutdownFlag)
|
||||
if (!IsRunningInbound)
|
||||
{
|
||||
const int SIO_UDP_CONNRESET = -1744830452;
|
||||
|
||||
@@ -127,8 +145,7 @@ namespace OpenMetaverse
|
||||
|
||||
m_udpSocket.Bind(ipep);
|
||||
|
||||
// we're not shutting down, we're starting up
|
||||
m_shutdownFlag = false;
|
||||
IsRunningInbound = true;
|
||||
|
||||
// kick off an async receive. The Start() method will return, the
|
||||
// actual receives will occur asynchronously and will be caught in
|
||||
@@ -138,28 +155,41 @@ namespace OpenMetaverse
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops the UDP server
|
||||
/// Start outbound UDP packet handling.
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
public void StartOutbound()
|
||||
{
|
||||
if (!m_shutdownFlag)
|
||||
IsRunningOutbound = true;
|
||||
}
|
||||
|
||||
public void StopInbound()
|
||||
{
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
|
||||
// will deny any more reader locks, in effect blocking all other send/receive
|
||||
// threads. Once we have the lock, we set shutdownFlag to inform the other
|
||||
// threads. Once we have the lock, we set IsRunningInbound = false to inform the other
|
||||
// threads that the socket is closed.
|
||||
m_shutdownFlag = true;
|
||||
IsRunningInbound = false;
|
||||
m_udpSocket.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopOutbound()
|
||||
{
|
||||
IsRunningOutbound = false;
|
||||
}
|
||||
|
||||
private void AsyncBeginReceive()
|
||||
{
|
||||
// allocate a packet buffer
|
||||
//WrappedObject<UDPPacketBuffer> wrappedBuffer = Pool.CheckOut();
|
||||
UDPPacketBuffer buf = new UDPPacketBuffer();
|
||||
UDPPacketBuffer buf;
|
||||
|
||||
if (!m_shutdownFlag)
|
||||
if (UsePools)
|
||||
buf = m_pool.GetObject();
|
||||
else
|
||||
buf = new UDPPacketBuffer();
|
||||
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -212,7 +242,7 @@ namespace OpenMetaverse
|
||||
{
|
||||
// Asynchronous receive operations will complete here through the call
|
||||
// to AsyncBeginReceive
|
||||
if (!m_shutdownFlag)
|
||||
if (IsRunningInbound)
|
||||
{
|
||||
// Asynchronous mode will start another receive before the
|
||||
// callback for this packet is even fired. Very parallel :-)
|
||||
@@ -221,8 +251,6 @@ namespace OpenMetaverse
|
||||
|
||||
// get the buffer that was created in AsyncBeginReceive
|
||||
// this is the received data
|
||||
//WrappedObject<UDPPacketBuffer> wrappedBuffer = (WrappedObject<UDPPacketBuffer>)iar.AsyncState;
|
||||
//UDPPacketBuffer buffer = wrappedBuffer.Instance;
|
||||
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
|
||||
|
||||
try
|
||||
@@ -239,7 +267,8 @@ namespace OpenMetaverse
|
||||
catch (ObjectDisposedException) { }
|
||||
finally
|
||||
{
|
||||
//wrappedBuffer.Dispose();
|
||||
if (UsePools)
|
||||
m_pool.ReturnObject(buffer);
|
||||
|
||||
// Synchronous mode waits until the packet callback completes
|
||||
// before starting the receive to fetch another packet
|
||||
@@ -252,7 +281,7 @@ namespace OpenMetaverse
|
||||
|
||||
public void AsyncBeginSend(UDPPacketBuffer buf)
|
||||
{
|
||||
if (!m_shutdownFlag)
|
||||
if (IsRunningOutbound)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -31,10 +31,10 @@ using System.Reflection;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Packets;
|
||||
using log4net;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
|
||||
public sealed class PacketPool
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
@@ -44,14 +44,28 @@ namespace OpenSim.Framework
|
||||
private bool packetPoolEnabled = true;
|
||||
private bool dataBlockPoolEnabled = true;
|
||||
|
||||
private PercentageStat m_packetsReusedStat = new PercentageStat(
|
||||
"PacketsReused",
|
||||
"Packets reused",
|
||||
"clientstack",
|
||||
"packetpool",
|
||||
StatVerbosity.Debug,
|
||||
"Number of packets reused out of all requests to the packet pool");
|
||||
|
||||
private PercentageStat m_blocksReusedStat = new PercentageStat(
|
||||
"BlocksReused",
|
||||
"Blocks reused",
|
||||
"clientstack",
|
||||
"packetpool",
|
||||
StatVerbosity.Debug,
|
||||
"Number of data blocks reused out of all requests to the packet pool");
|
||||
|
||||
/// <summary>
|
||||
/// Pool of packets available for reuse.
|
||||
/// </summary>
|
||||
private readonly Dictionary<PacketType, Stack<Packet>> pool = new Dictionary<PacketType, Stack<Packet>>();
|
||||
|
||||
private static Dictionary<Type, Stack<Object>> DataBlocks =
|
||||
new Dictionary<Type, Stack<Object>>();
|
||||
|
||||
static PacketPool()
|
||||
{
|
||||
}
|
||||
private static Dictionary<Type, Stack<Object>> DataBlocks = new Dictionary<Type, Stack<Object>>();
|
||||
|
||||
public static PacketPool Instance
|
||||
{
|
||||
@@ -70,8 +84,21 @@ namespace OpenSim.Framework
|
||||
get { return dataBlockPoolEnabled; }
|
||||
}
|
||||
|
||||
private PacketPool()
|
||||
{
|
||||
StatsManager.RegisterStat(m_packetsReusedStat);
|
||||
StatsManager.RegisterStat(m_blocksReusedStat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a packet of the given type.
|
||||
/// </summary>
|
||||
/// <param name='type'></param>
|
||||
/// <returns>Guaranteed to always return a packet, whether from the pool or newly constructed.</returns>
|
||||
public Packet GetPacket(PacketType type)
|
||||
{
|
||||
m_packetsReusedStat.Consequent++;
|
||||
|
||||
Packet packet;
|
||||
|
||||
if (!packetPoolEnabled)
|
||||
@@ -81,13 +108,19 @@ namespace OpenSim.Framework
|
||||
{
|
||||
if (!pool.ContainsKey(type) || pool[type] == null || (pool[type]).Count == 0)
|
||||
{
|
||||
// m_log.DebugFormat("[PACKETPOOL]: Building {0} packet", type);
|
||||
|
||||
// Creating a new packet if we cannot reuse an old package
|
||||
packet = Packet.BuildPacket(type);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.DebugFormat("[PACKETPOOL]: Pulling {0} packet", type);
|
||||
|
||||
// Recycle old packages
|
||||
packet = (pool[type]).Pop();
|
||||
m_packetsReusedStat.Antecedent++;
|
||||
|
||||
packet = pool[type].Pop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +169,7 @@ namespace OpenSim.Framework
|
||||
{
|
||||
PacketType type = GetType(bytes);
|
||||
|
||||
Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
|
||||
// Array.Clear(zeroBuffer, 0, zeroBuffer.Length);
|
||||
|
||||
int i = 0;
|
||||
Packet packet = GetPacket(type);
|
||||
@@ -183,6 +216,7 @@ namespace OpenSim.Framework
|
||||
switch (packet.Type)
|
||||
{
|
||||
// List pooling packets here
|
||||
case PacketType.AgentUpdate:
|
||||
case PacketType.PacketAck:
|
||||
case PacketType.ObjectUpdate:
|
||||
case PacketType.ImprovedTerseObjectUpdate:
|
||||
@@ -197,7 +231,9 @@ namespace OpenSim.Framework
|
||||
|
||||
if ((pool[type]).Count < 50)
|
||||
{
|
||||
(pool[type]).Push(packet);
|
||||
// m_log.DebugFormat("[PACKETPOOL]: Pushing {0} packet", type);
|
||||
|
||||
pool[type].Push(packet);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -209,16 +245,21 @@ namespace OpenSim.Framework
|
||||
}
|
||||
}
|
||||
|
||||
public static T GetDataBlock<T>() where T: new()
|
||||
public T GetDataBlock<T>() where T: new()
|
||||
{
|
||||
lock (DataBlocks)
|
||||
{
|
||||
m_blocksReusedStat.Consequent++;
|
||||
|
||||
Stack<Object> s;
|
||||
|
||||
if (DataBlocks.TryGetValue(typeof(T), out s))
|
||||
{
|
||||
if (s.Count > 0)
|
||||
{
|
||||
m_blocksReusedStat.Antecedent++;
|
||||
return (T)s.Pop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -229,7 +270,7 @@ namespace OpenSim.Framework
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReturnDataBlock<T>(T block) where T: new()
|
||||
public void ReturnDataBlock<T>(T block) where T: new()
|
||||
{
|
||||
if (block == null)
|
||||
return;
|
||||
@@ -244,4 +285,4 @@ namespace OpenSim.Framework
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
/// This will contain basic tests for the LindenUDP client stack
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class BasicCircuitTests
|
||||
public class BasicCircuitTests : OpenSimTestCase
|
||||
{
|
||||
private Scene m_scene;
|
||||
private TestLLUDPServer m_udpServer;
|
||||
@@ -65,8 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
public void TestAddClient()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// XmlConfigurator.Configure();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
AddUdpServer();
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace OpenSim.Region.ClientStack
|
||||
|
||||
protected override void StartupSpecific()
|
||||
{
|
||||
SceneManager = new SceneManager();
|
||||
SceneManager = SceneManager.Instance;
|
||||
m_clientStackManager = CreateClientStackManager();
|
||||
|
||||
Initialize();
|
||||
|
||||
@@ -57,39 +57,36 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a xfer uploader if one does not already exist.
|
||||
/// Return the xfer uploader for the given transaction.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If an uploader does not already exist for this transaction then it is created, otherwise the existing
|
||||
/// uploader is returned.
|
||||
/// </remarks>
|
||||
/// <param name="transactionID"></param>
|
||||
/// <param name="assetID">
|
||||
/// We must transfer the new asset ID into the uploader on creation, otherwise
|
||||
/// we can see race conditions with other threads which can retrieve an item before it is updated with the new
|
||||
/// asset id.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The xfer uploader requested. Null if one is already in existence.
|
||||
/// FIXME: This is a bizarre thing to do, and is probably meant to signal an error condition if multiple
|
||||
/// transfers are made. Needs to be corrected.
|
||||
/// </returns>
|
||||
public AssetXferUploader RequestXferUploader(UUID transactionID, UUID assetID)
|
||||
/// <returns>The asset xfer uploader</returns>
|
||||
public AssetXferUploader RequestXferUploader(UUID transactionID)
|
||||
{
|
||||
AssetXferUploader uploader;
|
||||
|
||||
lock (XferUploaders)
|
||||
{
|
||||
if (!XferUploaders.ContainsKey(transactionID))
|
||||
{
|
||||
AssetXferUploader uploader = new AssetXferUploader(this, m_Scene, assetID, m_dumpAssetsToFile);
|
||||
uploader = new AssetXferUploader(this, m_Scene, transactionID, m_dumpAssetsToFile);
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[AGENT ASSETS TRANSACTIONS]: Adding asset xfer uploader {0} since it didn't previously exist", transactionID);
|
||||
|
||||
XferUploaders.Add(transactionID, uploader);
|
||||
|
||||
return uploader;
|
||||
}
|
||||
else
|
||||
{
|
||||
uploader = XferUploaders[transactionID];
|
||||
}
|
||||
}
|
||||
|
||||
m_log.WarnFormat("[AGENT ASSETS TRANSACTIONS]: Ignoring request for asset xfer uploader {0} since it already exists", transactionID);
|
||||
|
||||
return null;
|
||||
return uploader;
|
||||
}
|
||||
|
||||
public void HandleXfer(ulong xferID, uint packetID, byte[] data)
|
||||
@@ -151,115 +148,28 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
string description, string name, sbyte invType,
|
||||
sbyte type, byte wearableType, uint nextOwnerMask)
|
||||
{
|
||||
AssetXferUploader uploader = null;
|
||||
AssetXferUploader uploader = RequestXferUploader(transactionID);
|
||||
|
||||
lock (XferUploaders)
|
||||
{
|
||||
if (XferUploaders.ContainsKey(transactionID))
|
||||
uploader = XferUploaders[transactionID];
|
||||
}
|
||||
|
||||
if (uploader != null)
|
||||
uploader.RequestCreateInventoryItem(
|
||||
remoteClient, transactionID, folderID,
|
||||
callbackID, description, name, invType, type,
|
||||
wearableType, nextOwnerMask);
|
||||
else
|
||||
m_log.ErrorFormat(
|
||||
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to create inventory item {1} from {2}",
|
||||
transactionID, name, remoteClient.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an uploaded asset. If the data is successfully retrieved,
|
||||
/// the transaction will be removed.
|
||||
/// </summary>
|
||||
/// <param name="transactionID"></param>
|
||||
/// <returns>The asset if the upload has completed, null if it has not.</returns>
|
||||
private AssetBase GetTransactionAsset(UUID transactionID)
|
||||
{
|
||||
lock (XferUploaders)
|
||||
{
|
||||
if (XferUploaders.ContainsKey(transactionID))
|
||||
{
|
||||
AssetXferUploader uploader = XferUploaders[transactionID];
|
||||
AssetBase asset = uploader.GetAssetData();
|
||||
RemoveXferUploader(transactionID);
|
||||
|
||||
return asset;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
uploader.RequestCreateInventoryItem(
|
||||
remoteClient, folderID, callbackID,
|
||||
description, name, invType, type, wearableType, nextOwnerMask);
|
||||
}
|
||||
|
||||
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient,
|
||||
SceneObjectPart part, UUID transactionID,
|
||||
TaskInventoryItem item)
|
||||
{
|
||||
AssetXferUploader uploader = null;
|
||||
AssetXferUploader uploader = RequestXferUploader(transactionID);
|
||||
|
||||
lock (XferUploaders)
|
||||
{
|
||||
if (XferUploaders.ContainsKey(transactionID))
|
||||
uploader = XferUploaders[transactionID];
|
||||
}
|
||||
|
||||
if (uploader != null)
|
||||
{
|
||||
AssetBase asset = GetTransactionAsset(transactionID);
|
||||
|
||||
// Only legacy viewers use this, and they prefer CAPS, which
|
||||
// we have, so this really never runs.
|
||||
// Allow it, but only for "safe" types.
|
||||
if ((InventoryType)item.InvType != InventoryType.Notecard &&
|
||||
(InventoryType)item.InvType != InventoryType.LSL)
|
||||
return;
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[AGENT ASSETS TRANSACTIONS]: Updating item {0} in {1} for transaction {2}",
|
||||
// item.Name, part.Name, transactionID);
|
||||
|
||||
asset.FullID = UUID.Random();
|
||||
asset.Name = item.Name;
|
||||
asset.Description = item.Description;
|
||||
asset.Type = (sbyte)item.Type;
|
||||
item.AssetID = asset.FullID;
|
||||
|
||||
m_Scene.AssetService.Store(asset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update task inventory item {1} in {2}",
|
||||
transactionID, item.Name, part.Name);
|
||||
}
|
||||
uploader.RequestUpdateTaskInventoryItem(remoteClient, item);
|
||||
}
|
||||
|
||||
public void RequestUpdateInventoryItem(IClientAPI remoteClient,
|
||||
UUID transactionID, InventoryItemBase item)
|
||||
{
|
||||
AssetXferUploader uploader = null;
|
||||
AssetXferUploader uploader = RequestXferUploader(transactionID);
|
||||
|
||||
lock (XferUploaders)
|
||||
{
|
||||
if (XferUploaders.ContainsKey(transactionID))
|
||||
uploader = XferUploaders[transactionID];
|
||||
}
|
||||
|
||||
if (uploader != null)
|
||||
{
|
||||
uploader.RequestUpdateInventoryItem(remoteClient, transactionID, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[AGENT ASSET TRANSACTIONS]: Could not find uploader with transaction ID {0} when handling request to update inventory item {1} for {2}",
|
||||
transactionID, item.Name, remoteClient.Name);
|
||||
}
|
||||
uploader.RequestUpdateInventoryItem(remoteClient, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,7 +215,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
|
||||
"[ASSET TRANSACTION MODULE] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
|
||||
item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
|
||||
|
||||
AgentAssetTransactions transactions =
|
||||
@@ -274,13 +274,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
}
|
||||
|
||||
AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId);
|
||||
AssetXferUploader uploader = transactions.RequestXferUploader(transaction, assetID);
|
||||
|
||||
if (uploader != null)
|
||||
{
|
||||
uploader.Initialise(remoteClient, assetID, transaction, type,
|
||||
data, storeLocal, tempFile);
|
||||
}
|
||||
AssetXferUploader uploader = transactions.RequestXferUploader(transaction);
|
||||
uploader.StartUpload(remoteClient, assetID, transaction, type, data, storeLocal, tempFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -40,39 +40,75 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// Upload state.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// New -> Uploading -> Complete
|
||||
/// </remarks>
|
||||
private enum UploadState
|
||||
{
|
||||
New,
|
||||
Uploading,
|
||||
Complete
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reference to the object that holds this uploader. Used to remove ourselves from it's list if we
|
||||
/// are performing a delayed update.
|
||||
/// </summary>
|
||||
AgentAssetTransactions m_transactions;
|
||||
|
||||
private UploadState m_uploadState = UploadState.New;
|
||||
|
||||
private AssetBase m_asset;
|
||||
private UUID InventFolder = UUID.Zero;
|
||||
private sbyte invType = 0;
|
||||
|
||||
private bool m_createItem = false;
|
||||
private uint m_createItemCallback = 0;
|
||||
private bool m_updateItem = false;
|
||||
private bool m_createItem;
|
||||
private uint m_createItemCallback;
|
||||
|
||||
private bool m_updateItem;
|
||||
private InventoryItemBase m_updateItemData;
|
||||
|
||||
private bool m_updateTaskItem;
|
||||
private TaskInventoryItem m_updateTaskItemData;
|
||||
|
||||
private string m_description = String.Empty;
|
||||
private bool m_dumpAssetToFile;
|
||||
private bool m_finished = false;
|
||||
private string m_name = String.Empty;
|
||||
private bool m_storeLocal;
|
||||
// private bool m_storeLocal;
|
||||
private uint nextPerm = 0;
|
||||
private IClientAPI ourClient;
|
||||
private UUID TransactionID = UUID.Zero;
|
||||
|
||||
private UUID m_transactionID;
|
||||
|
||||
private sbyte type = 0;
|
||||
private byte wearableType = 0;
|
||||
public ulong XferID;
|
||||
private Scene m_Scene;
|
||||
|
||||
public AssetXferUploader(AgentAssetTransactions transactions, Scene scene, UUID assetID, bool dumpAssetToFile)
|
||||
/// <summary>
|
||||
/// AssetXferUploader constructor
|
||||
/// </summary>
|
||||
/// <param name='transactions'>/param>
|
||||
/// <param name='scene'></param>
|
||||
/// <param name='transactionID'></param>
|
||||
/// <param name='dumpAssetToFile'>
|
||||
/// If true then when the asset is uploaded it is dumped to a file with the format
|
||||
/// String.Format("{6}_{7}_{0:d2}{1:d2}{2:d2}_{3:d2}{4:d2}{5:d2}.dat",
|
||||
/// now.Year, now.Month, now.Day, now.Hour, now.Minute,
|
||||
/// now.Second, m_asset.Name, m_asset.Type);
|
||||
/// for debugging purposes.
|
||||
/// </param>
|
||||
public AssetXferUploader(
|
||||
AgentAssetTransactions transactions, Scene scene, UUID transactionID, bool dumpAssetToFile)
|
||||
{
|
||||
m_asset = new AssetBase();
|
||||
|
||||
m_transactions = transactions;
|
||||
m_transactionID = transactionID;
|
||||
m_Scene = scene;
|
||||
m_asset = new AssetBase() { FullID = assetID };
|
||||
m_dumpAssetToFile = dumpAssetToFile;
|
||||
}
|
||||
|
||||
@@ -118,30 +154,50 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialise asset transfer from the client
|
||||
/// Start asset transfer from the client
|
||||
/// </summary>
|
||||
/// <param name="xferID"></param>
|
||||
/// <param name="packetID"></param>
|
||||
/// <param name="data"></param>
|
||||
public void Initialise(IClientAPI remoteClient, UUID assetID,
|
||||
UUID transaction, sbyte type, byte[] data, bool storeLocal,
|
||||
bool tempFile)
|
||||
/// <param name="remoteClient"></param>
|
||||
/// <param name="assetID"></param>
|
||||
/// <param name="transaction"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="data">
|
||||
/// Optional data. If present then the asset is created immediately with this data
|
||||
/// rather than requesting an upload from the client. The data must be longer than 2 bytes.
|
||||
/// </param>
|
||||
/// <param name="storeLocal"></param>
|
||||
/// <param name="tempFile"></param>
|
||||
public void StartUpload(
|
||||
IClientAPI remoteClient, UUID assetID, UUID transaction, sbyte type, byte[] data, bool storeLocal,
|
||||
bool tempFile)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[ASSET XFER UPLOADER]: Initialised xfer from {0}, asset {1}, transaction {2}, type {3}, storeLocal {4}, tempFile {5}, already received data length {6}",
|
||||
// remoteClient.Name, assetID, transaction, type, storeLocal, tempFile, data.Length);
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (m_uploadState != UploadState.New)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[ASSET XFER UPLOADER]: Tried to start upload of asset {0}, transaction {1} for {2} but this is already in state {3}. Aborting.",
|
||||
assetID, transaction, remoteClient.Name, m_uploadState);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_uploadState = UploadState.Uploading;
|
||||
}
|
||||
|
||||
ourClient = remoteClient;
|
||||
m_asset.Name = "blank";
|
||||
m_asset.Description = "empty";
|
||||
|
||||
m_asset.FullID = assetID;
|
||||
m_asset.Type = type;
|
||||
m_asset.CreatorID = remoteClient.AgentId.ToString();
|
||||
m_asset.Data = data;
|
||||
m_asset.Local = storeLocal;
|
||||
m_asset.Temporary = tempFile;
|
||||
|
||||
TransactionID = transaction;
|
||||
m_storeLocal = storeLocal;
|
||||
// m_storeLocal = storeLocal;
|
||||
|
||||
if (m_asset.Data.Length > 2)
|
||||
{
|
||||
@@ -166,36 +222,35 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
|
||||
protected void SendCompleteMessage()
|
||||
{
|
||||
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true,
|
||||
m_asset.FullID);
|
||||
|
||||
// We must lock in order to avoid a race with a separate thread dealing with an inventory item or create
|
||||
// message from other client UDP.
|
||||
lock (this)
|
||||
{
|
||||
m_finished = true;
|
||||
m_uploadState = UploadState.Complete;
|
||||
|
||||
ourClient.SendAssetUploadCompleteMessage(m_asset.Type, true, m_asset.FullID);
|
||||
|
||||
if (m_createItem)
|
||||
{
|
||||
DoCreateItem(m_createItemCallback);
|
||||
CompleteCreateItem(m_createItemCallback);
|
||||
}
|
||||
else if (m_updateItem)
|
||||
{
|
||||
StoreAssetForItemUpdate(m_updateItemData);
|
||||
|
||||
// Remove ourselves from the list of transactions if completion was delayed until the transaction
|
||||
// was complete.
|
||||
// TODO: Should probably do the same for create item.
|
||||
m_transactions.RemoveXferUploader(TransactionID);
|
||||
CompleteItemUpdate(m_updateItemData);
|
||||
}
|
||||
else if (m_storeLocal)
|
||||
else if (m_updateTaskItem)
|
||||
{
|
||||
m_Scene.AssetService.Store(m_asset);
|
||||
CompleteTaskItemUpdate(m_updateTaskItemData);
|
||||
}
|
||||
// else if (m_storeLocal)
|
||||
// {
|
||||
// m_Scene.AssetService.Store(m_asset);
|
||||
// }
|
||||
}
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ASSET XFER UPLOADER]: Uploaded asset {0} for transaction {1}",
|
||||
m_asset.FullID, TransactionID);
|
||||
m_asset.FullID, m_transactionID);
|
||||
|
||||
if (m_dumpAssetToFile)
|
||||
{
|
||||
@@ -223,40 +278,37 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
}
|
||||
|
||||
public void RequestCreateInventoryItem(IClientAPI remoteClient,
|
||||
UUID transactionID, UUID folderID, uint callbackID,
|
||||
UUID folderID, uint callbackID,
|
||||
string description, string name, sbyte invType,
|
||||
sbyte type, byte wearableType, uint nextOwnerMask)
|
||||
{
|
||||
if (TransactionID == transactionID)
|
||||
{
|
||||
InventFolder = folderID;
|
||||
m_name = name;
|
||||
m_description = description;
|
||||
this.type = type;
|
||||
this.invType = invType;
|
||||
this.wearableType = wearableType;
|
||||
nextPerm = nextOwnerMask;
|
||||
m_asset.Name = name;
|
||||
m_asset.Description = description;
|
||||
m_asset.Type = type;
|
||||
InventFolder = folderID;
|
||||
m_name = name;
|
||||
m_description = description;
|
||||
this.type = type;
|
||||
this.invType = invType;
|
||||
this.wearableType = wearableType;
|
||||
nextPerm = nextOwnerMask;
|
||||
m_asset.Name = name;
|
||||
m_asset.Description = description;
|
||||
m_asset.Type = type;
|
||||
|
||||
// We must lock to avoid a race with a separate thread uploading the asset.
|
||||
lock (this)
|
||||
// We must lock to avoid a race with a separate thread uploading the asset.
|
||||
lock (this)
|
||||
{
|
||||
if (m_uploadState == UploadState.Complete)
|
||||
{
|
||||
if (m_finished)
|
||||
{
|
||||
DoCreateItem(callbackID);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_createItem = true; //set flag so the inventory item is created when upload is complete
|
||||
m_createItemCallback = callbackID;
|
||||
}
|
||||
CompleteCreateItem(callbackID);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_createItem = true; //set flag so the inventory item is created when upload is complete
|
||||
m_createItemCallback = callbackID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestUpdateInventoryItem(IClientAPI remoteClient, UUID transactionID, InventoryItemBase item)
|
||||
public void RequestUpdateInventoryItem(IClientAPI remoteClient, InventoryItemBase item)
|
||||
{
|
||||
// We must lock to avoid a race with a separate thread uploading the asset.
|
||||
lock (this)
|
||||
@@ -271,9 +323,9 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
item.AssetID = m_asset.FullID;
|
||||
m_Scene.InventoryService.UpdateItem(item);
|
||||
|
||||
if (m_finished)
|
||||
if (m_uploadState == UploadState.Complete)
|
||||
{
|
||||
StoreAssetForItemUpdate(item);
|
||||
CompleteItemUpdate(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -287,20 +339,59 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestUpdateTaskInventoryItem(IClientAPI remoteClient, TaskInventoryItem taskItem)
|
||||
{
|
||||
// We must lock to avoid a race with a separate thread uploading the asset.
|
||||
lock (this)
|
||||
{
|
||||
m_asset.Name = taskItem.Name;
|
||||
m_asset.Description = taskItem.Description;
|
||||
m_asset.Type = (sbyte)taskItem.Type;
|
||||
taskItem.AssetID = m_asset.FullID;
|
||||
|
||||
if (m_uploadState == UploadState.Complete)
|
||||
{
|
||||
CompleteTaskItemUpdate(taskItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_updateTaskItem = true;
|
||||
m_updateTaskItemData = taskItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Store the asset for the given item.
|
||||
/// Store the asset for the given item when it has been uploaded.
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
private void StoreAssetForItemUpdate(InventoryItemBase item)
|
||||
private void CompleteItemUpdate(InventoryItemBase item)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier item update for {1} for {2}",
|
||||
// m_asset.FullID, item.Name, ourClient.Name);
|
||||
|
||||
m_Scene.AssetService.Store(m_asset);
|
||||
|
||||
m_transactions.RemoveXferUploader(m_transactionID);
|
||||
}
|
||||
|
||||
private void DoCreateItem(uint callbackID)
|
||||
/// <summary>
|
||||
/// Store the asset for the given task item when it has been uploaded.
|
||||
/// </summary>
|
||||
/// <param name="taskItem"></param>
|
||||
private void CompleteTaskItemUpdate(TaskInventoryItem taskItem)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[ASSET XFER UPLOADER]: Storing asset {0} for earlier task item update for {1} for {2}",
|
||||
// m_asset.FullID, taskItem.Name, ourClient.Name);
|
||||
|
||||
m_Scene.AssetService.Store(m_asset);
|
||||
|
||||
m_transactions.RemoveXferUploader(m_transactionID);
|
||||
}
|
||||
|
||||
private void CompleteCreateItem(uint callbackID)
|
||||
{
|
||||
m_Scene.AssetService.Store(m_asset);
|
||||
|
||||
@@ -326,20 +417,8 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
ourClient.SendInventoryItemCreateUpdate(item, callbackID);
|
||||
else
|
||||
ourClient.SendAlertMessage("Unable to create inventory item");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the asset data uploaded in this transfer.
|
||||
/// </summary>
|
||||
/// <returns>null if the asset has not finished uploading</returns>
|
||||
public AssetBase GetAssetData()
|
||||
{
|
||||
if (m_finished)
|
||||
{
|
||||
return m_asset;
|
||||
}
|
||||
|
||||
return null;
|
||||
m_transactions.RemoveXferUploader(m_transactionID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ using OpenSim.Services.Interfaces;
|
||||
[assembly: Addin("FlotsamAssetCache", "1.1")]
|
||||
[assembly: AddinDependency("OpenSim", "0.5")]
|
||||
|
||||
namespace Flotsam.RegionModules.AssetCache
|
||||
namespace OpenSim.Region.CoreModules.Asset
|
||||
{
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
|
||||
public class FlotsamAssetCache : ISharedRegionModule, IImprovedAssetCache, IAssetService
|
||||
@@ -107,8 +107,6 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
private IAssetService m_AssetService;
|
||||
private List<Scene> m_Scenes = new List<Scene>();
|
||||
|
||||
private bool m_DeepScanBeforePurge;
|
||||
|
||||
public FlotsamAssetCache()
|
||||
{
|
||||
m_InvalidChars.AddRange(Path.GetInvalidPathChars());
|
||||
@@ -170,8 +168,6 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
m_CacheDirectoryTierLen = assetConfig.GetInt("CacheDirectoryTierLength", m_CacheDirectoryTierLen);
|
||||
|
||||
m_CacheWarnAt = assetConfig.GetInt("CacheWarnAt", m_CacheWarnAt);
|
||||
|
||||
m_DeepScanBeforePurge = assetConfig.GetBoolean("DeepScanBeforePurge", m_DeepScanBeforePurge);
|
||||
}
|
||||
|
||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Cache Directory {0}", m_CacheDirectory);
|
||||
@@ -506,13 +502,10 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
// Purge all files last accessed prior to this point
|
||||
DateTime purgeLine = DateTime.Now - m_FileExpiration;
|
||||
|
||||
// An optional deep scan at this point will ensure assets present in scenes,
|
||||
// or referenced by objects in the scene, but not recently accessed
|
||||
// are not purged.
|
||||
if (m_DeepScanBeforePurge)
|
||||
{
|
||||
CacheScenes();
|
||||
}
|
||||
// An asset cache may contain local non-temporary assets that are not in the asset service. Therefore,
|
||||
// before cleaning up expired files we must scan the objects in the scene to make sure that we retain
|
||||
// such local assets if they have not been recently accessed.
|
||||
TouchAllSceneAssets(false);
|
||||
|
||||
foreach (string dir in Directory.GetDirectories(m_CacheDirectory))
|
||||
{
|
||||
@@ -705,11 +698,14 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through all Scenes, doing a deep scan through assets
|
||||
/// to cache all assets present in the scene or referenced by assets
|
||||
/// in the scene
|
||||
/// to update the access time of all assets present in the scene or referenced by assets
|
||||
/// in the scene.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private int CacheScenes()
|
||||
/// <param name="storeUncached">
|
||||
/// If true, then assets scanned which are not found in cache are added to the cache.
|
||||
/// </param>
|
||||
/// <returns>Number of distinct asset references found in the scene.</returns>
|
||||
private int TouchAllSceneAssets(bool storeUncached)
|
||||
{
|
||||
UuidGatherer gatherer = new UuidGatherer(m_AssetService);
|
||||
|
||||
@@ -732,7 +728,7 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
{
|
||||
File.SetLastAccessTime(filename, DateTime.Now);
|
||||
}
|
||||
else
|
||||
else if (storeUncached)
|
||||
{
|
||||
m_AssetService.Get(assetID.ToString());
|
||||
}
|
||||
@@ -860,13 +856,14 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case "assets":
|
||||
m_log.Info("[FLOTSAM ASSET CACHE]: Caching all assets, in all scenes.");
|
||||
m_log.Info("[FLOTSAM ASSET CACHE]: Ensuring assets are cached for all scenes.");
|
||||
|
||||
Util.FireAndForget(delegate {
|
||||
int assetsCached = CacheScenes();
|
||||
m_log.InfoFormat("[FLOTSAM ASSET CACHE]: Completed Scene Caching, {0} assets found.", assetsCached);
|
||||
int assetReferenceTotal = TouchAllSceneAssets(true);
|
||||
m_log.InfoFormat(
|
||||
"[FLOTSAM ASSET CACHE]: Completed check with {0} assets.",
|
||||
assetReferenceTotal);
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
@@ -35,7 +35,6 @@ using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Assets;
|
||||
using Flotsam.RegionModules.AssetCache;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.Framework.Scenes.Serialization;
|
||||
|
||||
@@ -238,8 +238,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
sp.ClearAttachments();
|
||||
}
|
||||
|
||||
|
||||
public bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp)
|
||||
{
|
||||
if (!Enabled)
|
||||
return false;
|
||||
|
||||
if (AttachObjectInternal(sp, group, attachmentPt, silent, temp))
|
||||
{
|
||||
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp)
|
||||
{
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
@@ -392,6 +406,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
}
|
||||
|
||||
public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId)
|
||||
{
|
||||
DetachSingleAttachmentToGround(sp, soLocalId, sp.AbsolutePosition, Quaternion.Identity);
|
||||
}
|
||||
|
||||
public void DetachSingleAttachmentToGround(IScenePresence sp, uint soLocalId, Vector3 absolutePos, Quaternion absoluteRot)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
@@ -434,7 +453,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
so.FromItemID = UUID.Zero;
|
||||
|
||||
SceneObjectPart rootPart = so.RootPart;
|
||||
so.AbsolutePosition = sp.AbsolutePosition;
|
||||
so.AbsolutePosition = absolutePos;
|
||||
if (absoluteRot != Quaternion.Identity)
|
||||
{
|
||||
so.UpdateGroupRotationR(absoluteRot);
|
||||
}
|
||||
so.AttachedAvatar = UUID.Zero;
|
||||
rootPart.SetParentLocalId(0);
|
||||
so.ClearPartAttachmentData();
|
||||
@@ -794,7 +817,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
// This will throw if the attachment fails
|
||||
try
|
||||
{
|
||||
AttachObject(sp, objatt, attachmentPt, false, false);
|
||||
AttachObjectInternal(sp, objatt, attachmentPt, false, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -859,6 +882,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID);
|
||||
item = m_scene.InventoryService.GetItem(item);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
|
||||
if (changed && m_scene.AvatarFactory != null)
|
||||
{
|
||||
@@ -948,15 +974,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
AttachmentPt &= 0x7f;
|
||||
|
||||
// Calls attach with a Zero position
|
||||
if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, false))
|
||||
{
|
||||
// m_log.Debug(
|
||||
// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
|
||||
// + ", AttachmentPoint: " + AttachmentPt);
|
||||
|
||||
// Save avatar attachment information
|
||||
m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);
|
||||
}
|
||||
AttachObject(sp, part.ParentGroup, AttachmentPt, false, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -62,7 +62,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
public class AttachmentsModuleTests : OpenSimTestCase
|
||||
{
|
||||
private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
|
||||
private OSChatMessage m_osChatMessageReceived;
|
||||
// private OSChatMessage m_osChatMessageReceived;
|
||||
|
||||
// Used to test whether the operations have fired the attach event. Must be reset after each test.
|
||||
private int m_numberOfAttachEventsFired;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void FixtureInit()
|
||||
@@ -83,7 +86,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
{
|
||||
// Console.WriteLine("Got chat [{0}]", oscm.Message);
|
||||
|
||||
m_osChatMessageReceived = oscm;
|
||||
// m_osChatMessageReceived = oscm;
|
||||
m_chatEvent.Set();
|
||||
}
|
||||
|
||||
@@ -99,6 +102,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
|
||||
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
|
||||
|
||||
scene.EventManager.OnAttach += (localID, itemID, avatarID) => m_numberOfAttachEventsFired++;
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
@@ -181,6 +186,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||
@@ -189,6 +196,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false);
|
||||
|
||||
// Check status on scene presence
|
||||
@@ -216,7 +224,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// TestHelpers.DisableLogging();
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -228,6 +237,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||
@@ -247,6 +258,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
Assert.That(sp.HasAttachments(), Is.False);
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -261,6 +275,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
@@ -280,6 +295,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -338,6 +356,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
ISceneEntity so
|
||||
= scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
|
||||
|
||||
// Check scene presence status
|
||||
@@ -353,6 +373,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
// Check object in scene
|
||||
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -369,6 +392,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
SceneObjectGroup so
|
||||
= (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
|
||||
|
||||
// Check status on scene presence
|
||||
@@ -380,6 +405,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -461,10 +489,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0];
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.IncomingCloseAgent(presence.UUID, false);
|
||||
|
||||
// Check that we can't retrieve this attachment from the scene.
|
||||
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -480,6 +512,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
|
||||
acd.Appearance = new AvatarAppearance();
|
||||
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
|
||||
|
||||
Assert.That(presence.HasAttachments(), Is.True);
|
||||
@@ -502,6 +536,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events. We expect OnAttach to fire on login.
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -522,10 +559,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
Vector3 newPosition = new Vector3(1, 2, 4);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
|
||||
|
||||
Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
|
||||
Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -574,6 +615,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Vector3 teleportPosition = new Vector3(10, 11, 12);
|
||||
Vector3 teleportLookAt = new Vector3(20, 21, 22);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
sceneA.RequestTeleportLocation(
|
||||
beforeTeleportSp.ControllingClient,
|
||||
sceneB.RegionInfo.RegionHandle,
|
||||
@@ -616,29 +658,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
|
||||
|
||||
Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
// I'm commenting this test because scene setup NEEDS InventoryService to
|
||||
// be non-null
|
||||
//[Test]
|
||||
// public void T032_CrossAttachments()
|
||||
// {
|
||||
// TestHelpers.InMethod();
|
||||
//
|
||||
// ScenePresence presence = scene.GetScenePresence(agent1);
|
||||
// ScenePresence presence2 = scene2.GetScenePresence(agent1);
|
||||
// presence2.AddAttachment(sog1);
|
||||
// presence2.AddAttachment(sog2);
|
||||
//
|
||||
// ISharedRegionModule serialiser = new SerialiserModule();
|
||||
// SceneHelpers.SetupSceneModules(scene, new IniConfigSource(), serialiser);
|
||||
// SceneHelpers.SetupSceneModules(scene2, new IniConfigSource(), serialiser);
|
||||
//
|
||||
// Assert.That(presence.HasAttachments(), Is.False, "Presence has attachments before cross");
|
||||
//
|
||||
// //Assert.That(presence2.CrossAttachmentsIntoNewRegion(region1, true), Is.True, "Cross was not successful");
|
||||
// Assert.That(presence2.HasAttachments(), Is.False, "Presence2 objects were not deleted");
|
||||
// Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects");
|
||||
// }
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -525,7 +525,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
{
|
||||
for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
|
||||
{
|
||||
for (int j = 0; j < appearance.Wearables[j].Count; j++)
|
||||
for (int j = 0; j < appearance.Wearables[i].Count; j++)
|
||||
{
|
||||
if (appearance.Wearables[i][j].ItemID == UUID.Zero)
|
||||
continue;
|
||||
@@ -533,6 +533,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
// Ignore ruth's assets
|
||||
if (appearance.Wearables[i][j].ItemID == AvatarWearable.DefaultWearables[i][0].ItemID)
|
||||
continue;
|
||||
|
||||
InventoryItemBase baseItem = new InventoryItemBase(appearance.Wearables[i][j].ItemID, userID);
|
||||
baseItem = invService.GetItem(baseItem);
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
client.FirstName+" "+client.LastName,
|
||||
destID, (byte)211, false,
|
||||
String.Empty,
|
||||
transactionID, false, new Vector3(), new byte[0]),
|
||||
transactionID, false, new Vector3(), new byte[0], true),
|
||||
delegate(bool success) {} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,9 +482,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
Util.FireAndForget(
|
||||
delegate
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}",
|
||||
friendList.Count, agentID, online);
|
||||
// m_log.DebugFormat(
|
||||
// "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}",
|
||||
// friendList.Count, agentID, online);
|
||||
|
||||
// Notify about this user status
|
||||
StatusNotify(friendList, agentID, online);
|
||||
|
||||
@@ -297,6 +297,74 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: This code was placed here to try and accomdate RLV which moves given folders named #RLV/~<name>
|
||||
// to a folder called name in #RLV. However, this approach may not be ultimately correct - from analysis
|
||||
// of Firestorm 4.2.2 on sending an InventoryOffered instead of TaskInventoryOffered (as was previously
|
||||
// done), the viewer itself would appear to move and rename the folder, rather than the simulator doing it here.
|
||||
else if (im.dialog == (byte) InstantMessageDialog.TaskInventoryAccepted)
|
||||
{
|
||||
UUID destinationFolderID = UUID.Zero;
|
||||
|
||||
if (im.binaryBucket != null && im.binaryBucket.Length >= 16)
|
||||
{
|
||||
destinationFolderID = new UUID(im.binaryBucket, 0);
|
||||
}
|
||||
|
||||
if (destinationFolderID != UUID.Zero)
|
||||
{
|
||||
InventoryFolderBase destinationFolder = new InventoryFolderBase(destinationFolderID, client.AgentId);
|
||||
if (destinationFolder == null)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[INVENTORY TRANSFER]: TaskInventoryAccepted message from {0} in {1} specified folder {2} which does not exist",
|
||||
client.Name, scene.Name, destinationFolderID);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
IInventoryService invService = scene.InventoryService;
|
||||
|
||||
UUID inventoryID = new UUID(im.imSessionID); // The inventory item/folder, back from it's trip
|
||||
|
||||
InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
|
||||
item = invService.GetItem(item);
|
||||
InventoryFolderBase folder = null;
|
||||
UUID? previousParentFolderID = null;
|
||||
|
||||
if (item != null) // It's an item
|
||||
{
|
||||
previousParentFolderID = item.Folder;
|
||||
item.Folder = destinationFolderID;
|
||||
|
||||
invService.DeleteItems(item.Owner, new List<UUID>() { item.ID });
|
||||
scene.AddInventoryItem(client, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
folder = new InventoryFolderBase(inventoryID, client.AgentId);
|
||||
folder = invService.GetFolder(folder);
|
||||
|
||||
if (folder != null) // It's a folder
|
||||
{
|
||||
previousParentFolderID = folder.ParentID;
|
||||
folder.ParentID = destinationFolderID;
|
||||
invService.MoveFolder(folder);
|
||||
}
|
||||
}
|
||||
|
||||
// Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
|
||||
if (previousParentFolderID != null)
|
||||
{
|
||||
InventoryFolderBase previousParentFolder
|
||||
= new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
|
||||
previousParentFolder = invService.GetFolder(previousParentFolder);
|
||||
scene.SendInventoryUpdate(client, previousParentFolder, true, true);
|
||||
|
||||
scene.SendInventoryUpdate(client, destinationFolder, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (
|
||||
im.dialog == (byte)InstantMessageDialog.InventoryDeclined
|
||||
|| im.dialog == (byte)InstantMessageDialog.TaskInventoryDeclined)
|
||||
@@ -315,9 +383,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||
InventoryItemBase item = new InventoryItemBase(inventoryID, client.AgentId);
|
||||
item = invService.GetItem(item);
|
||||
InventoryFolderBase folder = null;
|
||||
UUID? previousParentFolderID = null;
|
||||
|
||||
if (item != null && trashFolder != null)
|
||||
{
|
||||
previousParentFolderID = item.Folder;
|
||||
item.Folder = trashFolder.ID;
|
||||
|
||||
// Diva comment: can't we just update this item???
|
||||
@@ -333,6 +403,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||
|
||||
if (folder != null & trashFolder != null)
|
||||
{
|
||||
previousParentFolderID = folder.ParentID;
|
||||
folder.ParentID = trashFolder.ID;
|
||||
invService.MoveFolder(folder);
|
||||
}
|
||||
@@ -352,6 +423,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Transfer
|
||||
client.SendAgentAlertMessage("Unable to delete "+
|
||||
"received inventory" + reason, false);
|
||||
}
|
||||
// Tell client about updates to original parent and new parent (this should probably be factored with existing move item/folder code).
|
||||
else if (previousParentFolderID != null)
|
||||
{
|
||||
InventoryFolderBase previousParentFolder
|
||||
= new InventoryFolderBase((UUID)previousParentFolderID, client.AgentId);
|
||||
previousParentFolder = invService.GetFolder(previousParentFolder);
|
||||
scene.SendInventoryUpdate(client, previousParentFolder, true, true);
|
||||
|
||||
scene.SendInventoryUpdate(client, trashFolder, true, true);
|
||||
}
|
||||
|
||||
ScenePresence user = scene.GetScenePresence(new UUID(im.toAgentID));
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
|
||||
client.FirstName+" "+client.LastName, targetid,
|
||||
(byte)InstantMessageDialog.RequestTeleport, false,
|
||||
message, sessionID, false, presence.AbsolutePosition,
|
||||
new Byte[0]);
|
||||
new Byte[0], true);
|
||||
m.RegionID = client.Scene.RegionInfo.RegionID.Guid;
|
||||
|
||||
m_log.DebugFormat("[HG LURE MODULE]: RequestTeleport sessionID={0}, regionID={1}, message={2}", m.imSessionID, m.RegionID, m.message);
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
|
||||
client.FirstName+" "+client.LastName, targetid,
|
||||
(byte)InstantMessageDialog.RequestTeleport, false,
|
||||
message, dest, false, presence.AbsolutePosition,
|
||||
new Byte[0]);
|
||||
new Byte[0], true);
|
||||
|
||||
if (m_TransferModule != null)
|
||||
{
|
||||
|
||||
@@ -323,6 +323,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate assorted conditions
|
||||
string reason = string.Empty;
|
||||
if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason))
|
||||
{
|
||||
sp.ControllingClient.SendTeleportFailed(reason);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// This is it
|
||||
//
|
||||
@@ -354,6 +362,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing to validate here
|
||||
protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
|
||||
{
|
||||
reason = String.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance is within the max transfer distance.
|
||||
/// </summary>
|
||||
@@ -471,6 +486,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
if (sp.ParentID != (uint)0)
|
||||
sp.StandUp();
|
||||
|
||||
// At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
|
||||
// the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
|
||||
sp.ControllingClient.SendTeleportStart(teleportFlags);
|
||||
|
||||
// the avatar.Close below will clear the child region list. We need this below for (possibly)
|
||||
@@ -546,8 +563,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
// So let's wait
|
||||
Thread.Sleep(200);
|
||||
|
||||
// At least on LL 3.3.4 for teleports between different regions on the same simulator this appears
|
||||
// unnecessary - teleport will succeed and SEED caps will be requested without it (though possibly
|
||||
// only on TeleportFinish). This is untested for region teleport between different simulators
|
||||
// though this probably also works.
|
||||
m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -568,7 +588,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
|
||||
//sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent...");
|
||||
|
||||
if (!UpdateAgent(reg, finalDestination, agent))
|
||||
if (!UpdateAgent(reg, finalDestination, agent, sp))
|
||||
{
|
||||
// Region doesn't take it
|
||||
m_log.WarnFormat(
|
||||
@@ -695,7 +715,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return success;
|
||||
}
|
||||
|
||||
protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent)
|
||||
protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp)
|
||||
{
|
||||
return Scene.SimulationService.UpdateAgent(finalDestination, agent);
|
||||
}
|
||||
@@ -1053,6 +1073,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
Scene initiatingScene)
|
||||
{
|
||||
Thread.Sleep(10000);
|
||||
|
||||
IMessageTransferModule im = initiatingScene.RequestModuleInterface<IMessageTransferModule>();
|
||||
if (im != null)
|
||||
{
|
||||
@@ -1065,11 +1086,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
(uint)(int)position.X,
|
||||
(uint)(int)position.Y,
|
||||
(uint)(int)position.Z);
|
||||
GridInstantMessage m = new GridInstantMessage(initiatingScene, UUID.Zero,
|
||||
"Region", agent.UUID,
|
||||
(byte)InstantMessageDialog.GodLikeRequestTeleport, false,
|
||||
"", gotoLocation, false, new Vector3(127, 0, 0),
|
||||
new Byte[0]);
|
||||
|
||||
GridInstantMessage m
|
||||
= new GridInstantMessage(
|
||||
initiatingScene,
|
||||
UUID.Zero,
|
||||
"Region",
|
||||
agent.UUID,
|
||||
(byte)InstantMessageDialog.GodLikeRequestTeleport,
|
||||
false,
|
||||
"",
|
||||
gotoLocation,
|
||||
false,
|
||||
new Vector3(127, 0, 0),
|
||||
new Byte[0],
|
||||
false);
|
||||
|
||||
im.SendInstantMessage(m, delegate(bool success)
|
||||
{
|
||||
m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success);
|
||||
|
||||
@@ -54,6 +54,59 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
|
||||
private GatekeeperServiceConnector m_GatekeeperConnector;
|
||||
|
||||
protected bool m_RestrictAppearanceAbroad;
|
||||
protected string m_AccountName;
|
||||
protected List<AvatarAppearance> m_ExportedAppearances;
|
||||
protected List<AvatarAttachment> m_Attachs;
|
||||
|
||||
protected List<AvatarAppearance> ExportedAppearance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_ExportedAppearances != null)
|
||||
return m_ExportedAppearances;
|
||||
|
||||
m_ExportedAppearances = new List<AvatarAppearance>();
|
||||
m_Attachs = new List<AvatarAttachment>();
|
||||
|
||||
string[] names = m_AccountName.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
foreach (string name in names)
|
||||
{
|
||||
string[] parts = name.Trim().Split();
|
||||
if (parts.Length != 2)
|
||||
{
|
||||
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Wrong user account name format {0}. Specify 'First Last'", name);
|
||||
return null;
|
||||
}
|
||||
UserAccount account = Scene.UserAccountService.GetUserAccount(UUID.Zero, parts[0], parts[1]);
|
||||
if (account == null)
|
||||
{
|
||||
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unknown account {0}", m_AccountName);
|
||||
return null;
|
||||
}
|
||||
AvatarAppearance a = Scene.AvatarService.GetAppearance(account.PrincipalID);
|
||||
if (a != null)
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Successfully retrieved appearance for {0}", name);
|
||||
|
||||
foreach (AvatarAttachment att in a.GetAttachments())
|
||||
{
|
||||
InventoryItemBase item = new InventoryItemBase(att.ItemID, account.PrincipalID);
|
||||
item = Scene.InventoryService.GetItem(item);
|
||||
if (item != null)
|
||||
a.SetAttachment(att.AttachPoint, att.ItemID, item.AssetID);
|
||||
else
|
||||
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to retrieve item {0} from inventory {1}", att.ItemID, name);
|
||||
}
|
||||
|
||||
m_ExportedAppearances.Add(a);
|
||||
m_Attachs.AddRange(a.GetAttachments());
|
||||
}
|
||||
|
||||
return m_ExportedAppearances;
|
||||
}
|
||||
}
|
||||
|
||||
#region ISharedRegionModule
|
||||
|
||||
public override string Name
|
||||
@@ -72,8 +125,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
{
|
||||
IConfig transferConfig = source.Configs["EntityTransfer"];
|
||||
if (transferConfig != null)
|
||||
{
|
||||
m_levelHGTeleport = transferConfig.GetInt("LevelHGTeleport", 0);
|
||||
|
||||
m_RestrictAppearanceAbroad = transferConfig.GetBoolean("RestrictAppearanceAbroad", false);
|
||||
if (m_RestrictAppearanceAbroad)
|
||||
{
|
||||
m_AccountName = transferConfig.GetString("AccountForAppearance", string.Empty);
|
||||
if (m_AccountName == string.Empty)
|
||||
m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is on, but no account has been given for avatar appearance!");
|
||||
}
|
||||
}
|
||||
|
||||
InitialiseCommon(source);
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
|
||||
}
|
||||
@@ -85,7 +148,36 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
base.AddRegion(scene);
|
||||
|
||||
if (m_Enabled)
|
||||
{
|
||||
scene.RegisterModuleInterface<IUserAgentVerificationModule>(this);
|
||||
scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject;
|
||||
}
|
||||
}
|
||||
|
||||
void OnIncomingSceneObject(SceneObjectGroup so)
|
||||
{
|
||||
if (!so.IsAttachment)
|
||||
return;
|
||||
|
||||
if (so.Scene.UserManagementModule.IsLocalGridUser(so.AttachedAvatar))
|
||||
return;
|
||||
|
||||
// foreign user
|
||||
AgentCircuitData aCircuit = so.Scene.AuthenticateHandler.GetAgentCircuitData(so.AttachedAvatar);
|
||||
if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
|
||||
{
|
||||
if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI"))
|
||||
{
|
||||
string url = aCircuit.ServiceURLs["AssetServerURI"].ToString();
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Incoming attachement {0} for HG user {1} with asset server {2}", so.Name, so.AttachedAvatar, url);
|
||||
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
|
||||
HGUuidGatherer uuidGatherer = new HGUuidGatherer(so.Scene.AssetService, url);
|
||||
uuidGatherer.GatherAssetUuids(so, ids);
|
||||
|
||||
foreach (KeyValuePair<UUID, AssetType> kvp in ids)
|
||||
uuidGatherer.FetchAsset(kvp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNewClient(IClientAPI client)
|
||||
@@ -120,7 +212,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID);
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags);
|
||||
|
||||
if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
||||
if ((flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
||||
{
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID);
|
||||
GridRegion real_destination = m_GatekeeperConnector.GetHyperlinkRegion(region, region.RegionID);
|
||||
@@ -140,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return true;
|
||||
|
||||
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
|
||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -153,6 +245,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
{
|
||||
// Log them out of this grid
|
||||
Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
|
||||
string userId = Scene.UserManagementModule.GetUserUUI(sp.UUID);
|
||||
Scene.GridUserService.LoggedOut(userId, UUID.Zero, Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +256,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
reason = string.Empty;
|
||||
logout = false;
|
||||
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
|
||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
||||
{
|
||||
// this user is going to another grid
|
||||
// check if HyperGrid teleport is allowed, based on user level
|
||||
@@ -195,6 +289,124 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return base.CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout);
|
||||
}
|
||||
|
||||
protected override bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
|
||||
{
|
||||
reason = "Please wear your grid's allowed appearance before teleporting to another grid";
|
||||
if (!m_RestrictAppearanceAbroad)
|
||||
return true;
|
||||
|
||||
// The rest is only needed for controlling appearance
|
||||
|
||||
int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
|
||||
if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0)
|
||||
{
|
||||
// this user is going to another grid
|
||||
if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID))
|
||||
{
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Checking generic appearance");
|
||||
|
||||
// Check wearables
|
||||
for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
|
||||
{
|
||||
for (int j = 0; j < sp.Appearance.Wearables[i].Count; j++)
|
||||
{
|
||||
if (sp.Appearance.Wearables[i] == null)
|
||||
continue;
|
||||
|
||||
bool found = false;
|
||||
foreach (AvatarAppearance a in ExportedAppearance)
|
||||
if (a.Wearables[i] != null)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
found = false;
|
||||
foreach (AvatarAppearance a in ExportedAppearance)
|
||||
if (sp.Appearance.Wearables[i][j].AssetID == a.Wearables[i][j].AssetID)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check attachments
|
||||
foreach (AvatarAttachment att in sp.Appearance.GetAttachments())
|
||||
{
|
||||
bool found = false;
|
||||
foreach (AvatarAttachment att2 in m_Attachs)
|
||||
{
|
||||
if (att2.AssetID == att.AssetID)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Attachment not allowed to go outside {0}", att.AttachPoint);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reason = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//protected override bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agentData, ScenePresence sp)
|
||||
//{
|
||||
// int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID);
|
||||
// if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0)
|
||||
// {
|
||||
// // this user is going to another grid
|
||||
// if (m_RestrictAppearanceAbroad && Scene.UserManagementModule.IsLocalGridUser(agentData.AgentID))
|
||||
// {
|
||||
// // We need to strip the agent off its appearance
|
||||
// m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Sending generic appearance");
|
||||
|
||||
// // Delete existing npc attachments
|
||||
// Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, false);
|
||||
|
||||
// // XXX: We can't just use IAvatarFactoryModule.SetAppearance() yet since it doesn't transfer attachments
|
||||
// AvatarAppearance newAppearance = new AvatarAppearance(ExportedAppearance, true);
|
||||
// sp.Appearance = newAppearance;
|
||||
|
||||
// // Rez needed npc attachments
|
||||
// Scene.AttachmentsModule.RezAttachments(sp);
|
||||
|
||||
|
||||
// IAvatarFactoryModule module = Scene.RequestModuleInterface<IAvatarFactoryModule>();
|
||||
// //module.SendAppearance(sp.UUID);
|
||||
// module.RequestRebake(sp, false);
|
||||
|
||||
// Scene.AttachmentsModule.CopyAttachments(sp, agentData);
|
||||
// agentData.Appearance = sp.Appearance;
|
||||
// }
|
||||
// }
|
||||
|
||||
// foreach (AvatarAttachment a in agentData.Appearance.GetAttachments())
|
||||
// m_log.DebugFormat("[XXX]: {0}-{1}", a.ItemID, a.AssetID);
|
||||
|
||||
|
||||
// return base.UpdateAgent(reg, finalDestination, agentData, sp);
|
||||
//}
|
||||
|
||||
public override void TeleportHome(UUID id, IClientAPI client)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
|
||||
@@ -71,19 +71,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
|
||||
#region Internal functions
|
||||
|
||||
public AssetBase FetchAsset(string url, UUID assetID)
|
||||
public AssetMetadata FetchMetadata(string url, UUID assetID)
|
||||
{
|
||||
if (!url.EndsWith("/") && !url.EndsWith("="))
|
||||
url = url + "/";
|
||||
|
||||
AssetBase asset = m_scene.AssetService.Get(url + assetID.ToString());
|
||||
AssetMetadata meta = m_scene.AssetService.GetMetadata(url + assetID.ToString());
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Copied asset {0} from {1} to local asset server. ", asset.ID, url);
|
||||
return asset;
|
||||
}
|
||||
return null;
|
||||
if (meta != null)
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Fetched metadata for asset {0} of type {1} from {2} ", assetID, meta.Type, url);
|
||||
else
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Unable to fetched metadata for asset {0} from {1} ", assetID, url);
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
public bool PostAsset(string url, AssetBase asset)
|
||||
@@ -93,6 +93,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
if (!url.EndsWith("/") && !url.EndsWith("="))
|
||||
url = url + "/";
|
||||
|
||||
bool success = true;
|
||||
// See long comment in AssetCache.AddAsset
|
||||
if (!asset.Temporary || asset.Local)
|
||||
{
|
||||
@@ -103,14 +104,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
// not having a global naming infrastructure
|
||||
AssetBase asset1 = new AssetBase(asset.FullID, asset.Name, asset.Type, asset.Metadata.CreatorID);
|
||||
Copy(asset, asset1);
|
||||
try
|
||||
{
|
||||
asset1.ID = url + asset.ID;
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_log.Warn("[HG ASSET MAPPER]: Oops.");
|
||||
}
|
||||
asset1.ID = url + asset.ID;
|
||||
|
||||
AdjustIdentifiers(asset1.Metadata);
|
||||
if (asset1.Metadata.Type == (sbyte)AssetType.Object)
|
||||
@@ -118,11 +112,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
else
|
||||
asset1.Data = asset.Data;
|
||||
|
||||
m_scene.AssetService.Store(asset1);
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
|
||||
string id = m_scene.AssetService.Store(asset1);
|
||||
if (id == string.Empty)
|
||||
{
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Asset server {0} did not accept {1}", url, asset.ID);
|
||||
success = false;
|
||||
}
|
||||
else
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Posted copy of asset {0} from local asset server to {1}", asset1.ID, url);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
else
|
||||
m_log.Warn("[HG ASSET MAPPER]: Tried to post asset to remote server, but asset not in local cache.");
|
||||
|
||||
@@ -222,28 +222,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
|
||||
public void Get(UUID assetID, UUID ownerID, string userAssetURL)
|
||||
{
|
||||
// Get the item from the remote asset server onto the local AssetCache
|
||||
// and place an entry in m_assetMap
|
||||
// Get the item from the remote asset server onto the local AssetService
|
||||
|
||||
m_log.Debug("[HG ASSET MAPPER]: Fetching object " + assetID + " from asset server " + userAssetURL);
|
||||
AssetBase asset = FetchAsset(userAssetURL, assetID);
|
||||
AssetMetadata meta = FetchMetadata(userAssetURL, assetID);
|
||||
if (meta == null)
|
||||
return;
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
// OK, now fetch the inside.
|
||||
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
|
||||
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, userAssetURL);
|
||||
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
|
||||
if (ids.ContainsKey(assetID))
|
||||
ids.Remove(assetID);
|
||||
foreach (UUID uuid in ids.Keys)
|
||||
FetchAsset(userAssetURL, uuid);
|
||||
// The act of gathering UUIDs downloads the assets from the remote server
|
||||
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
|
||||
HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, userAssetURL);
|
||||
uuidGatherer.GatherAssetUuids(assetID, (AssetType)meta.Type, ids);
|
||||
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully fetched asset {0} from asset server {1}", asset.ID, userAssetURL);
|
||||
|
||||
}
|
||||
else
|
||||
m_log.Warn("[HG ASSET MAPPER]: Could not fetch asset from remote asset server " + userAssetURL);
|
||||
}
|
||||
|
||||
|
||||
@@ -257,19 +246,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
if (asset != null)
|
||||
{
|
||||
Dictionary<UUID, AssetType> ids = new Dictionary<UUID, AssetType>();
|
||||
HGUuidGatherer uuidGatherer = new HGUuidGatherer(this, m_scene.AssetService, string.Empty);
|
||||
HGUuidGatherer uuidGatherer = new HGUuidGatherer(m_scene.AssetService, string.Empty);
|
||||
uuidGatherer.GatherAssetUuids(asset.FullID, (AssetType)asset.Type, ids);
|
||||
bool success = false;
|
||||
foreach (UUID uuid in ids.Keys)
|
||||
{
|
||||
asset = m_scene.AssetService.Get(uuid.ToString());
|
||||
if (asset == null)
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Could not find asset {0}", uuid);
|
||||
else
|
||||
PostAsset(userAssetURL, asset);
|
||||
success = PostAsset(userAssetURL, asset);
|
||||
}
|
||||
|
||||
// maybe all pieces got there...
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
|
||||
// maybe all pieces got there...
|
||||
if (!success)
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Problems posting item {0} to asset server {1}", assetID, userAssetURL);
|
||||
else
|
||||
m_log.DebugFormat("[HG ASSET MAPPER]: Successfully posted item {0} to asset server {1}", assetID, userAssetURL);
|
||||
|
||||
}
|
||||
else
|
||||
|
||||
@@ -263,8 +263,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
//}
|
||||
|
||||
// OK, we're done fetching. Pass it up to the default RezObject
|
||||
return base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
|
||||
RezSelected, RemoveItem, fromTaskID, attachment);
|
||||
SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection,
|
||||
RezSelected, RemoveItem, fromTaskID, attachment);
|
||||
|
||||
if (sog == null)
|
||||
remoteClient.SendAgentAlertMessage("Unable to rez: problem accessing inventory or locating assets", false);
|
||||
|
||||
return sog;
|
||||
|
||||
}
|
||||
|
||||
@@ -308,6 +313,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
|
||||
protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
|
||||
{
|
||||
InventoryItemBase item = base.GetItem(agentID, itemID);
|
||||
if (item == null)
|
||||
return null;
|
||||
|
||||
string userAssetServer = string.Empty;
|
||||
if (IsForeignUser(agentID, out userAssetServer))
|
||||
|
||||
@@ -95,14 +95,14 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||
{
|
||||
foreach (IMonitor monitor in m_staticMonitors)
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"[MONITOR MODULE]: {0} reports {1} = {2}",
|
||||
m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue());
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, float> tuple in m_scene.StatsReporter.GetExtraSimStats())
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"[MONITOR MODULE]: {0} reports {1} = {2}",
|
||||
m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value);
|
||||
}
|
||||
|
||||
@@ -1,161 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using log4net;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for writing a high performance, high volume log file.
|
||||
/// Sometimes, to debug, one has a high volume logging to do and the regular
|
||||
/// log file output is not appropriate.
|
||||
/// Create a new instance with the parameters needed and
|
||||
/// call Write() to output a line. Call Close() when finished.
|
||||
/// If created with no parameters, it will not log anything.
|
||||
/// </summary>
|
||||
public class LogWriter : IDisposable
|
||||
{
|
||||
public bool Enabled { get; private set; }
|
||||
|
||||
private string m_logDirectory = ".";
|
||||
private int m_logMaxFileTimeMin = 5; // 5 minutes
|
||||
public String LogFileHeader { get; set; }
|
||||
|
||||
private StreamWriter m_logFile = null;
|
||||
private TimeSpan m_logFileLife;
|
||||
private DateTime m_logFileEndTime;
|
||||
private Object m_logFileWriteLock = new Object();
|
||||
|
||||
// set externally when debugging. If let 'null', this does not write any error messages.
|
||||
public ILog ErrorLogger = null;
|
||||
private string LogHeader = "[LOG WRITER]";
|
||||
|
||||
/// <summary>
|
||||
/// Create a log writer that will not write anything. Good for when not enabled
|
||||
/// but the write statements are still in the code.
|
||||
/// </summary>
|
||||
public LogWriter()
|
||||
{
|
||||
Enabled = false;
|
||||
m_logFile = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a log writer instance.
|
||||
/// </summary>
|
||||
/// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
|
||||
/// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
|
||||
/// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
|
||||
public LogWriter(string dir, string headr, int maxFileTime)
|
||||
{
|
||||
m_logDirectory = dir == null ? "." : dir;
|
||||
|
||||
LogFileHeader = headr == null ? "log-" : headr;
|
||||
|
||||
m_logMaxFileTimeMin = maxFileTime;
|
||||
if (m_logMaxFileTimeMin < 1)
|
||||
m_logMaxFileTimeMin = 5;
|
||||
|
||||
m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
|
||||
m_logFileEndTime = DateTime.Now + m_logFileLife;
|
||||
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Enabled = false;
|
||||
if (m_logFile != null)
|
||||
{
|
||||
m_logFile.Close();
|
||||
m_logFile.Dispose();
|
||||
m_logFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string line, params object[] args)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
Write(String.Format(line, args));
|
||||
}
|
||||
|
||||
public void Write(string line)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
try
|
||||
{
|
||||
lock (m_logFileWriteLock)
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
if (m_logFile == null || now > m_logFileEndTime)
|
||||
{
|
||||
if (m_logFile != null)
|
||||
{
|
||||
m_logFile.Close();
|
||||
m_logFile.Dispose();
|
||||
m_logFile = null;
|
||||
}
|
||||
|
||||
// First log file or time has expired, start writing to a new log file
|
||||
m_logFileEndTime = now + m_logFileLife;
|
||||
string path = (m_logDirectory.Length > 0 ? m_logDirectory
|
||||
+ System.IO.Path.DirectorySeparatorChar.ToString() : "")
|
||||
+ String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
|
||||
m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write));
|
||||
}
|
||||
if (m_logFile != null)
|
||||
{
|
||||
StringBuilder buff = new StringBuilder(line.Length + 25);
|
||||
buff.Append(now.ToString("yyyyMMddHHmmssfff"));
|
||||
// buff.Append(now.ToString("yyyyMMddHHmmss"));
|
||||
buff.Append(",");
|
||||
buff.Append(line);
|
||||
buff.Append("\r\n");
|
||||
m_logFile.Write(buff.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (ErrorLogger != null)
|
||||
{
|
||||
ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
|
||||
}
|
||||
Enabled = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using log4net;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Class for writing a high performance, high volume log file.
|
||||
/// Sometimes, to debug, one has a high volume logging to do and the regular
|
||||
/// log file output is not appropriate.
|
||||
/// Create a new instance with the parameters needed and
|
||||
/// call Write() to output a line. Call Close() when finished.
|
||||
/// If created with no parameters, it will not log anything.
|
||||
/// </summary>
|
||||
public class LogWriter : IDisposable
|
||||
{
|
||||
public bool Enabled { get; private set; }
|
||||
|
||||
private string m_logDirectory = ".";
|
||||
private int m_logMaxFileTimeMin = 5; // 5 minutes
|
||||
public String LogFileHeader { get; set; }
|
||||
|
||||
private StreamWriter m_logFile = null;
|
||||
private TimeSpan m_logFileLife;
|
||||
private DateTime m_logFileEndTime;
|
||||
private Object m_logFileWriteLock = new Object();
|
||||
|
||||
// set externally when debugging. If let 'null', this does not write any error messages.
|
||||
public ILog ErrorLogger = null;
|
||||
private string LogHeader = "[LOG WRITER]";
|
||||
|
||||
/// <summary>
|
||||
/// Create a log writer that will not write anything. Good for when not enabled
|
||||
/// but the write statements are still in the code.
|
||||
/// </summary>
|
||||
public LogWriter()
|
||||
{
|
||||
Enabled = false;
|
||||
m_logFile = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a log writer instance.
|
||||
/// </summary>
|
||||
/// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
|
||||
/// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
|
||||
/// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
|
||||
public LogWriter(string dir, string headr, int maxFileTime)
|
||||
{
|
||||
m_logDirectory = dir == null ? "." : dir;
|
||||
|
||||
LogFileHeader = headr == null ? "log-" : headr;
|
||||
|
||||
m_logMaxFileTimeMin = maxFileTime;
|
||||
if (m_logMaxFileTimeMin < 1)
|
||||
m_logMaxFileTimeMin = 5;
|
||||
|
||||
m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
|
||||
m_logFileEndTime = DateTime.Now + m_logFileLife;
|
||||
|
||||
Enabled = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Enabled = false;
|
||||
if (m_logFile != null)
|
||||
{
|
||||
m_logFile.Close();
|
||||
m_logFile.Dispose();
|
||||
m_logFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string line, params object[] args)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
Write(String.Format(line, args));
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (!Enabled) return;
|
||||
if (m_logFile != null)
|
||||
{
|
||||
m_logFile.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(string line)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
try
|
||||
{
|
||||
lock (m_logFileWriteLock)
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
if (m_logFile == null || now > m_logFileEndTime)
|
||||
{
|
||||
if (m_logFile != null)
|
||||
{
|
||||
m_logFile.Close();
|
||||
m_logFile.Dispose();
|
||||
m_logFile = null;
|
||||
}
|
||||
|
||||
// First log file or time has expired, start writing to a new log file
|
||||
m_logFileEndTime = now + m_logFileLife;
|
||||
string path = (m_logDirectory.Length > 0 ? m_logDirectory
|
||||
+ System.IO.Path.DirectorySeparatorChar.ToString() : "")
|
||||
+ String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
|
||||
m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write));
|
||||
}
|
||||
if (m_logFile != null)
|
||||
{
|
||||
StringBuilder buff = new StringBuilder(line.Length + 25);
|
||||
buff.Append(now.ToString("yyyyMMddHHmmssfff"));
|
||||
// buff.Append(now.ToString("yyyyMMddHHmmss"));
|
||||
buff.Append(",");
|
||||
buff.Append(line);
|
||||
buff.Append("\r\n");
|
||||
m_logFile.Write(buff.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (ErrorLogger != null)
|
||||
{
|
||||
ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
|
||||
}
|
||||
Enabled = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +137,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
||||
ud.FirstName = words[0];
|
||||
ud.LastName = "@" + words[1];
|
||||
users.Add(ud);
|
||||
// WARNING! that uriStr is not quite right... it may be missing the / at the end,
|
||||
// which will cause trouble (duplicate entries on some tables). We should
|
||||
// get the UUI instead from the UAS. TO BE FIXED.
|
||||
AddUser(userID, names[0], names[1], uriStr);
|
||||
m_log.DebugFormat("[USER MANAGEMENT MODULE]: User {0}@{1} found", words[0], words[1]);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Reflection;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Region.ClientStack.LindenUDP;
|
||||
using OpenSim.Region.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
@@ -429,8 +430,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
||||
|
||||
public void AddUser(UUID uuid, string first, string last, string homeURL)
|
||||
{
|
||||
// m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
|
||||
|
||||
//m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL);
|
||||
AddUser(uuid, homeURL + ";" + first + " " + last);
|
||||
}
|
||||
|
||||
@@ -553,8 +553,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
||||
MainConsole.Instance.Output("-----------------------------------------------------------------------------");
|
||||
foreach (KeyValuePair<UUID, UserData> kvp in m_UserCache)
|
||||
{
|
||||
MainConsole.Instance.Output(String.Format("{0} {1} {2}",
|
||||
kvp.Key, kvp.Value.FirstName, kvp.Value.LastName));
|
||||
MainConsole.Instance.Output(String.Format("{0} {1} {2} ({3})",
|
||||
kvp.Key, kvp.Value.FirstName, kvp.Value.LastName, kvp.Value.HomeURL));
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
{
|
||||
public class DynamicTexture : IDynamicTexture
|
||||
{
|
||||
public string InputCommands { get; private set; }
|
||||
public Uri InputUri { get; private set; }
|
||||
public string InputParams { get; private set; }
|
||||
public byte[] Data { get; private set; }
|
||||
public Size Size { get; private set; }
|
||||
public bool IsReuseable { get; private set; }
|
||||
|
||||
public DynamicTexture(string inputCommands, string inputParams, byte[] data, Size size, bool isReuseable)
|
||||
{
|
||||
InputCommands = inputCommands;
|
||||
InputParams = inputParams;
|
||||
Data = data;
|
||||
Size = size;
|
||||
IsReuseable = isReuseable;
|
||||
}
|
||||
|
||||
public DynamicTexture(Uri inputUri, string inputParams, byte[] data, Size size, bool isReuseable)
|
||||
{
|
||||
InputUri = inputUri;
|
||||
InputParams = inputParams;
|
||||
Data = data;
|
||||
Size = size;
|
||||
IsReuseable = isReuseable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
{
|
||||
public class DynamicTextureModule : IRegionModule, IDynamicTextureManager
|
||||
{
|
||||
//private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private const int ALL_SIDES = -1;
|
||||
|
||||
@@ -54,6 +54,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
/// </summary>
|
||||
public bool ReuseTextures { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If false, then textures which have a low data size are not reused when ReuseTextures = true.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// LL viewers 3.3.4 and before appear to not fully render textures pulled from the viewer cache if those
|
||||
/// textures have a relatively high pixel surface but a small data size. Typically, this appears to happen
|
||||
/// if the data size is smaller than the viewer's discard level 2 size estimate. So if this is setting is
|
||||
/// false, textures smaller than the calculation in IsSizeReuseable are always regenerated rather than reused
|
||||
/// to work around this problem.</remarks>
|
||||
public bool ReuseLowDataTextures { get; set; }
|
||||
|
||||
private Dictionary<UUID, Scene> RegisteredScenes = new Dictionary<UUID, Scene>();
|
||||
|
||||
private Dictionary<string, IDynamicTextureRender> RenderPlugins =
|
||||
@@ -83,18 +94,17 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
/// <summary>
|
||||
/// Called by code which actually renders the dynamic texture to supply texture data.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="isReuseable">True if the data generated can be reused for subsequent identical requests</param>
|
||||
public void ReturnData(UUID id, byte[] data, bool isReuseable)
|
||||
/// <param name="updaterId"></param>
|
||||
/// <param name="texture"></param>
|
||||
public void ReturnData(UUID updaterId, IDynamicTexture texture)
|
||||
{
|
||||
DynamicTextureUpdater updater = null;
|
||||
|
||||
lock (Updaters)
|
||||
{
|
||||
if (Updaters.ContainsKey(id))
|
||||
if (Updaters.ContainsKey(updaterId))
|
||||
{
|
||||
updater = Updaters[id];
|
||||
updater = Updaters[updaterId];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,11 +113,16 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
if (RegisteredScenes.ContainsKey(updater.SimUUID))
|
||||
{
|
||||
Scene scene = RegisteredScenes[updater.SimUUID];
|
||||
UUID newTextureID = updater.DataReceived(data, scene);
|
||||
UUID newTextureID = updater.DataReceived(texture.Data, scene);
|
||||
|
||||
if (ReuseTextures && isReuseable && !updater.BlendWithOldTexture)
|
||||
if (ReuseTextures
|
||||
&& !updater.BlendWithOldTexture
|
||||
&& texture.IsReuseable
|
||||
&& (ReuseLowDataTextures || IsDataSizeReuseable(texture)))
|
||||
{
|
||||
m_reuseableDynamicTextures.Store(
|
||||
GenerateReusableTextureKey(updater.BodyData, updater.Params), newTextureID);
|
||||
GenerateReusableTextureKey(texture.InputCommands, texture.InputParams), newTextureID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +138,27 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the texture is reuseable based on its data size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a workaround for a viewer bug where very small data size textures relative to their pixel size
|
||||
/// are not redisplayed properly when pulled from cache. The calculation here is based on the typical discard
|
||||
/// level of 2, a 'rate' of 0.125 and 4 components (which makes for a factor of 0.5).
|
||||
/// </remarks>
|
||||
/// <returns></returns>
|
||||
private bool IsDataSizeReuseable(IDynamicTexture texture)
|
||||
{
|
||||
// Console.WriteLine("{0} {1}", texture.Size.Width, texture.Size.Height);
|
||||
int discardLevel2DataThreshold = (int)Math.Ceiling((texture.Size.Width >> 2) * (texture.Size.Height >> 2) * 0.5);
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[DYNAMIC TEXTURE MODULE]: Discard level 2 threshold {0}, texture data length {1}",
|
||||
// discardLevel2DataThreshold, texture.Data.Length);
|
||||
|
||||
return discardLevel2DataThreshold < texture.Data.Length;
|
||||
}
|
||||
|
||||
public UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url,
|
||||
string extraParams, int updateTimer)
|
||||
{
|
||||
@@ -249,10 +285,18 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
}
|
||||
}
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[DYNAMIC TEXTURE MODULE]: Requesting generation of new dynamic texture for {0} in {1}",
|
||||
// part.Name, part.ParentGroup.Scene.Name);
|
||||
|
||||
RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[DYNAMIC TEXTURE MODULE]: Reusing cached texture {0} for {1} in {2}",
|
||||
// objReusableTextureUUID, part.Name, part.ParentGroup.Scene.Name);
|
||||
|
||||
// No need to add to updaters as the texture is always the same. Not that this functionality
|
||||
// apppears to be implemented anyway.
|
||||
updater.UpdatePart(part, (UUID)objReusableTextureUUID);
|
||||
@@ -285,7 +329,10 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
{
|
||||
IConfig texturesConfig = config.Configs["Textures"];
|
||||
if (texturesConfig != null)
|
||||
{
|
||||
ReuseTextures = texturesConfig.GetBoolean("ReuseDynamicTextures", false);
|
||||
ReuseLowDataTextures = texturesConfig.GetBoolean("ReuseDynamicLowDataTextures", false);
|
||||
}
|
||||
|
||||
if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
|
||||
{
|
||||
@@ -448,8 +495,10 @@ namespace OpenSim.Region.CoreModules.Scripting.DynamicTexture
|
||||
IJ2KDecoder cacheLayerDecode = scene.RequestModuleInterface<IJ2KDecoder>();
|
||||
if (cacheLayerDecode != null)
|
||||
{
|
||||
cacheLayerDecode.Decode(asset.FullID, asset.Data);
|
||||
cacheLayerDecode = null;
|
||||
if (!cacheLayerDecode.Decode(asset.FullID, asset.Data))
|
||||
m_log.WarnFormat(
|
||||
"[DYNAMIC TEXTURE MODULE]: Decoding of dynamically generated asset {0} for {1} in {2} failed",
|
||||
asset.ID, part.Name, part.ParentGroup.Scene.Name);
|
||||
}
|
||||
|
||||
UUID oldID = UpdatePart(part, asset.FullID);
|
||||
|
||||
@@ -32,6 +32,7 @@ using System.Net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Imaging;
|
||||
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using log4net;
|
||||
@@ -73,12 +74,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
|
||||
// return false;
|
||||
// }
|
||||
|
||||
public byte[] ConvertUrl(string url, string extraParams)
|
||||
public IDynamicTexture ConvertUrl(string url, string extraParams)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] ConvertData(string bodyData, string extraParams)
|
||||
public IDynamicTexture ConvertData(string bodyData, string extraParams)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -171,11 +172,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
|
||||
|
||||
private void HttpRequestReturn(IAsyncResult result)
|
||||
{
|
||||
|
||||
RequestState state = (RequestState) result.AsyncState;
|
||||
WebRequest request = (WebRequest) state.Request;
|
||||
Stream stream = null;
|
||||
byte[] imageJ2000 = new byte[0];
|
||||
Size newSize = new Size(0, 0);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -188,37 +189,43 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
|
||||
try
|
||||
{
|
||||
Bitmap image = new Bitmap(stream);
|
||||
Size newsize;
|
||||
|
||||
// TODO: make this a bit less hard coded
|
||||
if ((image.Height < 64) && (image.Width < 64))
|
||||
{
|
||||
newsize = new Size(32, 32);
|
||||
newSize.Width = 32;
|
||||
newSize.Height = 32;
|
||||
}
|
||||
else if ((image.Height < 128) && (image.Width < 128))
|
||||
{
|
||||
newsize = new Size(64, 64);
|
||||
newSize.Width = 64;
|
||||
newSize.Height = 64;
|
||||
}
|
||||
else if ((image.Height < 256) && (image.Width < 256))
|
||||
{
|
||||
newsize = new Size(128, 128);
|
||||
newSize.Width = 128;
|
||||
newSize.Height = 128;
|
||||
}
|
||||
else if ((image.Height < 512 && image.Width < 512))
|
||||
{
|
||||
newsize = new Size(256, 256);
|
||||
newSize.Width = 256;
|
||||
newSize.Height = 256;
|
||||
}
|
||||
else if ((image.Height < 1024 && image.Width < 1024))
|
||||
{
|
||||
newsize = new Size(512, 512);
|
||||
newSize.Width = 512;
|
||||
newSize.Height = 512;
|
||||
}
|
||||
else
|
||||
{
|
||||
newsize = new Size(1024, 1024);
|
||||
newSize.Width = 1024;
|
||||
newSize.Height = 1024;
|
||||
}
|
||||
|
||||
Bitmap resize = new Bitmap(image, newsize);
|
||||
|
||||
imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
|
||||
using (Bitmap resize = new Bitmap(image, newSize))
|
||||
{
|
||||
imageJ2000 = OpenJPEG.EncodeFromImage(resize, true);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -233,7 +240,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -243,10 +249,13 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
|
||||
}
|
||||
}
|
||||
|
||||
m_log.DebugFormat("[LOADIMAGEURLMODULE] Returning {0} bytes of image data for request {1}",
|
||||
m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}",
|
||||
imageJ2000.Length, state.RequestID);
|
||||
|
||||
m_textureManager.ReturnData(state.RequestID, imageJ2000, false);
|
||||
m_textureManager.ReturnData(
|
||||
state.RequestID,
|
||||
new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
|
||||
request.RequestUri, null, imageJ2000, newSize, false));
|
||||
}
|
||||
|
||||
#region Nested type: RequestState
|
||||
|
||||
@@ -211,6 +211,23 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
|
||||
RegisterScriptInvocation(target, mi);
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterScriptInvocations(IRegionModuleBase target)
|
||||
{
|
||||
foreach(MethodInfo method in target.GetType().GetMethods(
|
||||
BindingFlags.Public | BindingFlags.Instance |
|
||||
BindingFlags.Static))
|
||||
{
|
||||
if(method.GetCustomAttributes(
|
||||
typeof(ScriptInvocationAttribute), true).Any())
|
||||
{
|
||||
if(method.IsStatic)
|
||||
RegisterScriptInvocation(target.GetType(), method);
|
||||
else
|
||||
RegisterScriptInvocation(target, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Delegate[] GetScriptInvocationList()
|
||||
{
|
||||
@@ -313,6 +330,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterConstants(IRegionModuleBase target)
|
||||
{
|
||||
foreach (FieldInfo field in target.GetType().GetFields(
|
||||
BindingFlags.Public | BindingFlags.Static |
|
||||
BindingFlags.Instance))
|
||||
{
|
||||
if (field.GetCustomAttributes(
|
||||
typeof(ScriptConstantAttribute), true).Any())
|
||||
{
|
||||
RegisterConstant(field.Name, field.GetValue(target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Operation to check for a registered constant
|
||||
/// </summary>
|
||||
@@ -57,6 +57,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
|
||||
|
||||
m_dtm = new DynamicTextureModule();
|
||||
m_dtm.ReuseTextures = reuseTextures;
|
||||
// m_dtm.ReuseLowDataTextures = reuseTextures;
|
||||
|
||||
m_vrm = new VectorRenderModule();
|
||||
|
||||
@@ -201,6 +202,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
|
||||
public void TestRepeatSameDrawReusingTexture()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
|
||||
|
||||
@@ -228,6 +230,46 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender.Tests
|
||||
Assert.That(firstDynamicTextureID, Is.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test a low data dynamically generated texture such that it is treated as a low data texture that causes
|
||||
/// problems for current viewers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As we do not set DynamicTextureModule.ReuseLowDataTextures = true in this test, it should not reuse the
|
||||
/// texture
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void TestRepeatSameDrawLowDataTexture()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
string dtText = "PenColour BLACK; MoveTo 40,220; FontSize 32; Text Hello World;";
|
||||
|
||||
SetupScene(true);
|
||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(m_scene);
|
||||
|
||||
m_dtm.AddDynamicTextureData(
|
||||
m_scene.RegionInfo.RegionID,
|
||||
so.UUID,
|
||||
m_vrm.GetContentType(),
|
||||
dtText,
|
||||
"1024",
|
||||
0);
|
||||
|
||||
UUID firstDynamicTextureID = so.RootPart.Shape.Textures.GetFace(0).TextureID;
|
||||
|
||||
m_dtm.AddDynamicTextureData(
|
||||
m_scene.RegionInfo.RegionID,
|
||||
so.UUID,
|
||||
m_vrm.GetContentType(),
|
||||
dtText,
|
||||
"1024",
|
||||
0);
|
||||
|
||||
Assert.That(firstDynamicTextureID, Is.Not.EqualTo(so.RootPart.Shape.Textures.GetFace(0).TextureID));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRepeatSameDrawDifferentExtraParamsReusingTexture()
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ using System.Net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Imaging;
|
||||
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using log4net;
|
||||
@@ -46,6 +47,11 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
{
|
||||
public class VectorRenderModule : IRegionModule, IDynamicTextureRender
|
||||
{
|
||||
// These fields exist for testing purposes, please do not remove.
|
||||
// private static bool s_flipper;
|
||||
// private static byte[] s_asset1Data;
|
||||
// private static byte[] s_asset2Data;
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private Scene m_scene;
|
||||
@@ -80,20 +86,14 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
// return lines.Any((str, r) => str.StartsWith("Image"));
|
||||
// }
|
||||
|
||||
public byte[] ConvertUrl(string url, string extraParams)
|
||||
public IDynamicTexture ConvertUrl(string url, string extraParams)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] ConvertData(string bodyData, string extraParams)
|
||||
public IDynamicTexture ConvertData(string bodyData, string extraParams)
|
||||
{
|
||||
bool reuseable;
|
||||
return Draw(bodyData, extraParams, out reuseable);
|
||||
}
|
||||
|
||||
private byte[] ConvertData(string bodyData, string extraParams, out bool reuseable)
|
||||
{
|
||||
return Draw(bodyData, extraParams, out reuseable);
|
||||
return Draw(bodyData, extraParams);
|
||||
}
|
||||
|
||||
public bool AsyncConvertUrl(UUID id, string url, string extraParams)
|
||||
@@ -104,10 +104,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
|
||||
{
|
||||
// XXX: This isn't actually being done asynchronously!
|
||||
bool reuseable;
|
||||
byte[] data = ConvertData(bodyData, extraParams, out reuseable);
|
||||
|
||||
m_textureManager.ReturnData(id, data, reuseable);
|
||||
m_textureManager.ReturnData(id, ConvertData(bodyData, extraParams));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -115,14 +112,19 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
public void GetDrawStringSize(string text, string fontName, int fontSize,
|
||||
out double xSize, out double ySize)
|
||||
{
|
||||
using (Font myFont = new Font(fontName, fontSize))
|
||||
lock (this)
|
||||
{
|
||||
SizeF stringSize = new SizeF();
|
||||
lock (m_graph)
|
||||
using (Font myFont = new Font(fontName, fontSize))
|
||||
{
|
||||
stringSize = m_graph.MeasureString(text, myFont);
|
||||
xSize = stringSize.Width;
|
||||
ySize = stringSize.Height;
|
||||
SizeF stringSize = new SizeF();
|
||||
|
||||
// XXX: This lock may be unnecessary.
|
||||
lock (m_graph)
|
||||
{
|
||||
stringSize = m_graph.MeasureString(text, myFont);
|
||||
xSize = stringSize.Width;
|
||||
ySize = stringSize.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,6 +163,13 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
{
|
||||
m_textureManager.RegisterRender(GetContentType(), this);
|
||||
}
|
||||
|
||||
// This code exists for testing purposes, please do not remove.
|
||||
// s_asset1Data = m_scene.AssetService.Get("00000000-0000-1111-9999-000000000001").Data;
|
||||
// s_asset1Data = m_scene.AssetService.Get("9f4acf0d-1841-4e15-bdb8-3a12efc9dd8f").Data;
|
||||
|
||||
// Terrain dirt - smallest bin/assets file (6004 bytes)
|
||||
// s_asset2Data = m_scene.AssetService.Get("b8d3965a-ad78-bf43-699b-bff8eca6c975").Data;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
@@ -179,7 +188,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
|
||||
#endregion
|
||||
|
||||
private byte[] Draw(string data, string extraParams, out bool reuseable)
|
||||
private IDynamicTexture Draw(string data, string extraParams)
|
||||
{
|
||||
// We need to cater for old scripts that didnt use extraParams neatly, they use either an integer size which represents both width and height, or setalpha
|
||||
// we will now support multiple comma seperated params in the form width:256,height:512,alpha:255
|
||||
@@ -322,6 +331,7 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
|
||||
Bitmap bitmap = null;
|
||||
Graphics graph = null;
|
||||
bool reuseable = false;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -364,6 +374,14 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
}
|
||||
|
||||
byte[] imageJ2000 = new byte[0];
|
||||
|
||||
// This code exists for testing purposes, please do not remove.
|
||||
// if (s_flipper)
|
||||
// imageJ2000 = s_asset1Data;
|
||||
// else
|
||||
// imageJ2000 = s_asset2Data;
|
||||
//
|
||||
// s_flipper = !s_flipper;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -376,7 +394,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||
e.Message, e.StackTrace);
|
||||
}
|
||||
|
||||
return imageJ2000;
|
||||
return new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
|
||||
data, extraParams, imageJ2000, new Size(width, height), reuseable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
@@ -56,6 +56,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||
|
||||
private bool m_Enabled = false;
|
||||
|
||||
private AssetPermissions m_AssetPerms;
|
||||
|
||||
public Type ReplaceableInterface
|
||||
{
|
||||
get { return null; }
|
||||
@@ -128,6 +130,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||
if (m_LocalAssetServiceURI != string.Empty)
|
||||
m_LocalAssetServiceURI = m_LocalAssetServiceURI.Trim('/');
|
||||
|
||||
IConfig hgConfig = source.Configs["HGAssetService"];
|
||||
m_AssetPerms = new AssetPermissions(hgConfig); // it's ok if arg is null
|
||||
|
||||
m_Enabled = true;
|
||||
m_log.Info("[HG ASSET CONNECTOR]: HG asset broker enabled");
|
||||
}
|
||||
@@ -206,14 +211,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||
asset = m_HGService.Get(id);
|
||||
if (asset != null)
|
||||
{
|
||||
// Now store it locally
|
||||
// For now, let me just do it for textures and scripts
|
||||
if (((AssetType)asset.Type == AssetType.Texture) ||
|
||||
((AssetType)asset.Type == AssetType.LSLBytecode) ||
|
||||
((AssetType)asset.Type == AssetType.LSLText))
|
||||
{
|
||||
// Now store it locally, if allowed
|
||||
if (m_AssetPerms.AllowedImport(asset.Type))
|
||||
m_GridService.Store(asset);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -328,7 +330,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||
|
||||
string id = string.Empty;
|
||||
if (IsHG(asset.ID))
|
||||
id = m_HGService.Store(asset);
|
||||
{
|
||||
if (m_AssetPerms.AllowedExport(asset.Type))
|
||||
id = m_HGService.Store(asset);
|
||||
else
|
||||
return String.Empty;
|
||||
}
|
||||
else
|
||||
id = m_GridService.Store(asset);
|
||||
|
||||
|
||||
@@ -204,8 +204,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
|
||||
public byte[] GetData(string id)
|
||||
{
|
||||
// m_log.DebugFormat("[LOCAL ASSET SERVICES CONNECTOR]: Requesting data for asset {0}", id);
|
||||
|
||||
AssetBase asset = m_Cache.Get(id);
|
||||
|
||||
AssetBase asset = null;
|
||||
|
||||
if (m_Cache != null)
|
||||
asset = m_Cache.Get(id);
|
||||
|
||||
if (asset != null)
|
||||
return asset.Data;
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net.Config;
|
||||
using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset;
|
||||
using OpenSim.Tests.Common;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class AssetConnectorsTests : OpenSimTestCase
|
||||
{
|
||||
[Test]
|
||||
public void TestAddAsset()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
IConfigSource config = new IniConfigSource();
|
||||
config.AddConfig("Modules");
|
||||
config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
|
||||
config.AddConfig("AssetService");
|
||||
config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
|
||||
config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
|
||||
|
||||
LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
|
||||
lasc.Initialise(config);
|
||||
|
||||
AssetBase a1 = AssetHelpers.CreateNotecardAsset();
|
||||
lasc.Store(a1);
|
||||
|
||||
AssetBase retreivedA1 = lasc.Get(a1.ID);
|
||||
Assert.That(retreivedA1.ID, Is.EqualTo(a1.ID));
|
||||
Assert.That(retreivedA1.Metadata.ID, Is.EqualTo(a1.Metadata.ID));
|
||||
Assert.That(retreivedA1.Data.Length, Is.EqualTo(a1.Data.Length));
|
||||
|
||||
AssetMetadata retrievedA1Metadata = lasc.GetMetadata(a1.ID);
|
||||
Assert.That(retrievedA1Metadata.ID, Is.EqualTo(a1.ID));
|
||||
|
||||
byte[] retrievedA1Data = lasc.GetData(a1.ID);
|
||||
Assert.That(retrievedA1Data.Length, Is.EqualTo(a1.Data.Length));
|
||||
|
||||
// TODO: Add cache and check that this does receive a copy of the asset
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddTemporaryAsset()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
IConfigSource config = new IniConfigSource();
|
||||
config.AddConfig("Modules");
|
||||
config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
|
||||
config.AddConfig("AssetService");
|
||||
config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
|
||||
config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
|
||||
|
||||
LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
|
||||
lasc.Initialise(config);
|
||||
|
||||
AssetBase a1 = AssetHelpers.CreateNotecardAsset();
|
||||
a1.Temporary = true;
|
||||
|
||||
lasc.Store(a1);
|
||||
|
||||
Assert.That(lasc.Get(a1.ID), Is.Null);
|
||||
Assert.That(lasc.GetData(a1.ID), Is.Null);
|
||||
Assert.That(lasc.GetMetadata(a1.ID), Is.Null);
|
||||
|
||||
// TODO: Add cache and check that this does receive a copy of the asset
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddLocalAsset()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
IConfigSource config = new IniConfigSource();
|
||||
config.AddConfig("Modules");
|
||||
config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector");
|
||||
config.AddConfig("AssetService");
|
||||
config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService");
|
||||
config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll");
|
||||
|
||||
LocalAssetServicesConnector lasc = new LocalAssetServicesConnector();
|
||||
lasc.Initialise(config);
|
||||
|
||||
AssetBase a1 = AssetHelpers.CreateNotecardAsset();
|
||||
a1.Local = true;
|
||||
|
||||
lasc.Store(a1);
|
||||
|
||||
Assert.That(lasc.Get(a1.ID), Is.Null);
|
||||
Assert.That(lasc.GetData(a1.ID), Is.Null);
|
||||
Assert.That(lasc.GetMetadata(a1.ID), Is.Null);
|
||||
|
||||
// TODO: Add cache and check that this does receive a copy of the asset
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,11 +43,15 @@ using OpenSim.Tests.Common;
|
||||
namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class GridConnectorsTests
|
||||
public class GridConnectorsTests : OpenSimTestCase
|
||||
{
|
||||
LocalGridServicesConnector m_LocalConnector;
|
||||
private void SetUp()
|
||||
|
||||
[SetUp]
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
IConfigSource config = new IniConfigSource();
|
||||
config.AddConfig("Modules");
|
||||
config.AddConfig("GridService");
|
||||
@@ -71,8 +75,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
SetUp();
|
||||
|
||||
// Create 4 regions
|
||||
GridRegion r1 = new GridRegion();
|
||||
r1.RegionName = "Test Region 1";
|
||||
|
||||
@@ -65,11 +65,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
|
||||
|
||||
public void OnMakeRootAgent(ScenePresence sp)
|
||||
{
|
||||
// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName);
|
||||
|
||||
if (sp.PresenceType != PresenceType.Npc)
|
||||
{
|
||||
string userid = sp.Scene.UserManagementModule.GetUserUUI(sp.UUID);
|
||||
//m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected root presence {0} in {1}", userid, sp.Scene.RegionInfo.RegionName);
|
||||
m_GridUserService.SetLastPosition(
|
||||
sp.UUID.ToString(), UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
|
||||
userid, UUID.Zero, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnNewClient(IClientAPI client)
|
||||
@@ -82,9 +84,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
|
||||
if (client.SceneAgent.IsChildAgent)
|
||||
return;
|
||||
|
||||
// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName);
|
||||
string userId = client.AgentId.ToString();
|
||||
if (client.Scene is Scene)
|
||||
{
|
||||
Scene s = (Scene)client.Scene;
|
||||
userId = s.UserManagementModule.GetUserUUI(client.AgentId);
|
||||
}
|
||||
//m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", userId, client.Scene.RegionInfo.RegionName);
|
||||
|
||||
m_GridUserService.LoggedOut(
|
||||
client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID,
|
||||
userId, client.SessionId, client.Scene.RegionInfo.RegionID,
|
||||
client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private const int KEEPTIME = 30; // 30 secs
|
||||
private ExpiringCache<string, GridUserInfo> m_Infos = new ExpiringCache<string, GridUserInfo>();
|
||||
|
||||
#region ISharedRegionModule
|
||||
|
||||
private bool m_Enabled = false;
|
||||
@@ -128,23 +131,60 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser
|
||||
|
||||
public bool LoggedOut(string userID, UUID sessionID, UUID region, Vector3 position, Vector3 lookat)
|
||||
{
|
||||
if (m_Infos.Contains(userID))
|
||||
m_Infos.Remove(userID);
|
||||
|
||||
return m_RemoteConnector.LoggedOut(userID, sessionID, region, position, lookat);
|
||||
}
|
||||
|
||||
|
||||
public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
|
||||
{
|
||||
return m_RemoteConnector.SetHome(userID, regionID, position, lookAt);
|
||||
if (m_RemoteConnector.SetHome(userID, regionID, position, lookAt))
|
||||
{
|
||||
// Update the cache too
|
||||
GridUserInfo info = null;
|
||||
if (m_Infos.TryGetValue(userID, out info))
|
||||
{
|
||||
info.HomeRegionID = regionID;
|
||||
info.HomePosition = position;
|
||||
info.HomeLookAt = lookAt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt)
|
||||
{
|
||||
return m_RemoteConnector.SetLastPosition(userID, sessionID, regionID, position, lookAt);
|
||||
if (m_RemoteConnector.SetLastPosition(userID, sessionID, regionID, position, lookAt))
|
||||
{
|
||||
// Update the cache too
|
||||
GridUserInfo info = null;
|
||||
if (m_Infos.TryGetValue(userID, out info))
|
||||
{
|
||||
info.LastRegionID = regionID;
|
||||
info.LastPosition = position;
|
||||
info.LastLookAt = lookAt;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public GridUserInfo GetGridUserInfo(string userID)
|
||||
{
|
||||
return m_RemoteConnector.GetGridUserInfo(userID);
|
||||
GridUserInfo info = null;
|
||||
if (m_Infos.TryGetValue(userID, out info))
|
||||
return info;
|
||||
|
||||
info = m_RemoteConnector.GetGridUserInfo(userID);
|
||||
|
||||
m_Infos.AddOrUpdate(userID, info, KEEPTIME);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public GridUserInfo[] GetGridUserInfo(string[] userID)
|
||||
|
||||
@@ -43,6 +43,7 @@ using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.Framework.Scenes.Serialization;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using System.Threading;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
@@ -52,7 +53,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
public class ArchiveReadRequest
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// Contains data used while dearchiving a single scene.
|
||||
/// </summary>
|
||||
private class DearchiveContext
|
||||
{
|
||||
public Scene Scene { get; set; }
|
||||
|
||||
public List<string> SerialisedSceneObjects { get; set; }
|
||||
|
||||
public List<string> SerialisedParcels { get; set; }
|
||||
|
||||
public List<SceneObjectGroup> SceneObjects { get; set; }
|
||||
|
||||
public DearchiveContext(Scene scene)
|
||||
{
|
||||
Scene = scene;
|
||||
SerialisedSceneObjects = new List<string>();
|
||||
SerialisedParcels = new List<string>();
|
||||
SceneObjects = new List<SceneObjectGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version
|
||||
/// bumps here should be compatible.
|
||||
@@ -62,9 +86,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
/// <summary>
|
||||
/// Has the control file been loaded for this archive?
|
||||
/// </summary>
|
||||
public bool ControlFileLoaded { get; private set; }
|
||||
public bool ControlFileLoaded { get; private set; }
|
||||
|
||||
protected Scene m_scene;
|
||||
protected string m_loadPath;
|
||||
protected Scene m_rootScene;
|
||||
protected Stream m_loadStream;
|
||||
protected Guid m_requestId;
|
||||
protected string m_errorMessage;
|
||||
@@ -91,7 +116,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
if (m_UserMan == null)
|
||||
{
|
||||
m_UserMan = m_scene.RequestModuleInterface<IUserManagement>();
|
||||
m_UserMan = m_rootScene.RequestModuleInterface<IUserManagement>();
|
||||
}
|
||||
return m_UserMan;
|
||||
}
|
||||
@@ -104,10 +129,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
private IGroupsModule m_groupsModule;
|
||||
|
||||
private IAssetService m_assetService = null;
|
||||
|
||||
|
||||
public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_rootScene = scene;
|
||||
|
||||
m_loadPath = loadPath;
|
||||
try
|
||||
{
|
||||
m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress);
|
||||
@@ -128,12 +157,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
// Zero can never be a valid user id
|
||||
m_validUserUuids[UUID.Zero] = false;
|
||||
|
||||
m_groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
|
||||
m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
|
||||
m_assetService = m_rootScene.AssetService;
|
||||
}
|
||||
|
||||
public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_rootScene = scene;
|
||||
m_loadPath = null;
|
||||
m_loadStream = loadStream;
|
||||
m_merge = merge;
|
||||
m_skipAssets = skipAssets;
|
||||
@@ -142,33 +173,34 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
// Zero can never be a valid user id
|
||||
m_validUserUuids[UUID.Zero] = false;
|
||||
|
||||
m_groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
|
||||
m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
|
||||
m_assetService = m_rootScene.AssetService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dearchive the region embodied in this request.
|
||||
/// </summary>
|
||||
public void DearchiveRegion()
|
||||
{
|
||||
// The same code can handle dearchiving 0.1 and 0.2 OpenSim Archive versions
|
||||
DearchiveRegion0DotStar();
|
||||
}
|
||||
|
||||
private void DearchiveRegion0DotStar()
|
||||
{
|
||||
int successfulAssetRestores = 0;
|
||||
int failedAssetRestores = 0;
|
||||
List<string> serialisedSceneObjects = new List<string>();
|
||||
List<string> serialisedParcels = new List<string>();
|
||||
string filePath = "NONE";
|
||||
|
||||
TarArchiveReader archive = new TarArchiveReader(m_loadStream);
|
||||
DearchiveScenesInfo dearchivedScenes;
|
||||
|
||||
// We dearchive all the scenes at once, because the files in the TAR archive might be mixed.
|
||||
// Therefore, we have to keep track of the dearchive context of all the scenes.
|
||||
Dictionary<UUID, DearchiveContext> sceneContexts = new Dictionary<UUID, DearchiveContext>();
|
||||
|
||||
string fullPath = "NONE";
|
||||
TarArchiveReader archive = null;
|
||||
byte[] data;
|
||||
TarArchiveReader.TarEntryType entryType;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
|
||||
FindAndLoadControlFile(out archive, out dearchivedScenes);
|
||||
|
||||
while ((data = archive.ReadEntry(out fullPath, out entryType)) != null)
|
||||
{
|
||||
//m_log.DebugFormat(
|
||||
// "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length);
|
||||
@@ -176,9 +208,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
|
||||
continue;
|
||||
|
||||
|
||||
// Find the scene that this file belongs to
|
||||
|
||||
Scene scene;
|
||||
string filePath;
|
||||
if (!dearchivedScenes.GetRegionFromPath(fullPath, out scene, out filePath))
|
||||
continue; // this file belongs to a region that we're not loading
|
||||
|
||||
DearchiveContext sceneContext = null;
|
||||
if (scene != null)
|
||||
{
|
||||
if (!sceneContexts.TryGetValue(scene.RegionInfo.RegionID, out sceneContext))
|
||||
{
|
||||
sceneContext = new DearchiveContext(scene);
|
||||
sceneContexts.Add(scene.RegionInfo.RegionID, sceneContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Process the file
|
||||
|
||||
if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
|
||||
{
|
||||
serialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
|
||||
sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets)
|
||||
{
|
||||
@@ -192,19 +245,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
}
|
||||
else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
|
||||
{
|
||||
LoadTerrain(filePath, data);
|
||||
LoadTerrain(scene, filePath, data);
|
||||
}
|
||||
else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
|
||||
{
|
||||
LoadRegionSettings(filePath, data);
|
||||
LoadRegionSettings(scene, filePath, data, dearchivedScenes);
|
||||
}
|
||||
else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH))
|
||||
{
|
||||
serialisedParcels.Add(Encoding.UTF8.GetString(data));
|
||||
sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
else if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
|
||||
{
|
||||
LoadControlFile(filePath, data);
|
||||
// Ignore, because we already read the control file
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,15 +265,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ARCHIVER]: Aborting load with error in archive file {0}. {1}", filePath, e);
|
||||
m_log.Error(
|
||||
String.Format("[ARCHIVER]: Aborting load with error in archive file {0} ", fullPath), e);
|
||||
m_errorMessage += e.ToString();
|
||||
m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage);
|
||||
m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
archive.Close();
|
||||
if (archive != null)
|
||||
archive.Close();
|
||||
}
|
||||
|
||||
if (!m_skipAssets)
|
||||
@@ -234,32 +288,143 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_merge)
|
||||
foreach (DearchiveContext sceneContext in sceneContexts.Values)
|
||||
{
|
||||
m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
|
||||
m_scene.DeleteAllSceneObjects();
|
||||
m_log.InfoFormat("[ARCHIVER]: Loading region {0}", sceneContext.Scene.RegionInfo.RegionName);
|
||||
|
||||
if (!m_merge)
|
||||
{
|
||||
m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
|
||||
sceneContext.Scene.DeleteAllSceneObjects();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels);
|
||||
LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects);
|
||||
|
||||
// Inform any interested parties that the region has changed. We waited until now so that all
|
||||
// of the region's objects will be loaded when we send this notification.
|
||||
IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface<IEstateModule>();
|
||||
if (estateModule != null)
|
||||
estateModule.TriggerRegionInfoChange();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error("[ARCHIVER]: Error loading parcels or objects ", e);
|
||||
m_errorMessage += e.ToString();
|
||||
m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LoadParcels(serialisedParcels);
|
||||
LoadObjects(serialisedSceneObjects);
|
||||
// Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so
|
||||
// that users can enter the scene. If we allow the scripts to start in the loop above
|
||||
// then they significantly increase the time until the OAR finishes loading.
|
||||
Util.FireAndForget(delegate(object o)
|
||||
{
|
||||
Thread.Sleep(15000);
|
||||
m_log.Info("[ARCHIVER]: Starting scripts in scene objects");
|
||||
|
||||
foreach (DearchiveContext sceneContext in sceneContexts.Values)
|
||||
{
|
||||
foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects)
|
||||
{
|
||||
sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart
|
||||
sceneObject.ResumeScripts();
|
||||
}
|
||||
|
||||
sceneContext.SceneObjects.Clear();
|
||||
}
|
||||
});
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive");
|
||||
|
||||
m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage);
|
||||
m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, dearchivedScenes.GetLoadedScenes(), m_errorMessage);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches through the files in the archive for the control file, and reads it.
|
||||
/// We must read the control file first, in order to know which regions are available.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In most cases the control file *is* first, since that's how we create archives. However,
|
||||
/// it's possible that someone rewrote the archive externally so we can't rely on this fact.
|
||||
/// </remarks>
|
||||
/// <param name="archive"></param>
|
||||
/// <param name="dearchivedScenes"></param>
|
||||
private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes)
|
||||
{
|
||||
archive = new TarArchiveReader(m_loadStream);
|
||||
dearchivedScenes = new DearchiveScenesInfo();
|
||||
|
||||
string filePath;
|
||||
byte[] data;
|
||||
TarArchiveReader.TarEntryType entryType;
|
||||
bool firstFile = true;
|
||||
|
||||
while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
|
||||
{
|
||||
if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
|
||||
continue;
|
||||
|
||||
if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
|
||||
{
|
||||
LoadControlFile(filePath, data, dearchivedScenes);
|
||||
|
||||
// Find which scenes are available in the simulator
|
||||
ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup();
|
||||
SceneManager.Instance.ForEachScene(delegate(Scene scene2)
|
||||
{
|
||||
simulatorScenes.AddScene(scene2);
|
||||
});
|
||||
simulatorScenes.CalcSceneLocations();
|
||||
dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes);
|
||||
|
||||
// If the control file wasn't the first file then reset the read pointer
|
||||
if (!firstFile)
|
||||
{
|
||||
m_log.Warn("Control file wasn't the first file in the archive");
|
||||
if (m_loadStream.CanSeek)
|
||||
{
|
||||
m_loadStream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
else if (m_loadPath != null)
|
||||
{
|
||||
archive.Close();
|
||||
archive = null;
|
||||
m_loadStream.Close();
|
||||
m_loadStream = null;
|
||||
m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress);
|
||||
archive = new TarArchiveReader(m_loadStream);
|
||||
}
|
||||
else
|
||||
{
|
||||
// There isn't currently a scenario where this happens, but it's best to add a check just in case
|
||||
throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
firstFile = false;
|
||||
}
|
||||
|
||||
throw new Exception("Control file not found");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load serialized scene objects.
|
||||
/// </summary>
|
||||
/// <param name="serialisedSceneObjects"></param>
|
||||
protected void LoadObjects(List<string> serialisedSceneObjects)
|
||||
protected void LoadObjects(Scene scene, List<string> serialisedSceneObjects, List<SceneObjectGroup> sceneObjects)
|
||||
{
|
||||
// Reload serialized prims
|
||||
m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
|
||||
|
||||
UUID oldTelehubUUID = m_scene.RegionInfo.RegionSettings.TelehubObject;
|
||||
UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject;
|
||||
|
||||
IRegionSerialiserModule serialiser = m_scene.RequestModuleInterface<IRegionSerialiserModule>();
|
||||
IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
|
||||
int sceneObjectsLoadedCount = 0;
|
||||
|
||||
foreach (string serialisedSceneObject in serialisedSceneObjects)
|
||||
@@ -280,7 +445,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
|
||||
|
||||
bool isTelehub = (sceneObject.UUID == oldTelehubUUID);
|
||||
bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero);
|
||||
|
||||
// For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
|
||||
// on the same region server and multiple examples a single object archive to be imported
|
||||
@@ -290,8 +455,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
if (isTelehub)
|
||||
{
|
||||
// Change the Telehub Object to the new UUID
|
||||
m_scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID;
|
||||
m_scene.RegionInfo.RegionSettings.Save();
|
||||
scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID;
|
||||
scene.RegionInfo.RegionSettings.Save();
|
||||
oldTelehubUUID = UUID.Zero;
|
||||
}
|
||||
|
||||
@@ -301,17 +466,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
if (part.CreatorData == null || part.CreatorData == string.Empty)
|
||||
{
|
||||
if (!ResolveUserUuid(part.CreatorID))
|
||||
part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
if (!ResolveUserUuid(scene, part.CreatorID))
|
||||
part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
}
|
||||
if (UserManager != null)
|
||||
UserManager.AddUser(part.CreatorID, part.CreatorData);
|
||||
|
||||
if (!ResolveUserUuid(part.OwnerID))
|
||||
part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
if (!ResolveUserUuid(scene, part.OwnerID))
|
||||
part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
|
||||
if (!ResolveUserUuid(part.LastOwnerID))
|
||||
part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
if (!ResolveUserUuid(scene, part.LastOwnerID))
|
||||
part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
|
||||
if (!ResolveGroupUuid(part.GroupID))
|
||||
part.GroupID = UUID.Zero;
|
||||
@@ -328,15 +493,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
TaskInventoryDictionary inv = part.TaskInventory;
|
||||
foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
|
||||
{
|
||||
if (!ResolveUserUuid(kvp.Value.OwnerID))
|
||||
if (!ResolveUserUuid(scene, kvp.Value.OwnerID))
|
||||
{
|
||||
kvp.Value.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
}
|
||||
|
||||
if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty)
|
||||
{
|
||||
if (!ResolveUserUuid(kvp.Value.CreatorID))
|
||||
kvp.Value.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
|
||||
kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
}
|
||||
|
||||
if (UserManager != null)
|
||||
@@ -348,10 +513,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
}
|
||||
}
|
||||
|
||||
if (m_scene.AddRestoredSceneObject(sceneObject, true, false))
|
||||
if (scene.AddRestoredSceneObject(sceneObject, true, false))
|
||||
{
|
||||
sceneObjectsLoadedCount++;
|
||||
sceneObject.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, 0);
|
||||
sceneObject.CreateScriptInstances(0, false, scene.DefaultScriptEngine, 0);
|
||||
sceneObject.ResumeScripts();
|
||||
}
|
||||
}
|
||||
@@ -366,16 +531,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
if (oldTelehubUUID != UUID.Zero)
|
||||
{
|
||||
m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID);
|
||||
m_scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero;
|
||||
m_scene.RegionInfo.RegionSettings.ClearSpawnPoints();
|
||||
scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero;
|
||||
scene.RegionInfo.RegionSettings.ClearSpawnPoints();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load serialized parcels.
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="serialisedParcels"></param>
|
||||
protected void LoadParcels(List<string> serialisedParcels)
|
||||
protected void LoadParcels(Scene scene, List<string> serialisedParcels)
|
||||
{
|
||||
// Reload serialized parcels
|
||||
m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count);
|
||||
@@ -386,8 +552,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
// Validate User and Group UUID's
|
||||
|
||||
if (!ResolveUserUuid(parcel.OwnerID))
|
||||
parcel.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
if (!ResolveUserUuid(scene, parcel.OwnerID))
|
||||
parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
|
||||
|
||||
if (!ResolveGroupUuid(parcel.GroupID))
|
||||
{
|
||||
@@ -398,7 +564,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
List<LandAccessEntry> accessList = new List<LandAccessEntry>();
|
||||
foreach (LandAccessEntry entry in parcel.ParcelAccessList)
|
||||
{
|
||||
if (ResolveUserUuid(entry.AgentID))
|
||||
if (ResolveUserUuid(scene, entry.AgentID))
|
||||
accessList.Add(entry);
|
||||
// else, drop this access rule
|
||||
}
|
||||
@@ -414,23 +580,24 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
if (!m_merge)
|
||||
{
|
||||
bool setupDefaultParcel = (landData.Count == 0);
|
||||
m_scene.LandChannel.Clear(setupDefaultParcel);
|
||||
scene.LandChannel.Clear(setupDefaultParcel);
|
||||
}
|
||||
|
||||
m_scene.EventManager.TriggerIncomingLandDataFromStorage(landData);
|
||||
scene.EventManager.TriggerIncomingLandDataFromStorage(landData);
|
||||
m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Look up the given user id to check whether it's one that is valid for this grid.
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="uuid"></param>
|
||||
/// <returns></returns>
|
||||
private bool ResolveUserUuid(UUID uuid)
|
||||
private bool ResolveUserUuid(Scene scene, UUID uuid)
|
||||
{
|
||||
if (!m_validUserUuids.ContainsKey(uuid))
|
||||
{
|
||||
UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid);
|
||||
UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid);
|
||||
m_validUserUuids.Add(uuid, account != null);
|
||||
}
|
||||
|
||||
@@ -485,7 +652,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
string extension = filename.Substring(i);
|
||||
string uuid = filename.Remove(filename.Length - extension.Length);
|
||||
|
||||
if (m_scene.AssetService.GetMetadata(uuid) != null)
|
||||
if (m_assetService.GetMetadata(uuid) != null)
|
||||
{
|
||||
// m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid);
|
||||
return true;
|
||||
@@ -505,7 +672,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
// We're relying on the asset service to do the sensible thing and not store the asset if it already
|
||||
// exists.
|
||||
m_scene.AssetService.Store(asset);
|
||||
m_assetService.Store(asset);
|
||||
|
||||
/**
|
||||
* Create layers on decode for image assets. This is likely to significantly increase the time to load archives so
|
||||
@@ -533,12 +700,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
/// <summary>
|
||||
/// Load region settings data
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="settingsPath"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="dearchivedScenes"></param>
|
||||
/// <returns>
|
||||
/// true if settings were loaded successfully, false otherwise
|
||||
/// </returns>
|
||||
private bool LoadRegionSettings(string settingsPath, byte[] data)
|
||||
private bool LoadRegionSettings(Scene scene, string settingsPath, byte[] data, DearchiveScenesInfo dearchivedScenes)
|
||||
{
|
||||
RegionSettings loadedRegionSettings;
|
||||
|
||||
@@ -554,7 +723,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
return false;
|
||||
}
|
||||
|
||||
RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings;
|
||||
RegionSettings currentRegionSettings = scene.RegionInfo.RegionSettings;
|
||||
|
||||
currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit;
|
||||
currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage;
|
||||
@@ -591,12 +760,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints())
|
||||
currentRegionSettings.AddSpawnPoint(sp);
|
||||
|
||||
currentRegionSettings.LoadedCreationDateTime = dearchivedScenes.LoadedCreationDateTime;
|
||||
currentRegionSettings.LoadedCreationID = dearchivedScenes.GetOriginalRegionID(scene.RegionInfo.RegionID).ToString();
|
||||
|
||||
currentRegionSettings.Save();
|
||||
|
||||
m_scene.TriggerEstateSunUpdate();
|
||||
scene.TriggerEstateSunUpdate();
|
||||
|
||||
IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
|
||||
|
||||
IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
|
||||
if (estateModule != null)
|
||||
estateModule.sendRegionHandshakeToAll();
|
||||
|
||||
@@ -606,14 +777,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
/// <summary>
|
||||
/// Load terrain data
|
||||
/// </summary>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="terrainPath"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <returns>
|
||||
/// true if terrain was resolved successfully, false otherwise.
|
||||
/// </returns>
|
||||
private bool LoadTerrain(string terrainPath, byte[] data)
|
||||
private bool LoadTerrain(Scene scene, string terrainPath, byte[] data)
|
||||
{
|
||||
ITerrainModule terrainModule = m_scene.RequestModuleInterface<ITerrainModule>();
|
||||
ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
|
||||
|
||||
MemoryStream ms = new MemoryStream(data);
|
||||
terrainModule.LoadFromStream(terrainPath, ms);
|
||||
@@ -629,17 +801,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="data"></param>
|
||||
public void LoadControlFile(string path, byte[] data)
|
||||
/// <param name="dearchivedScenes"></param>
|
||||
public DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes)
|
||||
{
|
||||
XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
|
||||
XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
|
||||
XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context);
|
||||
|
||||
RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings;
|
||||
// Loaded metadata will be empty if no information exists in the archive
|
||||
dearchivedScenes.LoadedCreationDateTime = 0;
|
||||
dearchivedScenes.DefaultOriginalID = "";
|
||||
|
||||
// Loaded metadata will empty if no information exists in the archive
|
||||
currentRegionSettings.LoadedCreationDateTime = 0;
|
||||
currentRegionSettings.LoadedCreationID = "";
|
||||
bool multiRegion = false;
|
||||
|
||||
while (xtr.Read())
|
||||
{
|
||||
@@ -665,18 +838,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
int value;
|
||||
if (Int32.TryParse(xtr.ReadElementContentAsString(), out value))
|
||||
currentRegionSettings.LoadedCreationDateTime = value;
|
||||
dearchivedScenes.LoadedCreationDateTime = value;
|
||||
}
|
||||
else if (xtr.Name.ToString() == "id")
|
||||
else if (xtr.Name.ToString() == "row")
|
||||
{
|
||||
currentRegionSettings.LoadedCreationID = xtr.ReadElementContentAsString();
|
||||
multiRegion = true;
|
||||
dearchivedScenes.StartRow();
|
||||
}
|
||||
else if (xtr.Name.ToString() == "region")
|
||||
{
|
||||
dearchivedScenes.StartRegion();
|
||||
}
|
||||
else if (xtr.Name.ToString() == "id")
|
||||
{
|
||||
string id = xtr.ReadElementContentAsString();
|
||||
dearchivedScenes.DefaultOriginalID = id;
|
||||
if (multiRegion)
|
||||
dearchivedScenes.SetRegionOriginalID(id);
|
||||
}
|
||||
else if (xtr.Name.ToString() == "dir")
|
||||
{
|
||||
dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentRegionSettings.Save();
|
||||
|
||||
|
||||
dearchivedScenes.MultiRegionFormat = multiRegion;
|
||||
if (!multiRegion)
|
||||
{
|
||||
// Add the single scene
|
||||
dearchivedScenes.StartRow();
|
||||
dearchivedScenes.StartRegion();
|
||||
dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID);
|
||||
dearchivedScenes.SetRegionDirectory("");
|
||||
}
|
||||
|
||||
ControlFileLoaded = true;
|
||||
|
||||
return dearchivedScenes;
|
||||
}
|
||||
}
|
||||
}
|
||||
176
OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
Normal file
176
OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenMetaverse;
|
||||
using System.Drawing;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
/// <summary>
|
||||
/// A group of regions arranged in a rectangle, possibly with holes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The regions usually (but not necessarily) belong to an archive file, in which case we
|
||||
/// store additional information used to create the archive (e.g., each region's
|
||||
/// directory within the archive).
|
||||
/// </remarks>
|
||||
public class ArchiveScenesGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// All the regions. The outer dictionary contains rows (key: Y coordinate).
|
||||
/// The inner dictionaries contain each row's regions (key: X coordinate).
|
||||
/// </summary>
|
||||
public SortedDictionary<uint, SortedDictionary<uint, Scene>> Regions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The subdirectory where each region is stored in the archive.
|
||||
/// </summary>
|
||||
protected Dictionary<UUID, string> m_regionDirs;
|
||||
|
||||
/// <summary>
|
||||
/// The grid coordinates of the regions' bounding box.
|
||||
/// </summary>
|
||||
public Rectangle Rect { get; set; }
|
||||
|
||||
|
||||
public ArchiveScenesGroup()
|
||||
{
|
||||
Regions = new SortedDictionary<uint, SortedDictionary<uint, Scene>>();
|
||||
m_regionDirs = new Dictionary<UUID, string>();
|
||||
Rect = new Rectangle(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public void AddScene(Scene scene)
|
||||
{
|
||||
uint x = scene.RegionInfo.RegionLocX;
|
||||
uint y = scene.RegionInfo.RegionLocY;
|
||||
|
||||
SortedDictionary<uint, Scene> row;
|
||||
if (!Regions.TryGetValue(y, out row))
|
||||
{
|
||||
row = new SortedDictionary<uint, Scene>();
|
||||
Regions[y] = row;
|
||||
}
|
||||
|
||||
row[x] = scene;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after all the scenes have been added. Performs calculations that require
|
||||
/// knowledge of all the scenes.
|
||||
/// </summary>
|
||||
public void CalcSceneLocations()
|
||||
{
|
||||
if (Regions.Count == 0)
|
||||
return;
|
||||
|
||||
// Find the bounding rectangle
|
||||
|
||||
uint firstY = Regions.First().Key;
|
||||
uint lastY = Regions.Last().Key;
|
||||
|
||||
uint? firstX = null;
|
||||
uint? lastX = null;
|
||||
|
||||
foreach (SortedDictionary<uint, Scene> row in Regions.Values)
|
||||
{
|
||||
uint curFirstX = row.First().Key;
|
||||
uint curLastX = row.Last().Key;
|
||||
|
||||
firstX = (firstX == null) ? curFirstX : (firstX < curFirstX) ? firstX : curFirstX;
|
||||
lastX = (lastX == null) ? curLastX : (lastX > curLastX) ? lastX : curLastX;
|
||||
}
|
||||
|
||||
Rect = new Rectangle((int)firstX, (int)firstY, (int)(lastY - firstY + 1), (int)(lastX - firstX + 1));
|
||||
|
||||
|
||||
// Calculate the subdirectory in which each region will be stored in the archive
|
||||
|
||||
m_regionDirs.Clear();
|
||||
ForEachScene(delegate(Scene scene)
|
||||
{
|
||||
// We add the region's coordinates to ensure uniqueness even if multiple regions have the same name
|
||||
string path = string.Format("{0}_{1}_{2}",
|
||||
scene.RegionInfo.RegionLocX - Rect.X + 1,
|
||||
scene.RegionInfo.RegionLocY - Rect.Y + 1,
|
||||
scene.RegionInfo.RegionName.Replace(' ', '_'));
|
||||
m_regionDirs[scene.RegionInfo.RegionID] = path;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the subdirectory where the region is stored.
|
||||
/// </summary>
|
||||
/// <param name="regionID"></param>
|
||||
/// <returns></returns>
|
||||
public string GetRegionDir(UUID regionID)
|
||||
{
|
||||
return m_regionDirs[regionID];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs an action on all the scenes in this order: rows from South to North,
|
||||
/// and within each row West to East.
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
public void ForEachScene(Action<Scene> action)
|
||||
{
|
||||
foreach (SortedDictionary<uint, Scene> row in Regions.Values)
|
||||
{
|
||||
foreach (Scene scene in row.Values)
|
||||
{
|
||||
action(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the scene at position 'location'.
|
||||
/// </summary>
|
||||
/// <param name="location">A location in the grid</param>
|
||||
/// <param name="scene">The scene at this location</param>
|
||||
/// <returns>Whether the scene was found</returns>
|
||||
public bool TryGetScene(Point location, out Scene scene)
|
||||
{
|
||||
SortedDictionary<uint, Scene> row;
|
||||
if (Regions.TryGetValue((uint)location.Y, out row))
|
||||
{
|
||||
if (row.TryGetValue((uint)location.X, out scene))
|
||||
return true;
|
||||
}
|
||||
|
||||
scene = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
634
OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
Normal file
634
OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
Normal file
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Serialization;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using Ionic.Zlib;
|
||||
using GZipStream = Ionic.Zlib.GZipStream;
|
||||
using CompressionMode = Ionic.Zlib.CompressionMode;
|
||||
using OpenSim.Framework.Serialization.External;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
/// <summary>
|
||||
/// Prepare to write out an archive.
|
||||
/// </summary>
|
||||
public class ArchiveWriteRequest
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// The minimum major version of OAR that we can write.
|
||||
/// </summary>
|
||||
public static int MIN_MAJOR_VERSION = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum major version of OAR that we can write.
|
||||
/// </summary>
|
||||
public static int MAX_MAJOR_VERSION = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we're saving a multi-region archive.
|
||||
/// </summary>
|
||||
public bool MultiRegionFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether this archive will save assets. Default is true.
|
||||
/// </summary>
|
||||
public bool SaveAssets { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines which objects will be included in the archive, according to their permissions.
|
||||
/// Default is null, meaning no permission checks.
|
||||
/// </summary>
|
||||
public string CheckPermissions { get; set; }
|
||||
|
||||
protected Scene m_rootScene;
|
||||
protected Stream m_saveStream;
|
||||
protected TarArchiveWriter m_archiveWriter;
|
||||
protected Guid m_requestId;
|
||||
protected Dictionary<string, object> m_options;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="module">Calling module</param>
|
||||
/// <param name="savePath">The path to which to save data.</param>
|
||||
/// <param name="requestId">The id associated with this request</param>
|
||||
/// <exception cref="System.IO.IOException">
|
||||
/// If there was a problem opening a stream for the file specified by the savePath
|
||||
/// </exception>
|
||||
public ArchiveWriteRequest(Scene scene, string savePath, Guid requestId) : this(scene, requestId)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression);
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
|
||||
+ "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
|
||||
m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="scene">The root scene to archive</param>
|
||||
/// <param name="saveStream">The stream to which to save data.</param>
|
||||
/// <param name="requestId">The id associated with this request</param>
|
||||
public ArchiveWriteRequest(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId)
|
||||
{
|
||||
m_saveStream = saveStream;
|
||||
}
|
||||
|
||||
protected ArchiveWriteRequest(Scene scene, Guid requestId)
|
||||
{
|
||||
m_rootScene = scene;
|
||||
m_requestId = requestId;
|
||||
m_archiveWriter = null;
|
||||
|
||||
MultiRegionFormat = false;
|
||||
SaveAssets = true;
|
||||
CheckPermissions = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archive the region requested.
|
||||
/// </summary>
|
||||
/// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
|
||||
public void ArchiveRegion(Dictionary<string, object> options)
|
||||
{
|
||||
m_options = options;
|
||||
|
||||
if (options.ContainsKey("all") && (bool)options["all"])
|
||||
MultiRegionFormat = true;
|
||||
|
||||
if (options.ContainsKey("noassets") && (bool)options["noassets"])
|
||||
SaveAssets = false;
|
||||
|
||||
Object temp;
|
||||
if (options.TryGetValue("checkPermissions", out temp))
|
||||
CheckPermissions = (string)temp;
|
||||
|
||||
|
||||
// Find the regions to archive
|
||||
ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
|
||||
if (MultiRegionFormat)
|
||||
{
|
||||
m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count);
|
||||
SceneManager.Instance.ForEachScene(delegate(Scene scene)
|
||||
{
|
||||
scenesGroup.AddScene(scene);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
scenesGroup.AddScene(m_rootScene);
|
||||
}
|
||||
scenesGroup.CalcSceneLocations();
|
||||
|
||||
|
||||
m_archiveWriter = new TarArchiveWriter(m_saveStream);
|
||||
|
||||
try
|
||||
{
|
||||
// Write out control file. It should be first so that it will be found ASAP when loading the file.
|
||||
m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup));
|
||||
m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
|
||||
|
||||
// Archive the regions
|
||||
|
||||
Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
|
||||
|
||||
scenesGroup.ForEachScene(delegate(Scene scene)
|
||||
{
|
||||
string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : "";
|
||||
ArchiveOneRegion(scene, regionDir, assetUuids);
|
||||
});
|
||||
|
||||
// Archive the assets
|
||||
|
||||
if (SaveAssets)
|
||||
{
|
||||
m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count);
|
||||
|
||||
// Asynchronously request all the assets required to perform this archive operation
|
||||
AssetsRequest ar
|
||||
= new AssetsRequest(
|
||||
new AssetsArchiver(m_archiveWriter), assetUuids,
|
||||
m_rootScene.AssetService, m_rootScene.UserAccountService,
|
||||
m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets);
|
||||
|
||||
Util.FireAndForget(o => ar.Execute());
|
||||
|
||||
// CloseArchive() will be called from ReceivedAllAssets()
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
|
||||
CloseArchive(string.Empty);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CloseArchive(e.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
|
||||
{
|
||||
m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
|
||||
|
||||
EntityBase[] entities = scene.GetEntities();
|
||||
List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
|
||||
|
||||
int numObjectsSkippedPermissions = 0;
|
||||
|
||||
// Filter entities so that we only have scene objects.
|
||||
// FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
|
||||
// end up having to do this
|
||||
IPermissionsModule permissionsModule = scene.RequestModuleInterface<IPermissionsModule>();
|
||||
foreach (EntityBase entity in entities)
|
||||
{
|
||||
if (entity is SceneObjectGroup)
|
||||
{
|
||||
SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
|
||||
|
||||
if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
|
||||
{
|
||||
if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule))
|
||||
{
|
||||
// The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
|
||||
++numObjectsSkippedPermissions;
|
||||
}
|
||||
else
|
||||
{
|
||||
sceneObjects.Add(sceneObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SaveAssets)
|
||||
{
|
||||
UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService);
|
||||
int prevAssets = assetUuids.Count;
|
||||
|
||||
foreach (SceneObjectGroup sceneObject in sceneObjects)
|
||||
{
|
||||
assetGatherer.GatherAssetUuids(sceneObject, assetUuids);
|
||||
}
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
|
||||
sceneObjects.Count, assetUuids.Count - prevAssets);
|
||||
}
|
||||
|
||||
if (numObjectsSkippedPermissions > 0)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
|
||||
numObjectsSkippedPermissions);
|
||||
}
|
||||
|
||||
// Make sure that we also request terrain texture assets
|
||||
RegionSettings regionSettings = scene.RegionInfo.RegionSettings;
|
||||
|
||||
if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
|
||||
assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
|
||||
|
||||
if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
|
||||
assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
|
||||
|
||||
if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
|
||||
assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
|
||||
|
||||
if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
|
||||
assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
|
||||
|
||||
Save(scene, sceneObjects, regionDir);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the user has permission to export an object group to an OAR.
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <param name="objGroup">The object group</param>
|
||||
/// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param>
|
||||
/// <param name="permissionsModule">The scene's permissions module</param>
|
||||
/// <returns>Whether the user is allowed to export the object to an OAR</returns>
|
||||
private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule)
|
||||
{
|
||||
if (checkPermissions == null)
|
||||
return true;
|
||||
|
||||
if (permissionsModule == null)
|
||||
return true; // this shouldn't happen
|
||||
|
||||
// Check whether the user is permitted to export all of the parts in the SOG. If any
|
||||
// part can't be exported then the entire SOG can't be exported.
|
||||
|
||||
bool permitted = true;
|
||||
//int primNumber = 1;
|
||||
|
||||
foreach (SceneObjectPart obj in objGroup.Parts)
|
||||
{
|
||||
uint perm;
|
||||
PermissionClass permissionClass = permissionsModule.GetPermissionClass(user, obj);
|
||||
switch (permissionClass)
|
||||
{
|
||||
case PermissionClass.Owner:
|
||||
perm = obj.BaseMask;
|
||||
break;
|
||||
case PermissionClass.Group:
|
||||
perm = obj.GroupMask | obj.EveryoneMask;
|
||||
break;
|
||||
case PermissionClass.Everyone:
|
||||
default:
|
||||
perm = obj.EveryoneMask;
|
||||
break;
|
||||
}
|
||||
|
||||
bool canCopy = (perm & (uint)PermissionMask.Copy) != 0;
|
||||
bool canTransfer = (perm & (uint)PermissionMask.Transfer) != 0;
|
||||
|
||||
// Special case: if Everyone can copy the object then this implies it can also be
|
||||
// Transferred.
|
||||
// However, if the user is the Owner then we don't check EveryoneMask, because it seems that the mask
|
||||
// always (incorrectly) includes the Copy bit set in this case. But that's a mistake: the viewer
|
||||
// does NOT show that the object has Everyone-Copy permissions, and doesn't allow it to be copied.
|
||||
if (permissionClass != PermissionClass.Owner)
|
||||
canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
|
||||
|
||||
bool partPermitted = true;
|
||||
if (checkPermissions.Contains("C") && !canCopy)
|
||||
partPermitted = false;
|
||||
if (checkPermissions.Contains("T") && !canTransfer)
|
||||
partPermitted = false;
|
||||
|
||||
// If the user is the Creator of the object then it can always be included in the OAR
|
||||
bool creator = (obj.CreatorID.Guid == user.Guid);
|
||||
if (creator)
|
||||
partPermitted = true;
|
||||
|
||||
//string name = (objGroup.PrimCount == 1) ? objGroup.Name : string.Format("{0} ({1}/{2})", obj.Name, primNumber, objGroup.PrimCount);
|
||||
//m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, creator={8}, permitted={9}",
|
||||
// name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask,
|
||||
// permissionClass, checkPermissions, canCopy, canTransfer, creator, partPermitted);
|
||||
|
||||
if (!partPermitted)
|
||||
{
|
||||
permitted = false;
|
||||
break;
|
||||
}
|
||||
|
||||
//++primNumber;
|
||||
}
|
||||
|
||||
return permitted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the control file.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string CreateControlFile(ArchiveScenesGroup scenesGroup)
|
||||
{
|
||||
int majorVersion;
|
||||
int minorVersion;
|
||||
|
||||
if (MultiRegionFormat)
|
||||
{
|
||||
majorVersion = MAX_MAJOR_VERSION;
|
||||
minorVersion = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// To support older versions of OpenSim, we continue to create single-region OARs
|
||||
// using the old file format. In the future this format will be discontinued.
|
||||
majorVersion = 0;
|
||||
minorVersion = 8;
|
||||
}
|
||||
//
|
||||
// if (m_options.ContainsKey("version"))
|
||||
// {
|
||||
// string[] parts = m_options["version"].ToString().Split('.');
|
||||
// if (parts.Length >= 1)
|
||||
// {
|
||||
// majorVersion = Int32.Parse(parts[0]);
|
||||
//
|
||||
// if (parts.Length >= 2)
|
||||
// minorVersion = Int32.Parse(parts[1]);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION)
|
||||
// {
|
||||
// throw new Exception(
|
||||
// string.Format(
|
||||
// "OAR version number for save must be between {0} and {1}",
|
||||
// MIN_MAJOR_VERSION, MAX_MAJOR_VERSION));
|
||||
// }
|
||||
// else if (majorVersion == MAX_MAJOR_VERSION)
|
||||
// {
|
||||
// // Force 1.0
|
||||
// minorVersion = 0;
|
||||
// }
|
||||
// else if (majorVersion == MIN_MAJOR_VERSION)
|
||||
// {
|
||||
// // Force 0.4
|
||||
// minorVersion = 4;
|
||||
// }
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion);
|
||||
if (majorVersion == 1)
|
||||
{
|
||||
m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim versions prior to 0.7.4. Do not use the --all option if you want to produce a compatible OAR");
|
||||
}
|
||||
|
||||
String s;
|
||||
|
||||
using (StringWriter sw = new StringWriter())
|
||||
{
|
||||
using (XmlTextWriter xtw = new XmlTextWriter(sw))
|
||||
{
|
||||
xtw.Formatting = Formatting.Indented;
|
||||
xtw.WriteStartDocument();
|
||||
xtw.WriteStartElement("archive");
|
||||
xtw.WriteAttributeString("major_version", majorVersion.ToString());
|
||||
xtw.WriteAttributeString("minor_version", minorVersion.ToString());
|
||||
|
||||
xtw.WriteStartElement("creation_info");
|
||||
DateTime now = DateTime.UtcNow;
|
||||
TimeSpan t = now - new DateTime(1970, 1, 1);
|
||||
xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
|
||||
if (!MultiRegionFormat)
|
||||
xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString());
|
||||
xtw.WriteEndElement();
|
||||
|
||||
xtw.WriteElementString("assets_included", SaveAssets.ToString());
|
||||
|
||||
if (MultiRegionFormat)
|
||||
{
|
||||
WriteRegionsManifest(scenesGroup, xtw);
|
||||
}
|
||||
else
|
||||
{
|
||||
xtw.WriteStartElement("region_info");
|
||||
WriteRegionInfo(m_rootScene, xtw);
|
||||
xtw.WriteEndElement();
|
||||
}
|
||||
|
||||
xtw.WriteEndElement();
|
||||
|
||||
xtw.Flush();
|
||||
}
|
||||
|
||||
s = sw.ToString();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the list of regions included in a multi-region OAR.
|
||||
/// </summary>
|
||||
private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw)
|
||||
{
|
||||
xtw.WriteStartElement("regions");
|
||||
|
||||
// Write the regions in order: rows from South to North, then regions from West to East.
|
||||
// The list of regions can have "holes"; we write empty elements in their position.
|
||||
|
||||
for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y)
|
||||
{
|
||||
SortedDictionary<uint, Scene> row;
|
||||
if (scenesGroup.Regions.TryGetValue(y, out row))
|
||||
{
|
||||
xtw.WriteStartElement("row");
|
||||
|
||||
for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x)
|
||||
{
|
||||
Scene scene;
|
||||
if (row.TryGetValue(x, out scene))
|
||||
{
|
||||
xtw.WriteStartElement("region");
|
||||
xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString());
|
||||
xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID));
|
||||
WriteRegionInfo(scene, xtw);
|
||||
xtw.WriteEndElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write a placeholder for a missing region
|
||||
xtw.WriteElementString("region", "");
|
||||
}
|
||||
}
|
||||
|
||||
xtw.WriteEndElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write a placeholder for a missing row
|
||||
xtw.WriteElementString("row", "");
|
||||
}
|
||||
}
|
||||
|
||||
xtw.WriteEndElement(); // "regions"
|
||||
}
|
||||
|
||||
protected static void WriteRegionInfo(Scene scene, XmlTextWriter xtw)
|
||||
{
|
||||
bool isMegaregion;
|
||||
Vector2 size;
|
||||
|
||||
IRegionCombinerModule rcMod = scene.RequestModuleInterface<IRegionCombinerModule>();
|
||||
|
||||
if (rcMod != null)
|
||||
isMegaregion = rcMod.IsRootForMegaregion(scene.RegionInfo.RegionID);
|
||||
else
|
||||
isMegaregion = false;
|
||||
|
||||
if (isMegaregion)
|
||||
size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
|
||||
else
|
||||
size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize);
|
||||
|
||||
xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
|
||||
xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
|
||||
}
|
||||
|
||||
|
||||
protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
|
||||
{
|
||||
if (regionDir != string.Empty)
|
||||
regionDir = ArchiveConstants.REGIONS_PATH + regionDir + "/";
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
|
||||
|
||||
// Write out region settings
|
||||
string settingsPath = String.Format("{0}{1}{2}.xml",
|
||||
regionDir, ArchiveConstants.SETTINGS_PATH, scene.RegionInfo.RegionName);
|
||||
m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(scene.RegionInfo.RegionSettings));
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
|
||||
|
||||
// Write out land data (aka parcel) settings
|
||||
List<ILandObject> landObjects = scene.LandChannel.AllParcels();
|
||||
foreach (ILandObject lo in landObjects)
|
||||
{
|
||||
LandData landData = lo.LandData;
|
||||
string landDataPath = String.Format("{0}{1}{2}.xml",
|
||||
regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString());
|
||||
m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
|
||||
}
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
|
||||
|
||||
// Write out terrain
|
||||
string terrainPath = String.Format("{0}{1}{2}.r32",
|
||||
regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName);
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms);
|
||||
m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
|
||||
ms.Close();
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
|
||||
|
||||
// Write out scene object metadata
|
||||
IRegionSerialiserModule serializer = scene.RequestModuleInterface<IRegionSerialiserModule>();
|
||||
foreach (SceneObjectGroup sceneObject in sceneObjects)
|
||||
{
|
||||
//m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
|
||||
|
||||
string serializedObject = serializer.SerializeGroupToXml2(sceneObject, m_options);
|
||||
string objectPath = string.Format("{0}{1}", regionDir, ArchiveHelpers.CreateObjectPath(sceneObject));
|
||||
m_archiveWriter.WriteFile(objectPath, serializedObject);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ReceivedAllAssets(
|
||||
ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
|
||||
{
|
||||
foreach (UUID uuid in assetsNotFoundUuids)
|
||||
{
|
||||
m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
|
||||
}
|
||||
|
||||
// m_log.InfoFormat(
|
||||
// "[ARCHIVER]: Received {0} of {1} assets requested",
|
||||
// assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
|
||||
|
||||
CloseArchive(String.Empty);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Closes the archive and notifies that we're done.
|
||||
/// </summary>
|
||||
/// <param name="errorMessage">The error that occurred, or empty for success</param>
|
||||
protected void CloseArchive(string errorMessage)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_archiveWriter != null)
|
||||
m_archiveWriter.Close();
|
||||
m_saveStream.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(string.Format("[ARCHIVER]: Error closing archive: {0} ", e.Message), e);
|
||||
if (errorMessage == string.Empty)
|
||||
errorMessage = e.Message;
|
||||
}
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_rootScene.RegionInfo.RegionName);
|
||||
|
||||
m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Serialization;
|
||||
using OpenSim.Framework.Serialization.External;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
/// <summary>
|
||||
/// Method called when all the necessary assets for an archive request have been received.
|
||||
/// </summary>
|
||||
public delegate void AssetsRequestCallback(
|
||||
ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids);
|
||||
|
||||
/// <summary>
|
||||
/// Execute the write of an archive once we have received all the necessary data
|
||||
/// </summary>
|
||||
public class ArchiveWriteRequestExecution
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
protected ITerrainModule m_terrainModule;
|
||||
protected IRegionSerialiserModule m_serialiser;
|
||||
protected List<SceneObjectGroup> m_sceneObjects;
|
||||
protected Scene m_scene;
|
||||
protected TarArchiveWriter m_archiveWriter;
|
||||
protected Guid m_requestId;
|
||||
protected Dictionary<string, object> m_options;
|
||||
|
||||
public ArchiveWriteRequestExecution(
|
||||
List<SceneObjectGroup> sceneObjects,
|
||||
ITerrainModule terrainModule,
|
||||
IRegionSerialiserModule serialiser,
|
||||
Scene scene,
|
||||
TarArchiveWriter archiveWriter,
|
||||
Guid requestId,
|
||||
Dictionary<string, object> options)
|
||||
{
|
||||
m_sceneObjects = sceneObjects;
|
||||
m_terrainModule = terrainModule;
|
||||
m_serialiser = serialiser;
|
||||
m_scene = scene;
|
||||
m_archiveWriter = archiveWriter;
|
||||
m_requestId = requestId;
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
protected internal void ReceivedAllAssets(
|
||||
ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
|
||||
{
|
||||
try
|
||||
{
|
||||
Save(assetsFoundUuids, assetsNotFoundUuids);
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_archiveWriter.Close();
|
||||
}
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_scene.RegionInfo.RegionName);
|
||||
|
||||
m_scene.EventManager.TriggerOarFileSaved(m_requestId, String.Empty);
|
||||
}
|
||||
|
||||
protected internal void Save(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
|
||||
{
|
||||
foreach (UUID uuid in assetsNotFoundUuids)
|
||||
{
|
||||
m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
|
||||
}
|
||||
|
||||
// m_log.InfoFormat(
|
||||
// "[ARCHIVER]: Received {0} of {1} assets requested",
|
||||
// assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
|
||||
|
||||
// Write out region settings
|
||||
string settingsPath
|
||||
= String.Format("{0}{1}.xml", ArchiveConstants.SETTINGS_PATH, m_scene.RegionInfo.RegionName);
|
||||
m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(m_scene.RegionInfo.RegionSettings));
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
|
||||
|
||||
// Write out land data (aka parcel) settings
|
||||
List<ILandObject>landObjects = m_scene.LandChannel.AllParcels();
|
||||
foreach (ILandObject lo in landObjects)
|
||||
{
|
||||
LandData landData = lo.LandData;
|
||||
string landDataPath = String.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH,
|
||||
landData.GlobalID.ToString());
|
||||
m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
|
||||
}
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
|
||||
|
||||
// Write out terrain
|
||||
string terrainPath
|
||||
= String.Format("{0}{1}.r32", ArchiveConstants.TERRAINS_PATH, m_scene.RegionInfo.RegionName);
|
||||
|
||||
MemoryStream ms = new MemoryStream();
|
||||
m_terrainModule.SaveToStream(terrainPath, ms);
|
||||
m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
|
||||
ms.Close();
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
|
||||
|
||||
// Write out scene object metadata
|
||||
foreach (SceneObjectGroup sceneObject in m_sceneObjects)
|
||||
{
|
||||
//m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
|
||||
|
||||
string serializedObject = m_serialiser.SerializeGroupToXml2(sceneObject, m_options);
|
||||
m_archiveWriter.WriteFile(ArchiveHelpers.CreateObjectPath(sceneObject), serializedObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,438 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Serialization;
|
||||
using OpenSim.Region.CoreModules.World.Terrain;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using Ionic.Zlib;
|
||||
using GZipStream = Ionic.Zlib.GZipStream;
|
||||
using CompressionMode = Ionic.Zlib.CompressionMode;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
/// <summary>
|
||||
/// Prepare to write out an archive.
|
||||
/// </summary>
|
||||
public class ArchiveWriteRequestPreparation
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// The minimum major version of OAR that we can write.
|
||||
/// </summary>
|
||||
public static int MIN_MAJOR_VERSION = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum major version of OAR that we can write.
|
||||
/// </summary>
|
||||
public static int MAX_MAJOR_VERSION = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Determine whether this archive will save assets. Default is true.
|
||||
/// </summary>
|
||||
public bool SaveAssets { get; set; }
|
||||
|
||||
protected ArchiverModule m_module;
|
||||
protected Scene m_scene;
|
||||
protected Stream m_saveStream;
|
||||
protected Guid m_requestId;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="module">Calling module</param>
|
||||
/// <param name="savePath">The path to which to save data.</param>
|
||||
/// <param name="requestId">The id associated with this request</param>
|
||||
/// <exception cref="System.IO.IOException">
|
||||
/// If there was a problem opening a stream for the file specified by the savePath
|
||||
/// </exception>
|
||||
public ArchiveWriteRequestPreparation(ArchiverModule module, string savePath, Guid requestId) : this(module, requestId)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression);
|
||||
}
|
||||
catch (EntryPointNotFoundException e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
|
||||
+ "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
|
||||
m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
/// <param name="module">Calling module</param>
|
||||
/// <param name="saveStream">The stream to which to save data.</param>
|
||||
/// <param name="requestId">The id associated with this request</param>
|
||||
public ArchiveWriteRequestPreparation(ArchiverModule module, Stream saveStream, Guid requestId) : this(module, requestId)
|
||||
{
|
||||
m_saveStream = saveStream;
|
||||
}
|
||||
|
||||
protected ArchiveWriteRequestPreparation(ArchiverModule module, Guid requestId)
|
||||
{
|
||||
m_module = module;
|
||||
|
||||
// FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix
|
||||
// this.
|
||||
if (m_module != null)
|
||||
m_scene = m_module.Scene;
|
||||
|
||||
m_requestId = requestId;
|
||||
|
||||
SaveAssets = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Archive the region requested.
|
||||
/// </summary>
|
||||
/// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
|
||||
public void ArchiveRegion(Dictionary<string, object> options)
|
||||
{
|
||||
if (options.ContainsKey("noassets") && (bool)options["noassets"])
|
||||
SaveAssets = false;
|
||||
|
||||
try
|
||||
{
|
||||
Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
|
||||
|
||||
EntityBase[] entities = m_scene.GetEntities();
|
||||
List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
|
||||
|
||||
string checkPermissions = null;
|
||||
int numObjectsSkippedPermissions = 0;
|
||||
Object temp;
|
||||
if (options.TryGetValue("checkPermissions", out temp))
|
||||
checkPermissions = (string)temp;
|
||||
|
||||
// Filter entities so that we only have scene objects.
|
||||
// FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
|
||||
// end up having to do this
|
||||
foreach (EntityBase entity in entities)
|
||||
{
|
||||
if (entity is SceneObjectGroup)
|
||||
{
|
||||
SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
|
||||
|
||||
if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
|
||||
{
|
||||
if (!CanUserArchiveObject(m_scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, checkPermissions))
|
||||
{
|
||||
// The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
|
||||
++numObjectsSkippedPermissions;
|
||||
}
|
||||
else
|
||||
{
|
||||
sceneObjects.Add(sceneObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SaveAssets)
|
||||
{
|
||||
UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService);
|
||||
|
||||
foreach (SceneObjectGroup sceneObject in sceneObjects)
|
||||
{
|
||||
assetGatherer.GatherAssetUuids(sceneObject, assetUuids);
|
||||
}
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
|
||||
sceneObjects.Count, assetUuids.Count);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
|
||||
}
|
||||
|
||||
if (numObjectsSkippedPermissions > 0)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
|
||||
numObjectsSkippedPermissions);
|
||||
}
|
||||
|
||||
// Make sure that we also request terrain texture assets
|
||||
RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings;
|
||||
|
||||
if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
|
||||
assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
|
||||
|
||||
if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
|
||||
assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
|
||||
|
||||
if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
|
||||
assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
|
||||
|
||||
if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
|
||||
assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
|
||||
|
||||
TarArchiveWriter archiveWriter = new TarArchiveWriter(m_saveStream);
|
||||
|
||||
// Asynchronously request all the assets required to perform this archive operation
|
||||
ArchiveWriteRequestExecution awre
|
||||
= new ArchiveWriteRequestExecution(
|
||||
sceneObjects,
|
||||
m_scene.RequestModuleInterface<ITerrainModule>(),
|
||||
m_scene.RequestModuleInterface<IRegionSerialiserModule>(),
|
||||
m_scene,
|
||||
archiveWriter,
|
||||
m_requestId,
|
||||
options);
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Creating archive file. This may take some time.");
|
||||
|
||||
// Write out control file. This has to be done first so that subsequent loaders will see this file first
|
||||
// XXX: I know this is a weak way of doing it since external non-OAR aware tar executables will not do this
|
||||
archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options));
|
||||
m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
|
||||
|
||||
if (SaveAssets)
|
||||
{
|
||||
AssetsRequest ar
|
||||
= new AssetsRequest(
|
||||
new AssetsArchiver(archiveWriter), assetUuids,
|
||||
m_scene.AssetService, m_scene.UserAccountService,
|
||||
m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets);
|
||||
|
||||
Util.FireAndForget(o => ar.Execute());
|
||||
}
|
||||
else
|
||||
{
|
||||
awre.ReceivedAllAssets(new List<UUID>(), new List<UUID>());
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
m_saveStream.Close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the user has permission to export an object group to an OAR.
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <param name="objGroup">The object group</param>
|
||||
/// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param>
|
||||
/// <returns>Whether the user is allowed to export the object to an OAR</returns>
|
||||
private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions)
|
||||
{
|
||||
if (checkPermissions == null)
|
||||
return true;
|
||||
|
||||
IPermissionsModule module = m_scene.RequestModuleInterface<IPermissionsModule>();
|
||||
if (module == null)
|
||||
return true; // this shouldn't happen
|
||||
|
||||
// Check whether the user is permitted to export all of the parts in the SOG. If any
|
||||
// part can't be exported then the entire SOG can't be exported.
|
||||
|
||||
bool permitted = true;
|
||||
//int primNumber = 1;
|
||||
|
||||
foreach (SceneObjectPart obj in objGroup.Parts)
|
||||
{
|
||||
uint perm;
|
||||
PermissionClass permissionClass = module.GetPermissionClass(user, obj);
|
||||
switch (permissionClass)
|
||||
{
|
||||
case PermissionClass.Owner:
|
||||
perm = obj.BaseMask;
|
||||
break;
|
||||
case PermissionClass.Group:
|
||||
perm = obj.GroupMask | obj.EveryoneMask;
|
||||
break;
|
||||
case PermissionClass.Everyone:
|
||||
default:
|
||||
perm = obj.EveryoneMask;
|
||||
break;
|
||||
}
|
||||
|
||||
bool canCopy = (perm & (uint)PermissionMask.Copy) != 0;
|
||||
bool canTransfer = (perm & (uint)PermissionMask.Transfer) != 0;
|
||||
|
||||
// Special case: if Everyone can copy the object then this implies it can also be
|
||||
// Transferred.
|
||||
// However, if the user is the Owner then we don't check EveryoneMask, because it seems that the mask
|
||||
// always (incorrectly) includes the Copy bit set in this case. But that's a mistake: the viewer
|
||||
// does NOT show that the object has Everyone-Copy permissions, and doesn't allow it to be copied.
|
||||
if (permissionClass != PermissionClass.Owner)
|
||||
canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
|
||||
|
||||
bool partPermitted = true;
|
||||
if (checkPermissions.Contains("C") && !canCopy)
|
||||
partPermitted = false;
|
||||
if (checkPermissions.Contains("T") && !canTransfer)
|
||||
partPermitted = false;
|
||||
|
||||
// If the user is the Creator of the object then it can always be included in the OAR
|
||||
bool creator = (obj.CreatorID.Guid == user.Guid);
|
||||
if (creator)
|
||||
partPermitted = true;
|
||||
|
||||
//string name = (objGroup.PrimCount == 1) ? objGroup.Name : string.Format("{0} ({1}/{2})", obj.Name, primNumber, objGroup.PrimCount);
|
||||
//m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, creator={8}, permitted={9}",
|
||||
// name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask,
|
||||
// permissionClass, checkPermissions, canCopy, canTransfer, creator, partPermitted);
|
||||
|
||||
if (!partPermitted)
|
||||
{
|
||||
permitted = false;
|
||||
break;
|
||||
}
|
||||
|
||||
//++primNumber;
|
||||
}
|
||||
|
||||
return permitted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the control file for the most up to date archive
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string CreateControlFile(Dictionary<string, object> options)
|
||||
{
|
||||
int majorVersion = MAX_MAJOR_VERSION, minorVersion = 8;
|
||||
//
|
||||
// if (options.ContainsKey("version"))
|
||||
// {
|
||||
// string[] parts = options["version"].ToString().Split('.');
|
||||
// if (parts.Length >= 1)
|
||||
// {
|
||||
// majorVersion = Int32.Parse(parts[0]);
|
||||
//
|
||||
// if (parts.Length >= 2)
|
||||
// minorVersion = Int32.Parse(parts[1]);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION)
|
||||
// {
|
||||
// throw new Exception(
|
||||
// string.Format(
|
||||
// "OAR version number for save must be between {0} and {1}",
|
||||
// MIN_MAJOR_VERSION, MAX_MAJOR_VERSION));
|
||||
// }
|
||||
// else if (majorVersion == MAX_MAJOR_VERSION)
|
||||
// {
|
||||
// // Force 1.0
|
||||
// minorVersion = 0;
|
||||
// }
|
||||
// else if (majorVersion == MIN_MAJOR_VERSION)
|
||||
// {
|
||||
// // Force 0.4
|
||||
// minorVersion = 4;
|
||||
// }
|
||||
|
||||
m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion);
|
||||
//if (majorVersion == 1)
|
||||
//{
|
||||
// m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim 0.7.0.2 and earlier. Please use the --version=0 option if you want to produce a compatible OAR");
|
||||
//}
|
||||
|
||||
String s;
|
||||
|
||||
using (StringWriter sw = new StringWriter())
|
||||
{
|
||||
using (XmlTextWriter xtw = new XmlTextWriter(sw))
|
||||
{
|
||||
xtw.Formatting = Formatting.Indented;
|
||||
xtw.WriteStartDocument();
|
||||
xtw.WriteStartElement("archive");
|
||||
xtw.WriteAttributeString("major_version", majorVersion.ToString());
|
||||
xtw.WriteAttributeString("minor_version", minorVersion.ToString());
|
||||
|
||||
xtw.WriteStartElement("creation_info");
|
||||
DateTime now = DateTime.UtcNow;
|
||||
TimeSpan t = now - new DateTime(1970, 1, 1);
|
||||
xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
|
||||
xtw.WriteElementString("id", UUID.Random().ToString());
|
||||
xtw.WriteEndElement();
|
||||
|
||||
xtw.WriteStartElement("region_info");
|
||||
|
||||
bool isMegaregion;
|
||||
Vector2 size;
|
||||
IRegionCombinerModule rcMod = null;
|
||||
|
||||
// FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix
|
||||
// this, possibly by doing control file creation somewhere else.
|
||||
if (m_module != null)
|
||||
rcMod = m_module.RegionCombinerModule;
|
||||
|
||||
if (rcMod != null)
|
||||
isMegaregion = rcMod.IsRootForMegaregion(m_scene.RegionInfo.RegionID);
|
||||
else
|
||||
isMegaregion = false;
|
||||
|
||||
if (isMegaregion)
|
||||
size = rcMod.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
|
||||
else
|
||||
size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize);
|
||||
|
||||
xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
|
||||
xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
|
||||
|
||||
xtw.WriteEndElement();
|
||||
|
||||
xtw.WriteElementString("assets_included", SaveAssets.ToString());
|
||||
|
||||
xtw.WriteEndElement();
|
||||
|
||||
xtw.Flush();
|
||||
}
|
||||
|
||||
s = sw.ToString();
|
||||
}
|
||||
|
||||
// if (m_scene != null)
|
||||
// Console.WriteLine(
|
||||
// "[ARCHIVE WRITE REQUEST PREPARATION]: Control file for {0} is: {1}", m_scene.RegionInfo.RegionName, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,6 +146,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; });
|
||||
ops.Add("publish", v => options["wipe-owners"] = v != null);
|
||||
ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; });
|
||||
ops.Add("all", delegate(string v) { options["all"] = v != null; });
|
||||
|
||||
List<string> mainParams = ops.Parse(cmdparams);
|
||||
|
||||
@@ -169,7 +170,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
m_log.InfoFormat(
|
||||
"[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath);
|
||||
|
||||
new ArchiveWriteRequestPreparation(this, savePath, requestId).ArchiveRegion(options);
|
||||
new ArchiveWriteRequest(Scene, savePath, requestId).ArchiveRegion(options);
|
||||
}
|
||||
|
||||
public void ArchiveRegion(Stream saveStream)
|
||||
@@ -184,7 +185,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options)
|
||||
{
|
||||
new ArchiveWriteRequestPreparation(this, saveStream, requestId).ArchiveRegion(options);
|
||||
new ArchiveWriteRequest(Scene, saveStream, requestId).ArchiveRegion(options);
|
||||
}
|
||||
|
||||
public void DearchiveRegion(string loadPath)
|
||||
|
||||
@@ -46,6 +46,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// Method called when all the necessary assets for an archive request have been received.
|
||||
/// </summary>
|
||||
public delegate void AssetsRequestCallback(
|
||||
ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids);
|
||||
|
||||
enum RequestState
|
||||
{
|
||||
Initial,
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenMetaverse;
|
||||
using System.Drawing;
|
||||
using log4net;
|
||||
using System.Reflection;
|
||||
using OpenSim.Framework.Serialization;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
/// <summary>
|
||||
/// The regions included in an OAR file.
|
||||
/// </summary>
|
||||
public class DearchiveScenesInfo
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// One region in the archive.
|
||||
/// </summary>
|
||||
public class RegionInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// The subdirectory in which the region is stored.
|
||||
/// </summary>
|
||||
public string Directory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The region's coordinates (relative to the South-West corner of the block).
|
||||
/// </summary>
|
||||
public Point Location { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The UUID of the original scene from which this archived region was saved.
|
||||
/// </summary>
|
||||
public string OriginalID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The scene in the current simulator into which this region is loaded.
|
||||
/// If null then the region doesn't have a corresponding scene, and it won't be loaded.
|
||||
/// </summary>
|
||||
public Scene Scene { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether this archive uses the multi-region format.
|
||||
/// </summary>
|
||||
public Boolean MultiRegionFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maps (Region directory -> region)
|
||||
/// </summary>
|
||||
protected Dictionary<string, RegionInfo> m_directory2region = new Dictionary<string, RegionInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Maps (UUID of the scene in the simulator where the region will be loaded -> region)
|
||||
/// </summary>
|
||||
protected Dictionary<UUID, RegionInfo> m_newId2region = new Dictionary<UUID, RegionInfo>();
|
||||
|
||||
public int LoadedCreationDateTime { get; set; }
|
||||
public string DefaultOriginalID { get; set; }
|
||||
|
||||
// These variables are used while reading the archive control file
|
||||
protected int? m_curY = null;
|
||||
protected int? m_curX = null;
|
||||
protected RegionInfo m_curRegion;
|
||||
|
||||
|
||||
public DearchiveScenesInfo()
|
||||
{
|
||||
MultiRegionFormat = false;
|
||||
}
|
||||
|
||||
|
||||
// The following methods are used while reading the archive control file
|
||||
|
||||
public void StartRow()
|
||||
{
|
||||
m_curY = (m_curY == null) ? 0 : m_curY + 1;
|
||||
m_curX = null;
|
||||
}
|
||||
|
||||
public void StartRegion()
|
||||
{
|
||||
m_curX = (m_curX == null) ? 0 : m_curX + 1;
|
||||
// Note: this doesn't mean we have a real region in this location; this could just be a "hole"
|
||||
}
|
||||
|
||||
public void SetRegionOriginalID(string id)
|
||||
{
|
||||
m_curRegion = new RegionInfo();
|
||||
m_curRegion.Location = new Point((int)m_curX, (int)m_curY);
|
||||
m_curRegion.OriginalID = id;
|
||||
// 'curRegion' will be saved in 'm_directory2region' when SetRegionDir() is called
|
||||
}
|
||||
|
||||
public void SetRegionDirectory(string directory)
|
||||
{
|
||||
m_curRegion.Directory = directory;
|
||||
m_directory2region[directory] = m_curRegion;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets all the scenes present in the simulator.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This method matches regions in the archive to scenes in the simulator according to
|
||||
/// their relative position. We only load regions if there's an existing Scene in the
|
||||
/// grid location where the region should be loaded.
|
||||
/// </remarks>
|
||||
/// <param name="rootScene">The scene where the Load OAR operation was run</param>
|
||||
/// <param name="simulatorScenes">All the scenes in the simulator</param>
|
||||
public void SetSimulatorScenes(Scene rootScene, ArchiveScenesGroup simulatorScenes)
|
||||
{
|
||||
foreach (RegionInfo archivedRegion in m_directory2region.Values)
|
||||
{
|
||||
Point location = new Point((int)rootScene.RegionInfo.RegionLocX, (int)rootScene.RegionInfo.RegionLocY);
|
||||
location.Offset(archivedRegion.Location);
|
||||
|
||||
Scene scene;
|
||||
if (simulatorScenes.TryGetScene(location, out scene))
|
||||
{
|
||||
archivedRegion.Scene = scene;
|
||||
m_newId2region[scene.RegionInfo.RegionID] = archivedRegion;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("[ARCHIVER]: Not loading archived region {0} because there's no existing region at location {1},{2}",
|
||||
archivedRegion.Directory, location.X, location.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the archived region according to the path of a file in the archive.
|
||||
/// Also, converts the full path into a path that is relative to the region's directory.
|
||||
/// </summary>
|
||||
/// <param name="fullPath">The path of a file in the archive</param>
|
||||
/// <param name="scene">The corresponding Scene, or null if none</param>
|
||||
/// <param name="relativePath">The path relative to the region's directory. (Or the original
|
||||
/// path, if this file doesn't belong to a region.)</param>
|
||||
/// <returns>True: use this file; False: skip it</returns>
|
||||
public bool GetRegionFromPath(string fullPath, out Scene scene, out string relativePath)
|
||||
{
|
||||
scene = null;
|
||||
relativePath = fullPath;
|
||||
|
||||
if (!MultiRegionFormat)
|
||||
{
|
||||
if (m_newId2region.Count > 0)
|
||||
scene = m_newId2region.First().Value.Scene;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!fullPath.StartsWith(ArchiveConstants.REGIONS_PATH))
|
||||
return true; // this file doesn't belong to a region
|
||||
|
||||
string[] parts = fullPath.Split(new Char[] { '/' }, 3);
|
||||
if (parts.Length != 3)
|
||||
return false;
|
||||
string regionDirectory = parts[1];
|
||||
relativePath = parts[2];
|
||||
|
||||
RegionInfo region;
|
||||
if (m_directory2region.TryGetValue(regionDirectory, out region))
|
||||
{
|
||||
scene = region.Scene;
|
||||
return (scene != null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the original UUID of a region (from the simulator where the OAR was saved),
|
||||
/// given the UUID of the scene it was loaded into in the current simulator.
|
||||
/// </summary>
|
||||
/// <param name="newID"></param>
|
||||
/// <returns></returns>
|
||||
public string GetOriginalRegionID(UUID newID)
|
||||
{
|
||||
RegionInfo region;
|
||||
if (m_newId2region.TryGetValue(newID, out region))
|
||||
return region.OriginalID;
|
||||
else
|
||||
return DefaultOriginalID;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the scenes that have been (or will be) loaded.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<UUID> GetLoadedScenes()
|
||||
{
|
||||
return m_newId2region.Keys.ToList();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -47,32 +47,41 @@ using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
|
||||
using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader;
|
||||
using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter;
|
||||
using RegionSettings = OpenSim.Framework.RegionSettings;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ArchiverTests
|
||||
public class ArchiverTests : OpenSimTestCase
|
||||
{
|
||||
private Guid m_lastRequestId;
|
||||
private string m_lastErrorMessage;
|
||||
|
||||
protected SceneHelpers m_sceneHelpers;
|
||||
protected TestScene m_scene;
|
||||
protected ArchiverModule m_archiverModule;
|
||||
protected SerialiserModule m_serialiserModule;
|
||||
|
||||
protected TaskInventoryItem m_soundItem;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
// FIXME: Do something about this - relying on statics in unit tests causes trouble sooner or later
|
||||
new SceneManager();
|
||||
|
||||
m_archiverModule = new ArchiverModule();
|
||||
SerialiserModule serialiserModule = new SerialiserModule();
|
||||
m_serialiserModule = new SerialiserModule();
|
||||
TerrainModule terrainModule = new TerrainModule();
|
||||
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule);
|
||||
m_sceneHelpers = new SceneHelpers();
|
||||
m_scene = m_sceneHelpers.SetupScene();
|
||||
SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, m_serialiserModule, terrainModule);
|
||||
}
|
||||
|
||||
private void LoadCompleted(Guid requestId, string errorMessage)
|
||||
|
||||
private void LoadCompleted(Guid requestId, List<UUID> loadedScenes, string errorMessage)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
@@ -128,26 +137,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
SceneObjectPart part1 = CreateSceneObjectPart1();
|
||||
SceneObjectGroup sog1 = new SceneObjectGroup(part1);
|
||||
m_scene.AddNewSceneObject(sog1, false);
|
||||
|
||||
SceneObjectPart part2 = CreateSceneObjectPart2();
|
||||
|
||||
AssetNotecard nc = new AssetNotecard();
|
||||
nc.BodyText = "Hello World!";
|
||||
nc.Encode();
|
||||
UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000");
|
||||
UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000");
|
||||
AssetBase ncAsset
|
||||
= AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
|
||||
m_scene.AssetService.Store(ncAsset);
|
||||
SceneObjectGroup sog2 = new SceneObjectGroup(part2);
|
||||
TaskInventoryItem ncItem
|
||||
= new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
|
||||
part2.Inventory.AddInventoryItem(ncItem, true);
|
||||
|
||||
m_scene.AddNewSceneObject(sog2, false);
|
||||
SceneObjectGroup sog1;
|
||||
SceneObjectGroup sog2;
|
||||
UUID ncAssetUuid;
|
||||
CreateTestObjects(m_scene, out sog1, out sog2, out ncAssetUuid);
|
||||
|
||||
MemoryStream archiveWriteStream = new MemoryStream();
|
||||
m_scene.EventManager.OnOarFileSaved += SaveCompleted;
|
||||
@@ -186,7 +179,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
|
||||
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
|
||||
arr.LoadControlFile(filePath, data);
|
||||
arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
|
||||
|
||||
Assert.That(arr.ControlFileLoaded, Is.True);
|
||||
|
||||
@@ -211,6 +204,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
// TODO: Test presence of more files and contents of files.
|
||||
}
|
||||
|
||||
private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
|
||||
{
|
||||
SceneObjectPart part1 = CreateSceneObjectPart1();
|
||||
sog1 = new SceneObjectGroup(part1);
|
||||
scene.AddNewSceneObject(sog1, false);
|
||||
|
||||
AssetNotecard nc = new AssetNotecard();
|
||||
nc.BodyText = "Hello World!";
|
||||
nc.Encode();
|
||||
ncAssetUuid = UUID.Random();
|
||||
UUID ncItemUuid = UUID.Random();
|
||||
AssetBase ncAsset
|
||||
= AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
|
||||
m_scene.AssetService.Store(ncAsset);
|
||||
|
||||
TaskInventoryItem ncItem
|
||||
= new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
|
||||
SceneObjectPart part2 = CreateSceneObjectPart2();
|
||||
sog2 = new SceneObjectGroup(part2);
|
||||
part2.Inventory.AddInventoryItem(ncItem, true);
|
||||
|
||||
scene.AddNewSceneObject(sog2, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test saving an OpenSim Region Archive with the no assets option
|
||||
/// </summary>
|
||||
@@ -270,7 +287,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
|
||||
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
|
||||
arr.LoadControlFile(filePath, data);
|
||||
arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
|
||||
|
||||
Assert.That(arr.ControlFileLoaded, Is.True);
|
||||
|
||||
@@ -307,7 +324,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
|
||||
tar.WriteFile(
|
||||
ArchiveConstants.CONTROL_FILE_PATH,
|
||||
new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>()));
|
||||
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
|
||||
|
||||
SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
|
||||
SceneObjectPart sop2
|
||||
@@ -362,11 +379,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
// Also check that direct entries which will also have a file entry containing that directory doesn't
|
||||
// upset load
|
||||
tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
|
||||
|
||||
|
||||
tar.WriteFile(
|
||||
ArchiveConstants.CONTROL_FILE_PATH,
|
||||
new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>()));
|
||||
|
||||
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
|
||||
SceneObjectPart part1 = CreateSceneObjectPart1();
|
||||
|
||||
part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f);
|
||||
@@ -389,31 +405,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
Assert.That(soundDataResourceName, Is.Not.Null);
|
||||
|
||||
byte[] soundData;
|
||||
Console.WriteLine("Loading " + soundDataResourceName);
|
||||
using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(resource))
|
||||
{
|
||||
// FIXME: Use the inspector instead
|
||||
soundData = br.ReadBytes(99999999);
|
||||
UUID soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
||||
string soundAssetFileName
|
||||
= ArchiveConstants.ASSETS_PATH + soundUuid
|
||||
+ ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
|
||||
tar.WriteFile(soundAssetFileName, soundData);
|
||||
|
||||
/*
|
||||
AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
|
||||
scene.AssetService.Store(soundAsset);
|
||||
asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
|
||||
*/
|
||||
|
||||
TaskInventoryItem item1
|
||||
= new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
|
||||
part1.Inventory.AddInventoryItem(item1, true);
|
||||
}
|
||||
}
|
||||
|
||||
UUID soundUuid;
|
||||
CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid);
|
||||
|
||||
TaskInventoryItem item1
|
||||
= new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
|
||||
part1.Inventory.AddInventoryItem(item1, true);
|
||||
m_scene.AddNewSceneObject(object1, false);
|
||||
|
||||
string object1FileName = string.Format(
|
||||
@@ -435,6 +432,34 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
|
||||
Assert.That(m_lastErrorMessage, Is.Null);
|
||||
|
||||
TestLoadedRegion(part1, soundItemName, soundData);
|
||||
}
|
||||
|
||||
private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
|
||||
{
|
||||
using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
|
||||
{
|
||||
using (BinaryReader br = new BinaryReader(resource))
|
||||
{
|
||||
// FIXME: Use the inspector instead
|
||||
soundData = br.ReadBytes(99999999);
|
||||
soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
||||
string soundAssetFileName
|
||||
= ArchiveConstants.ASSETS_PATH + soundUuid
|
||||
+ ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
|
||||
tar.WriteFile(soundAssetFileName, soundData);
|
||||
|
||||
/*
|
||||
AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
|
||||
scene.AssetService.Store(soundAsset);
|
||||
asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
|
||||
{
|
||||
SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
|
||||
|
||||
Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
|
||||
@@ -454,9 +479,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
|
||||
|
||||
Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
|
||||
|
||||
// Temporary
|
||||
Console.WriteLine("Successfully completed {0}", MethodBase.GetCurrentMethod());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -516,7 +538,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
SerialiserModule serialiserModule = new SerialiserModule();
|
||||
TerrainModule terrainModule = new TerrainModule();
|
||||
|
||||
TestScene scene2 = new SceneHelpers().SetupScene();
|
||||
m_sceneHelpers = new SceneHelpers();
|
||||
TestScene scene2 = m_sceneHelpers.SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule);
|
||||
|
||||
// Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is
|
||||
@@ -554,7 +577,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
|
||||
tar.WriteFile(
|
||||
ArchiveConstants.CONTROL_FILE_PATH,
|
||||
new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>()));
|
||||
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
|
||||
|
||||
RegionSettings rs = new RegionSettings();
|
||||
rs.AgentLimit = 17;
|
||||
@@ -664,7 +687,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
SerialiserModule serialiserModule = new SerialiserModule();
|
||||
TerrainModule terrainModule = new TerrainModule();
|
||||
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
Scene scene = m_sceneHelpers.SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule);
|
||||
|
||||
m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false);
|
||||
@@ -700,5 +723,258 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
Assert.That(object2PartMerged.GroupPosition, Is.EqualTo(part2.GroupPosition), "object2 group position not equal after merge");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test saving a multi-region OAR.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSaveMultiRegionOar()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
// Create test regions
|
||||
|
||||
int WIDTH = 2;
|
||||
int HEIGHT = 2;
|
||||
|
||||
List<Scene> scenes = new List<Scene>();
|
||||
|
||||
// Maps (Directory in OAR file -> scene)
|
||||
Dictionary<string, Scene> regionPaths = new Dictionary<string, Scene>();
|
||||
|
||||
// Maps (Scene -> expected object paths)
|
||||
Dictionary<UUID, List<string>> expectedPaths = new Dictionary<UUID, List<string>>();
|
||||
|
||||
// List of expected assets
|
||||
List<UUID> expectedAssets = new List<UUID>();
|
||||
|
||||
for (uint y = 0; y < HEIGHT; y++)
|
||||
{
|
||||
for (uint x = 0; x < WIDTH; x++)
|
||||
{
|
||||
Scene scene;
|
||||
if (x == 0 && y == 0)
|
||||
{
|
||||
scene = m_scene; // this scene was already created in SetUp()
|
||||
}
|
||||
else
|
||||
{
|
||||
scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y);
|
||||
SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule());
|
||||
}
|
||||
scenes.Add(scene);
|
||||
|
||||
string dir = String.Format("{0}_{1}_{2}", x + 1, y + 1, scene.RegionInfo.RegionName.Replace(" ", "_"));
|
||||
regionPaths[dir] = scene;
|
||||
|
||||
SceneObjectGroup sog1;
|
||||
SceneObjectGroup sog2;
|
||||
UUID ncAssetUuid;
|
||||
|
||||
CreateTestObjects(scene, out sog1, out sog2, out ncAssetUuid);
|
||||
|
||||
expectedPaths[scene.RegionInfo.RegionID] = new List<string>();
|
||||
expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog1));
|
||||
expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog2));
|
||||
|
||||
expectedAssets.Add(ncAssetUuid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Save OAR
|
||||
|
||||
MemoryStream archiveWriteStream = new MemoryStream();
|
||||
m_scene.EventManager.OnOarFileSaved += SaveCompleted;
|
||||
|
||||
Guid requestId = new Guid("00000000-0000-0000-0000-808080808080");
|
||||
|
||||
Dictionary<string, Object> options = new Dictionary<string, Object>();
|
||||
options.Add("all", true);
|
||||
|
||||
lock (this)
|
||||
{
|
||||
m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options);
|
||||
Monitor.Wait(this, 60000);
|
||||
}
|
||||
|
||||
|
||||
// Check that the OAR contains the expected data
|
||||
|
||||
Assert.That(m_lastRequestId, Is.EqualTo(requestId));
|
||||
|
||||
byte[] archive = archiveWriteStream.ToArray();
|
||||
MemoryStream archiveReadStream = new MemoryStream(archive);
|
||||
TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
|
||||
|
||||
Dictionary<UUID, List<string>> foundPaths = new Dictionary<UUID, List<string>>();
|
||||
List<UUID> foundAssets = new List<UUID>();
|
||||
|
||||
foreach (Scene scene in scenes)
|
||||
{
|
||||
foundPaths[scene.RegionInfo.RegionID] = new List<string>();
|
||||
}
|
||||
|
||||
string filePath;
|
||||
TarArchiveReader.TarEntryType tarEntryType;
|
||||
|
||||
byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
|
||||
Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
|
||||
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
|
||||
arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
|
||||
|
||||
Assert.That(arr.ControlFileLoaded, Is.True);
|
||||
|
||||
while (tar.ReadEntry(out filePath, out tarEntryType) != null)
|
||||
{
|
||||
if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
|
||||
{
|
||||
// Assets are shared, so this file doesn't belong to any specific region.
|
||||
string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
|
||||
if (fileName.EndsWith("_notecard.txt"))
|
||||
foundAssets.Add(UUID.Parse(fileName.Substring(0, fileName.Length - "_notecard.txt".Length)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// This file belongs to one of the regions. Find out which one.
|
||||
Assert.IsTrue(filePath.StartsWith(ArchiveConstants.REGIONS_PATH));
|
||||
string[] parts = filePath.Split(new Char[] { '/' }, 3);
|
||||
Assert.AreEqual(3, parts.Length);
|
||||
string regionDirectory = parts[1];
|
||||
string relativePath = parts[2];
|
||||
Scene scene = regionPaths[regionDirectory];
|
||||
|
||||
if (relativePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
|
||||
{
|
||||
foundPaths[scene.RegionInfo.RegionID].Add(relativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(scenes.Count, foundPaths.Count);
|
||||
foreach (Scene scene in scenes)
|
||||
{
|
||||
Assert.That(foundPaths[scene.RegionInfo.RegionID], Is.EquivalentTo(expectedPaths[scene.RegionInfo.RegionID]));
|
||||
}
|
||||
|
||||
Assert.That(foundAssets, Is.EquivalentTo(expectedAssets));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test loading a multi-region OAR.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestLoadMultiRegionOar()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
// Create an ArchiveScenesGroup with the regions in the OAR. This is needed to generate the control file.
|
||||
|
||||
int WIDTH = 2;
|
||||
int HEIGHT = 2;
|
||||
|
||||
for (uint y = 0; y < HEIGHT; y++)
|
||||
{
|
||||
for (uint x = 0; x < WIDTH; x++)
|
||||
{
|
||||
Scene scene;
|
||||
if (x == 0 && y == 0)
|
||||
{
|
||||
scene = m_scene; // this scene was already created in SetUp()
|
||||
}
|
||||
else
|
||||
{
|
||||
scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y);
|
||||
SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
|
||||
SceneManager.Instance.ForEachScene(delegate(Scene scene)
|
||||
{
|
||||
scenesGroup.AddScene(scene);
|
||||
});
|
||||
scenesGroup.CalcSceneLocations();
|
||||
|
||||
// Generate the OAR file
|
||||
|
||||
MemoryStream archiveWriteStream = new MemoryStream();
|
||||
TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
|
||||
|
||||
ArchiveWriteRequest writeRequest = new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty);
|
||||
writeRequest.MultiRegionFormat = true;
|
||||
tar.WriteFile(
|
||||
ArchiveConstants.CONTROL_FILE_PATH, writeRequest.CreateControlFile(scenesGroup));
|
||||
|
||||
SceneObjectPart part1 = CreateSceneObjectPart1();
|
||||
part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f);
|
||||
part1.SitTargetPosition = new Vector3(1, 2, 3);
|
||||
|
||||
SceneObjectGroup object1 = new SceneObjectGroup(part1);
|
||||
|
||||
// Let's put some inventory items into our object
|
||||
string soundItemName = "sound-item1";
|
||||
UUID soundItemUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
|
||||
Type type = GetType();
|
||||
Assembly assembly = type.Assembly;
|
||||
string soundDataResourceName = null;
|
||||
string[] names = assembly.GetManifestResourceNames();
|
||||
foreach (string name in names)
|
||||
{
|
||||
if (name.EndsWith(".Resources.test-sound.wav"))
|
||||
soundDataResourceName = name;
|
||||
}
|
||||
Assert.That(soundDataResourceName, Is.Not.Null);
|
||||
|
||||
byte[] soundData;
|
||||
UUID soundUuid;
|
||||
CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid);
|
||||
|
||||
TaskInventoryItem item1
|
||||
= new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
|
||||
part1.Inventory.AddInventoryItem(item1, true);
|
||||
m_scene.AddNewSceneObject(object1, false);
|
||||
|
||||
string object1FileName = string.Format(
|
||||
"{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
|
||||
part1.Name,
|
||||
Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z),
|
||||
part1.UUID);
|
||||
string path = "regions/1_1_Unit_test_region/" + ArchiveConstants.OBJECTS_PATH + object1FileName;
|
||||
tar.WriteFile(path, SceneObjectSerializer.ToXml2Format(object1));
|
||||
|
||||
tar.Close();
|
||||
|
||||
|
||||
// Delete the current objects, to test that they're loaded from the OAR and didn't
|
||||
// just remain in the scene.
|
||||
SceneManager.Instance.ForEachScene(delegate(Scene scene)
|
||||
{
|
||||
scene.DeleteAllSceneObjects();
|
||||
});
|
||||
|
||||
// Create a "hole", to test that that the corresponding region isn't loaded from the OAR
|
||||
SceneManager.Instance.CloseScene(SceneManager.Instance.Scenes[1]);
|
||||
|
||||
|
||||
// Check thay the OAR file contains the expected data
|
||||
|
||||
MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
|
||||
|
||||
lock (this)
|
||||
{
|
||||
m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
|
||||
m_archiverModule.DearchiveRegion(archiveReadStream);
|
||||
}
|
||||
|
||||
Assert.That(m_lastErrorMessage, Is.Null);
|
||||
|
||||
Assert.AreEqual(3, SceneManager.Instance.Scenes.Count);
|
||||
|
||||
TestLoadedRegion(part1, soundItemName, soundData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using RegionFlags = OpenMetaverse.RegionFlags;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Estate
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@ using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using RegionFlags = OpenMetaverse.RegionFlags;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Land
|
||||
{
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
/// without recounting the whole sim.
|
||||
///
|
||||
/// We start out tainted so that the first get call resets the various prim counts.
|
||||
/// <value>
|
||||
/// </value>
|
||||
private bool m_Tainted = true;
|
||||
|
||||
private Object m_TaintLock = new Object();
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -83,46 +84,99 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects", false, "delete object owner",
|
||||
"delete object owner <UUID>",
|
||||
"Delete a scene object by owner", HandleDeleteObject);
|
||||
"Delete scene objects by owner",
|
||||
"Command will ask for confirmation before proceeding.",
|
||||
HandleDeleteObject);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects", false, "delete object creator",
|
||||
"delete object creator <UUID>",
|
||||
"Delete a scene object by creator", HandleDeleteObject);
|
||||
"Delete scene objects by creator",
|
||||
"Command will ask for confirmation before proceeding.",
|
||||
HandleDeleteObject);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects", false, "delete object uuid",
|
||||
"delete object uuid <UUID>",
|
||||
"Delete a scene object by uuid", HandleDeleteObject);
|
||||
"Delete a scene object by uuid",
|
||||
HandleDeleteObject);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects", false, "delete object name",
|
||||
"delete object name [--regex] <name>",
|
||||
"Delete a scene object by name.",
|
||||
"If --regex is specified then the name is treatead as a regular expression",
|
||||
"Command will ask for confirmation before proceeding.\n"
|
||||
+ "If --regex is specified then the name is treatead as a regular expression",
|
||||
HandleDeleteObject);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects", false, "delete object outside",
|
||||
"delete object outside",
|
||||
"Delete all scene objects outside region boundaries", HandleDeleteObject);
|
||||
"Delete all scene objects outside region boundaries",
|
||||
"Command will ask for confirmation before proceeding.",
|
||||
HandleDeleteObject);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects",
|
||||
false,
|
||||
"delete object pos",
|
||||
"delete object pos <start-coord> to <end-coord>",
|
||||
"Delete scene objects within the given area.",
|
||||
"Each component of the coord is comma separated. There must be no spaces between the commas.\n"
|
||||
+ "If you don't care about the z component you can simply omit it.\n"
|
||||
+ "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
|
||||
+ "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
|
||||
+ "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
|
||||
+ "e.g.\n"
|
||||
+ "delete object pos 20,20,20 to 40,40,40\n"
|
||||
+ "delete object pos 20,20 to 40,40\n"
|
||||
+ "delete object pos ,20,20 to ,40,40\n"
|
||||
+ "delete object pos ,,30 to ,,~\n"
|
||||
+ "delete object pos ,,-~ to ,,30",
|
||||
HandleDeleteObject);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects",
|
||||
false,
|
||||
"show object uuid",
|
||||
"show object uuid <UUID>",
|
||||
"Show details of a scene object with the given UUID", HandleShowObjectByUuid);
|
||||
"show object uuid [--full] <UUID>",
|
||||
"Show details of a scene object with the given UUID",
|
||||
"The --full option will print out information on all the parts of the object.\n"
|
||||
+ "For yet more detailed part information, use the \"show part\" commands.",
|
||||
HandleShowObjectByUuid);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects",
|
||||
false,
|
||||
"show object name",
|
||||
"show object name [--regex] <name>",
|
||||
"show object name [--full] [--regex] <name>",
|
||||
"Show details of scene objects with the given name.",
|
||||
"If --regex is specified then the name is treatead as a regular expression",
|
||||
"The --full option will print out information on all the parts of the object.\n"
|
||||
+ "For yet more detailed part information, use the \"show part\" commands.\n"
|
||||
+ "If --regex is specified then the name is treatead as a regular expression.",
|
||||
HandleShowObjectByName);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects",
|
||||
false,
|
||||
"show object pos",
|
||||
"show object pos [--full] <start-coord> to <end-coord>",
|
||||
"Show details of scene objects within the given area.",
|
||||
"The --full option will print out information on all the parts of the object.\n"
|
||||
+ "For yet more detailed part information, use the \"show part\" commands.\n"
|
||||
+ "Each component of the coord is comma separated. There must be no spaces between the commas.\n"
|
||||
+ "If you don't care about the z component you can simply omit it.\n"
|
||||
+ "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
|
||||
+ "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
|
||||
+ "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
|
||||
+ "e.g.\n"
|
||||
+ "show object pos 20,20,20 to 40,40,40\n"
|
||||
+ "show object pos 20,20 to 40,40\n"
|
||||
+ "show object pos ,20,20 to ,40,40\n"
|
||||
+ "show object pos ,,30 to ,,~\n"
|
||||
+ "show object pos ,,-~ to ,,30",
|
||||
HandleShowObjectByPos);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects",
|
||||
false,
|
||||
@@ -138,6 +192,25 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
"Show details of scene object parts with the given name.",
|
||||
"If --regex is specified then the name is treatead as a regular expression",
|
||||
HandleShowPartByName);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"Objects",
|
||||
false,
|
||||
"show part pos",
|
||||
"show part pos <start-coord> to <end-coord>",
|
||||
"Show details of scene object parts within the given area.",
|
||||
"Each component of the coord is comma separated. There must be no spaces between the commas.\n"
|
||||
+ "If you don't care about the z component you can simply omit it.\n"
|
||||
+ "If you don't care about the x or y components then you can leave them blank (though a comma is still required)\n"
|
||||
+ "If you want to specify the maxmimum value of a component then you can use ~ instead of a number\n"
|
||||
+ "If you want to specify the minimum value of a component then you can use -~ instead of a number\n"
|
||||
+ "e.g.\n"
|
||||
+ "show object pos 20,20,20 to 40,40,40\n"
|
||||
+ "show object pos 20,20 to 40,40\n"
|
||||
+ "show object pos ,20,20 to ,40,40\n"
|
||||
+ "show object pos ,,30 to ,,~\n"
|
||||
+ "show object pos ,,-~ to ,,30",
|
||||
HandleShowPartByPos);
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene scene)
|
||||
@@ -150,21 +223,68 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
// m_log.DebugFormat("[OBJECTS COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
|
||||
}
|
||||
|
||||
private void HandleShowObjectByUuid(string module, string[] cmd)
|
||||
/// <summary>
|
||||
/// Outputs the sogs to console.
|
||||
/// </summary>
|
||||
/// <param name='searchPredicate'></param>
|
||||
/// <param name='showFull'>If true then output all part details. If false then output summary.</param>
|
||||
private void OutputSogsToConsole(Predicate<SceneObjectGroup> searchPredicate, bool showFull)
|
||||
{
|
||||
List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups().FindAll(searchPredicate);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (SceneObjectGroup so in sceneObjects)
|
||||
{
|
||||
AddSceneObjectReport(sb, so, showFull);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
sb.AppendFormat("{0} object(s) found in {1}\n", sceneObjects.Count, m_scene.Name);
|
||||
|
||||
m_console.OutputFormat(sb.ToString());
|
||||
}
|
||||
|
||||
private void OutputSopsToConsole(Predicate<SceneObjectPart> searchPredicate, bool showFull)
|
||||
{
|
||||
List<SceneObjectGroup> sceneObjects = m_scene.GetSceneObjectGroups();
|
||||
List<SceneObjectPart> parts = new List<SceneObjectPart>();
|
||||
|
||||
sceneObjects.ForEach(so => parts.AddRange(Array.FindAll<SceneObjectPart>(so.Parts, searchPredicate)));
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (SceneObjectPart part in parts)
|
||||
{
|
||||
AddScenePartReport(sb, part, showFull);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
sb.AppendFormat("{0} parts found in {1}\n", parts.Count, m_scene.Name);
|
||||
|
||||
m_console.OutputFormat(sb.ToString());
|
||||
}
|
||||
|
||||
private void HandleShowObjectByUuid(string module, string[] cmdparams)
|
||||
{
|
||||
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||
return;
|
||||
|
||||
if (cmd.Length < 4)
|
||||
bool showFull = false;
|
||||
OptionSet options = new OptionSet().Add("full", v => showFull = v != null );
|
||||
|
||||
List<string> mainParams = options.Parse(cmdparams);
|
||||
|
||||
if (mainParams.Count < 4)
|
||||
{
|
||||
m_console.OutputFormat("Usage: show object uuid <uuid>");
|
||||
return;
|
||||
}
|
||||
|
||||
UUID objectUuid;
|
||||
if (!UUID.TryParse(cmd[3], out objectUuid))
|
||||
if (!UUID.TryParse(mainParams[3], out objectUuid))
|
||||
{
|
||||
m_console.OutputFormat("{0} is not a valid uuid", cmd[3]);
|
||||
m_console.OutputFormat("{0} is not a valid uuid", mainParams[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,7 +297,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
AddSceneObjectReport(sb, so);
|
||||
AddSceneObjectReport(sb, so, showFull);
|
||||
|
||||
m_console.OutputFormat(sb.ToString());
|
||||
}
|
||||
@@ -187,66 +307,85 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||
return;
|
||||
|
||||
bool showFull = false;
|
||||
bool useRegex = false;
|
||||
OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
|
||||
OptionSet options = new OptionSet();
|
||||
options.Add("full", v => showFull = v != null );
|
||||
options.Add("regex", v => useRegex = v != null );
|
||||
|
||||
List<string> mainParams = options.Parse(cmdparams);
|
||||
|
||||
if (mainParams.Count < 4)
|
||||
{
|
||||
m_console.OutputFormat("Usage: show object name [--regex] <name>");
|
||||
m_console.OutputFormat("Usage: show object name [--full] [--regex] <name>");
|
||||
return;
|
||||
}
|
||||
|
||||
string name = mainParams[3];
|
||||
|
||||
List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
|
||||
Action<SceneObjectGroup> searchAction;
|
||||
Predicate<SceneObjectGroup> searchPredicate;
|
||||
|
||||
if (useRegex)
|
||||
{
|
||||
Regex nameRegex = new Regex(name);
|
||||
searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }};
|
||||
searchPredicate = so => nameRegex.IsMatch(so.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }};
|
||||
searchPredicate = so => so.Name == name;
|
||||
}
|
||||
|
||||
m_scene.ForEachSOG(searchAction);
|
||||
|
||||
if (sceneObjects.Count == 0)
|
||||
{
|
||||
m_console.OutputFormat("No objects with name {0} found in {1}", name, m_scene.RegionInfo.RegionName);
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (SceneObjectGroup so in sceneObjects)
|
||||
{
|
||||
AddSceneObjectReport(sb, so);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
m_console.OutputFormat(sb.ToString());
|
||||
OutputSogsToConsole(searchPredicate, showFull);
|
||||
}
|
||||
|
||||
private void HandleShowPartByUuid(string module, string[] cmd)
|
||||
private void HandleShowObjectByPos(string module, string[] cmdparams)
|
||||
{
|
||||
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||
return;
|
||||
|
||||
if (cmd.Length < 4)
|
||||
bool showFull = false;
|
||||
OptionSet options = new OptionSet().Add("full", v => showFull = v != null );
|
||||
|
||||
List<string> mainParams = options.Parse(cmdparams);
|
||||
|
||||
if (mainParams.Count < 5)
|
||||
{
|
||||
m_console.OutputFormat("Usage: show part uuid <uuid>");
|
||||
m_console.OutputFormat("Usage: show object pos [--full] <start-coord> to <end-coord>");
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 startVector, endVector;
|
||||
|
||||
if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
|
||||
return;
|
||||
|
||||
Predicate<SceneObjectGroup> searchPredicate
|
||||
= so => Util.IsInsideBox(so.AbsolutePosition, startVector, endVector);
|
||||
|
||||
OutputSogsToConsole(searchPredicate, showFull);
|
||||
}
|
||||
|
||||
private void HandleShowPartByUuid(string module, string[] cmdparams)
|
||||
{
|
||||
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||
return;
|
||||
|
||||
// bool showFull = false;
|
||||
OptionSet options = new OptionSet();
|
||||
// options.Add("full", v => showFull = v != null );
|
||||
|
||||
List<string> mainParams = options.Parse(cmdparams);
|
||||
|
||||
if (mainParams.Count < 4)
|
||||
{
|
||||
m_console.OutputFormat("Usage: show part uuid [--full] <uuid>");
|
||||
return;
|
||||
}
|
||||
|
||||
UUID objectUuid;
|
||||
if (!UUID.TryParse(cmd[3], out objectUuid))
|
||||
if (!UUID.TryParse(mainParams[3], out objectUuid))
|
||||
{
|
||||
m_console.OutputFormat("{0} is not a valid uuid", cmd[3]);
|
||||
m_console.OutputFormat("{0} is not a valid uuid", mainParams[3]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -259,84 +398,188 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
AddScenePartReport(sb, sop);
|
||||
AddScenePartReport(sb, sop, true);
|
||||
|
||||
m_console.OutputFormat(sb.ToString());
|
||||
}
|
||||
|
||||
private void HandleShowPartByPos(string module, string[] cmdparams)
|
||||
{
|
||||
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||
return;
|
||||
|
||||
// bool showFull = false;
|
||||
OptionSet options = new OptionSet();
|
||||
// options.Add("full", v => showFull = v != null );
|
||||
|
||||
List<string> mainParams = options.Parse(cmdparams);
|
||||
|
||||
if (mainParams.Count < 5)
|
||||
{
|
||||
m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
|
||||
return;
|
||||
}
|
||||
|
||||
string rawConsoleStartVector = mainParams[3];
|
||||
Vector3 startVector;
|
||||
|
||||
if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
|
||||
{
|
||||
m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
|
||||
return;
|
||||
}
|
||||
|
||||
string rawConsoleEndVector = mainParams[5];
|
||||
Vector3 endVector;
|
||||
|
||||
if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
|
||||
{
|
||||
m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
|
||||
return;
|
||||
}
|
||||
|
||||
OutputSopsToConsole(sop => Util.IsInsideBox(sop.AbsolutePosition, startVector, endVector), true);
|
||||
}
|
||||
|
||||
private void HandleShowPartByName(string module, string[] cmdparams)
|
||||
{
|
||||
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||
return;
|
||||
|
||||
// bool showFull = false;
|
||||
bool useRegex = false;
|
||||
OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
|
||||
OptionSet options = new OptionSet();
|
||||
// options.Add("full", v => showFull = v != null );
|
||||
options.Add("regex", v => useRegex = v != null );
|
||||
|
||||
List<string> mainParams = options.Parse(cmdparams);
|
||||
|
||||
if (mainParams.Count < 4)
|
||||
{
|
||||
m_console.OutputFormat("Usage: show part name [--regex] <name>");
|
||||
m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
|
||||
return;
|
||||
}
|
||||
|
||||
string name = mainParams[3];
|
||||
|
||||
List<SceneObjectPart> parts = new List<SceneObjectPart>();
|
||||
|
||||
Action<SceneObjectGroup> searchAction;
|
||||
Predicate<SceneObjectPart> searchPredicate;
|
||||
|
||||
if (useRegex)
|
||||
{
|
||||
Regex nameRegex = new Regex(name);
|
||||
searchAction = so => so.ForEachPart(sop => { if (nameRegex.IsMatch(sop.Name)) { parts.Add(sop); } });
|
||||
searchPredicate = sop => nameRegex.IsMatch(sop.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchAction = so => so.ForEachPart(sop => { if (sop.Name == name) { parts.Add(sop); } });
|
||||
searchPredicate = sop => sop.Name == name;
|
||||
}
|
||||
|
||||
m_scene.ForEachSOG(searchAction);
|
||||
|
||||
if (parts.Count == 0)
|
||||
{
|
||||
m_console.OutputFormat("No parts with name {0} found in {1}", name, m_scene.RegionInfo.RegionName);
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
foreach (SceneObjectPart part in parts)
|
||||
{
|
||||
AddScenePartReport(sb, part);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
m_console.OutputFormat(sb.ToString());
|
||||
OutputSopsToConsole(searchPredicate, true);
|
||||
}
|
||||
|
||||
private StringBuilder AddSceneObjectReport(StringBuilder sb, SceneObjectGroup so)
|
||||
/// <summary>
|
||||
/// Append a scene object report to an input StringBuilder
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name='sb'></param>
|
||||
/// <param name='so'</param>
|
||||
/// <param name='showFull'>
|
||||
/// If true then information on all parts of an object is appended.
|
||||
/// If false then only summary information about an object is appended.
|
||||
/// </param>
|
||||
private StringBuilder AddSceneObjectReport(StringBuilder sb, SceneObjectGroup so, bool showFull)
|
||||
{
|
||||
sb.AppendFormat("Name: {0}\n", so.Name);
|
||||
sb.AppendFormat("Description: {0}\n", so.Description);
|
||||
sb.AppendFormat("Location: {0} @ {1}\n", so.AbsolutePosition, so.Scene.RegionInfo.RegionName);
|
||||
sb.AppendFormat("Parts: {0}\n", so.PrimCount);
|
||||
sb.AppendFormat("Flags: {0}\n", so.RootPart.Flags);
|
||||
if (showFull)
|
||||
{
|
||||
foreach (SceneObjectPart sop in so.Parts)
|
||||
{
|
||||
AddScenePartReport(sb, sop, false);
|
||||
sb.Append("\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddSummarySceneObjectReport(sb, so);
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
private StringBuilder AddScenePartReport(StringBuilder sb, SceneObjectPart sop)
|
||||
private StringBuilder AddSummarySceneObjectReport(StringBuilder sb, SceneObjectGroup so)
|
||||
{
|
||||
sb.AppendFormat("Name: {0}\n", sop.Name);
|
||||
sb.AppendFormat("Description: {0}\n", sop.Description);
|
||||
sb.AppendFormat("Location: {0} @ {1}\n", sop.AbsolutePosition, sop.ParentGroup.Scene.RegionInfo.RegionName);
|
||||
sb.AppendFormat("Parent: {0}",
|
||||
sop.IsRoot ? "Is Root\n" : string.Format("{0} {1}\n", sop.ParentGroup.Name, sop.ParentGroup.UUID));
|
||||
sb.AppendFormat("Link number: {0}\n", sop.LinkNum);
|
||||
sb.AppendFormat("Flags: {0}\n", sop.Flags);
|
||||
ConsoleDisplayList cdl = new ConsoleDisplayList();
|
||||
cdl.AddRow("Name", so.Name);
|
||||
cdl.AddRow("Descrition", so.Description);
|
||||
cdl.AddRow("Local ID", so.LocalId);
|
||||
cdl.AddRow("UUID", so.UUID);
|
||||
cdl.AddRow("Location", string.Format("{0} @ {1}", so.AbsolutePosition, so.Scene.Name));
|
||||
cdl.AddRow("Parts", so.PrimCount);
|
||||
cdl.AddRow("Flags", so.RootPart.Flags);
|
||||
|
||||
return sb;
|
||||
return sb.Append(cdl.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a scene object part report to an input StringBuilder
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name='sb'></param>
|
||||
/// <param name='sop'</param>
|
||||
/// <param name='showFull'>
|
||||
/// If true then information on each inventory item will be shown.
|
||||
/// If false then only summary inventory information is shown.
|
||||
/// </param>
|
||||
private StringBuilder AddScenePartReport(StringBuilder sb, SceneObjectPart sop, bool showFull)
|
||||
{
|
||||
ConsoleDisplayList cdl = new ConsoleDisplayList();
|
||||
cdl.AddRow("Name", sop.Name);
|
||||
cdl.AddRow("Description", sop.Description);
|
||||
cdl.AddRow("Local ID", sop.LocalId);
|
||||
cdl.AddRow("UUID", sop.UUID);
|
||||
cdl.AddRow("Location", string.Format("{0} @ {1}", sop.AbsolutePosition, sop.ParentGroup.Scene.Name));
|
||||
cdl.AddRow(
|
||||
"Parent",
|
||||
sop.IsRoot ? "Is Root" : string.Format("{0} {1}", sop.ParentGroup.Name, sop.ParentGroup.UUID));
|
||||
cdl.AddRow("Link number", sop.LinkNum);
|
||||
cdl.AddRow("Flags", sop.Flags);
|
||||
|
||||
object itemsOutput;
|
||||
if (showFull)
|
||||
{
|
||||
StringBuilder itemsSb = new StringBuilder("\n");
|
||||
itemsOutput = AddScenePartItemsReport(itemsSb, sop.Inventory).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
itemsOutput = sop.Inventory.Count;
|
||||
}
|
||||
|
||||
|
||||
cdl.AddRow("Items", itemsOutput);
|
||||
|
||||
return sb.Append(cdl.ToString());
|
||||
}
|
||||
|
||||
private StringBuilder AddScenePartItemsReport(StringBuilder sb, IEntityInventory inv)
|
||||
{
|
||||
ConsoleDisplayTable cdt = new ConsoleDisplayTable();
|
||||
cdt.Indent = 2;
|
||||
|
||||
cdt.AddColumn("Name", 50);
|
||||
cdt.AddColumn("Type", 12);
|
||||
cdt.AddColumn("Running", 7);
|
||||
cdt.AddColumn("Item UUID", 36);
|
||||
cdt.AddColumn("Asset UUID", 36);
|
||||
|
||||
foreach (TaskInventoryItem item in inv.GetInventoryItems())
|
||||
cdt.AddRow(
|
||||
item.Name,
|
||||
((InventoryType)item.InvType).ToString(),
|
||||
(InventoryType)item.InvType == InventoryType.LSL ? item.ScriptRunning.ToString() : "n/a",
|
||||
item.ItemID.ToString(),
|
||||
item.AssetID.ToString());
|
||||
|
||||
return sb.Append(cdt.ToString());
|
||||
}
|
||||
|
||||
private void HandleDeleteObject(string module, string[] cmd)
|
||||
@@ -450,6 +693,10 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
|
||||
break;
|
||||
|
||||
case "pos":
|
||||
deletes = GetDeleteCandidatesByPos(module, cmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
m_console.OutputFormat("Unrecognized mode {0}", mode);
|
||||
return;
|
||||
@@ -464,7 +711,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
string.Format(
|
||||
"Are you sure that you want to delete {0} objects from {1}",
|
||||
deletes.Count, m_scene.RegionInfo.RegionName),
|
||||
"n");
|
||||
"y/N");
|
||||
|
||||
if (response.ToLower() != "y")
|
||||
{
|
||||
@@ -486,9 +733,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
|
||||
private List<SceneObjectGroup> GetDeleteCandidatesByName(string module, string[] cmdparams)
|
||||
{
|
||||
if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene))
|
||||
return null;
|
||||
|
||||
bool useRegex = false;
|
||||
OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null );
|
||||
|
||||
@@ -522,5 +766,52 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
||||
|
||||
return sceneObjects;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get scene object delete candidates by position
|
||||
/// </summary>
|
||||
/// <param name='module'></param>
|
||||
/// <param name='cmdparams'></param>
|
||||
/// <returns>null if parsing failed on one of the arguments, otherwise a list of objects to delete. If there
|
||||
/// are no objects to delete then the list will be empty./returns>
|
||||
private List<SceneObjectGroup> GetDeleteCandidatesByPos(string module, string[] cmdparams)
|
||||
{
|
||||
if (cmdparams.Length < 5)
|
||||
{
|
||||
m_console.OutputFormat("Usage: delete object pos <start-coord> to <end-coord>");
|
||||
return null;
|
||||
}
|
||||
|
||||
Vector3 startVector, endVector;
|
||||
|
||||
if (!TryParseVectorRange(cmdparams.Skip(3).Take(3), out startVector, out endVector))
|
||||
return null;
|
||||
|
||||
return m_scene.GetSceneObjectGroups().FindAll(
|
||||
so => !so.IsAttachment && Util.IsInsideBox(so.AbsolutePosition, startVector, endVector));
|
||||
}
|
||||
|
||||
private bool TryParseVectorRange(IEnumerable<string> rawComponents, out Vector3 startVector, out Vector3 endVector)
|
||||
{
|
||||
string rawConsoleStartVector = rawComponents.Take(1).Single();
|
||||
|
||||
if (!ConsoleUtil.TryParseConsoleMinVector(rawConsoleStartVector, out startVector))
|
||||
{
|
||||
m_console.OutputFormat("Error: Start vector {0} does not have a valid format", rawConsoleStartVector);
|
||||
endVector = Vector3.Zero;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string rawConsoleEndVector = rawComponents.Skip(1).Take(1).Single();
|
||||
|
||||
if (!ConsoleUtil.TryParseConsoleMaxVector(rawConsoleEndVector, out endVector))
|
||||
{
|
||||
m_console.OutputFormat("Error: End vector {0} does not have a valid format", rawConsoleEndVector);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,6 +208,10 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height);
|
||||
}
|
||||
|
||||
// XXX: It shouldn't really be necesary to force a GC here as one should occur anyway pretty shortly
|
||||
// afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory
|
||||
// then this may be some issue with the Warp3D code itself, though it's also quite possible that generating
|
||||
// this map tile simply takes a lot of memory.
|
||||
GC.Collect();
|
||||
m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()");
|
||||
|
||||
|
||||
@@ -108,6 +108,15 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// <param name="objectLocalID"></param>
|
||||
void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID);
|
||||
|
||||
/// <summary>
|
||||
/// Detach the given item to the ground at the specified coordinates & rotation
|
||||
/// </summary>
|
||||
/// <param name="sp"></param>
|
||||
/// <param name="objectLocalID"></param>
|
||||
/// <param name="absolutePos"></param>
|
||||
/// <param name="absoluteRot"></param>
|
||||
void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID, Vector3 absolutePos, Quaternion absoluteRot);
|
||||
|
||||
/// <summary>
|
||||
/// Detach the given attachment so that it remains in the user's inventory.
|
||||
/// </summary>
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using OpenMetaverse;
|
||||
|
||||
@@ -33,7 +35,14 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
public interface IDynamicTextureManager
|
||||
{
|
||||
void RegisterRender(string handleType, IDynamicTextureRender render);
|
||||
void ReturnData(UUID id, byte[] data, bool isReuseable);
|
||||
|
||||
/// <summary>
|
||||
/// Used by IDynamicTextureRender implementations to return renders
|
||||
/// </summary>
|
||||
/// <param name='id'></param>
|
||||
/// <param name='data'></param>
|
||||
/// <param name='isReuseable'></param>
|
||||
void ReturnData(UUID id, IDynamicTexture texture);
|
||||
|
||||
UUID AddDynamicTextureURL(UUID simID, UUID primID, string contentType, string url, string extraParams,
|
||||
int updateTimer);
|
||||
@@ -125,11 +134,53 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
// /// <param name='extraParams'></param>
|
||||
// bool AlwaysIdenticalConversion(string bodyData, string extraParams);
|
||||
|
||||
byte[] ConvertUrl(string url, string extraParams);
|
||||
byte[] ConvertData(string bodyData, string extraParams);
|
||||
IDynamicTexture ConvertUrl(string url, string extraParams);
|
||||
IDynamicTexture ConvertData(string bodyData, string extraParams);
|
||||
|
||||
bool AsyncConvertUrl(UUID id, string url, string extraParams);
|
||||
bool AsyncConvertData(UUID id, string bodyData, string extraParams);
|
||||
|
||||
void GetDrawStringSize(string text, string fontName, int fontSize,
|
||||
out double xSize, out double ySize);
|
||||
}
|
||||
|
||||
public interface IDynamicTexture
|
||||
{
|
||||
/// <summary>
|
||||
/// Input commands used to generate this data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if input commands were not used.
|
||||
/// </remarks>
|
||||
string InputCommands { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Uri used to generate this data.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if a uri was not used.
|
||||
/// </remarks>
|
||||
Uri InputUri { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Extra input params used to generate this data.
|
||||
/// </summary>
|
||||
string InputParams { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Texture data.
|
||||
/// </summary>
|
||||
byte[] Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Size of texture.
|
||||
/// </summary>
|
||||
Size Size { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Signal whether the texture is reuseable (i.e. whether the same input data will always generate the same
|
||||
/// texture).
|
||||
/// </summary>
|
||||
bool IsReuseable { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,18 +267,26 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
|
||||
void ApplyGodPermissions(uint perms);
|
||||
|
||||
/// <summary>
|
||||
/// Number of items in this inventory.
|
||||
/// </summary>
|
||||
int Count { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this inventory contains any scripts
|
||||
/// </summary></returns>
|
||||
bool ContainsScripts();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the count of scripts contained
|
||||
/// </summary></returns>
|
||||
/// Number of scripts in this inventory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Includes both running and non running scripts.
|
||||
/// </remarks>
|
||||
int ScriptCount();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the count of running scripts contained
|
||||
/// Number of running scripts in this inventory.
|
||||
/// </summary></returns>
|
||||
int RunningScriptCount();
|
||||
|
||||
|
||||
@@ -46,6 +46,11 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// </summary>
|
||||
void sendRegionHandshakeToAll();
|
||||
|
||||
/// <summary>
|
||||
/// Fires the OnRegionInfoChange event.
|
||||
/// </summary>
|
||||
void TriggerRegionInfoChange();
|
||||
|
||||
void setEstateTerrainBaseTexture(int level, UUID texture);
|
||||
void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
|
||||
public interface IJsonStoreModule
|
||||
{
|
||||
bool CreateStore(string value, out UUID result);
|
||||
bool CreateStore(string value, ref UUID result);
|
||||
bool DestroyStore(UUID storeID);
|
||||
bool TestPath(UUID storeID, string path, bool useJson);
|
||||
bool SetValue(UUID storeID, string path, string value, bool useJson);
|
||||
|
||||
@@ -74,6 +74,14 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// <param name="methods"></param>
|
||||
void RegisterScriptInvocation(Type target, string[] methods);
|
||||
|
||||
/// <summary>
|
||||
/// Automatically register script invocations by checking for methods
|
||||
/// with <see cref="ScriptInvocationAttribute"/>. Should only check
|
||||
/// public methods.
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
void RegisterScriptInvocations(IRegionModuleBase target);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array of all registered script calls
|
||||
/// </summary>
|
||||
@@ -96,11 +104,43 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// <param name="key"></param>
|
||||
void DispatchReply(UUID scriptId, int code, string text, string key);
|
||||
|
||||
/// For constants
|
||||
/// <summary>
|
||||
/// Operation to for a region module to register a constant to be used
|
||||
/// by the script engine
|
||||
/// </summary>
|
||||
/// <param name="cname">
|
||||
/// The name of the constant. LSL convention is for constant names to
|
||||
/// be uppercase.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The value of the constant. Should be of a type that can be
|
||||
/// converted to one of <see cref="OpenSim.Region.ScriptEngine.Shared.LSL_Types"/>
|
||||
/// </param>
|
||||
void RegisterConstant(string cname, object value);
|
||||
|
||||
/// <summary>
|
||||
/// Automatically register all constants on a region module by
|
||||
/// checking for fields with <see cref="ScriptConstantAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
void RegisterConstants(IRegionModuleBase target);
|
||||
|
||||
/// <summary>
|
||||
/// Operation to check for a registered constant
|
||||
/// </summary>
|
||||
/// <param name="cname">Name of constant</param>
|
||||
/// <returns>Value of constant or null if none found.</returns>
|
||||
object LookupModConstant(string cname);
|
||||
|
||||
// For use ONLY by the script API
|
||||
void RaiseEvent(UUID script, string id, string module, string command, string key);
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class ScriptInvocationAttribute : Attribute
|
||||
{ }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class ScriptConstantAttribute : Attribute
|
||||
{ }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,31 @@
|
||||
using System;
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using OpenMetaverse;
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
{
|
||||
if (m_defaultAnimation.AnimID == animID)
|
||||
{
|
||||
ResetDefaultAnimation();
|
||||
m_defaultAnimation = new OpenSim.Framework.Animation(UUID.Zero, 1, UUID.Zero);
|
||||
}
|
||||
else if (HasAnimation(animID))
|
||||
{
|
||||
@@ -149,19 +149,26 @@ namespace OpenSim.Region.Framework.Scenes.Animation
|
||||
{
|
||||
lock (m_animations)
|
||||
{
|
||||
animIDs = new UUID[m_animations.Count + 1];
|
||||
sequenceNums = new int[m_animations.Count + 1];
|
||||
objectIDs = new UUID[m_animations.Count + 1];
|
||||
int defaultSize = 0;
|
||||
if (m_defaultAnimation.AnimID != UUID.Zero)
|
||||
defaultSize++;
|
||||
|
||||
animIDs[0] = m_defaultAnimation.AnimID;
|
||||
sequenceNums[0] = m_defaultAnimation.SequenceNum;
|
||||
objectIDs[0] = m_defaultAnimation.ObjectID;
|
||||
animIDs = new UUID[m_animations.Count + defaultSize];
|
||||
sequenceNums = new int[m_animations.Count + defaultSize];
|
||||
objectIDs = new UUID[m_animations.Count + defaultSize];
|
||||
|
||||
if (m_defaultAnimation.AnimID != UUID.Zero)
|
||||
{
|
||||
animIDs[0] = m_defaultAnimation.AnimID;
|
||||
sequenceNums[0] = m_defaultAnimation.SequenceNum;
|
||||
objectIDs[0] = m_defaultAnimation.ObjectID;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_animations.Count; ++i)
|
||||
{
|
||||
animIDs[i + 1] = m_animations[i].AnimID;
|
||||
sequenceNums[i + 1] = m_animations[i].SequenceNum;
|
||||
objectIDs[i + 1] = m_animations[i].ObjectID;
|
||||
animIDs[i + defaultSize] = m_animations[i].AnimID;
|
||||
sequenceNums[i + defaultSize] = m_animations[i].SequenceNum;
|
||||
objectIDs[i + defaultSize] = m_animations[i].ObjectID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user