Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SkyrimPlatform fills savegames with garbage #1956

Open
Pospelove opened this issue May 9, 2024 · 0 comments
Open

SkyrimPlatform fills savegames with garbage #1956

Pospelove opened this issue May 9, 2024 · 0 comments

Comments

@Pospelove
Copy link
Contributor

Pospelove commented May 9, 2024

TL;DR: SkyrimPlatform calls DispatchMethodCall2/DispatchStaticCall for latent functions like Utility.wait which creates a new stack each time leading to garbaging savegames.

repro:

  1. Use this javascript plugin (should be in Data/Platform/Plugins, with any name, e.g. foo.js)
var sp = skyrimPlatform;

var lastUpdate = 0;

sp.on("update", () => {
    sp.printConsole("Time since last update: " + (Date.now() - lastUpdate) + "ms")
    for (let i = 0; i < 1000; i++)sp.Utility.wait(1)
    sp.printConsole("!Shittifying the savegame")
    lastUpdate = Date.now();
});

sp.once("tick", () => {
    sp.printConsole("Loaded shittifying plugin")
});
  1. in main menu coc riverwood
  2. wait for a half-minute
  3. save <name> or manually save game via esc
  4. Load in re-saver. You will see:
image image

Related code:

// CallNative.cpp

if (funcInfo->IsLatent()) {
    VmFunctionArguments vmFuncArgs(
      [](void* numArgs) { return (size_t)numArgs; },
      [&args_, &f](size_t i) {
        FixedString unusedNameOut;
        TypeInfo typeOut;
        f->GetParam(i, unusedNameOut, typeOut);
        return AnySafeToVariable(args_.args[i], typeOut.IsInt());
      },
      (void*)numArgs);
    auto fsClassName = AnySafeToVariable(className).GetString();
    auto fsClassFunc = AnySafeToVariable(classFunc).GetString();
    auto selfScriptObject = rawSelf
      ? AnySafeToVariable(self).value.obj
      : RE::BSTSmartPointer<RE::BSScript::Object>();

    auto funcReturnType = funcInfo->GetReturnType().className;
    auto jsThrQPtr = &jsThrQ;
    auto cb = latentCallback;
    auto onResult = [cb, funcReturnType, jsThrQPtr](const Variable& result) {
      jsThrQPtr->AddTask([=] {
        if (!cb)
          throw NullPointerException("cb");
        cb(VariableToAnySafe(result, funcReturnType));
      });
    };
    VmCall::Run(*vmImpl, fsClassName, fsClassFunc, &selfScriptObject,
                vmFuncArgs, onResult, nullptr);
    return ObjectPtr();
  }
// VmCall.h

// ...

   auto args = const_cast<VmFunctionArguments*>(&arguments);
   auto functor = VmCallback::New(onResult);
   if (self && *self)
     return vm.DispatchMethodCall2((*self)->handle, className, functionName,
                                   args, functor);

   std::stringstream err;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant