Skip to content

Commit 092a6c7

Browse files
authored
Merge pull request #767 from twpol/feature/sunrise-sunset
Refine sunrise and sunset
2 parents c9abcd2 + 82c5f1c commit 092a6c7

File tree

5 files changed

+359
-255
lines changed

5 files changed

+359
-255
lines changed
Lines changed: 172 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,217 @@
1-
// COPYRIGHT 2009, 2010 by the Open Rails project.
2-
//
1+
// COPYRIGHT 2009 - 2023 by the Open Rails project.
2+
//
33
// This file is part of Open Rails.
4-
//
4+
//
55
// Open Rails is free software: you can redistribute it and/or modify
66
// it under the terms of the GNU General Public License as published by
77
// the Free Software Foundation, either version 3 of the License, or
88
// (at your option) any later version.
9-
//
9+
//
1010
// Open Rails is distributed in the hope that it will be useful,
1111
// but WITHOUT ANY WARRANTY; without even the implied warranty of
1212
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1313
// GNU General Public License for more details.
14-
//
14+
//
1515
// You should have received a copy of the GNU General Public License
1616
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
1717

1818
using System.Collections.Generic;
19-
using System.Diagnostics;
19+
using System.Linq;
2020
using Orts.Parsers.Msts;
2121

22-
/*
23-
stf.ParseBlock(new STFReader.TokenProcessor[] {
24-
new STFReader.TokenProcessor("", ()=>{ }),
25-
});
26-
*/
27-
2822
namespace Orts.Formats.Msts
2923
{
3024
public class EnvironmentFile
3125
{
32-
public float WaterWaveHeight;
33-
public float WaterWaveSpeed;
34-
public float WorldSkynLayers;
35-
public List<ENVFileWaterLayer> WaterLayers;
36-
public List<ENVFileSkyLayer> SkyLayers;
37-
public List<ENVFileSkySatellite> SkySatellite;
26+
public List<WaterLayer> WaterLayers;
27+
public List<SkyLayer> SkyLayers;
28+
public List<SkySatellite> SkySatellites;
3829

3930
public EnvironmentFile(string filePath)
4031
{
4132
using (STFReader stf = new STFReader(filePath, false))
42-
stf.ParseFile(new STFReader.TokenProcessor[] {
43-
new STFReader.TokenProcessor("world", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
44-
new STFReader.TokenProcessor("world_water", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
45-
new STFReader.TokenProcessor("world_water_wave_height", ()=>{ WaterWaveHeight = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }),
46-
new STFReader.TokenProcessor("world_water_wave_speed", ()=>{ WaterWaveSpeed = stf.ReadFloatBlock(STFReader.UNITS.Speed, null); }),
47-
new STFReader.TokenProcessor("world_water_layers", ()=>{ ParseWaterLayers(stf); }),
48-
});}),
49-
});}),
50-
});
51-
52-
using (STFReader stf = new STFReader(filePath, false))
53-
stf.ParseFile(new STFReader.TokenProcessor[] {
54-
new STFReader.TokenProcessor("world", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
55-
new STFReader.TokenProcessor("world_sky", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
56-
new STFReader.TokenProcessor("worldskynlayers_behind_satellites", ()=>{ WorldSkynLayers = stf.ReadFloatBlock( STFReader.UNITS.Any, null ); }),
57-
new STFReader.TokenProcessor("world_sky_layers", ()=>{ ParseSkyLayers(stf); }),
58-
new STFReader.TokenProcessor("world_sky_satellites", ()=>{ ParseWorldSkySatellites(stf); }),
59-
});}),
60-
});}),
61-
});
62-
}
63-
private void ParseWaterLayers(STFReader stf)
64-
{
65-
stf.MustMatch("(");
66-
int texturelayers = stf.ReadInt(null);
67-
WaterLayers = new List<ENVFileWaterLayer>(texturelayers);
68-
stf.ParseBlock(new STFReader.TokenProcessor[] {
69-
new STFReader.TokenProcessor("world_water_layer", ()=>{ if(texturelayers-- > 0) WaterLayers.Add(new ENVFileWaterLayer(stf)); })
70-
});
71-
}
72-
private void ParseSkyLayers(STFReader stf)
73-
{
74-
stf.MustMatch("(");
75-
int skylayers = stf.ReadInt(null);
76-
SkyLayers = new List<ENVFileSkyLayer>(skylayers);
77-
78-
stf.ParseBlock(new STFReader.TokenProcessor[]
7933
{
80-
new STFReader.TokenProcessor("world_sky_layer", ()=>{ if(skylayers-- > 0) SkyLayers.Add(new ENVFileSkyLayer(stf)); })});
81-
34+
stf.ParseFile(new[]
35+
{
36+
new STFReader.TokenProcessor("world", () => stf.ParseWholeBlock(new[]
37+
{
38+
new STFReader.TokenProcessor("world_water", () => stf.ParseWholeBlock(new[]
39+
{
40+
new STFReader.TokenProcessor("world_water_layers", () => stf.ParseBlockList(ref WaterLayers, "world_water_layer", s => new WaterLayer(s))),
41+
})),
42+
new STFReader.TokenProcessor("world_sky", () => stf.ParseWholeBlock(new[]
43+
{
44+
new STFReader.TokenProcessor("world_sky_layers", () => stf.ParseBlockList(ref SkyLayers, "world_sky_layer", s => new SkyLayer(s))),
45+
new STFReader.TokenProcessor("world_sky_satellites", () => stf.ParseBlockList(ref SkySatellites, "world_sky_satellite", s => new SkySatellite(s))),
46+
})),
47+
})),
48+
});
49+
}
8250
}
83-
private void ParseWorldSkySatellites(STFReader stf)
84-
{
85-
stf.MustMatch("(");
86-
int skysatellite = stf.ReadInt(null);
87-
SkySatellite = new List<ENVFileSkySatellite>(skysatellite);
8851

89-
stf.ParseBlock(new STFReader.TokenProcessor[]
90-
{
91-
new STFReader.TokenProcessor("world_sky_satellite", () => { if (skysatellite-- > 0) SkySatellite.Add(new ENVFileSkySatellite(stf)); })});
92-
}
52+
public SkySatellite Sun => SkySatellites?.FirstOrDefault(s => s.Type == SkySatellite.SkySatelliteType.Sun);
9353

