Skip to content

Commit

Permalink
good handling of concurrent invalid actions such as both agents grabb…
Browse files Browse the repository at this point in the history
…ing the same object
  • Loading branch information
xavierpuigf committed Jan 3, 2021
1 parent f4ae958 commit 768e3e7
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 46 deletions.
97 changes: 67 additions & 30 deletions Assets/Story Generator/Scripts/ScriptExecution.cs
Original file line number Diff line number Diff line change
Expand Up @@ -813,11 +813,12 @@ public class ScriptExecutor
private IObjectSelectorProvider objectSelectorProvider;
private IGameObjectPropertiesCalculator propCalculator; // Class which can caclulate interaction positions
public List<ScriptPair> script; // Script (filled with subsequent calls of AddAction)
public List<ScriptLine> sLines; // Original Script
private CharacterControl characterControl; // Class which can execute actions (Walk, Grab, etc.)
private List<ICameraControl> cameraControls; // Camera control class
private int gotoExecDepth;
private System.Diagnostics.Stopwatch execStartTime;
private ProcessingReport report;
public ProcessingReport report;
private bool randomizeExecution; // Randomize selection of interaction position
private Recorder recorder;
private int processingTimeLimit = 20 * 1000; // Max search time for admissible solution (in milliseconds)
Expand All @@ -830,11 +831,11 @@ public class ScriptExecutor
public static Hashtable actionsPerLine = new Hashtable();
public static int currRunlineNo = 0; // The line no being executed now
public static int currActionsFinished = 0; // The number of actions finished for currRunLineNo. Moving to the next line if currActionsFinished == actionsPerLine[currRunlineNo];


// *****
private TestDriver caller;

//private IList<ScriptLine> sLines { get; set; }

public ScriptExecutor(IList<GameObject> nameList, RoomSelector roomSelector,
IObjectSelectorProvider objectSelectorProvider, Recorder rcdr, int charIndex, InteractionCache interaction_cache, bool smooth_walk = false)
Expand All @@ -851,6 +852,7 @@ public ScriptExecutor(IList<GameObject> nameList, RoomSelector roomSelector,

propCalculator = new DefaultGameObjectPropertiesCalculator();
script = new List<ScriptPair>();
sLines = new List<ScriptLine>();
recorder = rcdr;
report = new ProcessingReport();
}
Expand Down Expand Up @@ -881,11 +883,13 @@ public void Initialize(CharacterControl chc, List<ICameraControl> cac)
chc.report = report;
cameraControls = cac;
script.Clear();
sLines.Clear();
}

public void ClearScript()
{
script.Clear();
sLines.Clear();
}

private IEnumerable<GameObject> SelectObjects(IObjectSelector selector)
Expand Down Expand Up @@ -3869,7 +3873,7 @@ public ScriptReaderException(string message) :
}
}

class ScriptLine
public class ScriptLine
{
public InteractionType Interaction { get; set; }
public IList<Tuple<string, int>> Parameters { get; set; }
Expand All @@ -3882,19 +3886,71 @@ internal bool CompareParameters(ScriptLine otherSl)
}
}

