opensim-development – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | eva | 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 | |||
28 | using System; |
||
29 | using System.Collections.Generic; |
||
30 | using System.Reflection; |
||
31 | using log4net; |
||
32 | using Mono.Addins; |
||
33 | using Nini.Config; |
||
34 | using OpenMetaverse; |
||
35 | using OpenSim.Framework; |
||
36 | using OpenSim.Region.Framework.Interfaces; |
||
37 | using OpenSim.Region.Framework.Scenes; |
||
38 | |||
39 | namespace OpenSim.Region.CoreModules |
||
40 | { |
||
41 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SunModule")] |
||
42 | public class SunModule : ISunModule |
||
43 | { |
||
44 | /// <summary> |
||
45 | /// Note: Sun Hour can be a little deceaving. Although it's based on a 24 hour clock |
||
46 | /// it is not based on ~06:00 == Sun Rise. Rather it is based on 00:00 being sun-rise. |
||
47 | /// </summary> |
||
48 | |||
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
||
50 | |||
51 | // |
||
52 | // Global Constants used to determine where in the sky the sun is |
||
53 | // |
||
54 | private const double m_SeasonalTilt = 0.03 * Math.PI; // A daily shift of approximately 1.7188 degrees |
||
55 | private const double m_AverageTilt = -0.25 * Math.PI; // A 45 degree tilt |
||
56 | private const double m_SunCycle = 2.0D * Math.PI; // A perfect circle measured in radians |
||
57 | private const double m_SeasonalCycle = 2.0D * Math.PI; // Ditto |
||
58 | |||
59 | // |
||
60 | // Per Region Values |
||
61 | // |
||
62 | |||
63 | private bool ready = false; |
||
64 | |||
65 | // This solves a chick before the egg problem |
||
66 | // the local SunFixedHour and SunFixed variables MUST be updated |
||
67 | // at least once with the proper Region Settings before we start |
||
68 | // updating those region settings in GenSunPos() |
||
69 | private bool receivedEstateToolsSunUpdate = false; |
||
70 | |||
71 | // Sun's position information is updated and sent to clients every m_UpdateInterval frames |
||
72 | private int m_UpdateInterval = 0; |
||
73 | |||
74 | // Number of real time hours per virtual day |
||
75 | private double m_DayLengthHours = 0; |
||
76 | |||
77 | // Number of virtual days to a virtual year |
||
78 | private int m_YearLengthDays = 0; |
||
79 | |||
80 | // Ratio of Daylight hours to Night time hours. This is accomplished by shifting the |
||
81 | // sun's orbit above the horizon |
||
82 | private double m_HorizonShift = 0; |
||
83 | |||
84 | // Used to scale current and positional time to adjust length of an hour during day vs night. |
||
85 | private double m_DayTimeSunHourScale; |
||
86 | |||
87 | // private double m_longitude = 0; |
||
88 | // private double m_latitude = 0; |
||
89 | // Configurable defaults Defaults close to SL |
||
90 | private int d_frame_mod = 100; // Every 10 seconds (actually less) |
||
91 | private double d_day_length = 4; // A VW day is 4 RW hours long |
||
92 | private int d_year_length = 60; // There are 60 VW days in a VW year |
||
93 | private double d_day_night = 0.5; // axis offset: Default Hoizon shift to try and closely match the sun model in LL Viewer |
||
94 | private double d_DayTimeSunHourScale = 0.5; // Day/Night hours are equal |
||
95 | |||
96 | |||
97 | // private double d_longitude = -73.53; |
||
98 | // private double d_latitude = 41.29; |
||
99 | |||
100 | // Frame counter |
||
101 | private uint m_frame = 0; |
||
102 | |||
103 | // Cached Scene reference |
||
104 | private Scene m_scene = null; |
||
105 | |||
106 | // Calculated Once in the lifetime of a region |
||
107 | private long TicksToEpoch; // Elapsed time for 1/1/1970 |
||
108 | private uint SecondsPerSunCycle; // Length of a virtual day in RW seconds |
||
109 | private uint SecondsPerYear; // Length of a virtual year in RW seconds |
||
110 | private double SunSpeed; // Rate of passage in radians/second |
||
111 | private double SeasonSpeed; // Rate of change for seasonal effects |
||
112 | // private double HoursToRadians; // Rate of change for seasonal effects |
||
113 | private long TicksUTCOffset = 0; // seconds offset from UTC |
||
114 | // Calculated every update |
||
115 | private float OrbitalPosition; // Orbital placement at a point in time |
||
116 | private double HorizonShift; // Axis offset to skew day and night |
||
117 | private double TotalDistanceTravelled; // Distance since beginning of time (in radians) |
||
118 | private double SeasonalOffset; // Seaonal variation of tilt |
||
119 | private float Magnitude; // Normal tilt |
||
120 | // private double VWTimeRatio; // VW time as a ratio of real time |
||
121 | |||
122 | // Working values |
||
123 | private Vector3 Position = Vector3.Zero; |
||
124 | private Vector3 Velocity = Vector3.Zero; |
||
125 | private Quaternion Tilt = new Quaternion(1.0f, 0.0f, 0.0f, 0.0f); |
||
126 | |||
127 | // Used to fix the sun in the sky so it doesn't move based on current time |
||
128 | private bool m_SunFixed = false; |
||
129 | private float m_SunFixedHour = 0f; |
||
130 | |||
131 | private const int TICKS_PER_SECOND = 10000000; |
||
132 | |||
133 | private ulong m_CurrentTimeOffset = 0; |
||
134 | |||
135 | // Current time in elapsed seconds since Jan 1st 1970 |
||
136 | private ulong CurrentTime |
||
137 | { |
||
138 | get |
||
139 | { |
||
140 | ulong ctime = (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND); |
||
141 | return ctime + m_CurrentTimeOffset; |
||
142 | } |
||
143 | } |
||
144 | |||
145 | // Time in seconds since UTC to use to calculate sun position. |
||
146 | ulong PosTime = 0; |
||
147 | |||
148 | /// <summary> |
||
149 | /// Calculate the sun's orbital position and its velocity. |
||
150 | /// </summary> |
||
151 | private void GenSunPos() |
||
152 | { |
||
153 | // Time in seconds since UTC to use to calculate sun position. |
||
154 | PosTime = CurrentTime; |
||
155 | |||
156 | if (m_SunFixed) |
||
157 | { |
||
158 | // SunFixedHour represents the "hour of day" we would like |
||
159 | // It's represented in 24hr time, with 0 hour being sun-rise |
||
160 | // Because our day length is probably not 24hrs {LL is 6} we need to do a bit of math |
||
161 | |||
162 | // Determine the current "day" from current time, so we can use "today" |
||
163 | // to determine Seasonal Tilt and what'not |
||
164 | |||
165 | // Integer math rounded is on purpose to drop fractional day, determines number |
||
166 | // of virtual days since Epoch |
||
167 | PosTime = CurrentTime / SecondsPerSunCycle; |
||
168 | |||
169 | // Since we want number of seconds since Epoch, multiply back up |
||
170 | PosTime *= SecondsPerSunCycle; |
||
171 | |||
172 | // Then offset by the current Fixed Sun Hour |
||
173 | // Fixed Sun Hour needs to be scaled to reflect the user configured Seconds Per Sun Cycle |
||
174 | PosTime += (ulong)((m_SunFixedHour / 24.0) * (ulong)SecondsPerSunCycle); |
||
175 | } |
||
176 | else |
||
177 | { |
||
178 | if (m_DayTimeSunHourScale != 0.5f) |
||
179 | { |
||
180 | ulong CurDaySeconds = CurrentTime % SecondsPerSunCycle; |
||
181 | double CurDayPercentage = (double)CurDaySeconds / SecondsPerSunCycle; |
||
182 | |||
183 | ulong DayLightSeconds = (ulong)(m_DayTimeSunHourScale * SecondsPerSunCycle); |
||
184 | ulong NightSeconds = SecondsPerSunCycle - DayLightSeconds; |
||
185 | |||
186 | PosTime = CurrentTime / SecondsPerSunCycle; |
||
187 | PosTime *= SecondsPerSunCycle; |
||
188 | |||
189 | if (CurDayPercentage < 0.5) |
||
190 | { |
||
191 | PosTime += (ulong)((CurDayPercentage / .5) * DayLightSeconds); |
||
192 | } |
||
193 | else |
||
194 | { |
||
195 | PosTime += DayLightSeconds; |
||
196 | PosTime += (ulong)(((CurDayPercentage - 0.5) / .5) * NightSeconds); |
||
197 | } |
||
198 | } |
||
199 | } |
||
200 | |||
201 | TotalDistanceTravelled = SunSpeed * PosTime; // distance measured in radians |
||
202 | |||
203 | OrbitalPosition = (float)(TotalDistanceTravelled % m_SunCycle); // position measured in radians |
||
204 | |||
205 | // TotalDistanceTravelled += HoursToRadians-(0.25*Math.PI)*Math.Cos(HoursToRadians)-OrbitalPosition; |
||
206 | // OrbitalPosition = (float) (TotalDistanceTravelled%SunCycle); |
||
207 | |||
208 | SeasonalOffset = SeasonSpeed * PosTime; // Present season determined as total radians travelled around season cycle |
||
209 | Tilt.W = (float)(m_AverageTilt + (m_SeasonalTilt * Math.Sin(SeasonalOffset))); // Calculate seasonal orbital N/S tilt |
||
210 | |||
211 | // m_log.Debug("[SUN] Total distance travelled = "+TotalDistanceTravelled+", present position = "+OrbitalPosition+"."); |
||
212 | // m_log.Debug("[SUN] Total seasonal progress = "+SeasonalOffset+", present tilt = "+Tilt.W+"."); |
||
213 | |||
214 | // The sun rotates about the Z axis |
||
215 | |||
216 | Position.X = (float)Math.Cos(-TotalDistanceTravelled); |
||
217 | Position.Y = (float)Math.Sin(-TotalDistanceTravelled); |
||
218 | Position.Z = 0; |
||
219 | |||
220 | // For interest we rotate it slightly about the X access. |
||
221 | // Celestial tilt is a value that ranges .025 |
||
222 | |||
223 | Position *= Tilt; |
||
224 | |||
225 | // Finally we shift the axis so that more of the |
||
226 | // circle is above the horizon than below. This |
||
227 | // makes the nights shorter than the days. |
||
228 | |||
229 | Position = Vector3.Normalize(Position); |
||
230 | Position.Z = Position.Z + (float)HorizonShift; |
||
231 | Position = Vector3.Normalize(Position); |
||
232 | |||
233 | // m_log.Debug("[SUN] Position("+Position.X+","+Position.Y+","+Position.Z+")"); |
||
234 | |||
235 | Velocity.X = 0; |
||
236 | Velocity.Y = 0; |
||
237 | Velocity.Z = (float)SunSpeed; |
||
238 | |||
239 | // Correct angular velocity to reflect the seasonal rotation |
||
240 | |||
241 | Magnitude = Position.Length(); |
||
242 | if (m_SunFixed) |
||
243 | { |
||
244 | Velocity.X = 0; |
||
245 | Velocity.Y = 0; |
||
246 | Velocity.Z = 0; |
||
247 | } |
||
248 | else |
||
249 | { |
||
250 | Velocity = (Velocity * Tilt) * (1.0f / Magnitude); |
||
251 | } |
||
252 | |||
253 | // TODO: Decouple this, so we can get rid of Linden Hour info |
||
254 | // Update Region with new Sun Vector |
||
255 | // set estate settings for region access to sun position |
||
256 | if (receivedEstateToolsSunUpdate) |
||
257 | { |
||
258 | m_scene.RegionInfo.RegionSettings.SunVector = Position; |
||
259 | } |
||
260 | } |
||
261 | |||
262 | private float GetCurrentTimeAsLindenSunHour() |
||
263 | { |
||
264 | float curtime = m_SunFixed ? m_SunFixedHour : GetCurrentSunHour(); |
||
265 | return (curtime + 6.0f) % 24.0f; |
||
266 | } |
||
267 | |||
268 | #region INonSharedRegion Methods |
||
269 | |||
270 | // Called immediately after the module is loaded for a given region |
||
271 | // i.e. Immediately after instance creation. |
||
272 | public void Initialise(IConfigSource config) |
||
273 | { |
||
274 | m_frame = 0; |
||
275 | |||
276 | // This one puts an entry in the main help screen |
||
277 | // m_scene.AddCommand("Regions", this, "sun", "sun", "Usage: sun [param] [value] - Get or Update Sun module paramater", null); |
||
278 | |||
279 | TimeZone local = TimeZone.CurrentTimeZone; |
||
280 | TicksUTCOffset = local.GetUtcOffset(local.ToLocalTime(DateTime.Now)).Ticks; |
||
281 | m_log.DebugFormat("[SUN]: localtime offset is {0}", TicksUTCOffset); |
||
282 | |||
283 | // Align ticks with Second Life |
||
284 | |||
285 | TicksToEpoch = new DateTime(1970, 1, 1).Ticks; |
||
286 | |||
287 | // Just in case they don't have the stanzas |
||
288 | try |
||
289 | { |
||
290 | // Mode: determines how the sun is handled |
||
291 | // m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude); |
||
292 | // Mode: determines how the sun is handled |
||
293 | // m_longitude = config.Configs["Sun"].GetDouble("longitude", d_longitude); |
||
294 | // Year length in days |
||
295 | m_YearLengthDays = config.Configs["Sun"].GetInt("year_length", d_year_length); |
||
296 | // Day length in decimal hours |
||
297 | m_DayLengthHours = config.Configs["Sun"].GetDouble("day_length", d_day_length); |
||
298 | |||
299 | // Horizon shift, this is used to shift the sun's orbit, this affects the day / night ratio |
||
300 | // must hard code to ~.5 to match sun position in LL based viewers |
||
301 | m_HorizonShift = config.Configs["Sun"].GetDouble("day_night_offset", d_day_night); |
||
302 | |||
303 | // Scales the sun hours 0...12 vs 12...24, essentially makes daylight hours longer/shorter vs nighttime hours |
||
304 | m_DayTimeSunHourScale = config.Configs["Sun"].GetDouble("day_time_sun_hour_scale", d_DayTimeSunHourScale); |
||
305 | |||
306 | // Update frequency in frames |
||
307 | m_UpdateInterval = config.Configs["Sun"].GetInt("update_interval", d_frame_mod); |
||
308 | } |
||
309 | catch (Exception e) |
||
310 | { |
||
311 | m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message); |
||
312 | m_YearLengthDays = d_year_length; |
||
313 | m_DayLengthHours = d_day_length; |
||
314 | m_HorizonShift = d_day_night; |
||
315 | m_UpdateInterval = d_frame_mod; |
||
316 | m_DayTimeSunHourScale = d_DayTimeSunHourScale; |
||
317 | |||
318 | // m_latitude = d_latitude; |
||
319 | // m_longitude = d_longitude; |
||
320 | } |
||
321 | |||
322 | SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60); |
||
323 | SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays); |
||
324 | |||
325 | // Ration of real-to-virtual time |
||
326 | |||
327 | // VWTimeRatio = 24/m_day_length; |
||
328 | |||
329 | // Speed of rotation needed to complete a cycle in the |
||
330 | // designated period (day and season) |
||
331 | |||
332 | SunSpeed = m_SunCycle/SecondsPerSunCycle; |
||
333 | SeasonSpeed = m_SeasonalCycle/SecondsPerYear; |
||
334 | |||
335 | // Horizon translation |
||
336 | |||
337 | HorizonShift = m_HorizonShift; // Z axis translation |
||
338 | // HoursToRadians = (SunCycle/24)*VWTimeRatio; |
||
339 | |||
340 | m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days"); |
||
341 | m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift); |
||
342 | m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale); |
||
343 | m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames"); |
||
344 | } |
||
345 | |||
346 | public Type ReplaceableInterface |
||
347 | { |
||
348 | get { return null; } |
||
349 | } |
||
350 | |||
351 | public void AddRegion(Scene scene) |
||
352 | { |
||
353 | m_scene = scene; |
||
354 | // Insert our event handling hooks |
||
355 | |||
356 | scene.EventManager.OnFrame += SunUpdate; |
||
357 | scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel; |
||
358 | scene.EventManager.OnEstateToolsSunUpdate += EstateToolsSunUpdate; |
||
359 | scene.EventManager.OnGetCurrentTimeAsLindenSunHour += GetCurrentTimeAsLindenSunHour; |
||
360 | |||
361 | scene.RegisterModuleInterface<ISunModule>(this); |
||
362 | |||
363 | // This one enables the ability to type just "sun" without any parameters |
||
364 | // m_scene.AddCommand("Regions", this, "sun", "", "", HandleSunConsoleCommand); |
||
365 | foreach (KeyValuePair<string, string> kvp in GetParamList()) |
||
366 | { |
||
367 | string sunCommand = string.Format("sun {0}", kvp.Key); |
||
368 | m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand); |
||
369 | } |
||
370 | m_scene.AddCommand("Regions", this, "sun help", "sun help", "list parameters that can be changed", "", HandleSunConsoleCommand); |
||
371 | m_scene.AddCommand("Regions", this, "sun list", "sun list", "list parameters that can be changed", "", HandleSunConsoleCommand); |
||
372 | ready = true; |
||
373 | } |
||
374 | |||
375 | public void RemoveRegion(Scene scene) |
||
376 | { |
||
377 | ready = false; |
||
378 | |||
379 | // Remove our hooks |
||
380 | m_scene.EventManager.OnFrame -= SunUpdate; |
||
381 | m_scene.EventManager.OnAvatarEnteringNewParcel -= AvatarEnteringParcel; |
||
382 | m_scene.EventManager.OnEstateToolsSunUpdate -= EstateToolsSunUpdate; |
||
383 | m_scene.EventManager.OnGetCurrentTimeAsLindenSunHour -= GetCurrentTimeAsLindenSunHour; |
||
384 | } |
||
385 | |||
386 | public void RegionLoaded(Scene scene) |
||
387 | { |
||
388 | } |
||
389 | |||
390 | public void Close() |
||
391 | { |
||
392 | } |
||
393 | |||
394 | public string Name |
||
395 | { |
||
396 | get { return "SunModule"; } |
||
397 | } |
||
398 | |||
399 | #endregion |
||
400 | |||
401 | #region EventManager Events |
||
402 | |||
403 | public void SunToClient(IClientAPI client) |
||
404 | { |
||
405 | if (ready) |
||
406 | { |
||
407 | if (m_SunFixed) |
||
408 | { |
||
409 | // m_log.DebugFormat("[SUN]: Fixed SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", |
||
410 | // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); |
||
411 | client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); |
||
412 | } |
||
413 | else |
||
414 | { |
||
415 | // m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", |
||
416 | // m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString()); |
||
417 | client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition); |
||
418 | } |
||
419 | } |
||
420 | } |
||
421 | |||
422 | public void SunUpdate() |
||
423 | { |
||
424 | if (((m_frame++ % m_UpdateInterval) != 0) || !ready || m_SunFixed || !receivedEstateToolsSunUpdate) |
||
425 | return; |
||
426 | |||
427 | GenSunPos(); // Generate shared values once |
||
428 | |||
429 | SunUpdateToAllClients(); |
||
430 | } |
||
431 | |||
432 | /// <summary> |
||
433 | /// When an avatar enters the region, it's probably a good idea to send them the current sun info |
||
434 | /// </summary> |
||
435 | /// <param name="avatar"></param> |
||
436 | /// <param name="localLandID"></param> |
||
437 | /// <param name="regionID"></param> |
||
438 | private void AvatarEnteringParcel(ScenePresence avatar, int localLandID, UUID regionID) |
||
439 | { |
||
440 | SunToClient(avatar.ControllingClient); |
||
441 | } |
||
442 | |||
443 | public void EstateToolsSunUpdate(ulong regionHandle) |
||
444 | { |
||
445 | if (m_scene.RegionInfo.RegionHandle == regionHandle) |
||
446 | { |
||
447 | float sunFixedHour; |
||
448 | bool fixedSun; |
||
449 | |||
450 | if (m_scene.RegionInfo.RegionSettings.UseEstateSun) |
||
451 | { |
||
452 | sunFixedHour = (float)m_scene.RegionInfo.EstateSettings.SunPosition; |
||
453 | fixedSun = m_scene.RegionInfo.EstateSettings.FixedSun; |
||
454 | } |
||
455 | else |
||
456 | { |
||
457 | sunFixedHour = (float)m_scene.RegionInfo.RegionSettings.SunPosition - 6.0f; |
||
458 | fixedSun = m_scene.RegionInfo.RegionSettings.FixedSun; |
||
459 | } |
||
460 | |||
461 | // Must limit the Sun Hour to 0 ... 24 |
||
462 | while (sunFixedHour > 24.0f) |
||
463 | sunFixedHour -= 24; |
||
464 | |||
465 | while (sunFixedHour < 0) |
||
466 | sunFixedHour += 24; |
||
467 | |||
468 | m_SunFixedHour = sunFixedHour; |
||
469 | m_SunFixed = fixedSun; |
||
470 | |||
471 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Fixed Sun? : {0}", m_SunFixed.ToString()); |
||
472 | // m_log.DebugFormat("[SUN]: Sun Settings Update: Sun Hour : {0}", m_SunFixedHour.ToString()); |
||
473 | |||
474 | receivedEstateToolsSunUpdate = true; |
||
475 | |||
476 | // Generate shared values |
||
477 | GenSunPos(); |
||
478 | |||
479 | // When sun settings are updated, we should update all clients with new settings. |
||
480 | SunUpdateToAllClients(); |
||
481 | |||
482 | // m_log.DebugFormat("[SUN]: PosTime : {0}", PosTime.ToString()); |
||
483 | } |
||
484 | } |
||
485 | |||
486 | #endregion |
||
487 | |||
488 | private void SunUpdateToAllClients() |
||
489 | { |
||
490 | m_scene.ForEachRootClient(delegate(IClientAPI client) |
||
491 | { |
||
492 | SunToClient(client); |
||
493 | }); |
||
494 | } |
||
495 | |||
496 | #region ISunModule Members |
||
497 | |||
498 | public double GetSunParameter(string param) |
||
499 | { |
||
500 | switch (param.ToLower()) |
||
501 | { |
||
502 | case "year_length": |
||
503 | return m_YearLengthDays; |
||
504 | |||
505 | case "day_length": |
||
506 | return m_DayLengthHours; |
||
507 | |||
508 | case "day_night_offset": |
||
509 | return m_HorizonShift; |
||
510 | |||
511 | case "day_time_sun_hour_scale": |
||
512 | return m_DayTimeSunHourScale; |
||
513 | |||
514 | case "update_interval": |
||
515 | return m_UpdateInterval; |
||
516 | |||
517 | case "current_time": |
||
518 | return GetCurrentTimeAsLindenSunHour(); |
||
519 | |||
520 | default: |
||
521 | throw new Exception("Unknown sun parameter."); |
||
522 | } |
||
523 | } |
||
524 | |||
525 | public void SetSunParameter(string param, double value) |
||
526 | { |
||
527 | switch (param) |
||
528 | { |
||
529 | case "year_length": |
||
530 | m_YearLengthDays = (int)value; |
||
531 | SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays); |
||
532 | SeasonSpeed = m_SeasonalCycle/SecondsPerYear; |
||
533 | break; |
||
534 | |||
535 | case "day_length": |
||
536 | m_DayLengthHours = value; |
||
537 | SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60); |
||
538 | SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays); |
||
539 | SunSpeed = m_SunCycle/SecondsPerSunCycle; |
||
540 | SeasonSpeed = m_SeasonalCycle/SecondsPerYear; |
||
541 | break; |
||
542 | |||
543 | case "day_night_offset": |
||
544 | m_HorizonShift = value; |
||
545 | HorizonShift = m_HorizonShift; |
||
546 | break; |
||
547 | |||
548 | case "day_time_sun_hour_scale": |
||
549 | m_DayTimeSunHourScale = value; |
||
550 | break; |
||
551 | |||
552 | case "update_interval": |
||
553 | m_UpdateInterval = (int)value; |
||
554 | break; |
||
555 | |||
556 | case "current_time": |
||
557 | value = (value + 18.0) % 24.0; |
||
558 | // set the current offset so that the effective sun time is the parameter |
||
559 | m_CurrentTimeOffset = 0; // clear this first so we use raw time |
||
560 | m_CurrentTimeOffset = (ulong)(SecondsPerSunCycle * value/ 24.0) - (CurrentTime % SecondsPerSunCycle); |
||
561 | break; |
||
562 | |||
563 | default: |
||
564 | throw new Exception("Unknown sun parameter."); |
||
565 | |||
566 | // Generate shared values |
||
567 | GenSunPos(); |
||
568 | |||
569 | // When sun settings are updated, we should update all clients with new settings. |
||
570 | SunUpdateToAllClients(); |
||
571 | } |
||
572 | } |
||
573 | |||
574 | public float GetCurrentSunHour() |
||
575 | { |
||
576 | float ticksleftover = CurrentTime % SecondsPerSunCycle; |
||
577 | |||
578 | return (24.0f * (ticksleftover / SecondsPerSunCycle)); |
||
579 | } |
||
580 | |||
581 | #endregion |
||
582 | |||
583 | public void HandleSunConsoleCommand(string module, string[] cmdparams) |
||
584 | { |
||
585 | if (m_scene.ConsoleScene() == null) |
||
586 | { |
||
587 | // FIXME: If console region is root then this will be printed by every module. Currently, there is no |
||
588 | // way to prevent this, short of making the entire module shared (which is complete overkill). |
||
589 | // One possibility is to return a bool to signal whether the module has completely handled the command |
||
590 | m_log.InfoFormat("[Sun]: Please change to a specific region in order to set Sun parameters."); |
||
591 | return; |
||
592 | } |
||
593 | |||
594 | if (m_scene.ConsoleScene() != m_scene) |
||
595 | { |
||
596 | m_log.InfoFormat("[Sun]: Console Scene is not my scene."); |
||
597 | return; |
||
598 | } |
||
599 | |||
600 | m_log.InfoFormat("[Sun]: Processing command."); |
||
601 | |||
602 | foreach (string output in ParseCmdParams(cmdparams)) |
||
603 | { |
||
604 | MainConsole.Instance.Output(output); |
||
605 | } |
||
606 | } |
||
607 | |||
608 | private Dictionary<string, string> GetParamList() |
||
609 | { |
||
610 | Dictionary<string, string> Params = new Dictionary<string, string>(); |
||
611 | |||
612 | Params.Add("year_length", "number of days to a year"); |
||
613 | Params.Add("day_length", "number of hours to a day"); |
||
614 | Params.Add("day_night_offset", "induces a horizon shift"); |
||
615 | Params.Add("update_interval", "how often to update the sun's position in frames"); |
||
616 | Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio"); |
||
617 | Params.Add("current_time", "time in seconds of the simulator"); |
||
618 | |||
619 | return Params; |
||
620 | } |
||
621 | |||
622 | private List<string> ParseCmdParams(string[] args) |
||
623 | { |
||
624 | List<string> Output = new List<string>(); |
||
625 | |||
626 | if ((args.Length == 1) || (args[1].ToLower() == "help") || (args[1].ToLower() == "list")) |
||
627 | { |
||
628 | Output.Add("The following parameters can be changed or viewed:"); |
||
629 | foreach (KeyValuePair<string, string> kvp in GetParamList()) |
||
630 | { |
||
631 | Output.Add(String.Format("{0} - {1}",kvp.Key, kvp.Value)); |
||
632 | } |
||
633 | return Output; |
||
634 | } |
||
635 | |||
636 | if (args.Length == 2) |
||
637 | { |
||
638 | try |
||
639 | { |
||
640 | double value = GetSunParameter(args[1]); |
||
641 | Output.Add(String.Format("Parameter {0} is {1}.", args[1], value.ToString())); |
||
642 | } |
||
643 | catch (Exception) |
||
644 | { |
||
645 | Output.Add(String.Format("Unknown parameter {0}.", args[1])); |
||
646 | } |
||
647 | |||
648 | } |
||
649 | else if (args.Length == 3) |
||
650 | { |
||
651 | double value = 0.0; |
||
652 | if (! double.TryParse(args[2], out value)) |
||
653 | { |
||
654 | Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2])); |
||
655 | return Output; |
||
656 | } |
||
657 | |||
658 | SetSunParameter(args[1].ToLower(), value); |
||
659 | Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString())); |
||
660 | } |
||
661 | |||
662 | return Output; |
||
663 | } |
||
664 | } |
||
665 | } |