94-
public class ENVFileWaterLayer
54+
public class WaterLayer
9555
{
9656
public float Height;
9757
public string TextureName;
9858

99-
public ENVFileWaterLayer(STFReader stf)
59+
public WaterLayer(STFReader stf)
10060
{
101-
stf.MustMatch("(");
102-
stf.ParseBlock(new STFReader.TokenProcessor[] {
103-
new STFReader.TokenProcessor("world_water_layer_height", ()=>{ Height = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }),
104-
new STFReader.TokenProcessor("world_anim_shader", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
105-
new STFReader.TokenProcessor("world_shader", ()=>{ stf.MustMatch("("); stf.ReadString()/*TextureMode*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
106-
new STFReader.TokenProcessor("terrain_texslots", ()=>{ stf.MustMatch("("); stf.ReadInt(null)/*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
107-
new STFReader.TokenProcessor("terrain_texslot", ()=>{ stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }),
108-
});}),
109-
});}),
110-
});}),
61+
stf.ParseWholeBlock(new[]
62+
{
63+
new STFReader.TokenProcessor("world_water_layer_height", () => { Height = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }),
64+
new STFReader.TokenProcessor("world_anim_shader", () => stf.ParseWholeBlock(new[]
65+
{
66+
new STFReader.TokenProcessor("world_shader", () =>
67+
{
68+
stf.MustMatch("(");
69+
stf.ReadString() /*TextureMode*/;
70+
stf.ParseBlock(new[]
71+
{
72+
new STFReader.TokenProcessor("terrain_texslots", () =>
73+
{
74+
stf.MustMatch("(");
75+
stf.ReadInt(null) /*Count*/;
76+
stf.ParseBlock(new[]
77+
{
78+
new STFReader.TokenProcessor("terrain_texslot", () =>
79+
{
80+
stf.MustMatch("(");
81+
TextureName = stf.ReadString();
82+
stf.SkipRestOfBlock();
83+
}),
84+
});
85+
}),
86+
});
87+
}),
88+
})),
11189
});
11290
}
11391
}
11492

