1- import asyncio
21import discord
3- import json
42import os
5- import shutil
6- import subprocess
7- import tempfile
8- import tomli
9- import tomli_w
103
11- from core import Plugin , command , utils , Status , Server , PluginInstallationError , MizFile , UnsupportedMizFileException
4+ from core import Plugin , command , utils , Status , Server , PluginInstallationError , UnsupportedMizFileException
125from discord import app_commands
136from services .bot import DCSServerBot
147from typing import Optional
@@ -25,8 +18,9 @@ def __init__(self, bot: DCSServerBot):
2518 )
2619 self .version = utils .get_windows_version (os .path .join (os .path .expandvars (self .installation ), 'realweather.exe' ))
2720
28- async def change_weather_1x (self , server : Server , filename : str , airbase : dict , config : dict ) -> str :
29- config = {
21+ @staticmethod
22+ def generate_config_1_0 (airbase : dict , config : dict ) -> dict :
23+ return {
3024 "metar" : {
3125 "icao" : airbase ['code' ]
3226 },
@@ -41,46 +35,10 @@ async def change_weather_1x(self, server: Server, filename: str, airbase: dict,
4135 }
4236 }
4337 }
44- rw_home = os .path .expandvars (self .installation )
45- tmpfd , tmpname = tempfile .mkstemp ()
46- os .close (tmpfd )
47- with open (os .path .join (rw_home , 'config.json' ), mode = 'r' , encoding = 'utf-8' ) as infile :
48- cfg = json .load (infile )
49- # create proper configuration
50- for name , element in cfg .items ():
51- if name == 'files' :
52- element ['input-mission' ] = filename
53- element ['output-mission' ] = tmpname
54- if name in config :
55- if isinstance (config [name ], dict ):
56- element |= config [name ]
57- else :
58- cfg [name ] = config [name ]
59- cwd = await server .get_missions_dir ()
60- with open (os .path .join (cwd , 'config.json' ), mode = 'w' , encoding = 'utf-8' ) as outfile :
61- json .dump (cfg , outfile , indent = 2 )
6238
63- def run_subprocess ():
64- subprocess .run ([os .path .join (rw_home , 'realweather.exe' )], cwd = cwd , stdout = subprocess .DEVNULL ,
65- stderr = subprocess .DEVNULL )
66- await asyncio .to_thread (run_subprocess )
67-
68- # check if DCS Real Weather corrupted the miz file
69- # (as the original author does not see any reason to do that on his own)
70- await asyncio .to_thread (MizFile , tmpname )
71-
72- # mission is good, take it
73- # make an initial backup, if there is none
74- if '.dcssb' not in filename and not os .path .exists (filename + '.orig' ):
75- shutil .copy2 (filename , filename + '.orig' )
76-
77- new_filename = utils .create_writable_mission (filename )
78- shutil .copy2 (tmpname , new_filename )
79- os .remove (tmpname )
80- return new_filename
81-
82- async def change_weather_2x (self , server : Server , filename : str , airbase : dict , config : dict ) -> str :
83- config = {
39+ @staticmethod
40+ def generate_config_2_0 (airbase : dict , config : dict ) -> dict :
41+ return {
8442 "options" : {
8543 "weather" : {
8644 "enable" : True ,
@@ -109,45 +67,12 @@ async def change_weather_2x(self, server: Server, filename: str, airbase: dict,
10967 }
11068 }
11169 }
112- rw_home = os .path .expandvars (self .installation )
113- tmpfd , tmpname = tempfile .mkstemp ()
114- os .close (tmpfd )
115- with open (os .path .join (rw_home , 'config.toml' ), mode = 'rb' ) as infile :
116- cfg = tomli .load (infile )
117- # create proper configuration
118- for name , element in cfg .items ():
119- if name == 'realweather' :
120- element ['mission' ] = {
121- "input" : filename ,
122- "output" : tmpname
123- }
124- elif name in config :
125- if isinstance (config [name ], dict ):
126- element |= config [name ]
127- else :
128- cfg [name ] = config [name ]
129- cwd = await server .get_missions_dir ()
130- with open (os .path .join (cwd , 'config.toml' ), mode = 'wb' ) as outfile :
131- tomli_w .dump (cfg , outfile )
13270
133- def run_subprocess ():
134- subprocess .run ([os .path .join (rw_home , 'realweather.exe' )], cwd = cwd , stdout = subprocess .DEVNULL ,
135- stderr = subprocess .DEVNULL )
136- await asyncio .to_thread (run_subprocess )
137-
138- # check if DCS Real Weather corrupted the miz file
139- # (as the original author does not see any reason to do that on his own)
140- await asyncio .to_thread (MizFile , tmpname )
141-
142- # mission is good, take it
143- # make an initial backup, if there is none
144- if '.dcssb' not in filename and not os .path .exists (filename + '.orig' ):
145- shutil .copy2 (filename , filename + '.orig' )
146-
147- new_filename = utils .create_writable_mission (filename )
148- shutil .copy2 (tmpname , new_filename )
149- os .remove (tmpname )
150- return new_filename
71+ def generate_config (self , airbase : dict , config : dict ) -> dict :
72+ if self .version .split ('.' )[0 ] == '1' :
73+ return self .generate_config_1_0 (airbase , config )
74+ else :
75+ return self .generate_config_2_0 (airbase , config )
15176
15277 @command (description = 'Modify mission with a preset' )
15378 @app_commands .guild_only ()
@@ -163,50 +88,62 @@ async def realweather(self, interaction: discord.Interaction,
16388 temperature : Optional [bool ] = False , pressure : Optional [bool ] = False ,
16489 time : Optional [bool ] = False ):
16590 ephemeral = utils .get_ephemeral (interaction )
166- if server .status in [Status .PAUSED , Status .RUNNING ]:
91+ airbase = server .current_mission .airbases [idx ]
92+ # noinspection PyUnresolvedReferences
93+ await interaction .response .defer (ephemeral = ephemeral )
94+
95+ msg = await interaction .followup .send ('Changing weather...' , ephemeral = ephemeral )
96+ status = server .status
97+ if not server .locals .get ('mission_rewrite' , True ) and server .status in [Status .RUNNING , Status .PAUSED ]:
16798 question = 'Do you want to restart the server for a weather change?'
16899 if server .is_populated ():
169100 result = await utils .populated_question (interaction , question , ephemeral = ephemeral )
101+ if result :
102+ result = 'yes'
170103 else :
171104 result = await utils .yn_question (interaction , question , ephemeral = ephemeral )
172105 if not result :
173106 return
174- airbase = server .current_mission .airbases [idx ]
175- startup = False
176- msg = await interaction .followup .send ('Changing weather...' , ephemeral = ephemeral )
177- if not server .locals .get ('mission_rewrite' , True ) and server .status != Status .STOPPED :
178- await server .stop ()
179- startup = True
180- filename = await server .get_current_mission_file ()
181- config = {
182- "wind" : wind ,
183- "clouds" : clouds ,
184- "fog" : fog ,
185- "dust" : dust ,
186- "temperature" : temperature ,
187- "pressure" : pressure ,
188- "time" : time
189- }
107+ if result == 'yes' :
108+ await server .stop ()
109+ else :
110+ result = None
190111 try :
191- if self .version .split ('.' )[0 ] == '1' :
192- new_filename = await self .change_weather_1x (server , utils .get_orig_file (filename ), airbase , config )
112+ config = self .generate_config (airbase , {
113+ "wind" : wind ,
114+ "clouds" : clouds ,
115+ "fog" : fog ,
116+ "dust" : dust ,
117+ "temperature" : temperature ,
118+ "pressure" : pressure ,
119+ "time" : time
120+ })
121+ try :
122+ filename = await server .get_current_mission_file ()
123+ new_filename = await server .run_on_extension ('RealWeather' , 'apply_realweather' ,
124+ filename = filename , config = config )
125+ except (FileNotFoundError , UnsupportedMizFileException ):
126+ await msg .edit (content = 'Could not apply weather due to an error in RealWeather.' )
127+ return
128+ message = 'Weather changed.'
129+ if new_filename != filename :
130+ self .log .info (f" => New mission written: { new_filename } " )
131+ await server .replaceMission (int (server .settings ['listStartIndex' ]), new_filename )
193132 else :
194- new_filename = await self .change_weather_2x (server , utils .get_orig_file (filename ), airbase , config )
195- self .log .info (f"Realweather applied on server { server .name } ." )
196- except (FileNotFoundError , UnsupportedMizFileException ):
197- await msg .edit (content = 'Could not apply weather due to an error in RealWeather.' )
198- return
199- message = 'Weather changed.'
200- if new_filename != filename :
201- self .log .info (f" => New mission written: { new_filename } " )
202- await server .replaceMission (int (server .settings ['listStartIndex' ]), new_filename )
203- else :
204- self .log .info (f" => Mission { filename } overwritten." )
205- if startup or server .status not in [Status .STOPPED , Status .SHUTDOWN ]:
206- await server .restart (modify_mission = False )
207- message += '\n Mission reloaded.'
208- await self .bot .audit ("changed weather" , server = server , user = interaction .user )
209- await msg .edit (content = message )
133+ self .log .info (f" => Mission { filename } overwritten." )
134+
135+ if status == server .status and status in [Status .RUNNING , Status .PAUSED ]:
136+ await server .restart (modify_mission = False )
137+ message += '\n Mission reloaded.'
138+ elif result == 'later' :
139+ server .on_empty = {"command" : "load" , "mission_file" : new_filename , "user" : interaction .user }
140+ msg += 'Mission will restart, when server is empty.'
141+
142+ await self .bot .audit ("changed weather" , server = server , user = interaction .user )
143+ await msg .edit (content = message )
144+ finally :
145+ if status in [Status .RUNNING , Status .PAUSED ] and server .status == Status .STOPPED :
146+ await server .start ()
210147
211148
212149async def setup (bot : DCSServerBot ):
0 commit comments