Ticket #4698: serialization_vector_js_object_fix.diff

File serialization_vector_js_object_fix.diff, 22.9 KB (added by fatherbushido, 7 years ago)
  • binaries/data/mods/_test.sim/globalscripts/test-global-helper.js

    diff --git a/binaries/data/mods/_test.sim/globalscripts/test-global-helper.js b/binaries/data/mods/_test.sim/globalscripts/test-global-helper.js
    index 884d084927..ace5e854a9 100644
    a b Vector2D.prototype.add = function(v)  
    2121    return this;
    2222};
    2323
     24Vector2D.prototype.lengthSquared = function()
     25{
     26    return this.x*this.x + this.y*this.y
     27};
     28
     29Vector2D.prototype.nop = function()
     30{
     31    return "working";
     32};
     33
    2434function Vector3D(x, y, z)
    2535{
    2636    if (arguments.length == 3)
  • binaries/data/mods/_test.sim/simulation/components/test-serialize.js

    diff --git a/binaries/data/mods/_test.sim/simulation/components/test-serialize.js b/binaries/data/mods/_test.sim/simulation/components/test-serialize.js
    index 9893d6d794..87e458da81 100644
    a b TestScript1_consts.prototype.GetX = function() {  
    8888};
    8989
    9090Engine.RegisterComponentType(IID_Test1, "TestScript1_consts", TestScript1_consts);
     91
     92// -------- //
     93
     94function TestScript1_vector() {}
     95
     96TestScript1_vector.prototype.Init = function() {
     97    this.list = [ {pos: new Vector2D(1, 2)}];
     98};
     99
     100TestScript1_vector.prototype.GetX = function() {
     101    return this.list[0].pos.lengthSquared();
     102};
     103
     104Engine.RegisterComponentType(IID_Test1, "TestScript1_vector", TestScript1_vector);
  • source/network/NetMessageSim.cpp

    diff --git a/source/network/NetMessageSim.cpp b/source/network/NetMessageSim.cpp
    index 28b0dfeb33..6efda7f535 100644
    a b u8* CSimulationMessage::Serialize(u8* pBuffer) const  
    141141    serializer.NumberI32_Unbounded("player", m_Player);
    142142    serializer.NumberU32_Unbounded("turn", m_Turn);
    143143
    144     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     144    serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data), false);
    145145    return serializer.GetBuffer();
    146146}
    147147
    size_t CSimulationMessage::GetSerializedLength() const  
    170170
    171171    // TODO: The cast can probably be removed if and when ScriptVal can take a JS::HandleValue instead of
    172172    // a JS::MutableHandleValue (relies on JSAPI change). Also search for other casts like this one in that case.
    173     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     173    serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data), false);
    174174    return CNetMessage::GetSerializedLength() + serializer.GetLength();
    175175}
    176176
    u8* CGameSetupMessage::Serialize(u8* pBuffer) const  
    200200    // TODO: ought to handle serialization exceptions
    201201    u8* pos = CNetMessage::Serialize(pBuffer);
    202202    CBufferBinarySerializer serializer(m_ScriptInterface, pos);
    203     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     203    serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data), false);
    204204    return serializer.GetBuffer();
    205205}
    206206
    const u8* CGameSetupMessage::Deserialize(const u8* pStart, const u8* pEnd)  
    217217size_t CGameSetupMessage::GetSerializedLength() const
    218218{
    219219    CLengthBinarySerializer serializer(m_ScriptInterface);
    220     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     220    serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data), false);
    221221    return CNetMessage::GetSerializedLength() + serializer.GetLength();
    222222}
    223223
  • source/simulation2/components/CCmpAIManager.cpp

    diff --git a/source/simulation2/components/CCmpAIManager.cpp b/source/simulation2/components/CCmpAIManager.cpp
    index d62ee29205..ddf22bf9b0 100644
    a b public:  
    671671            JS::RootedValue sharedData(cx);
    672672            if (!m_ScriptInterface->CallFunction(m_SharedAIObj, "Serialize", &sharedData))
    673673                LOGERROR("AI shared script Serialize call failed");
    674             serializer.ScriptVal("sharedData", &sharedData);
     674            serializer.ScriptVal("sharedData", &sharedData, false);
    675675        }
    676676        for (size_t i = 0; i < m_Players.size(); ++i)
    677677        {
    public:  
    684684            {
    685685                JS::RootedValue val(cx);
    686686                m_ScriptInterface->ReadStructuredClone(m_Players[i]->m_Commands[j], &val);
    687                 serializer.ScriptVal("command", &val);
     687                serializer.ScriptVal("command", &val, false);
    688688            }
    689689
    690690            bool hasCustomSerialize = m_ScriptInterface->HasProperty(m_Players[i]->m_Obj, "Serialize");
    public:  
    693693                JS::RootedValue scriptData(cx);
    694694                if (!m_ScriptInterface->CallFunction(m_Players[i]->m_Obj, "Serialize", &scriptData))
    695695                    LOGERROR("AI script Serialize call failed");
    696                 serializer.ScriptVal("data", &scriptData);
     696                serializer.ScriptVal("data", &scriptData, false);
    697697            }
    698698            else
    699699            {
    700                 serializer.ScriptVal("data", &m_Players[i]->m_Obj);
     700                serializer.ScriptVal("data", &m_Players[i]->m_Obj, false);
    701701            }
    702702        }
    703703
  • source/simulation2/components/CCmpCommandQueue.cpp

    diff --git a/source/simulation2/components/CCmpCommandQueue.cpp b/source/simulation2/components/CCmpCommandQueue.cpp
    index 90d4d3e5eb..fdf8ee4a2a 100644
    a b public:  
    5858        for (size_t i = 0; i < m_LocalQueue.size(); ++i)
    5959        {
    6060            serialize.NumberI32_Unbounded("player", m_LocalQueue[i].player);
    61             serialize.ScriptVal("data", &m_LocalQueue[i].data);
     61            serialize.ScriptVal("data", &m_LocalQueue[i].data, false);
    6262        }
    6363    }
    6464
  • source/simulation2/scripting/ScriptComponent.cpp

    diff --git a/source/simulation2/scripting/ScriptComponent.cpp b/source/simulation2/scripting/ScriptComponent.cpp
    index 4e96c7bdf5..39580e9994 100644
    a b void CComponentTypeScript::Serialize(ISerializer& serialize)  
    8282        JS::RootedValue val(cx);
    8383        if (!m_ScriptInterface.CallFunction(m_Instance, "Serialize", &val))
    8484            LOGERROR("Script Serialize call failed");
    85         serialize.ScriptVal("object", &val);
     85        serialize.ScriptVal("object", &val, false); // TODO: make this new parameter optional
     86        // TODO: or (maybe even better) provide another serialize function for it
     87        // then we just need to make both call the right binaryserializer one in the end
    8688    }
    8789    else
    8890    {
    89         serialize.ScriptVal("object", &m_Instance);
     91        // We want to ignore the prototype of the top level object for components.
     92        serialize.ScriptVal("object", &m_Instance, true);
    9093    }
    9194}
    9295
  • source/simulation2/serialization/BinarySerializer.cpp

    diff --git a/source/simulation2/serialization/BinarySerializer.cpp b/source/simulation2/serialization/BinarySerializer.cpp
    index 2f1e737132..5f959e687b 100644
    a b  
    2626#include "scriptinterface/ScriptExtraHeaders.h"
    2727#include "SerializedScriptTypes.h"
    2828
     29#include "ps/Filesystem.h" // TODO part fo the gvfs hack
     30
    2931static u8 GetArrayType(js::Scalar::Type arrayType)
    3032{
    3133    switch(arrayType)
    CBinarySerializerScriptImpl::CBinarySerializerScriptImpl(const ScriptInterface&  
    6062{
    6163    m_ScriptBackrefs.init();
    6264    m_SerializablePrototypes->init();
     65
     66    // TODO fix/remove the set functions for these prototypes, and let them just add things
     67    // TODO call into the scriptinterface to let that add it
     68    // TODO do the same thing for the deserializer
     69    if (g_VFS) // TODO hack for tests
     70    {
     71        m_SerializablePrototypes->add(m_ScriptInterface.GetContext(), &m_ScriptInterface.GetCachedValue(ScriptInterface::CACHE_VECTOR2DPROTO).toObject(), L"Vector2D");
     72        m_SerializablePrototypes->add(m_ScriptInterface.GetContext(), &m_ScriptInterface.GetCachedValue(ScriptInterface::CACHE_VECTOR3DPROTO).toObject(), L"Vector3D");
     73    }
    6374}
    6475
    65 void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)
     76void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val, bool ignoreCustomPrototype)
    6677{
    6778    JSContext* cx = m_ScriptInterface.GetContext();
    6879    JSAutoRequest rq(cx);
    void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)  
    159170                if (!proto)
    160171                    throw PSERROR_Serialize_ScriptError("JS_GetPrototype failed");
    161172
    162                 if (m_SerializablePrototypes->empty() || !IsSerializablePrototype(proto))
     173                if (IdentifyStandardPrototype(proto) == JSProto_Object || ignoreCustomPrototype)
    163174                {
     175debug_printf("default proto\n");
     176
    164177                    // Standard Object prototype
    165178                    m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_OBJECT);
     179                }
     180                else if (/*IdentifyStandardPrototype(proto) == JSProto_Null && */!IsSerializablePrototype(proto))
     181                {
     182                    // TODO we could print the current value
    166183
    167                     // TODO: maybe we should throw an error for unrecognized non-Object prototypes?
    168                     //  (requires fixing AI serialization first and excluding component scripts)
     184                    // TODO: Can we get some more data about what the prototype is? (apart from null that is)
     185                    throw PSERROR_Serialize_ScriptError("Unhandled custom prototype");
    169186                }
    170187                else
    171188                {
    void CBinarySerializerScriptImpl::HandleScriptVal(JS::HandleValue val)  
    174191
    175192                    const std::wstring prototypeName = GetPrototypeName(proto);
    176193                    m_Serializer.String("proto name", prototypeName, 0, 256);
     194debug_printf("other %ls\n", prototypeName.c_str());
    177195
    178196                    // Does it have custom Serialize function?
    179197                    // if so, we serialize the data it returns, rather than the object's properties directly
  • source/simulation2/serialization/BinarySerializer.h

    diff --git a/source/simulation2/serialization/BinarySerializer.h b/source/simulation2/serialization/BinarySerializer.h
    index 235b69a278..11a18c3c06 100644
    a b public:  
    8686    CBinarySerializerScriptImpl(const ScriptInterface& scriptInterface, ISerializer& serializer);
    8787
    8888    void ScriptString(const char* name, JS::HandleString string);
    89     void HandleScriptVal(JS::HandleValue val);
     89    void HandleScriptVal(JS::HandleValue val, bool ignoreCustomObjectPrototype = true);
    9090    void SetSerializablePrototypes(shared_ptr<ObjectIdCache<std::wstring> > prototypes);
    9191private:
    9292    const ScriptInterface& m_ScriptInterface;
    protected:  
    206206        m_Impl.Put(name, (u8*)value.data(), value.length());
    207207    }
    208208
    209     virtual void PutScriptVal(const char* UNUSED(name), JS::MutableHandleValue value)
     209    virtual void PutScriptVal(const char* UNUSED(name), JS::MutableHandleValue value, bool isComponentObject)
    210210    {
    211         m_ScriptImpl->HandleScriptVal(value);
     211        m_ScriptImpl->HandleScriptVal(value, isComponentObject);
    212212    }
    213213
    214214    virtual void PutRaw(const char* name, const u8* data, size_t len)
  • source/simulation2/serialization/DebugSerializer.cpp

    diff --git a/source/simulation2/serialization/DebugSerializer.cpp b/source/simulation2/serialization/DebugSerializer.cpp
    index 7f1f49f1ec..ffff9bc492 100644
    a b void CDebugSerializer::PutString(const char* name, const std::string& value)  
    147147    m_Stream << INDENT << name << ": " << "\"" << escaped << "\"\n";
    148148}
    149149
    150 void CDebugSerializer::PutScriptVal(const char* name, JS::MutableHandleValue value)
     150void CDebugSerializer::PutScriptVal(const char* name, JS::MutableHandleValue value, bool)
    151151{
    152152    std::string source = m_ScriptInterface.ToString(value, true);
    153153
  • source/simulation2/serialization/DebugSerializer.h

    diff --git a/source/simulation2/serialization/DebugSerializer.h b/source/simulation2/serialization/DebugSerializer.h
    index 7ad4871540..e30e6ba20d 100644
    a b protected:  
    5454    virtual void PutNumber(const char* name, fixed value);
    5555    virtual void PutBool(const char* name, bool value);
    5656    virtual void PutString(const char* name, const std::string& value);
    57     virtual void PutScriptVal(const char* name, JS::MutableHandleValue value);
     57    virtual void PutScriptVal(const char* name, JS::MutableHandleValue value, bool);
    5858    virtual void PutRaw(const char* name, const u8* data, size_t len);
    5959
    6060private:
  • source/simulation2/serialization/ISerializer.cpp

    diff --git a/source/simulation2/serialization/ISerializer.cpp b/source/simulation2/serialization/ISerializer.cpp
    index 92b9124e88..10c379fca7 100644
    a b void ISerializer::String(const char* name, const std::wstring& value, uint32_t m  
    9292    PutString(name, str);
    9393}
    9494
    95 void ISerializer::ScriptVal(const char* name, JS::MutableHandleValue value)
     95void ISerializer::ScriptVal(const char* name, JS::MutableHandleValue value, bool a)
    9696{
    97     PutScriptVal(name, value);
     97    PutScriptVal(name, value, a);
    9898}
    9999
    100100void ISerializer::RawBytes(const char* name, const u8* data, size_t len)
  • source/simulation2/serialization/ISerializer.h

    diff --git a/source/simulation2/serialization/ISerializer.h b/source/simulation2/serialization/ISerializer.h
    index 4ab47bb0b7..4ca1016bab 100644
    a b public:  
    220220     * The value must not contain any unserializable values (like functions).
    221221     * NOTE: We have to use a mutable handle because JS_Stringify requires that for unknown reasons.
    222222     */
    223     void ScriptVal(const char* name, JS::MutableHandleValue value);
     223    void ScriptVal(const char* name, JS::MutableHandleValue value, bool);
    224224
    225225    /**
    226226     * Serialize a stream of bytes.
    protected:  
    257257    virtual void PutBool(const char* name, bool value) = 0;
    258258    virtual void PutString(const char* name, const std::string& value) = 0;
    259259    // We have to use a mutable handle because JS_Stringify requires that for unknown reasons.
    260     virtual void PutScriptVal(const char* name, JS::MutableHandleValue value) = 0;
     260    virtual void PutScriptVal(const char* name, JS::MutableHandleValue value, bool) = 0;
    261261    virtual void PutRaw(const char* name, const u8* data, size_t len) = 0;
    262262};
    263263
  • source/simulation2/serialization/StdDeserializer.cpp

    diff --git a/source/simulation2/serialization/StdDeserializer.cpp b/source/simulation2/serialization/StdDeserializer.cpp
    index 131898ccd9..6a1097841c 100644
    a b  
    1 /* Copyright (C) 2016 Wildfire Games.
     1/* Copyright (C) 2017 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    2727
    2828#include "lib/byte_order.h"
    2929
     30#include "ps/Filesystem.h" // gvfs hack
     31
    3032CStdDeserializer::CStdDeserializer(ScriptInterface& scriptInterface, std::istream& stream) :
    3133    m_ScriptInterface(scriptInterface), m_Stream(stream),
    3234    m_dummyObject(scriptInterface.GetJSRuntime())
    CStdDeserializer::CStdDeserializer(ScriptInterface& scriptInterface, std::istrea  
    4042    // needs to be serialized and then tagged
    4143    m_dummyObject = JS_NewPlainObject(cx);
    4244    m_ScriptBackrefs.push_back(JS::Heap<JSObject*>(m_dummyObject));
     45
     46    if (g_VFS)
     47    {
     48        JS::Heap<JSObject*> v2proto(&m_ScriptInterface.GetCachedValue(ScriptInterface::CACHE_VECTOR2DPROTO).toObject());
     49        m_SerializablePrototypes.insert(std::make_pair(L"Vector2D", v2proto));
     50        JS::Heap<JSObject*> v3proto(&m_ScriptInterface.GetCachedValue(ScriptInterface::CACHE_VECTOR3DPROTO).toObject());
     51        m_SerializablePrototypes.insert(std::make_pair(L"Vector2D", v3proto));
     52    }
    4353}
    4454
    4555CStdDeserializer::~CStdDeserializer()
    void CStdDeserializer::SetSerializablePrototypes(std::map<std::wstring, JS::Heap  
    512522    m_SerializablePrototypes = prototypes;
    513523}
    514524
    515 bool CStdDeserializer::IsSerializablePrototype(const std::wstring& name)
     525bool CStdDeserializer::IsSerializablePrototype(const std::wstring& name) const
    516526{
    517527    return m_SerializablePrototypes.find(name) != m_SerializablePrototypes.end();
    518528}
    519529
    520 void CStdDeserializer::GetSerializablePrototype(const std::wstring& name, JS::MutableHandleObject ret)
     530void CStdDeserializer::GetSerializablePrototype(const std::wstring& name, JS::MutableHandleObject ret) const
    521531{
    522     std::map<std::wstring, JS::Heap<JSObject*> >::iterator it = m_SerializablePrototypes.find(name);
     532    std::map<std::wstring, JS::Heap<JSObject*> >::const_iterator it = m_SerializablePrototypes.find(name);
    523533    if (it != m_SerializablePrototypes.end())
    524534        ret.set(it->second);
    525535    else
    526         ret.set(NULL);
     536        ret.set(nullptr);
    527537}
  • source/simulation2/serialization/StdDeserializer.h

    diff --git a/source/simulation2/serialization/StdDeserializer.h b/source/simulation2/serialization/StdDeserializer.h
    index 1d16e56993..d2c3f48655 100644
    a b  
    1 /* Copyright (C) 2016 Wildfire Games.
     1/* Copyright (C) 2017 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
    private:  
    6363
    6464    std::map<std::wstring, JS::Heap<JSObject*> > m_SerializablePrototypes;
    6565
    66     bool IsSerializablePrototype(const std::wstring& name);
    67     void GetSerializablePrototype(const std::wstring& name, JS::MutableHandleObject ret);
     66    bool IsSerializablePrototype(const std::wstring& name) const;
     67    void GetSerializablePrototype(const std::wstring& name, JS::MutableHandleObject ret) const;
    6868};
    6969
    7070#endif // INCLUDED_STDDESERIALIZER
  • source/simulation2/tests/test_ComponentManager.h

    diff --git a/source/simulation2/tests/test_ComponentManager.h b/source/simulation2/tests/test_ComponentManager.h
    index 1cbffd1602..735ecbb53b 100644
    a b public:  
    716716        man.LoadComponentTypes();
    717717        TS_ASSERT(man.LoadScript(L"simulation/components/test-serialize.js"));
    718718
    719         entity_id_t ent1 = 1, ent2 = 2, ent3 = 3, ent4 = 4;
     719        entity_id_t ent1 = 1, ent2 = 2, ent3 = 3, ent4 = 4, ent5 = 5;
    720720        CEntityHandle hnd1 = man.AllocateEntityHandle(ent1);
    721721        CEntityHandle hnd2 = man.AllocateEntityHandle(ent2);
    722722        CEntityHandle hnd3 = man.AllocateEntityHandle(ent3);
    723723        CEntityHandle hnd4 = man.AllocateEntityHandle(ent4);
     724        CEntityHandle hnd5 = man.AllocateEntityHandle(ent5);
    724725        CParamNode noParam;
    725726
    726727        CParamNode testParam;
    public:  
    729730        man.AddComponent(hnd1, man.LookupCID("TestScript1_values"), testParam);
    730731        man.AddComponent(hnd2, man.LookupCID("TestScript1_entity"), testParam);
    731732
     733// TODO is this actually accurate?
    732734        // TODO: Since the upgrade to SpiderMonkey v24 this test won't be able to correctly represent
    733735        // non-tree structures because sharp variables were removed (bug 566700).
    734736        // This also affects the debug serializer and it could make sense to implement correct serialization again.
    public:  
    736738
    737739        man.AddComponent(hnd4, man.LookupCID("TestScript1_custom"), testParam);
    738740
     741        man.AddComponent(hnd5, man.LookupCID("TestScript1_vector"), testParam);
     742
    739743        TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), 1234);
    740744        {
    741745            TestLogger log; // swallow warnings about this.entity being read-only
    742746            TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), (int)ent2);
    743747        }
    744748        TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent3, IID_Test1))->GetX(), 8);
     749        TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent5, IID_Test1))->GetX(), 5);
    745750
    746751        std::stringstream debugStream;
    747752        TS_ASSERT(man.DumpDebugState(debugStream, true));
    entities:\n\  
    780785    object: {\n\
    781786  \"c\": 1\n\
    782787}\n\
     788\n\
     789- id: 5\n\
     790  TestScript1_vector:\n\
     791    object: {\n\
     792  \"list\": [\n\
     793    {\n\
     794      \"pos\": {\n\
     795        \"x\": 1,\n\
     796        \"y\": 2\n\
     797      }\n\
     798    }\n\
     799  ]\n\
     800}\n\
    783801\n"
    784802        );
    785803
    entities:\n\  
    799817            TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man2.QueryInterface(ent2, IID_Test1))->GetX(), (int)ent2);
    800818        }
    801819        TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man2.QueryInterface(ent3, IID_Test1))->GetX(), 12);
     820        TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent5, IID_Test1))->GetX(), 5);
    802821    }
    803822
    804823    void test_script_serialization_errors()
  • source/simulation2/tests/test_Serializer.h

    diff --git a/source/simulation2/tests/test_Serializer.h b/source/simulation2/tests/test_Serializer.h
    index d9aee50552..4d160fc1cb 100644
    a b public:  
    289289
    290290    // TODO: test exceptions more thoroughly
    291291
    292     void helper_script_roundtrip(const char* msg, const char* input, const char* expected, size_t expstreamlen = 0, const char* expstream = NULL, const char* debug = NULL)
     292    void helper_script_roundtrip(const char* msg, const char* input, const char* expected, size_t expstreamlen = 0, const char* expstream = NULL, const char* debug = NULL, bool loadglobalscripts = false)
    293293    {
    294294        ScriptInterface script("Test", "Test", g_ScriptRuntime);
     295
     296        if (loadglobalscripts)
     297            script.LoadGlobalScripts();
     298
    295299        JSContext* cx = script.GetContext();
    296300        JSAutoRequest rq(cx);
    297301
    public:  
    302306        {
    303307            std::stringstream dbgstream;
    304308            CDebugSerializer serialize(script, dbgstream);
    305             serialize.ScriptVal("script", &obj);
     309            serialize.ScriptVal("script", &obj, false);
    306310            TS_ASSERT_STR_EQUALS(dbgstream.str(), debug);
    307311        }
    308312
    309313        std::stringstream stream;
    310314        CStdSerializer serialize(script, stream);
    311315
    312         serialize.ScriptVal("script", &obj);
     316        serialize.ScriptVal("script", &obj, false);
     317
     318// TODO hack
     319if (loadglobalscripts) {
     320    std::string foo_;
     321    TSM_ASSERT(msg, script.CallFunction(obj, "nop", foo_));
     322    TS_ASSERT_STR_EQUALS(foo_, "working");
     323}
    313324
    314325        if (expstream)
    315326        {
    public:  
    327338        std::string source;
    328339        TSM_ASSERT(msg, script.CallFunction(newobj, "toSource", source));
    329340        TS_ASSERT_STR_EQUALS(source, expected);
     341
     342// TODO hack
     343if (loadglobalscripts) {
     344    std::string foo;
     345    TSM_ASSERT(msg, script.CallFunction(newobj, "nop", foo));
     346    TS_ASSERT_STR_EQUALS(foo, "working");
     347}
    330348    }
    331349
    332350    void test_script_basic()
    public:  
    717735
    718736    // TODO: prototype objects
    719737
     738    void test_script_vector()
     739    {
     740        g_VFS = CreateVfs(20 * MiB);
     741        TS_ASSERT_OK(g_VFS->Mount(L"", DataDir()/"mods"/"_test.sim", VFS_MOUNT_MUST_EXIST));
     742        TS_ASSERT_OK(g_VFS->Mount(L"cache", DataDir()/"_testcache"));
     743
     744        helper_script_roundtrip("Vector2D",
     745            "var a = new Vector2D(1, 2); a.add({x:1, y:1}); warn(\"\"+(a instanceof Vector2D)); a",
     746        /* expected: */
     747            "({x:2, y:3})",
     748        /* expected stream */
     749            39,
     750            "\x0B" // SCRIPT_TYPE_OBJECT_PROTOTYPE
     751            "\x08\0\0\0" // len of prototype name
     752            "Vector2D" // prototype name
     753            "\x02\0\0\0" // num props
     754                "\x01\x01\0\0\0" "x" // "x"
     755                "\x05" // SCRIPT_TYPE_INT
     756                "\x02\0\0\0" // 2
     757
     758                "\x01\x01\0\0\0" "y" // "y"
     759                "\x05" // SCRIPT_TYPE_INT
     760                "\x03\0\0\0" // 3
     761            ,
     762            NULL,
     763            true
     764               
     765        );
     766        g_VFS.reset();
     767    }
     768
    720769    void test_script_nonfinite()
    721770    {
    722771        helper_script_roundtrip("nonfinite", "[0, Infinity, -Infinity, NaN, -1/Infinity]", "[0, Infinity, -Infinity, NaN, -0]");
    public:  
    766815        TestLogger logger;
    767816
    768817        TS_ASSERT(script.Eval("([1, 2, function () { }])", &obj));
    769         TS_ASSERT_THROWS(serialize.ScriptVal("script", &obj), PSERROR_Serialize_InvalidScriptValue);
     818        TS_ASSERT_THROWS(serialize.ScriptVal("script", &obj, false), PSERROR_Serialize_InvalidScriptValue);
    770819    }
    771820
    772821    void test_script_splice()
    public:  
    801850            std::stringstream stream;
    802851            CStdSerializer serialize(script, stream);
    803852
    804             serialize.ScriptVal("script", &obj);
     853            serialize.ScriptVal("script", &obj, false);
    805854
    806855            CStdDeserializer deserialize(script, stream);
    807856
    public:  
    882931        DeleteDirectory(DataDir()/"_testcache");
    883932        CXeromyces::Terminate();
    884933    }
    885 
    886934};