115-
}
116-
117-
public class ENVFileSkyLayer
118-
{
119-
public string Fadein_Begin_Time;
120-
public string Fadein_End_Time;
121-
public string TextureName;
122-
public string TextureMode;
123-
public float TileX;
124-
public float TileY;
125-
126-
127-
public ENVFileSkyLayer(STFReader stf)
93+
public class SkyLayer
12894
{
129-
stf.MustMatch("(");
130-
stf.ParseBlock(new STFReader.TokenProcessor[] {
131-
new STFReader.TokenProcessor("world_sky_layer_fadein", ()=>{ stf.MustMatch("("); Fadein_Begin_Time = stf.ReadString(); Fadein_End_Time = stf.ReadString(); stf.SkipRestOfBlock();}),
132-
new STFReader.TokenProcessor("world_anim_shader", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
133-
new STFReader.TokenProcessor("world_anim_shader_frames", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
134-
new STFReader.TokenProcessor("world_anim_shader_frame", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
135-
new STFReader.TokenProcessor("world_anim_shader_frame_uvtiles", ()=>{ stf.MustMatch("("); TileX = stf.ReadFloat(STFReader.UNITS.Any, 1.0f); TileY = stf.ReadFloat(STFReader.UNITS.Any, 1.0f); stf.ParseBlock(new STFReader.TokenProcessor[] {
136-
});}),
137-
});}),
138-
});}),
139-
new STFReader.TokenProcessor("world_shader", ()=>{ stf.MustMatch("("); TextureMode = stf.ReadString(); stf.ParseBlock(new STFReader.TokenProcessor[] {
140-
new STFReader.TokenProcessor("terrain_texslots", ()=>{ stf.MustMatch("("); stf.ReadInt(null)/*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
141-
new STFReader.TokenProcessor("terrain_texslot", ()=>{ stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }),
142-
});}),
143-
});}),
144-
});}),
145-
});
95+
public string FadeInBeginTime;
96+
public string FadeInEndTime;
97+
public string TextureName;
98+
public string TextureMode;
99+
public float TileX;
100+
public float TileY;
146101

102+
public SkyLayer(STFReader stf)
103+
{
104+
stf.ParseWholeBlock(new[]
105+
{
106+
new STFReader.TokenProcessor("world_sky_layer_fadein", () =>
107+
{
108+
stf.MustMatch("(");
109+
FadeInBeginTime = stf.ReadString();
110+
FadeInEndTime = stf.ReadString();
111+
stf.SkipRestOfBlock();
112+
}),
113+
new STFReader.TokenProcessor("world_anim_shader", () => stf.ParseWholeBlock(new[]
114+
{
115+
new STFReader.TokenProcessor("world_anim_shader_frames", () => stf.ParseWholeBlock(new[]
116+
{
117+
new STFReader.TokenProcessor("world_anim_shader_frame", () => stf.ParseWholeBlock(new[]
118+
{
119+
new STFReader.TokenProcessor("world_anim_shader_frame_uvtiles", () =>
120+
{
121+
stf.MustMatch("(");
122+
TileX = stf.ReadFloat(STFReader.UNITS.Any, 1.0f);
123+
TileY = stf.ReadFloat(STFReader.UNITS.Any, 1.0f);
124+
stf.ParseBlock(new STFReader.TokenProcessor[0]);
125+
}),
126+
})),
127+
})),
128+
new STFReader.TokenProcessor("world_shader", () =>
129+
{
130+
stf.MustMatch("(");
131+
TextureMode = stf.ReadString();
132+
stf.ParseBlock(new[]
133+
{
134+
new STFReader.TokenProcessor("terrain_texslots", () =>
135+
{
136+
stf.MustMatch("(");
137+
stf.ReadInt(null) /*Count*/;
138+
stf.ParseBlock(new[]
139+
{
140+
new STFReader.TokenProcessor("terrain_texslot", () =>
141+
{
142+
stf.MustMatch("(");
143+
TextureName = stf.ReadString();
144+
stf.SkipRestOfBlock();
145+
}),
146+
});
147+
}),
148+
});
149+
}),
150+
})),
151+
});
152+
}
147153
}
148-
}
149-
public class ENVFileSkySatellite
150-
{
151-
152-
public string TextureName;
153-
public string TextureMode;
154154

155-
public ENVFileSkySatellite(STFReader stf)
155+
public class SkySatellite
156156
{
157-
stf.MustMatch("(");
158-
stf.ParseBlock(new STFReader.TokenProcessor[] {
159-
new STFReader.TokenProcessor("world_anim_shader", ()=>{ stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
160-
new STFReader.TokenProcessor("world_shader", ()=>{ stf.MustMatch("("); TextureMode = stf.ReadString(); stf.ParseBlock(new STFReader.TokenProcessor[] {
161-
new STFReader.TokenProcessor("terrain_texslots", ()=>{ stf.MustMatch("("); stf.ReadInt(null)/*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
162-
new STFReader.TokenProcessor("terrain_texslot", ()=>{ stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }),
163-
});}),
164-
});}),
165-
});}),
157+
public int RiseTime;
158+
public int SetTime;
159+
public SkySatelliteType Type;
160+
public string TextureName;
161+
public string TextureMode;
162+
163+
public SkySatellite(STFReader stf)
164+
{
165+
stf.ParseWholeBlock(new[]
166+
{
167+
new STFReader.TokenProcessor("world_sky_satellite_rise_time", () => RiseTime = ParseTime(stf.ReadStringBlock("00:00:00"))),
168+
new STFReader.TokenProcessor("world_sky_satellite_set_time", () => SetTime = ParseTime(stf.ReadStringBlock("00:00:00"))),
169+
new STFReader.TokenProcessor("world_sky_satellite_light", () => Type = (SkySatelliteType)stf.ReadIntBlock((int)SkySatelliteType.Unknown)),
170+
new STFReader.TokenProcessor("world_anim_shader", () => stf.ParseWholeBlock(new[]
171+
{
172+
new STFReader.TokenProcessor("world_shader", () =>
173+
{
174+
stf.MustMatch("(");
175+
TextureMode = stf.ReadString();
176+
stf.ParseBlock(new[]
177+
{
178+
new STFReader.TokenProcessor("terrain_texslots", () =>
179+
{
180+
stf.MustMatch("(");
181+
stf.ReadInt(null) /*Count*/;
182+
stf.ParseBlock(new[]
183+
{
184+
new STFReader.TokenProcessor("terrain_texslot", () =>
185+
{
186+
stf.MustMatch("(");
187+
TextureName = stf.ReadString();
188+
stf.SkipRestOfBlock();
189+
}),
190+
});
191+
}),
192+
});
193+
}),
194+
})),
166195
});
196+
}
197+
198+
public enum SkySatelliteType
199+
{
200+
Unknown = -1,
201+
Moon = 0,
202+
Sun = 1,
203+
}
204+
205+
int ParseTime(string time)
206+
{
207+
var timeParts = time.Split(':');
208+
if (timeParts.Length != 3 || !byte.TryParse(timeParts[0], out var hours) || !byte.TryParse(timeParts[1], out var minutes) || !byte.TryParse(timeParts[2], out var seconds))
209+
{
210+
return 0;
211+
}
212+
213+
return (hours * 3600) + (minutes * 60) + seconds;
214+
}
167215
}
168216
}
169217
}

0 commit comments

Comments
 (0)