|
|
|
@ -21,81 +21,63 @@
|
|
|
|
|
|
|
|
|
|
#include "filter.hpp"
|
|
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
void test(
|
|
|
|
|
const MWWorld::Ptr& actor, int& compiled, int& total, const Compiler::Extensions* extensions, int warningsMode)
|
|
|
|
|
bool test(const MWWorld::Ptr& actor, const ESM::DialInfo& info, int& compiled, int& total,
|
|
|
|
|
const Compiler::Extensions* extensions, const MWScript::CompilerContext& context,
|
|
|
|
|
Compiler::StreamErrorHandler& errorHandler)
|
|
|
|
|
{
|
|
|
|
|
MWDialogue::Filter filter(actor, 0, false);
|
|
|
|
|
|
|
|
|
|
MWScript::CompilerContext compilerContext(MWScript::CompilerContext::Type_Dialogue);
|
|
|
|
|
compilerContext.setExtensions(extensions);
|
|
|
|
|
Compiler::StreamErrorHandler errorHandler;
|
|
|
|
|
errorHandler.setWarningsMode(warningsMode);
|
|
|
|
|
|
|
|
|
|
const MWWorld::Store<ESM::Dialogue>& dialogues
|
|
|
|
|
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Dialogue>();
|
|
|
|
|
for (MWWorld::Store<ESM::Dialogue>::iterator it = dialogues.begin(); it != dialogues.end(); ++it)
|
|
|
|
|
bool success = true;
|
|
|
|
|
++total;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::vector<const ESM::DialInfo*> infos = filter.listAll(*it);
|
|
|
|
|
|
|
|
|
|
for (std::vector<const ESM::DialInfo*>::iterator iter = infos.begin(); iter != infos.end(); ++iter)
|
|
|
|
|
{
|
|
|
|
|
const ESM::DialInfo* info = *iter;
|
|
|
|
|
if (!info->mResultScript.empty())
|
|
|
|
|
{
|
|
|
|
|
bool success = true;
|
|
|
|
|
++total;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
errorHandler.reset();
|
|
|
|
|
|
|
|
|
|
std::istringstream input(info->mResultScript + "\n");
|
|
|
|
|
std::istringstream input(info.mResultScript + "\n");
|
|
|
|
|
|
|
|
|
|
Compiler::Scanner scanner(errorHandler, input, extensions);
|
|
|
|
|
Compiler::Scanner scanner(errorHandler, input, extensions);
|
|
|
|
|
|
|
|
|
|
Compiler::Locals locals;
|
|
|
|
|
Compiler::Locals locals;
|
|
|
|
|
|
|
|
|
|
std::string_view actorScript = actor.getClass().getScript(actor);
|
|
|
|
|
std::string_view actorScript = actor.getClass().getScript(actor);
|
|
|
|
|
if (!actorScript.empty())
|
|
|
|
|
{
|
|
|
|
|
// grab local variables from actor's script, if available.
|
|
|
|
|
locals = MWBase::Environment::get().getScriptManager()->getLocals(actorScript);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!actorScript.empty())
|
|
|
|
|
{
|
|
|
|
|
// grab local variables from actor's script, if available.
|
|
|
|
|
locals = MWBase::Environment::get().getScriptManager()->getLocals(actorScript);
|
|
|
|
|
}
|
|
|
|
|
Compiler::ScriptParser parser(errorHandler, context, locals, false);
|
|
|
|
|
|
|
|
|
|
Compiler::ScriptParser parser(errorHandler, compilerContext, locals, false);
|
|
|
|
|
scanner.scan(parser);
|
|
|
|
|
|
|
|
|
|
scanner.scan(parser);
|
|
|
|
|
if (!errorHandler.isGood())
|
|
|
|
|
success = false;
|
|
|
|
|
|
|
|
|
|
if (!errorHandler.isGood())
|
|
|
|
|
success = false;
|
|
|
|
|
++compiled;
|
|
|
|
|
}
|
|
|
|
|
catch (const Compiler::SourceException&)
|
|
|
|
|
{
|
|
|
|
|
// error has already been reported via error handler
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& error)
|
|
|
|
|
{
|
|
|
|
|
Log(Debug::Error) << "Dialogue error: An exception has been thrown: " << error.what();
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++compiled;
|
|
|
|
|
}
|
|
|
|
|
catch (const Compiler::SourceException& /* error */)
|
|
|
|
|
{
|
|
|
|
|
// error has already been reported via error handler
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& error)
|
|
|
|
|
{
|
|
|
|
|
Log(Debug::Error)
|
|
|
|
|
<< std::string("Dialogue error: An exception has been thrown: ") + error.what();
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
Log(Debug::Error) << "Error: compiling failed (dialogue script): \n"
|
|
|
|
|
<< info->mResultScript << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool superficiallyMatches(const MWWorld::Ptr& ptr, const ESM::DialInfo& info)
|
|
|
|
|
{
|
|
|
|
|
if (ptr.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
MWDialogue::Filter filter(ptr, 0, false);
|
|
|
|
|
return filter.couldPotentiallyMatch(info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
@ -109,20 +91,79 @@ namespace MWDialogue
|
|
|
|
|
std::pair<int, int> compileAll(const Compiler::Extensions* extensions, int warningsMode)
|
|
|
|
|
{
|
|
|
|
|
int compiled = 0, total = 0;
|
|
|
|
|
const MWWorld::Store<ESM::NPC>& npcs = MWBase::Environment::get().getWorld()->getStore().get<ESM::NPC>();
|
|
|
|
|
for (MWWorld::Store<ESM::NPC>::iterator it = npcs.begin(); it != npcs.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->mId);
|
|
|
|
|
test(ref.getPtr(), compiled, total, extensions, warningsMode);
|
|
|
|
|
}
|
|
|
|
|
const auto& store = MWBase::Environment::get().getWorld()->getStore();
|
|
|
|
|
|
|
|
|
|
MWScript::CompilerContext compilerContext(MWScript::CompilerContext::Type_Dialogue);
|
|
|
|
|
compilerContext.setExtensions(extensions);
|
|
|
|
|
Compiler::StreamErrorHandler errorHandler;
|
|
|
|
|
errorHandler.setWarningsMode(warningsMode);
|
|
|
|
|
|
|
|
|
|
const MWWorld::Store<ESM::Creature>& creatures
|
|
|
|
|
= MWBase::Environment::get().getWorld()->getStore().get<ESM::Creature>();
|
|
|
|
|
for (MWWorld::Store<ESM::Creature>::iterator it = creatures.begin(); it != creatures.end(); ++it)
|
|
|
|
|
std::unique_ptr<MWWorld::ManualRef> ref;
|
|
|
|
|
for (const ESM::Dialogue& topic : store.get<ESM::Dialogue>())
|
|
|
|
|
{
|
|
|
|
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), it->mId);
|
|
|
|
|
test(ref.getPtr(), compiled, total, extensions, warningsMode);
|
|
|
|
|
MWWorld::Ptr ptr;
|
|
|
|
|
for (const ESM::DialInfo& info : topic.mInfo)
|
|
|
|
|
{
|
|
|
|
|
if (info.mResultScript.empty())
|
|
|
|
|
continue;
|
|
|
|
|
if (!info.mActor.empty())
|
|
|
|
|
{
|
|
|
|
|
// We know it can only ever be this actor
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ref = std::make_unique<MWWorld::ManualRef>(store, info.mActor);
|
|
|
|
|
ptr = ref->getPtr();
|
|
|
|
|
}
|
|
|
|
|
catch (const std::logic_error&)
|
|
|
|
|
{
|
|
|
|
|
// Too bad it doesn't exist
|
|
|
|
|
ptr = {};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Try to find a matching actor
|
|
|
|
|
if (!superficiallyMatches(ptr, info))
|
|
|
|
|
{
|
|
|
|
|
ptr = {};
|
|
|
|
|
bool found = false;
|
|
|
|
|
for (const auto& npc : store.get<ESM::NPC>())
|
|
|
|
|
{
|
|
|
|
|
ref = std::make_unique<MWWorld::ManualRef>(store, npc.mId);
|
|
|
|
|
if (superficiallyMatches(ref->getPtr(), info))
|
|
|
|
|
{
|
|
|
|
|
ptr = ref->getPtr();
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found)
|
|
|
|
|
{
|
|
|
|
|
for (const auto& creature : store.get<ESM::Creature>())
|
|
|
|
|
{
|
|
|
|
|
ref = std::make_unique<MWWorld::ManualRef>(store, creature.mId);
|
|
|
|
|
if (superficiallyMatches(ref->getPtr(), info))
|
|
|
|
|
{
|
|
|
|
|
ptr = ref->getPtr();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (ptr.isEmpty())
|
|
|
|
|
Log(Debug::Error) << "Could not find an actor to test " << info.mId << " in " << topic.mId;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
errorHandler.reset();
|
|
|
|
|
errorHandler.setContext(info.mId + " in " + topic.mId);
|
|
|
|
|
if (!test(ptr, info, compiled, total, extensions, compilerContext, errorHandler))
|
|
|
|
|
Log(Debug::Error) << "Test failed for " << info.mId << " in " << topic.mId << '\n'
|
|
|
|
|
<< info.mResultScript;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::make_pair(total, compiled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|