UltimateDoomBuilder/UltimateDoomBuilder

UDBScript: An element with the same key already exists in the ExpandoObject. (Accessing fields property of a thing)

Closed this issue · 1 comments

Accessing the fields property of a thing via UDBScript after changing its scale and reloading the map causes an error. Minimal reproducible example here:

  1. Create a UDBScript file with the following:
/// <reference path="../udbscript.d.ts" />
`#version 5`;
`#name Fields exception`;

let selection = UDB.Map.getSelectedOrHighlightedThings();
if (selection.length == 0) UDB.exit();
UDB.showMessage(selection[0].fields);
  1. Create a UDMF map and place a thing in it.
  2. Change the scale of the thing, doesn't matter if it's X or Y scale.
  3. Running the provided script when the thing is selected should display a simple message: System.Dynamic.ExpandoObject
  4. Save and reload the map.
  5. Select the thing again and run the script. This time, an error occurs with the following traces:

JavaScript:

	An element with the same key 'scalex' already exists in the ExpandoObject.

Internal:

	at System.Dynamic.ExpandoObject.TrySetValue(Object indexClass, Int32 index, Object value, String name, Boolean ignoreCase, Boolean add)
	at System.Dynamic.ExpandoObject.TryAddMember(String key, Object value)
	at CodeImp.DoomBuilder.UDBScript.Wrapper.ThingWrapper.AddManagedFields(IDictionary`2 fields) in c:\build\UltimateDoomBuilder\Source\Plugins\UDBScript\API\ThingWrapper.cs:line 536
	at CodeImp.DoomBuilder.UDBScript.Wrapper.MapElementWrapper.get_fields() in c:\build\UltimateDoomBuilder\Source\Plugins\UDBScript\API\MapElementWrapper.cs:line 97
--- End of stack trace from previous location where exception was thrown ---
	at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
	at Jint.Runtime.Interop.Reflection.ReflectionAccessor.GetValue(Engine engine, Object target, String memberName)
	at Jint.Runtime.Descriptors.Specialized.ReflectionDescriptor.DoGet(JsValue thisObj)
	at Jint.Native.Object.ObjectInstance.UnwrapJsValue(PropertyDescriptor desc, JsValue thisObject)
	at Jint.Engine.GetValue(Reference reference, Boolean returnReferenceToPool)
	at Jint.Runtime.Interpreter.Expressions.JintCallExpression.ArgumentListEvaluation(EvaluationContext context)
	at Jint.Runtime.Interpreter.Expressions.JintCallExpression.EvaluateInternal(EvaluationContext context)
	at Jint.Runtime.Interpreter.Expressions.JintExpression.GetValue(EvaluationContext context)
	at Jint.Runtime.Interpreter.Statements.JintExpressionStatement.ExecuteInternal(EvaluationContext context)
	at Jint.Runtime.Interpreter.JintStatementList.Execute(EvaluationContext context)
	at Jint.Engine.ScriptEvaluation(ScriptRecord scriptRecord, ParserOptions parserOptions)
	at Jint.Engine.ExecuteWithConstraints[T](Boolean strict, Func`1 callback)
	at Jint.Engine.Execute(Prepared`1& preparedScript)
	at Jint.Engine.Execute(String code, String source)
	at CodeImp.DoomBuilder.UDBScript.ScriptRunner.Run() in c:\build\UltimateDoomBuilder\Source\Plugins\UDBScript\ScriptRunner.cs:line 414
	at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
	at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
	at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
	at CodeImp.DoomBuilder.UDBScript.ScriptRunnerForm.<RunScript>d__13.MoveNext() in c:\build\UltimateDoomBuilder\Source\Plugins\UDBScript\Windows\ScriptRunnerForm.cs:line 195

I've noticed the following:

  • This seems to apply mostly or only to scalex and scaley fields. Changing any of the other Rendering or Behaviour group values doesn't seem to cause issues.
  • Upon resetting the scale, the fields property is immediately accessible by the script again.

The weirdness continues. Addendum to the last point:

Upon resetting the scale, reading thing.fields.scalex returns the previous value, not 1.0 or null as should be the default. However, writing to it is possible - once. Once it is written into and attempted to be written into again, the same error occurs. Resetting scalex and saving and reloading the map allows the field to be written into multiple times without issue again, until the map is once again saved and reloaded with non-default scale.