public class ScriptReader
public class ScriptChecker
{

public static void ReadScript(ScriptExecutor sExecutor, string fileName,
ActionEquivalenceProvider actionEquivProvider, string scriptPath = @"ActionScripts/")
public static List<Tuple<int, Tuple<String, String>>> SolveConflicts(List<ScriptExecutor> sExecutors)
{
IList<ScriptLine> sLines = ReadScriptLines(scriptPath + fileName, actionEquivProvider);

for (int i = 0; i < sLines.Count; i++)
// Solve conflicts when multiple agents are trying to open/grab the same object
Dictionary<int, List<int>> dict_conflicts = new Dictionary<int, List<int>>();
Dictionary<int, InteractionType> action_conflicts = new Dictionary<int, InteractionType> ();
List < Tuple<int, Tuple<String, String>> > conflict_messages = new List<Tuple<int, Tuple<String, String>>>();
for (int i = 0; i < sExecutors.Count(); i++)
{
ScriptLineToAction(sExecutor, i, sLines);
for (int script_index = 0; script_index < sExecutors[i].sLines.Count(); script_index++)
{
if (sExecutors[i].sLines[script_index].Interaction == InteractionType.OPEN ||
sExecutors[i].sLines[script_index].Interaction == InteractionType.CLOSE ||
sExecutors[i].sLines[script_index].Interaction == InteractionType.GRAB){
int index_object = sExecutors[i].sLines[script_index].Parameters[0].Item2;
if (!dict_conflicts.ContainsKey(index_object))
{

dict_conflicts[index_object] = new List<int>();
action_conflicts[index_object] = sExecutors[i].sLines[script_index].Interaction;
}

dict_conflicts[index_object].Add(i);
}
}
}

foreach (KeyValuePair<int, List<int>> kvp in dict_conflicts)
{
if (kvp.Value.Count() > 1)
{
InteractionType conflict_action = action_conflicts[kvp.Key];
int index_char_perform = RandomUtils.Choose(kvp.Value);
for (int i = 0; i < kvp.Value.Count(); i++)
{
int index_char = kvp.Value[i];
if (index_char != index_char_perform)
{
sExecutors[index_char].script.Clear();
sExecutors[index_char].sLines.Clear();
Tuple<String, String> ct = new Tuple<String, String> ("PROCESS UNDEF", $"Agent {index_char_perform} tried to do the same action");
if (conflict_action == InteractionType.OPEN)
ct = new Tuple<String, String>("PROCESS OPEN", $"Agent {index_char_perform} tried to open the object at the same time");

if (conflict_action == InteractionType.CLOSE)
ct = new Tuple<String, String>("PROCESS CLOSE", $"Agent {index_char_perform} tried to open the object at the same time");


if (conflict_action == InteractionType.GRAB)
ct = new Tuple<String, String>("PROCESS GRAB", $"Agent {index_char_perform} tried to grab the object at the same time");


conflict_messages.Add(new Tuple<int, Tuple<string, string>>(index_char, ct));
}
}
}
}
return conflict_messages;
}
}

