mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-09-21 20:06:40 +00:00
Allow to use a generator as MapGenerator
This way it's clear what's the input and what's the output of the computation. All map generation scripts should reman working. They are adopted in a future commit. `Engine.SetProgress` and `Engine.ExportMap` can be removed in a future commit. Comments by: @marder, @sera, @Stan Differential Revision: https://code.wildfiregames.com/D5220 This was SVN commit r28093.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2023 Wildfire Games.
|
||||
/* Copyright (C) 2024 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@@ -22,8 +22,10 @@
|
||||
#include "ScriptExceptions.h"
|
||||
#include "ScriptRequest.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
class ScriptInterface;
|
||||
@@ -80,6 +82,17 @@ private:
|
||||
template<typename C, typename R, typename ...Types>
|
||||
struct args_info<R(C::*)(Types ...) const> : public args_info<R(C::*)(Types ...)> {};
|
||||
|
||||
struct IteratorResultError : std::runtime_error
|
||||
{
|
||||
IteratorResultError(const std::string& property) :
|
||||
IteratorResultError{property.c_str()}
|
||||
{}
|
||||
IteratorResultError(const char* property) :
|
||||
std::runtime_error{fmt::format("Failed to get `{}` from an `IteratorResult`.", property)}
|
||||
{}
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -346,6 +359,59 @@ public:
|
||||
return Call(rq, val, name, IgnoreResult, std::forward<const Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a JS function @a name, property of object @a val, with the argument @a args. Repeatetly
|
||||
* invokes @a yieldCallback with the yielded value.
|
||||
* @return the final value of the generator.
|
||||
*/
|
||||
template<typename Callback>
|
||||
static JS::Value RunGenerator(const ScriptRequest& rq, JS::HandleValue val, const char* name,
|
||||
JS::HandleValue arg, Callback yieldCallback)
|
||||
{
|
||||
JS::RootedValue generator{rq.cx};
|
||||
if (!ScriptFunction::Call(rq, val, name, &generator, arg))
|
||||
throw std::runtime_error{fmt::format("Failed to call the generator `{}`.", name)};
|
||||
|
||||
const auto continueGenerator = [&](const char* property, auto... args) -> JS::Value
|
||||
{
|
||||
JS::RootedValue iteratorResult{rq.cx};
|
||||
if (!ScriptFunction::Call(rq, generator, property, &iteratorResult, args...))
|
||||
throw std::runtime_error{fmt::format("Failed to call `{}`.", name)};
|
||||
return iteratorResult;
|
||||
};
|
||||
|
||||
JS::PersistentRootedValue error{rq.cx, JS::UndefinedValue()};
|
||||
while (true)
|
||||
{
|
||||
JS::RootedValue iteratorResult{rq.cx, error.isUndefined() ? continueGenerator("next") :
|
||||
continueGenerator("throw", std::exchange(error, JS::UndefinedValue()))};
|
||||
|
||||
try
|
||||
{
|
||||
JS::RootedObject iteratorResultObject{rq.cx, &iteratorResult.toObject()};
|
||||
|
||||
bool done;
|
||||
if (!Script::FromJSProperty(rq, iteratorResult, "done", done, true))
|
||||
throw IteratorResultError{"done"};
|
||||
|
||||
JS::RootedValue value{rq.cx};
|
||||
if (!JS_GetProperty(rq.cx, iteratorResultObject, "value", &value))
|
||||
throw IteratorResultError{"value"};
|
||||
|
||||
if (done)
|
||||
return value;
|
||||
|
||||
yieldCallback(value);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
JS::RootedValue global{rq.cx, rq.globalValue()};
|
||||
if (!ScriptFunction::Call(rq, global, "Error", &error, e.what()))
|
||||
throw std::runtime_error{"Failed to construct `Error`."};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a function spec from a C++ function.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user