mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-12-01 16:12:33 +00:00
5b2b149b40
Improved UDBScript to version 5: - Added Plane class - Added BlockMap, BlockEntry, and BlackMapQueryResult classes - Sector class - Added getLabelPositions method to get the position of sector labels (where tags, effects etc. are displayed) - Added support for JavaScript BigInt for UDMF fields. This means it's not necessary anymore to use UniValue to assign integers to new UDMF fields. Instead it can be done like this: sector.fields.my_int_field = 1n; - Added type information file (udbscript.d.ts)
342 lines
No EOL
8.7 KiB
C#
342 lines
No EOL
8.7 KiB
C#
#region ================== Copyright (c) 2022 Boris Iwanski
|
|
|
|
/*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
*
|
|
* it under the terms of the GNU General Public License as published by
|
|
*
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
*
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
|
*
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program.If not, see<http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#endregion
|
|
|
|
#region ================== Namespaces
|
|
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using CodeImp.DoomBuilder.Windows;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.UDBScript
|
|
{
|
|
public partial class ScriptRunnerForm : DelayedForm
|
|
{
|
|
#region ================== Constants
|
|
|
|
/// <summary>
|
|
/// How long a script is allowed to run until the form is made visible.
|
|
/// </summary>
|
|
const int RUNTIME_THRESHOLD = 1000;
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
/// <summary>
|
|
/// Cancellation token for stopping the script.
|
|
/// </summary>
|
|
CancellationTokenSource cancellationtokensource;
|
|
|
|
/// <summary>
|
|
/// If script is currently executed or not.
|
|
/// </summary>
|
|
bool running;
|
|
|
|
/// <summary>
|
|
/// How many milliseconds the script has been running
|
|
/// </summary>
|
|
double runningseconds;
|
|
|
|
/// <summary>
|
|
/// Determines if the form should be automatically closed when the script is finished.
|
|
/// </summary>
|
|
bool autoclose;
|
|
|
|
/// <summary>
|
|
/// Stopwatch used to determine how long the script is already running.
|
|
/// </summary>
|
|
Stopwatch stopwatch;
|
|
|
|
/// <summary>
|
|
/// Timer for making the form visible when the script is running for too long.
|
|
/// </summary>
|
|
System.Windows.Forms.Timer timer;
|
|
|
|
|
|
#endregion
|
|
|
|
#region ================== Methods
|
|
|
|
public ScriptRunnerForm()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes a method, but stops the timer before running the code, and starting the timer after the code ran.
|
|
/// </summary>
|
|
/// <param name="method">Method to invoke</param>
|
|
/// <returns>Return value of the method</returns>
|
|
public object InvokePaused(Delegate method)
|
|
{
|
|
if (InvokeRequired)
|
|
{
|
|
return Invoke(new Func<object>(() => InvokePaused(method)));
|
|
}
|
|
else
|
|
{
|
|
stopwatch.Stop();
|
|
object result = Invoke(method);
|
|
stopwatch.Start();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes a method.
|
|
/// </summary>
|
|
/// <param name="action">Method to invoke</param>
|
|
public void RunAction(Action action)
|
|
{
|
|
if (InvokeRequired)
|
|
Invoke(action);
|
|
else
|
|
action();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the value of the progress bar (in the range from 0 to 100).
|
|
/// </summary>
|
|
/// <param name="value">Value of the progress bar (in the range from 0 to 100)</param>
|
|
private void SetProgress(int value)
|
|
{
|
|
if (progressbar.Style != ProgressBarStyle.Continuous)
|
|
progressbar.Style = ProgressBarStyle.Continuous;
|
|
|
|
// Do some trickery to remove the movement of the progress bar, since it can
|
|
// otherwise screw with how much the progress bar is filled
|
|
if (progressbar.Value != value)
|
|
{
|
|
if (value > progressbar.Maximum)
|
|
value = progressbar.Maximum;
|
|
else if (value < progressbar.Minimum)
|
|
value = progressbar.Minimum;
|
|
|
|
if (progressbar.Maximum == value)
|
|
{
|
|
progressbar.Value = value;
|
|
progressbar.Value = value - 1;
|
|
}
|
|
else
|
|
{
|
|
progressbar.Value = value + 1;
|
|
}
|
|
progressbar.Value = value;
|
|
}
|
|
|
|
// Make the form visible so that the user can actually see the progress bar
|
|
MakeVisible();
|
|
}
|
|
|
|
private void SetProgressStatus(string status)
|
|
{
|
|
lbStatus.Text = status;
|
|
}
|
|
|
|
private void Log(string text)
|
|
{
|
|
// If there's something in the log we don't want to automatically
|
|
// close the form, otherwise the user could not read the contents
|
|
autoclose = false;
|
|
|
|
// Since we don't want to have a useless line at the end of the textbox
|
|
// we add a new line before adding the new text (unless there's no text
|
|
// at all yet, then we don't add a new line
|
|
if (!string.IsNullOrEmpty(tbLog.Text))
|
|
tbLog.AppendText(Environment.NewLine);
|
|
|
|
// Add the new text
|
|
tbLog.AppendText(text);
|
|
|
|
// Make the form visible so that the user can actually see the status bar
|
|
MakeVisible();
|
|
}
|
|
|
|
private async void RunScript(CancellationToken cancellationtoken)
|
|
{
|
|
// Callbacks for setting the progress bar, status text, and adding log lines from the script
|
|
Progress<int> progress = new Progress<int>(SetProgress);
|
|
Progress<string> status = new Progress<string>(SetProgressStatus);
|
|
Progress<string> log = new Progress<string>(Log);
|
|
|
|
running = true;
|
|
|
|
// Prepare running the script
|
|
BuilderPlug.Me.ScriptRunner.PreRun(cancellationtoken, progress, status, log);
|
|
|
|
try
|
|
{
|
|
await Task.Run(() => BuilderPlug.Me.ScriptRunner.Run());
|
|
stopwatch.Stop();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
stopwatch.Stop();
|
|
BuilderPlug.Me.ScriptRunner.HandleExceptions(ex);
|
|
}
|
|
|
|
// Clean up and update after running the script
|
|
BuilderPlug.Me.ScriptRunner.PostRun();
|
|
|
|
running = false;
|
|
|
|
Text = "Script finished";
|
|
lbStatus.Text = "Script finished. Runtime: " + BuilderPlug.Me.ScriptRunner.GetRuntimeString();
|
|
btnAction.Text = "Close";
|
|
btnAction.Enabled = true;
|
|
|
|
SetProgress(0);
|
|
|
|
// Stop the progress bar from animating when the script finished
|
|
if (progressbar.Style == ProgressBarStyle.Marquee)
|
|
progressbar.Style = ProgressBarStyle.Continuous;
|
|
|
|
if (autoclose)
|
|
{
|
|
MakeInvisible();
|
|
//Hide();
|
|
Close();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the form visible.
|
|
/// </summary>
|
|
private void MakeVisible()
|
|
{
|
|
Opacity = 1.0;
|
|
btnAction.Enabled = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the form invisible.
|
|
/// </summary>
|
|
private void MakeInvisible()
|
|
{
|
|
Opacity = 0.0;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Events
|
|
|
|
/// <summary>
|
|
/// Cancels the currently running script, or closes the form if no script is running.
|
|
/// </summary>
|
|
/// <param name="sender">The sender</param>
|
|
/// <param name="e">Event arguments</param>
|
|
private void btnAction_Click(object sender, EventArgs e)
|
|
{
|
|
if (running)
|
|
{
|
|
btnAction.Enabled = false;
|
|
cancellationtokensource.Cancel();
|
|
}
|
|
else
|
|
{
|
|
MakeInvisible();
|
|
//Hide();
|
|
Close();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets everything up for running the script, and then immediately runs the script.
|
|
/// </summary>
|
|
/// <param name="sender">The sender</param>
|
|
/// <param name="e">Event arguments</param>
|
|
private void ScriptRunnerForm_Shown(object sender, EventArgs e)
|
|
{
|
|
cancellationtokensource = new CancellationTokenSource();
|
|
autoclose = true;
|
|
runningseconds = 0;
|
|
|
|
progressbar.Value = 0;
|
|
progressbar.Style = ProgressBarStyle.Marquee;
|
|
|
|
Text = "Running script";
|
|
lbStatus.Text = "Running script...";
|
|
|
|
btnAction.Text = "Cancel";
|
|
// Disable the button because it could otherwise be pressed while the form is invisible.
|
|
// It'll be enabled as soon as the form is made visible
|
|
btnAction.Enabled = false;
|
|
|
|
tbLog.Clear();
|
|
|
|
// The timer ticks ever 100ms. The method it runs checks how long the script is running
|
|
// and makes the form visible if the runtime threshold has been reached
|
|
timer = new System.Windows.Forms.Timer();
|
|
timer.Interval = 100;
|
|
timer.Tick += timerShow_Tick;
|
|
timer.Start();
|
|
|
|
// This stopwatch is used to measure how long the script has been running
|
|
stopwatch = new Stopwatch();
|
|
stopwatch.Start();
|
|
|
|
// Start running the script
|
|
RunScript(cancellationtokensource.Token);
|
|
}
|
|
|
|
protected override void OnLoad(EventArgs e)
|
|
{
|
|
base.OnLoad(e);
|
|
|
|
MakeInvisible();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes the form visible if the runtime threshold has been reached. Shows the elapsed time the script is running.
|
|
/// </summary>
|
|
/// <param name="sender">The sender</param>
|
|
/// <param name="e">Event arguments</param>
|
|
private void timerShow_Tick(object sender, EventArgs e)
|
|
{
|
|
if (Opacity == 0.0 && stopwatch.ElapsedMilliseconds > 1000)
|
|
{
|
|
MakeVisible();
|
|
}
|
|
|
|
double newrunningsecods = Math.Floor(stopwatch.Elapsed.TotalSeconds);
|
|
|
|
if(newrunningsecods > runningseconds)
|
|
{
|
|
runningseconds = newrunningsecods;
|
|
Text = "Running script (" + string.Format("{0:D2}:{1:D2}:{2:D2}", stopwatch.Elapsed.Hours, stopwatch.Elapsed.Minutes, stopwatch.Elapsed.Seconds) + ")";
|
|
}
|
|
}
|
|
|
|
private void ScriptRunnerForm_FormClosed(object sender, FormClosedEventArgs e)
|
|
{
|
|
timer.Stop();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |