Browse Source

Merge pull request #410 from FungusGames/fungus-script-support

Fungus script support
master
Chris Gregan 9 years ago
parent
commit
9f02563a6b
  1. 41
      Assets/Fungus/Flowchart/Scripts/Block.cs
  2. 4
      Assets/Fungus/Flowchart/Scripts/Commands/Call.cs
  3. 131
      Assets/Fungus/Flowchart/Scripts/Flowchart.cs
  4. 2
      Assets/Fungus/Narrative/Scripts/Commands/Say.cs
  5. 10
      Assets/Fungus/Narrative/Scripts/MenuDialog.cs
  6. 10
      Assets/Fungus/Narrative/Scripts/SayDialog.cs
  7. 414
      Assets/Fungus/Thirdparty/CSVParser/CsvParser.cs
  8. 8
      Assets/Fungus/UI/Scripts/Writer.cs
  9. 38
      Assets/Tests/Scripting/Scripting.unity

41
Assets/Fungus/Flowchart/Scripts/Block.cs

@ -142,26 +142,25 @@ namespace Fungus
return executionCount; return executionCount;
} }
public virtual bool Execute(Action onComplete = null) /// <summary>
/// Execute the Block in a coroutine. Only one running instance of each Block is permitted.
/// </summary>
/// <param name="commandIndex">Index of command to start execution at</param>
/// <param name="onComplete">Delegate function to call when execution completes</param>
public virtual IEnumerator Execute(int commandIndex = 0, Action onComplete = null)
{ {
if (executionState != ExecutionState.Idle) if (executionState != ExecutionState.Idle)
{ {
return false; yield break;
} }
if (!executionInfoSet)
{
SetExecutionInfo();
}
executionCount++; if (!executionInfoSet)
StartCoroutine(ExecuteBlock(onComplete)); {
SetExecutionInfo();
}
return true; executionCount++;
}
protected virtual IEnumerator ExecuteBlock(Action onComplete = null)
{
Flowchart flowchart = GetFlowchart(); Flowchart flowchart = GetFlowchart();
executionState = ExecutionState.Executing; executionState = ExecutionState.Executing;
@ -175,6 +174,8 @@ namespace Fungus
} }
#endif #endif
jumpToCommandIndex = commandIndex;
int i = 0; int i = 0;
while (true) while (true)
{ {
@ -248,10 +249,10 @@ namespace Fungus
executionState = ExecutionState.Idle; executionState = ExecutionState.Idle;
activeCommand = null; activeCommand = null;
if (onComplete != null) if (onComplete != null)
{ {
onComplete(); onComplete();
} }
} }
public virtual void Stop() public virtual void Stop()

4
Assets/Fungus/Flowchart/Scripts/Commands/Call.cs

@ -64,12 +64,12 @@ namespace Fungus
flowchart.selectedBlock = targetBlock; flowchart.selectedBlock = targetBlock;
} }
targetBlock.Execute(onComplete); StartCoroutine(targetBlock.Execute(0, onComplete));
} }
else else
{ {
// Execute block in another Flowchart // Execute block in another Flowchart
targetFlowchart.ExecuteBlock(targetBlock, onComplete); targetFlowchart.ExecuteBlock(targetBlock, 0, onComplete);
} }
} }

131
Assets/Fungus/Flowchart/Scripts/Flowchart.cs

