Systems/Scripts/Script.cs
using Sandbox;
using Sandbox.Diagnostics;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using VNScript;
// ReSharper disable ClassWithVirtualMembersNeverInherited.Global
// ReSharper disable VirtualMemberCallInConstructor
namespace VNBase.Assets;
/// <summary>
/// Defines a VNBase script asset.
/// </summary>
public class Script : IAsset
{
// ReSharper disable once MemberCanBeProtected.Global
public virtual string Code { get; set; } = string.Empty;
/// <summary>
/// The script to run after this one has finished.
/// </summary>
public virtual Script? NextScript { get; set; }
/// <summary>
/// If this script is initialized from a file,
/// this is the path to that script file.
/// </summary>
[FilePath]
public string Path { get; set; } = string.Empty;
/// <summary>
/// If this script was initialized from a file or not.
/// </summary>
public bool FromFile => !string.IsNullOrEmpty( Path );
/// <summary>
/// Called when a choice is selected from this script.
/// </summary>
[Hide]
public Action<VNScript.Script.Choice>? OnChoiceSelected { get; set; }
[Hide]
private IEnvironment? _environment;
[Hide]
private VNScript.Script? _parsedScript;
[JsonIgnore, Hide]
private static readonly Logger Log = new( "Script" );
/// <summary>
/// Create a new empty script.
/// </summary>
public Script() { }
/// <summary>
/// Create a new script from a file.
/// </summary>
/// <param name="path">The path to the script file.</param>
public Script( string path )
{
if ( !FileSystem.Mounted.FileExists( path ) )
{
Log.Error( $"Unable to load script! Script file couldn't be found by path: {path}" );
return;
}
Code = FileSystem.Mounted.ReadAllText( path );
Path = path;
}
/// <summary>
/// Create a new script from a file.
/// </summary>
/// <param name="path">The path to the script file.</param>
/// <param name="nextScript">The next script to run after this one has finished.</param>
public Script( string path, Script nextScript ) : this( path )
{
NextScript = nextScript;
}
/// <summary>
/// Called when the script is loaded by the <see cref="ScriptPlayer"/>
/// </summary>
public virtual void OnLoad() { }
/// <summary>
/// Called after the script has finished executing by the <see cref="ScriptPlayer"/>
/// </summary>
public virtual void OnUnload() { }
/// <summary>
/// Get this scripts local environment map.
/// </summary>
public virtual IEnvironment GetEnvironment()
{
if ( _environment is not null )
{
return _environment;
}
// Create new environment
_environment = new EnvironmentMap( new Dictionary<string, Value>() );
// If we have a parsed script, load its variables into the environment
if ( _parsedScript is not null )
{
foreach ( var kvp in _parsedScript.Variables )
{
// Extract variable name from the key
var varName = kvp.Key switch
{
Value.VariableReferenceValue varRef => varRef.Name, Value.StringValue str => str.Text, _ => null
};
if ( string.IsNullOrEmpty( varName ) )
{
continue;
}
// Evaluate the value in the current environment and store it
var evaluatedValue = kvp.Value.Evaluate( _environment );
_environment.SetVariable( varName, evaluatedValue );
}
}
return _environment;
}
internal virtual VNScript.Script Parse()
{
var codeBlocks = SParen.ParseText( Code ).ToList();
_parsedScript = VNScript.Script.ParseScript( codeBlocks );
// Reset environment so it gets rebuilt
_environment = null;
return _parsedScript;
}
}