public class ScriptReader
{

public static void ParseScript(List<ScriptExecutor> sExecutors, IList<string> scriptLines,
ActionEquivalenceProvider actionEquivProvider)
Expand All @@ -3918,7 +3974,7 @@ private static void ParseScriptForChar(ScriptExecutor sExecutor, IList<string> s
if (sl != null)
sLines.Add(sl);
}
//sExecutor.sLines = new List<ScriptLine>(sLines);
sExecutor.sLines = new List<ScriptLine>(sLines);
for (int i = 0; i < sLines.Count; i++)
{
ScriptLineToAction(sExecutor, i, sLines);
Expand Down Expand Up @@ -4048,25 +4104,6 @@ private static void ScriptLineToAction(ScriptExecutor sExecutor, int index, ILis

}

static IList<ScriptLine> ReadScriptLines(string fileName, ActionEquivalenceProvider actionEquivProvider)
{
var result = new List<ScriptLine>();

using (System.IO.StreamReader file = new System.IO.StreamReader(fileName))
{
string line;
int lineNo = 0;

while ((line = file.ReadLine()) != null)
{
var sl = ParseLine(line, lineNo++, actionEquivProvider);

if (sl != null)
result.Add(sl);
}
}
return result;
}

private static ScriptLine ParseLine(string line, int lineNo, ActionEquivalenceProvider actionEquivProvider)
{
Expand Down
66 changes: 50 additions & 16 deletions Assets/Story Generator/Scripts/TestDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -611,25 +611,35 @@ IEnumerator ProcessNetworkRequest()
parseSuccess = false;
response.success = false;
response.message = $"Error parsing script: {e.Message}";
continue;
}

//s_SimulatePerfMarker.Begin();


if (parseSuccess)
{
List<Tuple<int, Tuple<String, String>>> error_messages = new List<Tuple<int, Tuple<String, String>>>();
if (!config.find_solution)
error_messages = ScriptChecker.SolveConflicts(sExecutors);
for (int i = 0; i < numCharacters; i++)
{
StartCoroutine(sExecutors[i].ProcessAndExecute(config.recording, this));
//yield return sExecutors[i].ProcessAndExecute(true, this);
}

while (finishedChars != numCharacters)
{
yield return new WaitForSeconds(0.01f);
}
}

// Add back errors from concurrent actions

for (int error_index = 0; error_index < error_messages.Count; error_index++)
{
sExecutors[error_messages[error_index].Item1].report.AddItem(error_messages[error_index].Item2.Item1, error_messages[error_index].Item2.Item2);
}

}

//s_SimulatePerfMarker.End();

Expand All @@ -641,49 +651,65 @@ IEnumerator ProcessNetworkRequest()
response.message = "";
response.success = false;
bool[] success_per_agent = new bool[numCharacters];


bool agent_failed_action = false;
Dictionary <int, Dictionary <String, String> > messages = new Dictionary<int, Dictionary<String, String> > ();
if (!config.recording)
{
for (int i = 0; i < numCharacters; i++)
{
Dictionary<String, String> current_message = new Dictionary<String, String>();

if (!sExecutors[i].Success)
{
//response.success = false;
response.message += $"ScriptExcutor {i}: ";
response.message += sExecutors[i].CreateReportString();
response.message += "\n";
String message = "";
message += $"ScriptExcutor {i}: ";
message += sExecutors[i].CreateReportString();
message += "\n";
current_message["message"] = message;

success_per_agent[i] = false;
agent_failed_action = true;
}
else
{
current_message["message"] = "Success";
response.success = true;
success_per_agent[i] = true;
}
messages[i] = current_message;
}
}
else
{
for (int i = 0; i < numCharacters; i++)
{
Dictionary<String, String> current_message = new Dictionary<String, String>();
Recorder rec = recorders[i];
if (!sExecutors[i].Success)
{
//response.success = false;
response.message += $"ScriptExcutor {i}: ";
response.message += sExecutors[i].CreateReportString();
response.message += "\n";
String message = "";
message += $"ScriptExcutor {i}: ";
message += sExecutors[i].CreateReportString();
message += "\n";
current_message["message"] = message;
}
else if (rec.Error != null)
{
//Directory.Delete(rec.OutputDirectory);
//response.success = false;
response.message += $"Recorder {i}: ";
response.message += recorder.Error.Message;
response.message += "\n";
agent_failed_action = true;
String message = "";
message += $"Recorder {i}: ";
message += recorder.Error.Message;
message += "\n";
rec.Recording = false;
current_message["message"] = message;
}
else
{
current_message["message"] = "Success";
response.success = true;
success_per_agent[i] = true;
rec.MarkTermination();
Expand All @@ -696,15 +722,23 @@ IEnumerator ProcessNetworkRequest()
});
rec.CreateTextualGTs();
}


messages[i] = current_message;
}
}


// If any of the agent fails an action, report failure
if (parseSuccess)
{
response.message = JsonConvert.SerializeObject(messages);
}
if (agent_failed_action)
response.success = false;
ISet<GameObject> changedObjs = new HashSet<GameObject>();
IDictionary<Tuple<string, int>, ScriptObjectData> script_object_changed = new Dictionary<Tuple<string, int>, ScriptObjectData>();
List<ActionObjectData> last_action = new List<ActionObjectData>();
bool single_action = true;

for (int char_index = 0; char_index < numCharacters; char_index++)
{
if (success_per_agent[char_index])
Expand Down

0 comments on commit 768e3e7

Please sign in to comment.