@ -371,61 +371,50 @@ namespace Fungus
} }
/** /**
* Start running another Flowchart by executing a specific child block. * Execute a child block in the Flowchart.
* The block must be in an idle state to be executed.
* You can use this method in a UI event. e.g. to handle a button click. * You can use this method in a UI event. e.g. to handle a button click.
* Returns true if the Block started execution.
*/ */
public virtual void ExecuteBlock(string blockName) public virtual bool ExecuteBlock(string blockName)
{
Block [] blocks = GetComponentsInChildren<Block>();
foreach (Block block in blocks)
{
if (block.blockName == blockName)
{
ExecuteBlock(block);
}
}
}
/**
* Sends a message to this Flowchart only.
* Any block with a matching MessageReceived event handler will start executing.
*/
public virtual void SendFungusMessage(string messageName)
{
MessageReceived[] eventHandlers = GetComponentsInChildren<MessageReceived>();
foreach (MessageReceived eventHandler in eventHandlers)
{
eventHandler.OnSendFungusMessage(messageName);
}
}
/**
* Sends a message to all Flowchart objects in the current scene.
* Any block with a matching MessageReceived event handler will start executing.
*/
public static void BroadcastFungusMessage(string messageName)
{ {
MessageReceived[] eventHandlers = GameObject.FindObjectsOfType<MessageReceived>(); Block block = null;
foreach (MessageReceived eventHandler in eventHandlers) foreach (Block b in GetComponentsInChildren<Block>())
{ {
eventHandler.OnSendFungusMessage(messageName); if (b.blockName == blockName)
} {
block = b;
break;
}
}
if (block == null)
{
Debug.LogError("Block " + blockName + "does not exist");
return false;
}
return ExecuteBlock(block);
} }
/** /**
* Start executing a specific child block in the flowchart. * Execute a child block in the flowchart.
* The block must be in an idle state to be executed. * The block must be in an idle state to be executed.
* This version provides extra options to control how the block is executed.
* Returns true if the Block started execution. * Returns true if the Block started execution.
*/ */
public virtual bool ExecuteBlock(Block block, Action onComplete = null) public virtual bool ExecuteBlock(Block block, int commandIndex = 0, Action onComplete = null)
{ {
// Block must be a component of the Flowchart game object if (block == null)
if (block == null || {
block.gameObject != gameObject) Debug.LogError("Block must not be null");
{ return false;
return false; }
}
if (block.gameObject != gameObject)
{
Debug.LogError("Block must belong to the same gameobject as this Flowchart");
return false;
}
// Can't restart a running block, have to wait until it's idle again // Can't restart a running block, have to wait until it's idle again
if (block.IsExecuting()) if (block.IsExecuting())
@ -433,10 +422,10 @@ namespace Fungus
return false; return false;
} }
// Execute the first command in the command list // Start executing the Block as a new coroutine
block.Execute(onComplete); StartCoroutine(block.Execute(commandIndex, onComplete));
return true; return true;
} }
/** /**
@ -454,6 +443,32 @@ namespace Fungus
} }
} }
/**
* Sends a message to this Flowchart only.
* Any block with a matching MessageReceived event handler will start executing.
*/
public virtual void SendFungusMessage(string messageName)
{
MessageReceived[] eventHandlers = GetComponentsInChildren<MessageReceived>();
foreach (MessageReceived eventHandler in eventHandlers)
{
eventHandler.OnSendFungusMessage(messageName);
}
}
/**
* Sends a message to all Flowchart objects in the current scene.
* Any block with a matching MessageReceived event handler will start executing.
*/
public static void BroadcastFungusMessage(string messageName)
{
MessageReceived[] eventHandlers = GameObject.FindObjectsOfType<MessageReceived>();
foreach (MessageReceived eventHandler in eventHandlers)
{
eventHandler.OnSendFungusMessage(messageName);
}
}
/** /**
* Returns a new variable key that is guaranteed not to clash with any existing variable in the list. * Returns a new variable key that is guaranteed not to clash with any existing variable in the list.
*/ */
@ -590,6 +605,26 @@ namespace Fungus
} }
} }
/**
* Returns the variable with the specified key, or null if the key is not found.
* You will need to cast the returned variable to the correct sub-type.
* You can then access the variable's value using the Value property. e.g.
* BooleanVariable boolVar = flowchart.GetVariable("MyBool") as BooleanVariable;
* boolVar.Value = false;
*/
public Variable GetVariable(string key)
{
foreach (Variable variable in variables)
{
if (variable != null && variable.key == key)
{
return variable;
}
}
return null;
}
/** /**
* Returns the variable with the specified key, or null if the key is not found. * Returns the variable with the specified key, or null if the key is not found.
* You can then access the variable's value using the Value property. e.g. * You can then access the variable's value using the Value property. e.g.

2
Assets/Fungus/Narrative/Scripts/Commands/Say.cs

@ -99,7 +99,7 @@ namespace Fungus
string subbedText = flowchart.SubstituteVariables(displayText); string subbedText = flowchart.SubstituteVariables(displayText);
sayDialog.Say(subbedText, !extendPrevious, waitForClick, fadeWhenDone, voiceOverClip, stopVoiceover, delegate { sayDialog.Say(subbedText, !extendPrevious, waitForClick, fadeWhenDone, stopVoiceover, voiceOverClip, delegate {
Continue(); Continue();
}); });
} }

10
Assets/Fungus/Narrative/Scripts/MenuDialog.cs

@ -13,8 +13,11 @@ namespace Fungus
// Currently active Menu Dialog used to display Menu options // Currently active Menu Dialog used to display Menu options
public static MenuDialog activeMenuDialog; public static MenuDialog activeMenuDialog;
protected Button[] cachedButtons; [NonSerialized]
protected Slider cachedSlider; public Button[] cachedButtons;
[NonSerialized]
public Slider cachedSlider;
public static MenuDialog GetMenuDialog() public static MenuDialog GetMenuDialog()
{ {
@ -139,7 +142,7 @@ namespace Fungus
return addedOption; return addedOption;
} }
protected virtual void HideSayDialog() public virtual void HideSayDialog()
{ {
SayDialog sayDialog = SayDialog.GetSayDialog(); SayDialog sayDialog = SayDialog.GetSayDialog();
if (sayDialog != null) if (sayDialog != null)
@ -150,7 +153,6 @@ namespace Fungus
public virtual void ShowTimer(float duration, Block targetBlock) public virtual void ShowTimer(float duration, Block targetBlock)
{ {
if (cachedSlider != null) if (cachedSlider != null)
{ {
cachedSlider.gameObject.SetActive(true); cachedSlider.gameObject.SetActive(true);

10
Assets/Fungus/Narrative/Scripts/SayDialog.cs

@ -126,12 +126,12 @@ namespace Fungus
} }
} }
public virtual void Say(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, AudioClip voiceOverClip, bool stopVoiceover, Action onComplete) public virtual void Say(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, bool stopVoiceover, AudioClip voiceOverClip, Action onComplete)
{ {
StartCoroutine(SayInternal(text, clearPrevious, waitForInput, fadeWhenDone, voiceOverClip, stopVoiceover, onComplete)); StartCoroutine(SayInternal(text, clearPrevious, waitForInput, fadeWhenDone, stopVoiceover, voiceOverClip, onComplete));
} }
protected virtual IEnumerator SayInternal(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, AudioClip voiceOverClip, bool stopVoiceover, Action onComplete) public virtual IEnumerator SayInternal(string text, bool clearPrevious, bool waitForInput, bool fadeWhenDone, bool stopVoiceover, AudioClip voiceOverClip, Action onComplete)
{ {
Writer writer = GetWriter(); Writer writer = GetWriter();
@ -144,6 +144,8 @@ namespace Fungus
} }
} }
gameObject.SetActive(true);
this.fadeWhenDone = fadeWhenDone; this.fadeWhenDone = fadeWhenDone;
// Voice over clip takes precedence over a character sound effect if provided // Voice over clip takes precedence over a character sound effect if provided
@ -158,8 +160,8 @@ namespace Fungus
{ {
soundEffectClip = speakingCharacter.soundEffect; soundEffectClip = speakingCharacter.soundEffect;
} }
writer.Write(text, clearPrevious, waitForInput, stopVoiceover, soundEffectClip, onComplete);
yield return writer.Write(text, clearPrevious, waitForInput, stopVoiceover, soundEffectClip, onComplete);
} }
protected virtual void LateUpdate() protected virtual void LateUpdate()

414
Assets/Fungus/Thirdparty/CSVParser/CsvParser.cs vendored

@ -5,215 +5,215 @@ using System.Text;
namespace Ideafixxxer.CsvParser namespace Ideafixxxer.CsvParser
{ {
public class CsvParser public class CsvParser
{ {
private const char CommaCharacter = ','; private const char CommaCharacter = ',';
private const char QuoteCharacter = '"'; private const char QuoteCharacter = '"';
#region Nested types #region Nested types
private abstract class ParserState private abstract class ParserState
{ {
public static readonly LineStartState LineStartState = new LineStartState(); public static readonly LineStartState LineStartState = new LineStartState();
public static readonly ValueStartState ValueStartState = new ValueStartState(); public static readonly ValueStartState ValueStartState = new ValueStartState();
public static readonly ValueState ValueState = new ValueState(); public static readonly ValueState ValueState = new ValueState();
public static readonly QuotedValueState QuotedValueState = new QuotedValueState(); public static readonly QuotedValueState QuotedValueState = new QuotedValueState();
public static readonly QuoteState QuoteState = new QuoteState(); public static readonly QuoteState QuoteState = new QuoteState();
public abstract ParserState AnyChar(char ch, ParserContext context); public abstract ParserState AnyChar(char ch, ParserContext context);
public abstract ParserState Comma(ParserContext context); public abstract ParserState Comma(ParserContext context);
public abstract ParserState Quote(ParserContext context); public abstract ParserState Quote(ParserContext context);
public abstract ParserState EndOfLine(ParserContext context); public abstract ParserState EndOfLine(ParserContext context);
} }
private class LineStartState : ParserState private class LineStartState : ParserState
{ {
public override ParserState AnyChar(char ch, ParserContext context) public override ParserState AnyChar(char ch, ParserContext context)
{ {
context.AddChar(ch); context.AddChar(ch);
return ValueState; return ValueState;
} }
public override ParserState Comma(ParserContext context) public override ParserState Comma(ParserContext context)
{ {
context.AddValue(); context.AddValue();
return ValueStartState; return ValueStartState;
} }
public override ParserState Quote(ParserContext context) public override ParserState Quote(ParserContext context)
{ {
return QuotedValueState; return QuotedValueState;
} }
public override ParserState EndOfLine(ParserContext context) public override ParserState EndOfLine(ParserContext context)
{ {
context.AddLine(); context.AddLine();
return LineStartState; return LineStartState;
} }
} }
private class ValueStartState : LineStartState private class ValueStartState : LineStartState
{ {
public override ParserState EndOfLine(ParserContext context) public override ParserState EndOfLine(ParserContext context)
{ {
context.AddValue(); context.AddValue();
context.AddLine(); context.AddLine();
return LineStartState; return LineStartState;
} }
} }
private class ValueState : ParserState private class ValueState : ParserState
{ {
public override ParserState AnyChar(char ch, ParserContext context) public override ParserState AnyChar(char ch, ParserContext context)
{ {
context.AddChar(ch); context.AddChar(ch);
return ValueState; return ValueState;
} }
public override ParserState Comma(ParserContext context) public override ParserState Comma(ParserContext context)
{ {
context.AddValue(); context.AddValue();
return ValueStartState; return ValueStartState;
} }
public override ParserState Quote(ParserContext context) public override ParserState Quote(ParserContext context)
{ {
context.AddChar(QuoteCharacter); context.AddChar(QuoteCharacter);
return ValueState; return ValueState;
} }
public override ParserState EndOfLine(ParserContext context) public override ParserState EndOfLine(ParserContext context)
{ {
context.AddValue(); context.AddValue();
context.AddLine(); context.AddLine();
return LineStartState; return LineStartState;
} }
} }
private class QuotedValueState : ParserState private class QuotedValueState : ParserState
{ {
public override ParserState AnyChar(char ch, ParserContext context) public override ParserState AnyChar(char ch, ParserContext context)
{ {
context.AddChar(ch); context.AddChar(ch);
return QuotedValueState; return QuotedValueState;
} }
public override ParserState Comma(ParserContext context) public override ParserState Comma(ParserContext context)
{ {
context.AddChar(CommaCharacter); context.AddChar(CommaCharacter);
return QuotedValueState; return QuotedValueState;
} }
public override ParserState Quote(ParserContext context) public override ParserState Quote(ParserContext context)
{ {
return QuoteState; return QuoteState;
} }
public override ParserState EndOfLine(ParserContext context) public override ParserState EndOfLine(ParserContext context)
{ {
context.AddChar('\r'); context.AddChar('\r');
context.AddChar('\n'); context.AddChar('\n');
return QuotedValueState; return QuotedValueState;
} }
} }
private class QuoteState : ParserState private class QuoteState : ParserState
{ {
public override ParserState AnyChar(char ch, ParserContext context) public override ParserState AnyChar(char ch, ParserContext context)
{ {
//undefined, ignore " //undefined, ignore "
context.AddChar(ch); context.AddChar(ch);
return QuotedValueState; return QuotedValueState;
} }
public override ParserState Comma(ParserContext context) public override ParserState Comma(ParserContext context)
{ {
context.AddValue(); context.AddValue();
return ValueStartState; return ValueStartState;
} }
public override ParserState Quote(ParserContext context) public override ParserState Quote(ParserContext context)
{ {
context.AddChar(QuoteCharacter); context.AddChar(QuoteCharacter);
return QuotedValueState; return QuotedValueState;
} }
public override ParserState EndOfLine(ParserContext context) public override ParserState EndOfLine(ParserContext context)
{ {
context.AddValue(); context.AddValue();
context.AddLine(); context.AddLine();
return LineStartState; return LineStartState;
} }
} }
private class ParserContext private class ParserContext
{ {
private readonly StringBuilder _currentValue = new StringBuilder(); private readonly StringBuilder _currentValue = new StringBuilder();
private readonly List<string[]> _lines = new List<string[]>(); private readonly List<string[]> _lines = new List<string[]>();
private readonly List<string> _currentLine = new List<string>(); private readonly List<string> _currentLine = new List<string>();
public void AddChar(char ch) public void AddChar(char ch)
{ {
_currentValue.Append(ch); _currentValue.Append(ch);
} }
public void AddValue() public void AddValue()
{ {
_currentLine.Add(_currentValue.ToString()); _currentLine.Add(_currentValue.ToString());
_currentValue.Remove(0, _currentValue.Length); _currentValue.Remove(0, _currentValue.Length);
} }
public void AddLine() public void AddLine()
{ {
_lines.Add(_currentLine.ToArray()); _lines.Add(_currentLine.ToArray());
_currentLine.Clear(); _currentLine.Clear();
} }
public List<string[]> GetAllLines() public List<string[]> GetAllLines()
{ {
if (_currentValue.Length > 0) if (_currentValue.Length > 0)
{ {
AddValue(); AddValue();
} }
if (_currentLine.Count > 0) if (_currentLine.Count > 0)
{ {
AddLine(); AddLine();
} }
return _lines; return _lines;
} }
} }
#endregion #endregion
public string[][] Parse(string csvData) public string[][] Parse(string csvData)
{ {
var context = new ParserContext(); var context = new ParserContext();
// Handle both Windows and Mac line endings // Handle both Windows and Mac line endings
string[] lines = csvData.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); string[] lines = csvData.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
ParserState currentState = ParserState.LineStartState; ParserState currentState = ParserState.LineStartState;
foreach (string next in lines) foreach (string next in lines)
{ {
foreach (char ch in next) foreach (char ch in next)
{ {
switch (ch) switch (ch)
{ {
case CommaCharacter: case CommaCharacter:
currentState = currentState.Comma(context); currentState = currentState.Comma(context);
break; break;
case QuoteCharacter: case QuoteCharacter:
currentState = currentState.Quote(context); currentState = currentState.Quote(context);
break; break;
default: default:
currentState = currentState.AnyChar(ch, context); currentState = currentState.AnyChar(ch, context);
break; break;
} }
} }
currentState = currentState.EndOfLine(context); currentState = currentState.EndOfLine(context);
} }
List<string[]> allLines = context.GetAllLines(); List<string[]> allLines = context.GetAllLines();
return allLines.ToArray(); return allLines.ToArray();
} }
} }
} }

8
Assets/Fungus/UI/Scripts/Writer.cs

@ -317,7 +317,7 @@ namespace Fungus
} }
} }
public virtual void Write(string content, bool clear, bool waitForInput, bool stopAudio, AudioClip audioClip, Action onComplete) public virtual IEnumerator Write(string content, bool clear, bool waitForInput, bool stopAudio, AudioClip audioClip, Action onComplete)
{ {
if (clear) if (clear)
{ {
@ -326,7 +326,7 @@ namespace Fungus
if (!HasTextObject()) if (!HasTextObject())
{ {
return; yield break;
} }
// If this clip is null then WriterAudio will play the default sound effect (if any) // If this clip is null then WriterAudio will play the default sound effect (if any)
@ -341,7 +341,9 @@ namespace Fungus
TextTagParser tagParser = new TextTagParser(); TextTagParser tagParser = new TextTagParser();
List<TextTagParser.Token> tokens = tagParser.Tokenize(tokenText); List<TextTagParser.Token> tokens = tagParser.Tokenize(tokenText);
StartCoroutine(ProcessTokens(tokens, stopAudio, onComplete)); gameObject.SetActive(true);
yield return StartCoroutine(ProcessTokens(tokens, stopAudio, onComplete));
} }
virtual protected bool CheckParamCount(List<string> paramList, int count) virtual protected bool CheckParamCount(List<string> paramList, int count)

38
Assets/Tests/Scripting/Scripting.unity

@ -3005,7 +3005,7 @@ MonoBehaviour:
targetComponentFullname: UnityEngine.Component[] targetComponentFullname: UnityEngine.Component[]
targetComponentText: Flowchart targetComponentText: Flowchart
targetMethod: ExecuteBlock targetMethod: ExecuteBlock
targetMethodText: 'ExecuteBlock (String, Int32, Action): Void' targetMethodText: 'ExecuteBlock (String): Boolean'
methodParameters: methodParameters:
- objValue: - objValue:
typeAssemblyname: System.String, mscorlib, Version=2.0.0.0, Culture=neutral, typeAssemblyname: System.String, mscorlib, Version=2.0.0.0, Culture=neutral,
@ -3024,43 +3024,9 @@ MonoBehaviour:
vector2Value: {x: 0, y: 0} vector2Value: {x: 0, y: 0}
vector3Value: {x: 0, y: 0, z: 0} vector3Value: {x: 0, y: 0, z: 0}
variableKey: variableKey:
- objValue:
typeAssemblyname: System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
typeFullname: System.Int32
intValue: 0
boolValue: 0
floatValue: 0
stringValue:
colorValue: {r: 0, g: 0, b: 0, a: 0}
gameObjectValue: {fileID: 0}
materialValue: {fileID: 0}
objectValue: {fileID: 0}
spriteValue: {fileID: 0}
textureValue: {fileID: 0}
vector2Value: {x: 0, y: 0}
vector3Value: {x: 0, y: 0, z: 0}
variableKey:
- objValue:
typeAssemblyname: System.Action, System.Core, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
typeFullname: System.Action
intValue: 0
boolValue: 0
floatValue: 0
stringValue:
colorValue: {r: 0, g: 0, b: 0, a: 0}
gameObjectValue: {fileID: 0}
materialValue: {fileID: 0}
objectValue: {fileID: 0}
spriteValue: {fileID: 0}
textureValue: {fileID: 0}
vector2Value: {x: 0, y: 0}
vector3Value: {x: 0, y: 0, z: 0}
variableKey:
saveReturnValue: 0 saveReturnValue: 0
returnValueVariableKey: returnValueVariableKey:
returnValueType: System.Void returnValueType: System.Boolean
showInherited: 0 showInherited: 0
callMode: 0 callMode: 0
--- !u!114 &1618689151 --- !u!114 &1618689151

Loading…
Cancel
Save