EnvironmentModule.cs 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Net;
  30. using System.Reflection;
  31. using OpenMetaverse;
  32. using OpenMetaverse.StructuredData;
  33. using OpenSim.Framework;
  34. using OpenSim.Framework.Servers.HttpServer;
  35. using OpenSim.Region.Framework.Interfaces;
  36. using OpenSim.Region.Framework.Scenes;
  37. using OpenSim.Services.Interfaces;
  38. using log4net;
  39. using Nini.Config;
  40. using Mono.Addins;
  41. using Caps = OpenSim.Framework.Capabilities.Caps;
  42. using OSDArray = OpenMetaverse.StructuredData.OSDArray;
  43. using OSDMap = OpenMetaverse.StructuredData.OSDMap;
  44. using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;
  45. namespace OpenSim.Region.CoreModules.World.LightShare
  46. {
  47. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EnvironmentModule")]
  48. public class EnvironmentModule : INonSharedRegionModule, IEnvironmentModule
  49. {
  50. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  51. private Scene m_scene = null;
  52. private UUID regionID = UUID.Zero;
  53. private bool Enabled = false;
  54. private IEstateModule m_estateModule;
  55. private IEventQueue m_eventQueue;
  56. private IAssetService m_assetService;
  57. private ILandChannel m_landChannel;
  58. private static ViewerEnvironment m_DefaultEnv = null;
  59. // 1/1 day-to-night ratio
  60. //private static readonly string m_defaultDayAssetID = "5646d39e-d3d7-6aff-ed71-30fc87d64a91"; // Default Daycycle
  61. // 3/1 day-to-night ratio
  62. private static readonly string m_defaultDayAssetID = "5646d39e-d3d7-6aff-ed71-30fc87d64a92"; // Default Daycycle (More Daylight)
  63. private static UUID m_defaultDayAssetUUID = new("5646d39e-d3d7-6aff-ed71-30fc87d64a92");
  64. //private static string m_defaultSkyAssetID = "3ae23978-ac82-bcf3-a9cb-ba6e52dcb9ad";
  65. private static UUID m_defaultSkyAssetUUID = new("3ae23978-ac82-bcf3-a9cb-ba6e52dcb9ad");
  66. //private static string m_defaultWaterAssetID = "59d1a851-47e7-0e5f-1ed7-6b715154f41a";
  67. private static UUID m_defaultWaterAssetUUID = new("59d1a851-47e7-0e5f-1ed7-6b715154f41a");
  68. private int m_regionEnvVersion = -1;
  69. private double m_framets;
  70. #region INonSharedRegionModule
  71. public void Initialise(IConfigSource source)
  72. {
  73. IConfig config = source.Configs["ClientStack.LindenCaps"];
  74. if (config is null)
  75. return;
  76. if (!config.GetString("Cap_EnvironmentSettings", string.Empty).Equals("localhost"))
  77. {
  78. m_log.InfoFormat("[{0}]: Module is disabled.", Name);
  79. return;
  80. }
  81. Enabled = true;
  82. m_log.InfoFormat("[{0}]: Module is enabled.", Name);
  83. }
  84. public void Close()
  85. {
  86. }
  87. public string Name
  88. {
  89. get { return "EnvironmentModule"; }
  90. }
  91. public Type ReplaceableInterface
  92. {
  93. get { return null; }
  94. }
  95. public void AddRegion(Scene scene)
  96. {
  97. if (!Enabled)
  98. return;
  99. scene.RegisterModuleInterface<IEnvironmentModule>(this);
  100. m_scene = scene;
  101. regionID = scene.RegionInfo.RegionID;
  102. }
  103. public void RegionLoaded(Scene scene)
  104. {
  105. if (!Enabled)
  106. return;
  107. m_estateModule = scene.RequestModuleInterface<IEstateModule>();
  108. if (m_estateModule is null)
  109. {
  110. Enabled = false;
  111. return;
  112. }
  113. m_eventQueue = m_scene.RequestModuleInterface<IEventQueue>();
  114. if (m_eventQueue is null)
  115. {
  116. Enabled = false;
  117. return;
  118. }
  119. m_assetService = m_scene.AssetService;
  120. if (m_assetService is null)
  121. {
  122. Enabled = false;
  123. return;
  124. }
  125. m_landChannel = m_scene.LandChannel;
  126. if (m_landChannel is null)
  127. {
  128. Enabled = false;
  129. return;
  130. }
  131. if (m_DefaultEnv is null)
  132. {
  133. AssetBase defEnv = m_assetService.Get(m_defaultDayAssetID);
  134. if(defEnv is not null)
  135. {
  136. byte[] envData = defEnv.Data;
  137. try
  138. {
  139. OSD oenv = OSDParser.Deserialize(envData);
  140. m_DefaultEnv = new ViewerEnvironment();
  141. m_DefaultEnv.CycleFromOSD(oenv);
  142. }
  143. catch (Exception e)
  144. {
  145. m_DefaultEnv = null;
  146. m_log.Warn(string.Format("[Environment {0}] failed to decode default environment asset ", m_scene.Name), e);
  147. }
  148. }
  149. }
  150. m_DefaultEnv ??= new ViewerEnvironment();
  151. string senv = scene.SimulationDataService.LoadRegionEnvironmentSettings(scene.RegionInfo.RegionID);
  152. if(!string.IsNullOrEmpty(senv))
  153. {
  154. try
  155. {
  156. OSD oenv = OSDParser.Deserialize(senv);
  157. ViewerEnvironment VEnv = new();
  158. if (oenv is OSDArray)
  159. {
  160. VEnv.FromWLOSD(oenv);
  161. StoreOnRegion(VEnv);
  162. m_log.Info($"[Environment {m_scene.Name}] migrated WindLight environment settings to EEP");
  163. }
  164. else
  165. {
  166. VEnv.FromOSD(oenv);
  167. }
  168. scene.RegionEnvironment = VEnv;
  169. m_regionEnvVersion = VEnv.version;
  170. }
  171. catch (Exception e)
  172. {
  173. m_log.Error($"[Environment {m_scene.Name}] failed to load initial Environment {e.Message}");
  174. scene.RegionEnvironment = null;
  175. m_regionEnvVersion = -1;
  176. }
  177. }
  178. else
  179. {
  180. scene.RegionEnvironment = null;
  181. m_regionEnvVersion = -1;
  182. }
  183. m_framets = 0;
  184. UpdateEnvTime();
  185. scene.EventManager.OnRegisterCaps += OnRegisterCaps;
  186. scene.EventManager.OnFrame += UpdateEnvTime;
  187. scene.EventManager.OnAvatarEnteringNewParcel += OnAvatarEnteringNewParcel;
  188. }
  189. public void RemoveRegion(Scene scene)
  190. {
  191. if (!Enabled)
  192. return;
  193. scene.EventManager.OnRegisterCaps -= OnRegisterCaps;
  194. }
  195. #endregion
  196. #region IEnvironmentModule
  197. public void StoreOnRegion(ViewerEnvironment VEnv)
  198. {
  199. try
  200. {
  201. if (VEnv is null)
  202. {
  203. m_scene.SimulationDataService.RemoveRegionEnvironmentSettings(regionID);
  204. m_scene.RegionEnvironment = null;
  205. m_regionEnvVersion = -1;
  206. }
  207. else
  208. {
  209. m_regionEnvVersion++;
  210. VEnv.version = m_regionEnvVersion;
  211. OSD env = VEnv.ToOSD();
  212. //m_scene.SimulationDataService.StoreRegionEnvironmentSettings(regionID, OSDParser.SerializeLLSDXmlString(env));
  213. m_scene.SimulationDataService.StoreRegionEnvironmentSettings(regionID, OSDParser.SerializeLLSDNotationFull(env));
  214. m_scene.RegionEnvironment = VEnv;
  215. }
  216. m_framets = 0;
  217. UpdateEnvTime();
  218. }
  219. catch (Exception e)
  220. {
  221. m_log.Error($"[Environment {m_scene.Name}] failed to store Environment {e.Message}");
  222. }
  223. }
  224. public void ResetEnvironmentSettings(UUID regionUUID)
  225. {
  226. if (!Enabled)
  227. return;
  228. StoreOnRegion(null);
  229. WindlightRefresh(0);
  230. }
  231. public void WindlightRefresh(int interpolate, bool forRegion = true)
  232. {
  233. List<byte[]> ls = null;
  234. m_scene.ForEachRootScenePresence(delegate (ScenePresence sp)
  235. {
  236. if(sp.IsInTransit || sp.IsNPC)
  237. return;
  238. IClientAPI client = sp.ControllingClient;
  239. if (!client.IsActive)
  240. return;
  241. uint vflags = client.GetViewerCaps();
  242. if ((vflags & 0x8000) != 0)
  243. {
  244. if (forRegion)
  245. m_estateModule.HandleRegionInfoRequest(client);
  246. }
  247. else if ((vflags & 0x4000) != 0)
  248. m_eventQueue.WindlightRefreshEvent(interpolate, client.AgentId);
  249. else
  250. {
  251. ls ??= MakeLightShareData();
  252. SendLightShare(client, ls);
  253. }
  254. });
  255. }
  256. public void WindlightRefreshForced(IScenePresence isp, int interpolate)
  257. {
  258. List<byte[]> ls = null;
  259. IClientAPI client = isp.ControllingClient;
  260. if (!client.IsActive)
  261. return;
  262. uint vflags = client.GetViewerCaps();
  263. if ((vflags & 0x8000) != 0)
  264. {
  265. ScenePresence sp = isp as ScenePresence;
  266. ILandObject lo = m_scene.LandChannel.GetLandObject(sp.AbsolutePosition.X, sp.AbsolutePosition.Y);
  267. if (lo is not null && lo.LandData is not null && lo.LandData.Environment is not null)
  268. lo.SendLandUpdateToClient(client);
  269. m_estateModule.HandleRegionInfoRequest(client);
  270. }
  271. else if ((vflags & 0x4000) != 0)
  272. m_eventQueue.WindlightRefreshEvent(interpolate, client.AgentId);
  273. else
  274. {
  275. ls ??= MakeLightShareData();
  276. SendLightShare(client, ls);
  277. }
  278. }
  279. public void FromLightShare(RegionLightShareData ls)
  280. {
  281. if (!Enabled)
  282. return;
  283. ViewerEnvironment VEnv = new();
  284. VEnv.FromLightShare(ls);
  285. StoreOnRegion(VEnv);
  286. WindlightRefresh(0);
  287. }
  288. public RegionLightShareData ToLightShare()
  289. {
  290. if (!Enabled)
  291. return new RegionLightShareData();
  292. RegionLightShareData ls = null;
  293. try
  294. {
  295. ViewerEnvironment VEnv = m_scene.RegionEnvironment;
  296. if(VEnv is not null)
  297. ls = VEnv.ToLightShare();
  298. }
  299. catch (Exception e)
  300. {
  301. m_log.ErrorFormat("[{0}]: Unable to convert environment to lightShare, Exception: {1} - {2}",
  302. Name, e.Message, e.StackTrace);
  303. }
  304. return ls ?? new RegionLightShareData();
  305. }
  306. #endregion
  307. #region Events
  308. private void OnRegisterCaps(UUID agentID, Caps caps)
  309. {
  310. // m_log.DebugFormat("[{0}]: Register capability for agentID {1} in region {2}",
  311. // Name, agentID, caps.RegionName);
  312. caps.RegisterSimpleHandler("EnvironmentSettings",
  313. new SimpleStreamHandler("/" + UUID.Random(), delegate (IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
  314. {
  315. processEnv(httpRequest, httpResponse, agentID);
  316. }));
  317. //Extended
  318. caps.RegisterSimpleHandler("ExtEnvironment",
  319. new SimpleStreamHandler("/" + UUID.Random(), delegate (IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
  320. {
  321. processExtEnv(httpRequest, httpResponse, agentID, caps);
  322. }));
  323. }
  324. #endregion
  325. private void processEnv(IOSHttpRequest request, IOSHttpResponse response, UUID agentID)
  326. {
  327. switch (request.HttpMethod)
  328. {
  329. case "POST":
  330. SetEnvironmentSettings(request, response, agentID);
  331. return;
  332. case "GET":
  333. GetEnvironmentSettings(response, agentID);
  334. return;
  335. default:
  336. {
  337. response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
  338. return;
  339. }
  340. }
  341. }
  342. private void processExtEnv(IOSHttpRequest request, IOSHttpResponse response, UUID agentID, Caps caps)
  343. {
  344. switch(request.HttpMethod)
  345. {
  346. case "PUT":
  347. case "POST":
  348. SetExtEnvironmentSettings(request, response, agentID, caps);
  349. return;
  350. case "GET":
  351. GetExtEnvironmentSettings(request, response, agentID);
  352. return;
  353. case "DELETE":
  354. DeleteExtEnvironmentSettings(request, response, agentID);
  355. return;
  356. default:
  357. {
  358. response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
  359. return;
  360. }
  361. }
  362. }
  363. private void DeleteExtEnvironmentSettings(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID agentID)
  364. {
  365. int parcel = -1;
  366. if (httpRequest.Query.Count > 0)
  367. {
  368. if (httpRequest.Query.ContainsKey("parcelid"))
  369. {
  370. _ = Int32.TryParse((string)httpRequest.Query["parcelid"], out parcel);
  371. }
  372. }
  373. if(parcel == -1)
  374. {
  375. StoreOnRegion(null);
  376. WindlightRefresh(0);
  377. }
  378. else
  379. {
  380. ILandObject land = m_scene.LandChannel.GetLandObject(parcel);
  381. if (land is not null && land.LandData is not null)
  382. {
  383. land.StoreEnvironment(null);
  384. WindlightRefresh(0, false);
  385. }
  386. }
  387. osUTF8 sb = LLSDxmlEncode2.Start();
  388. LLSDxmlEncode2.AddMap(sb);
  389. LLSDxmlEncode2.AddElem("messageID", UUID.Zero, sb);
  390. LLSDxmlEncode2.AddElem("regionID", regionID, sb);
  391. LLSDxmlEncode2.AddElem("success", true, sb);
  392. LLSDxmlEncode2.AddEndMap(sb);
  393. httpResponse.RawBuffer = LLSDxmlEncode2.EndToBytes(sb);
  394. httpResponse.StatusCode = (int)HttpStatusCode.OK;
  395. }
  396. private void GetExtEnvironmentSettings(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID agentID)
  397. {
  398. int parcelid = -1;
  399. if (httpRequest.Query.Count > 0)
  400. {
  401. if (httpRequest.Query.ContainsKey("parcelid"))
  402. {
  403. _ = Int32.TryParse((string)httpRequest.Query["parcelid"], out parcelid);
  404. }
  405. }
  406. ScenePresence sp = m_scene.GetScenePresence(agentID);
  407. if (sp == null)
  408. {
  409. httpResponse.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
  410. httpResponse.AddHeader("Retry-After", "5");
  411. return;
  412. }
  413. ViewerEnvironment VEnv = null;
  414. if (sp.Environment is not null)
  415. VEnv = sp.Environment;
  416. else if (parcelid == -1)
  417. VEnv = GetRegionEnvironment();
  418. else
  419. {
  420. if (m_scene.RegionInfo.EstateSettings.AllowEnvironmentOverride)
  421. {
  422. ILandObject land = m_scene.LandChannel.GetLandObject(parcelid);
  423. if(land is not null && land.LandData is not null && land.LandData.Environment is not null)
  424. VEnv = land.LandData.Environment;
  425. }
  426. if(VEnv is null)
  427. {
  428. OSD def = ViewerEnvironment.DefaultToOSD(regionID, parcelid);
  429. httpResponse.RawBuffer = OSDParser.SerializeLLSDXmlToBytes(def);
  430. httpResponse.StatusCode = (int)HttpStatusCode.OK;
  431. return;
  432. }
  433. }
  434. byte[] envBytes = VEnv.ToCapBytes(regionID, parcelid);
  435. if(envBytes is null)
  436. {
  437. osUTF8 sb = LLSDxmlEncode2.Start();
  438. LLSDxmlEncode2.AddArray(sb);
  439. LLSDxmlEncode2.AddMap(sb);
  440. LLSDxmlEncode2.AddElem("messageID", UUID.Zero, sb);
  441. LLSDxmlEncode2.AddElem("regionID", regionID, sb);
  442. LLSDxmlEncode2.AddEndMap(sb);
  443. LLSDxmlEncode2.AddEndArray(sb);
  444. httpResponse.RawBuffer = LLSDxmlEncode2.EndToBytes(sb);
  445. }
  446. else
  447. httpResponse.RawBuffer = envBytes;
  448. httpResponse.StatusCode = (int)HttpStatusCode.OK;
  449. }
  450. private void SetExtEnvironmentSettings(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID agentID, Caps caps)
  451. {
  452. bool success = false;
  453. string message = "Could not process request";
  454. int parcel = -1;
  455. int track = -1;
  456. osUTF8 sb = LLSDxmlEncode2.Start();
  457. ScenePresence sp = m_scene.GetScenePresence(agentID);
  458. if (sp is null || sp.IsChildAgent || sp.IsNPC)
  459. {
  460. message = "Could not locate your avatar";
  461. goto Error;
  462. }
  463. if (httpRequest.Query.Count > 0)
  464. {
  465. if (httpRequest.Query.ContainsKey("parcelid"))
  466. {
  467. if (!Int32.TryParse((string)httpRequest.Query["parcelid"], out parcel))
  468. {
  469. message = "Failed to decode request";
  470. goto Error;
  471. }
  472. }
  473. if (httpRequest.Query.ContainsKey("trackno"))
  474. {
  475. if (!Int32.TryParse((string)httpRequest.Query["trackno"], out track))
  476. {
  477. message = "Failed to decode request";
  478. goto Error;
  479. }
  480. }
  481. if (track != -1)
  482. {
  483. message = "Environment Track not supported";
  484. goto Error;
  485. }
  486. }
  487. ViewerEnvironment VEnv;
  488. ILandObject lchannel;
  489. if (parcel == -1)
  490. {
  491. if (!m_scene.Permissions.CanIssueEstateCommand(agentID, false))
  492. {
  493. message = "Insufficient estate permissions, settings has not been saved.";
  494. goto Error;
  495. }
  496. VEnv = m_scene.RegionEnvironment;
  497. lchannel = null;
  498. }
  499. else
  500. {
  501. lchannel = m_landChannel.GetLandObject(parcel);
  502. if(lchannel is null || lchannel.LandData is null)
  503. {
  504. message = "Could not locate requested parcel";
  505. goto Error;
  506. }
  507. if (!m_scene.Permissions.CanEditParcelProperties(agentID, lchannel, GroupPowers.AllowEnvironment, true)) // wrong
  508. {
  509. message = "No permission to change parcel environment";
  510. goto Error;
  511. }
  512. VEnv = lchannel.LandData.Environment;
  513. }
  514. try
  515. {
  516. OSD req = OSDParser.Deserialize(httpRequest.InputStream);
  517. if(req is OSDMap map)
  518. {
  519. if(map.TryGetValue("environment", out OSD env))
  520. {
  521. // need a proper clone
  522. VEnv ??= m_DefaultEnv.Clone();
  523. OSDMap evmap = env as OSDMap;
  524. if(evmap.TryGetValue("day_asset", out OSD tmp) && !evmap.ContainsKey("day_cycle"))
  525. {
  526. string id = tmp.AsString();
  527. AssetBase asset = m_assetService.Get(id);
  528. if(asset is null || asset.Data is null || asset.Data.Length == 0)
  529. {
  530. httpResponse.StatusCode = (int)HttpStatusCode.NotFound;
  531. return;
  532. }
  533. try
  534. {
  535. OSD oenv = OSDParser.Deserialize(asset.Data);
  536. evmap.TryGetValue("day_name", out tmp);
  537. if(tmp is OSDString)
  538. VEnv.FromAssetOSD(tmp.AsString(), oenv);
  539. else
  540. VEnv.FromAssetOSD(null, oenv);
  541. }
  542. catch
  543. {
  544. httpResponse.StatusCode = (int)HttpStatusCode.NotFound;
  545. return;
  546. }
  547. }
  548. else
  549. VEnv.FromOSD(env);
  550. if(lchannel is null)
  551. {
  552. StoreOnRegion(VEnv);
  553. m_log.InfoFormat("[{0}]: ExtEnvironment region {1} settings from agentID {2} saved",
  554. Name, caps.RegionName, agentID);
  555. }
  556. else
  557. {
  558. lchannel.StoreEnvironment(VEnv);
  559. m_log.InfoFormat("[{0}]: ExtEnvironment parcel {1} of region {2} settings from agentID {3} saved",
  560. Name, parcel, caps.RegionName, agentID);
  561. }
  562. WindlightRefresh(0, lchannel is null);
  563. success = true;
  564. }
  565. }
  566. else if (req is OSDArray)
  567. {
  568. VEnv = new ViewerEnvironment();
  569. VEnv.FromWLOSD(req);
  570. StoreOnRegion(VEnv);
  571. success = true;
  572. WindlightRefresh(0);
  573. m_log.InfoFormat("[{0}]: ExtEnvironment region {1} settings from agentID {2} saved",
  574. Name, caps.RegionName, agentID);
  575. LLSDxmlEncode2.AddMap(sb);
  576. LLSDxmlEncode2.AddElem("messageID", UUID.Zero, sb);
  577. LLSDxmlEncode2.AddElem("regionID", regionID, sb);
  578. LLSDxmlEncode2.AddElem("success", success, sb);
  579. LLSDxmlEncode2.AddEndMap(sb);
  580. httpResponse.RawBuffer = LLSDxmlEncode2.EndToBytes(sb);
  581. httpResponse.StatusCode = (int)HttpStatusCode.OK;
  582. return;
  583. }
  584. }
  585. catch (Exception e)
  586. {
  587. m_log.ErrorFormat("[{0}]: ExtEnvironment settings not saved for region {1}, Exception: {2} - {3}",
  588. Name, caps.RegionName, e.Message, e.StackTrace);
  589. success = false;
  590. message = String.Format("ExtEnvironment Set for region {0} has failed, settings not saved.", caps.RegionName);
  591. }
  592. Error:
  593. LLSDxmlEncode2.AddMap(sb);
  594. LLSDxmlEncode2.AddElem("success", success, sb);
  595. if(!success)
  596. LLSDxmlEncode2.AddElem("message", message, sb);
  597. LLSDxmlEncode2.AddEndMap(sb);
  598. httpResponse.RawBuffer = LLSDxmlEncode2.EndToBytes(sb);
  599. httpResponse.StatusCode = (int)HttpStatusCode.OK;
  600. }
  601. private void GetEnvironmentSettings(IOSHttpResponse response, UUID agentID)
  602. {
  603. // m_log.DebugFormat("[{0}]: Environment GET handle for agentID {1} in region {2}",
  604. // Name, agentID, caps.RegionName);
  605. ViewerEnvironment VEnv = null;
  606. ScenePresence sp = m_scene.GetScenePresence(agentID);
  607. if (sp is null)
  608. {
  609. response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
  610. response.AddHeader("Retry-After", "5");
  611. return;
  612. }
  613. if (sp.Environment is not null)
  614. VEnv = sp.Environment;
  615. else
  616. {
  617. if(m_scene.RegionInfo.EstateSettings.AllowEnvironmentOverride)
  618. {
  619. ILandObject land = m_scene.LandChannel.GetLandObject(sp.AbsolutePosition.X, sp.AbsolutePosition.Y);
  620. if (land is not null && land.LandData is not null && land.LandData.Environment is not null)
  621. VEnv = land.LandData.Environment;
  622. }
  623. }
  624. VEnv ??= GetRegionEnvironment();
  625. byte[] envBytes = VEnv.ToCapWLBytes(UUID.Zero, regionID);
  626. if(envBytes is null)
  627. {
  628. osUTF8 sb = LLSDxmlEncode2.Start();
  629. LLSDxmlEncode2.AddArray(sb);
  630. LLSDxmlEncode2.AddMap(sb);
  631. LLSDxmlEncode2.AddElem("messageID", UUID.Zero, sb);
  632. LLSDxmlEncode2.AddElem("regionID", regionID, sb);
  633. LLSDxmlEncode2.AddEndMap(sb);
  634. LLSDxmlEncode2.AddEndArray(sb);
  635. response.RawBuffer = LLSDxmlEncode2.EndToBytes(sb);
  636. }
  637. else
  638. response.RawBuffer = envBytes;
  639. response.StatusCode = (int)HttpStatusCode.OK;
  640. }
  641. private void SetEnvironmentSettings(IOSHttpRequest request, IOSHttpResponse response, UUID agentID)
  642. {
  643. // m_log.DebugFormat("[{0}]: Environment SET handle from agentID {1} in region {2}",
  644. // Name, agentID, caps.RegionName);
  645. bool success = false;
  646. string fail_reason = "";
  647. if (!m_scene.Permissions.CanIssueEstateCommand(agentID, false))
  648. {
  649. fail_reason = "Insufficient estate permissions, settings has not been saved.";
  650. goto Error;
  651. }
  652. ScenePresence sp = m_scene.GetScenePresence(agentID);
  653. if (sp is null || sp.IsChildAgent || sp.IsNPC)
  654. {
  655. response.StatusCode = (int)HttpStatusCode.NotFound;
  656. return;
  657. }
  658. if (sp.Environment is not null)
  659. {
  660. fail_reason = "The environment you see is a forced one. Disable if on control object or tp out and back to region";
  661. goto Error;
  662. }
  663. ILandObject land = m_scene.LandChannel.GetLandObject(sp.AbsolutePosition.X, sp.AbsolutePosition.Y);
  664. if (land is not null && land.LandData is not null && land.LandData.Environment is not null)
  665. {
  666. fail_reason = "The parcel where you are has own environment set. You need a updated viewer to change environment";
  667. goto Error;
  668. }
  669. try
  670. {
  671. ViewerEnvironment VEnv = new();
  672. OSD env = OSDParser.Deserialize(request.InputStream);
  673. VEnv.FromWLOSD(env);
  674. StoreOnRegion(VEnv);
  675. WindlightRefresh(0);
  676. m_log.InfoFormat("[{0}]: New Environment settings has been saved from agentID {1} in region {2}",
  677. Name, agentID, m_scene.Name);
  678. success = true;
  679. }
  680. catch (Exception e)
  681. {
  682. m_log.ErrorFormat("[{0}]: Environment settings has not been saved for region {1}, Exception: {2} - {3}",
  683. Name, m_scene.Name, e.Message, e.StackTrace);
  684. success = false;
  685. fail_reason = String.Format("Environment Set for region {0} has failed, settings not saved.", m_scene.Name);
  686. }
  687. Error:
  688. osUTF8 sb = LLSDxmlEncode2.Start();
  689. LLSDxmlEncode2.AddMap(sb);
  690. LLSDxmlEncode2.AddElem("messageID", UUID.Zero, sb);
  691. LLSDxmlEncode2.AddElem("regionID", regionID, sb);
  692. LLSDxmlEncode2.AddElem("success", success, sb);
  693. if(!success)
  694. LLSDxmlEncode2.AddElem("fail_reason", fail_reason, sb);
  695. LLSDxmlEncode2.AddEndMap(sb);
  696. response.RawBuffer = LLSDxmlEncode2.EndToBytes(sb);
  697. response.StatusCode = (int)HttpStatusCode.OK;
  698. }
  699. public byte[] GetDefaultAssetData(int type)
  700. {
  701. OSD osddata;
  702. switch(type)
  703. {
  704. case 0:
  705. SkyData sky = new() { Name = "DefaultSky" };
  706. osddata = sky.ToOSD();
  707. break;
  708. case 1:
  709. WaterData water = new() { Name = "DefaultWater" };
  710. osddata = water.ToOSD();
  711. break;
  712. case 2:
  713. DayCycle day = new() { Name="New Daycycle" };
  714. DayCycle.TrackEntry te = new();
  715. WaterData dwater = new(){ Name = "DefaultWater" };
  716. day.waterframes["DefaultWater"] = dwater;
  717. te.time = 0;
  718. te.frameName = "DefaultWater";
  719. day.waterTrack.Add(te);
  720. SkyData dsky = new() { Name = "DefaultSky" } ;
  721. day.skyframes["DefaultSky"] = dsky;
  722. te.time = 0;
  723. te.frameName = "DefaultSky";
  724. day.skyTrack0.Add(te);
  725. osddata = day.ToOSD();
  726. break;
  727. default:
  728. return null;
  729. }
  730. return OSDParser.SerializeLLSDNotationToBytes(osddata,true);
  731. }
  732. public UUID GetDefaultAsset(int type)
  733. {
  734. return type switch
  735. {
  736. 0 => m_defaultSkyAssetUUID,
  737. 1 => m_defaultWaterAssetUUID,
  738. 2 => m_defaultDayAssetUUID,
  739. _ => UUID.Zero,
  740. };
  741. }
  742. public List<byte[]> MakeLightShareData()
  743. {
  744. if(m_scene.RegionEnvironment == null)
  745. return null;
  746. RegionLightShareData wl = ToLightShare();
  747. byte[] mBlock = new Byte[249];
  748. int pos = 0;
  749. wl.waterColor.ToBytes(mBlock, 0); pos += 12;
  750. Utils.FloatToBytes(wl.waterFogDensityExponent).CopyTo(mBlock, pos); pos += 4;
  751. Utils.FloatToBytes(wl.underwaterFogModifier).CopyTo(mBlock, pos); pos += 4;
  752. wl.reflectionWaveletScale.ToBytes(mBlock, pos); pos += 12;
  753. Utils.FloatToBytes(wl.fresnelScale).CopyTo(mBlock, pos); pos += 4;
  754. Utils.FloatToBytes(wl.fresnelOffset).CopyTo(mBlock, pos); pos += 4;
  755. Utils.FloatToBytes(wl.refractScaleAbove).CopyTo(mBlock, pos); pos += 4;
  756. Utils.FloatToBytes(wl.refractScaleBelow).CopyTo(mBlock, pos); pos += 4;
  757. Utils.FloatToBytes(wl.blurMultiplier).CopyTo(mBlock, pos); pos += 4;
  758. wl.bigWaveDirection.ToBytes(mBlock, pos); pos += 8;
  759. wl.littleWaveDirection.ToBytes(mBlock, pos); pos += 8;
  760. wl.normalMapTexture.ToBytes(mBlock, pos); pos += 16;
  761. wl.horizon.ToBytes(mBlock, pos); pos += 16;
  762. Utils.FloatToBytes(wl.hazeHorizon).CopyTo(mBlock, pos); pos += 4;
  763. wl.blueDensity.ToBytes(mBlock, pos); pos += 16;
  764. Utils.FloatToBytes(wl.hazeDensity).CopyTo(mBlock, pos); pos += 4;
  765. Utils.FloatToBytes(wl.densityMultiplier).CopyTo(mBlock, pos); pos += 4;
  766. Utils.FloatToBytes(wl.distanceMultiplier).CopyTo(mBlock, pos); pos += 4;
  767. wl.sunMoonColor.ToBytes(mBlock, pos); pos += 16;
  768. Utils.FloatToBytes(wl.sunMoonPosition).CopyTo(mBlock, pos); pos += 4;
  769. wl.ambient.ToBytes(mBlock, pos); pos += 16;
  770. Utils.FloatToBytes(wl.eastAngle).CopyTo(mBlock, pos); pos += 4;
  771. Utils.FloatToBytes(wl.sunGlowFocus).CopyTo(mBlock, pos); pos += 4;
  772. Utils.FloatToBytes(wl.sunGlowSize).CopyTo(mBlock, pos); pos += 4;
  773. Utils.FloatToBytes(wl.sceneGamma).CopyTo(mBlock, pos); pos += 4;
  774. Utils.FloatToBytes(wl.starBrightness).CopyTo(mBlock, pos); pos += 4;
  775. wl.cloudColor.ToBytes(mBlock, pos); pos += 16;
  776. wl.cloudXYDensity.ToBytes(mBlock, pos); pos += 12;
  777. Utils.FloatToBytes(wl.cloudCoverage).CopyTo(mBlock, pos); pos += 4;
  778. Utils.FloatToBytes(wl.cloudScale).CopyTo(mBlock, pos); pos += 4;
  779. wl.cloudDetailXYDensity.ToBytes(mBlock, pos); pos += 12;
  780. Utils.FloatToBytes(wl.cloudScrollX).CopyTo(mBlock, pos); pos += 4;
  781. Utils.FloatToBytes(wl.cloudScrollY).CopyTo(mBlock, pos); pos += 4;
  782. Utils.UInt16ToBytes(wl.maxAltitude).CopyTo(mBlock, pos); pos += 2;
  783. mBlock[pos] = Convert.ToByte(wl.cloudScrollXLock); pos++;
  784. mBlock[pos] = Convert.ToByte(wl.cloudScrollYLock); pos++;
  785. mBlock[pos] = Convert.ToByte(wl.drawClassicClouds); // pos++;
  786. List<byte[]> param = new() { mBlock };
  787. return param;
  788. }
  789. public void SendLightShare(IClientAPI client, List<byte[]> param)
  790. {
  791. if(param is null || param.Count == 0)
  792. client.SendGenericMessage("WindlightReset", UUID.Random(), new List<byte[]>());
  793. else
  794. client.SendGenericMessage("Windlight", UUID.Random(), param);
  795. }
  796. private void OnAvatarEnteringNewParcel(ScenePresence sp, int localLandID, UUID regionID)
  797. {
  798. if (sp.Environment is not null || sp.IsNPC)
  799. return;
  800. if (!m_scene.RegionInfo.EstateSettings.AllowEnvironmentOverride)
  801. return;
  802. IClientAPI client = sp.ControllingClient;
  803. uint vflags = client.GetViewerCaps();
  804. if((vflags & 0x8000) != 0)
  805. return;
  806. m_eventQueue.WindlightRefreshEvent(1, client.AgentId);
  807. }
  808. private void UpdateEnvTime()
  809. {
  810. double now = Util.GetTimeStamp();
  811. if (now - m_framets < 2.5) // this will be a conf option
  812. return;
  813. m_framets = now;
  814. UpdateClientsSunTime();
  815. }
  816. private void UpdateClientsSunTime()
  817. {
  818. if(m_scene.GetNumberOfClients() == 0)
  819. return;
  820. //m_log.DebugFormat("{0} {1} {2} {3}", dayFrac, eepDayFrac, wldayFrac, Util.UnixTimeSinceEpoch_uS());
  821. m_scene.ForEachRootScenePresence(delegate (ScenePresence sp)
  822. {
  823. if(sp.IsDeleted || sp.IsInTransit || sp.IsNPC)
  824. return;
  825. ViewerEnvironment VEnv;
  826. if(sp.Environment is not null)
  827. VEnv = sp.Environment;
  828. else
  829. VEnv = GetEnvironment(sp.AbsolutePosition.X, sp.AbsolutePosition.Y);
  830. float dayFrac = GetDayFractionTime(VEnv);
  831. IClientAPI client = sp.ControllingClient;
  832. uint vflags = client.GetViewerCaps();
  833. if ((vflags & 0x8000) != 0)
  834. {
  835. client.SendViewerTime(Vector3.Zero, dayFrac * Utils.TWO_PI);
  836. return;
  837. }
  838. if (dayFrac <= 0.25f)
  839. dayFrac += 1.5f;
  840. else if (dayFrac > 0.75f)
  841. dayFrac += 0.5f;
  842. else if (dayFrac >= 0.333333f)
  843. dayFrac = 3f * dayFrac - 1f;
  844. else
  845. dayFrac = 3f * dayFrac + 1f;
  846. dayFrac = Utils.Clamp(dayFrac, 0, 2f);
  847. dayFrac *= Utils.PI;
  848. client.SendViewerTime(Vector3.Zero, dayFrac);
  849. });
  850. }
  851. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  852. public ViewerEnvironment GetEnvironment(Vector3 pos)
  853. {
  854. ILandObject lo = m_landChannel.GetLandObject(pos.X, pos.Y);
  855. if (lo != null && lo.LandData != null && lo.LandData.Environment != null)
  856. return lo.LandData.Environment;
  857. return m_scene.RegionEnvironment ?? m_DefaultEnv;
  858. }
  859. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  860. public ViewerEnvironment GetEnvironment(float x, float y)
  861. {
  862. ILandObject lo = m_landChannel.GetLandObject(x, y);
  863. if (lo != null && lo.LandData != null && lo.LandData.Environment != null)
  864. return lo.LandData.Environment;
  865. return m_scene.RegionEnvironment ?? m_DefaultEnv;
  866. }
  867. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  868. public ViewerEnvironment GetRegionEnvironment()
  869. {
  870. return m_scene.RegionEnvironment ?? m_DefaultEnv;
  871. }
  872. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  873. public float GetDayFractionTime(ViewerEnvironment env)
  874. {
  875. double dayfrac = env.DayLength;
  876. dayfrac = ((Util.UnixTimeSinceEpochSecs() + env.DayOffset) % dayfrac) / dayfrac;
  877. return (float)Utils.Clamp(dayfrac, 0, 1);
  878. }
  879. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  880. public float GetRegionDayFractionTime()
  881. {
  882. return GetDayFractionTime(GetRegionEnvironment());
  883. }
  884. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  885. public int GetDayLength(ViewerEnvironment env)
  886. {
  887. return env.DayLength;
  888. }
  889. [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
  890. public int GetDayOffset(ViewerEnvironment env)
  891. {
  892. return env.DayOffset;
  893. }
  894. public Vector3 GetSunDir(ViewerEnvironment env, float altitude)
  895. {
  896. env.getPositions_sundir(altitude, GetDayFractionTime(env), out Vector3 sundir);
  897. return sundir;
  898. }
  899. public Quaternion GetSunRot(ViewerEnvironment env, float altitude)
  900. {
  901. env.getPositions_sunrot(altitude, GetDayFractionTime(env), out Quaternion sunrot);
  902. return sunrot;
  903. }
  904. public Vector3 GetMoonDir(ViewerEnvironment env, float altitude)
  905. {
  906. env.getPositions_moondir(altitude, GetDayFractionTime(env), out Vector3 moondir);
  907. return moondir;
  908. }
  909. public Quaternion GetMoonRot(ViewerEnvironment env, float altitude)
  910. {
  911. env.getPositions_moonrot(altitude, GetDayFractionTime(env), out Quaternion moonrot);
  912. return moonrot;
  913. }
  914. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  915. public int GetRegionDayLength()
  916. {
  917. return GetRegionEnvironment().DayLength;
  918. }
  919. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  920. public int GetRegionDayOffset()
  921. {
  922. return GetRegionEnvironment().DayOffset;
  923. }
  924. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  925. public Vector3 GetRegionSunDir(float altitude)
  926. {
  927. return GetSunDir(GetRegionEnvironment(), altitude);
  928. }
  929. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  930. public Quaternion GetRegionSunRot(float altitude)
  931. {
  932. return GetSunRot(GetRegionEnvironment(), altitude);
  933. }
  934. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  935. public Vector3 GetRegionMoonDir(float altitude)
  936. {
  937. return GetMoonDir(GetRegionEnvironment(), altitude);
  938. }
  939. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  940. public Quaternion GetRegionMoonRot(float altitude)
  941. {
  942. return GetMoonRot(GetRegionEnvironment(), altitude);
  943. }
  944. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  945. public int GetDayLength(Vector3 pos)
  946. {
  947. return GetEnvironment(pos.X, pos.Y).DayLength;
  948. }
  949. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  950. public int GetDayOffset(Vector3 pos)
  951. {
  952. return GetEnvironment(pos.X, pos.Y).DayOffset;
  953. }
  954. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  955. public Vector3 GetSunDir(Vector3 pos)
  956. {
  957. return GetSunDir(GetEnvironment(pos.X, pos.Y), pos.Z);
  958. }
  959. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  960. public Quaternion GetSunRot(Vector3 pos)
  961. {
  962. return GetSunRot(GetEnvironment(pos.X, pos.Y), pos.Z);
  963. }
  964. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  965. public Vector3 GetMoonDir(Vector3 pos)
  966. {
  967. return GetMoonDir(GetEnvironment(pos.X, pos.Y), pos.Z);
  968. }
  969. [System.Runtime.CompilerServices.MethodImpl(MethodImplOptions.AggressiveInlining)]
  970. public Quaternion GetMoonRot(Vector3 pos)
  971. {
  972. return GetMoonRot(GetEnvironment(pos.X, pos.Y), pos.Z);
  973. }
  974. }
  975. }