|
29 | 29 | #include "clock.h" |
30 | 30 | #include "audio/iaudioengine.h" |
31 | 31 | #include "blocks/standardblocks.h" |
32 | | -#include "blocks/variableblocks.h" |
33 | | -#include "blocks/listblocks.h" |
34 | 32 | #include "scratch/monitor_p.h" |
35 | 33 |
|
36 | 34 | using namespace libscratchcpp; |
@@ -314,56 +312,8 @@ void Engine::compile() |
314 | 312 | // Compile monitor blocks to bytecode |
315 | 313 | std::cout << "Compiling stage monitors..." << std::endl; |
316 | 314 |
|
317 | | - for (auto monitor : m_monitors) { |
318 | | - Target *target = monitor->sprite() ? dynamic_cast<Target *>(monitor->sprite()) : stage(); |
319 | | - Compiler compiler(this, target); |
320 | | - auto block = monitor->block(); |
321 | | - auto section = blockSection(block->opcode()); |
322 | | - auto container = blockSectionContainer(block->opcode()); |
323 | | - |
324 | | - if (container) { |
325 | | - MonitorNameFunc nameFunc = container->resolveMonitorNameFunc(block->opcode()); |
326 | | - |
327 | | - if (nameFunc) |
328 | | - monitor->setName(nameFunc(block.get())); |
329 | | - |
330 | | - MonitorChangeFunc changeFunc = container->resolveMonitorChangeFunc(block->opcode()); |
331 | | - monitor->setValueChangeFunction(changeFunc); |
332 | | - } |
333 | | - |
334 | | - if (section) { |
335 | | - auto script = std::make_shared<Script>(target, block, this); |
336 | | - monitor->setScript(script); |
337 | | - compiler.init(); |
338 | | - compiler.setBlock(block); |
339 | | - |
340 | | - if (block->compileFunction()) |
341 | | - block->compile(&compiler); |
342 | | - else |
343 | | - std::cout << "warning: monitor block doesn't have a compile function: " << block->opcode() << std::endl; |
344 | | - |
345 | | - // Workaround for register leak warning spam: pause the script after getting the monitor value |
346 | | - compiler.addFunctionCall([](VirtualMachine *vm) -> unsigned int { |
347 | | - vm->stop(false, false, false); |
348 | | - return 0; |
349 | | - }); |
350 | | - |
351 | | - compiler.end(); |
352 | | - |
353 | | - script->setBytecode(compiler.bytecode()); |
354 | | - script->setConstValues(compiler.constValues()); |
355 | | - script->setVariables(compiler.variables()); |
356 | | - script->setLists(compiler.lists()); |
357 | | - } else { |
358 | | - std::cout << "warning: unsupported monitor block: " << block->opcode() << std::endl; |
359 | | - m_unsupportedBlocks.insert(block->opcode()); |
360 | | - } |
361 | | - |
362 | | - const auto &unsupportedBlocks = compiler.unsupportedBlocks(); |
363 | | - |
364 | | - for (const std::string &opcode : unsupportedBlocks) |
365 | | - m_unsupportedBlocks.insert(opcode); |
366 | | - } |
| 315 | + for (auto monitor : m_monitors) |
| 316 | + compileMonitor(monitor); |
367 | 317 | } |
368 | 318 |
|
369 | 319 | void Engine::start() |
@@ -1231,9 +1181,6 @@ void Engine::setTargets(const std::vector<std::shared_ptr<Target>> &newTargets) |
1231 | 1181 |
|
1232 | 1182 | // Sort the executable targets by layer order |
1233 | 1183 | std::sort(m_executableTargets.begin(), m_executableTargets.end(), [](Target *t1, Target *t2) { return t1->layerOrder() < t2->layerOrder(); }); |
1234 | | - |
1235 | | - // Create missing monitors |
1236 | | - createMissingMonitors(); |
1237 | 1184 | } |
1238 | 1185 |
|
1239 | 1186 | Target *Engine::targetAt(int index) const |
@@ -1401,9 +1348,42 @@ void Engine::setMonitors(const std::vector<std::shared_ptr<Monitor>> &newMonitor |
1401 | 1348 | m_monitors.push_back(monitor); |
1402 | 1349 | m_monitorAdded(monitor.get()); |
1403 | 1350 | } |
| 1351 | +} |
| 1352 | + |
| 1353 | +Monitor *Engine::createVariableMonitor(std::shared_ptr<Variable> var, const std::string &opcode, const std::string &varFieldName, int varFieldId, BlockComp compileFunction) |
| 1354 | +{ |
| 1355 | + if (var->monitor()) |
| 1356 | + return var->monitor(); |
| 1357 | + else { |
| 1358 | + auto monitor = std::make_shared<Monitor>(var->id(), opcode); |
| 1359 | + auto field = std::make_shared<Field>(varFieldName, var->name(), var); |
| 1360 | + field->setFieldId(varFieldId); |
| 1361 | + monitor->block()->addField(field); |
| 1362 | + monitor->block()->setCompileFunction(compileFunction); |
| 1363 | + |
| 1364 | + addVarOrListMonitor(monitor, var->target()); |
| 1365 | + var->setMonitor(monitor.get()); |
| 1366 | + compileMonitor(monitor); |
| 1367 | + return monitor.get(); |
| 1368 | + } |
| 1369 | +} |
1404 | 1370 |
|
1405 | | - // Create missing monitors |
1406 | | - createMissingMonitors(); |
| 1371 | +Monitor *Engine::createListMonitor(std::shared_ptr<List> list, const std::string &opcode, const std::string &listFieldName, int listFieldId, BlockComp compileFunction) |
| 1372 | +{ |
| 1373 | + if (list->monitor()) |
| 1374 | + return list->monitor(); |
| 1375 | + else { |
| 1376 | + auto monitor = std::make_shared<Monitor>(list->id(), opcode); |
| 1377 | + auto field = std::make_shared<Field>(listFieldName, list->name(), list); |
| 1378 | + field->setFieldId(listFieldId); |
| 1379 | + monitor->block()->addField(field); |
| 1380 | + monitor->block()->setCompileFunction(compileFunction); |
| 1381 | + |
| 1382 | + addVarOrListMonitor(monitor, list->target()); |
| 1383 | + list->setMonitor(monitor.get()); |
| 1384 | + compileMonitor(monitor); |
| 1385 | + return monitor.get(); |
| 1386 | + } |
1407 | 1387 | } |
1408 | 1388 |
|
1409 | 1389 | sigslot::signal<Monitor *> &Engine::monitorAdded() |
@@ -1759,6 +1739,58 @@ const std::unordered_set<std::string> &Engine::unsupportedBlocks() const |
1759 | 1739 | return m_unsupportedBlocks; |
1760 | 1740 | } |
1761 | 1741 |
|
| 1742 | +void Engine::compileMonitor(std::shared_ptr<Monitor> monitor) |
| 1743 | +{ |
| 1744 | + Target *target = monitor->sprite() ? dynamic_cast<Target *>(monitor->sprite()) : stage(); |
| 1745 | + Compiler compiler(this, target); |
| 1746 | + auto block = monitor->block(); |
| 1747 | + auto section = blockSection(block->opcode()); |
| 1748 | + auto container = blockSectionContainer(block->opcode()); |
| 1749 | + |
| 1750 | + if (container) { |
| 1751 | + MonitorNameFunc nameFunc = container->resolveMonitorNameFunc(block->opcode()); |
| 1752 | + |
| 1753 | + if (nameFunc) |
| 1754 | + monitor->setName(nameFunc(block.get())); |
| 1755 | + |
| 1756 | + MonitorChangeFunc changeFunc = container->resolveMonitorChangeFunc(block->opcode()); |
| 1757 | + monitor->setValueChangeFunction(changeFunc); |
| 1758 | + } |
| 1759 | + |
| 1760 | + if (section) { |
| 1761 | + auto script = std::make_shared<Script>(target, block, this); |
| 1762 | + monitor->setScript(script); |
| 1763 | + compiler.init(); |
| 1764 | + compiler.setBlock(block); |
| 1765 | + |
| 1766 | + if (block->compileFunction()) |
| 1767 | + block->compile(&compiler); |
| 1768 | + else |
| 1769 | + std::cout << "warning: monitor block doesn't have a compile function: " << block->opcode() << std::endl; |
| 1770 | + |
| 1771 | + // Workaround for register leak warning spam: pause the script after getting the monitor value |
| 1772 | + compiler.addFunctionCall([](VirtualMachine *vm) -> unsigned int { |
| 1773 | + vm->stop(false, false, false); |
| 1774 | + return 0; |
| 1775 | + }); |
| 1776 | + |
| 1777 | + compiler.end(); |
| 1778 | + |
| 1779 | + script->setBytecode(compiler.bytecode()); |
| 1780 | + script->setConstValues(compiler.constValues()); |
| 1781 | + script->setVariables(compiler.variables()); |
| 1782 | + script->setLists(compiler.lists()); |
| 1783 | + } else { |
| 1784 | + std::cout << "warning: unsupported monitor block: " << block->opcode() << std::endl; |
| 1785 | + m_unsupportedBlocks.insert(block->opcode()); |
| 1786 | + } |
| 1787 | + |
| 1788 | + const auto &unsupportedBlocks = compiler.unsupportedBlocks(); |
| 1789 | + |
| 1790 | + for (const std::string &opcode : unsupportedBlocks) |
| 1791 | + m_unsupportedBlocks.insert(opcode); |
| 1792 | +} |
| 1793 | + |
1762 | 1794 | void Engine::finalize() |
1763 | 1795 | { |
1764 | 1796 | m_eventLoopMutex.lock(); |
@@ -1797,60 +1829,6 @@ void Engine::removeExecutableClones() |
1797 | 1829 | m_executableTargets.erase(std::remove(m_executableTargets.begin(), m_executableTargets.end(), clone.get()), m_executableTargets.end()); |
1798 | 1830 | } |
1799 | 1831 |
|
1800 | | -void Engine::createMissingMonitors() |
1801 | | -{ |
1802 | | - // This is called when setting targets and monitors because we never know in which order they're set |
1803 | | - // If there aren't any targets yet, quit |
1804 | | - if (m_targets.empty()) |
1805 | | - return; |
1806 | | - |
1807 | | - for (auto target : m_targets) { |
1808 | | - // Read all variables |
1809 | | - const auto &variables = target->variables(); |
1810 | | - |
1811 | | - for (auto variable : variables) { |
1812 | | - // Find the monitor for this variable |
1813 | | - auto it = std::find_if(m_monitors.begin(), m_monitors.end(), [variable](std::shared_ptr<Monitor> monitor) { |
1814 | | - // TODO: Move the opcode out of Engine |
1815 | | - return monitor->opcode() == "data_variable" && monitor->id() == variable->id(); |
1816 | | - }); |
1817 | | - |
1818 | | - // If it doesn't exist, create it |
1819 | | - if (it == m_monitors.end()) { |
1820 | | - auto monitor = std::make_shared<Monitor>(variable->id(), "data_variable"); |
1821 | | - // TODO: Move field information out of Engine |
1822 | | - auto field = std::make_shared<Field>("VARIABLE", variable->name(), variable); |
1823 | | - field->setFieldId(VariableBlocks::VARIABLE); |
1824 | | - monitor->block()->addField(field); |
1825 | | - |
1826 | | - addVarOrListMonitor(monitor, target.get()); |
1827 | | - } |
1828 | | - } |
1829 | | - |
1830 | | - // Read all lists |
1831 | | - const auto &lists = target->lists(); |
1832 | | - |
1833 | | - for (auto list : lists) { |
1834 | | - // Find the monitor for this list |
1835 | | - auto it = std::find_if(m_monitors.begin(), m_monitors.end(), [list](std::shared_ptr<Monitor> monitor) { |
1836 | | - // TODO: Move the opcode out of Engine |
1837 | | - return monitor->opcode() == "data_listcontents" && monitor->id() == list->id(); |
1838 | | - }); |
1839 | | - |
1840 | | - // If it doesn't exist, create it |
1841 | | - if (it == m_monitors.end()) { |
1842 | | - auto monitor = std::make_shared<Monitor>(list->id(), "data_listcontents"); |
1843 | | - // TODO: Move field information out of Engine |
1844 | | - auto field = std::make_shared<Field>("LIST", list->name(), list); |
1845 | | - field->setFieldId(ListBlocks::LIST); |
1846 | | - monitor->block()->addField(field); |
1847 | | - |
1848 | | - addVarOrListMonitor(monitor, target.get()); |
1849 | | - } |
1850 | | - } |
1851 | | - } |
1852 | | -} |
1853 | | - |
1854 | 1832 | void Engine::addVarOrListMonitor(std::shared_ptr<Monitor> monitor, Target *target) |
1855 | 1833 | { |
1856 | 1834 | if (!target->isStage()) |
|
0 commit comments