c++bug修复
This commit is contained in:
@@ -11,7 +11,6 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js';
|
||||
// const friendToggle = new FriendToggle();
|
||||
window.RankBadgeGenerator = RankBadgeGenerator;
|
||||
window.CONFIG = CONFIG;
|
||||
import disableDevtool from 'disable-devtool';
|
||||
import { initDisableDevtool } from '../../playground/devtool-control.js';
|
||||
import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js';
|
||||
import { debug } from 'scratch-vm/src/util/log.js';
|
||||
@@ -561,7 +560,7 @@ const UnityComponent = function (props) {
|
||||
|
||||
useEffect(() => {
|
||||
if (CONFIG.disabledev) {
|
||||
disableDevtool({
|
||||
initDisableDevtool({
|
||||
ondevtoolopen: () => {
|
||||
|
||||
// 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗
|
||||
@@ -1906,4 +1905,4 @@ UnityComponent.propTypes = {
|
||||
vm: PropTypes.instanceOf(VM).isRequired
|
||||
};
|
||||
|
||||
export default UnityComponent;
|
||||
export default UnityComponent;
|
||||
|
||||
@@ -510,10 +510,49 @@ export class CppSyntaxValidator {
|
||||
}
|
||||
}
|
||||
|
||||
// 声明写入当前作用域,赋值更新最近的已有变量;函数不继承调用者的局部变量。
|
||||
class CppVariableScope extends Map {
|
||||
constructor(parent = null) {
|
||||
super();
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
declare(name, value) {
|
||||
return super.set(name, value);
|
||||
}
|
||||
|
||||
has(name) {
|
||||
return super.has(name) || Boolean(this.parent && this.parent.has(name));
|
||||
}
|
||||
|
||||
get(name) {
|
||||
return super.has(name) ? super.get(name) : this.parent && this.parent.get(name);
|
||||
}
|
||||
|
||||
set(name, value) {
|
||||
if (!super.has(name) && this.parent && this.parent.has(name)) {
|
||||
this.parent.set(name, value);
|
||||
return this;
|
||||
}
|
||||
return super.set(name, value);
|
||||
}
|
||||
|
||||
*entries() {
|
||||
const visible = new Map(this.parent ? this.parent.entries() : []);
|
||||
for (const [name, value] of super.entries()) visible.set(name, value);
|
||||
yield* visible.entries();
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this.entries();
|
||||
}
|
||||
}
|
||||
|
||||
export class CppCodeExecutor {
|
||||
constructor(code, setHighlightedLine) {
|
||||
this.code = code;
|
||||
this.variables = new Map();
|
||||
this.globalVariables = new CppVariableScope();
|
||||
this.variables = this.globalVariables;
|
||||
this.functions = new Map(); // 存储自定义函数
|
||||
this.currentLine = 0;
|
||||
this.lines = [];
|
||||
@@ -527,7 +566,7 @@ export class CppCodeExecutor {
|
||||
try {
|
||||
this.isRunning = true;
|
||||
this.parseCode();
|
||||
await this.executeMain();
|
||||
await this.withVariableScope(() => this.executeMain(), this.globalVariables);
|
||||
} catch (error) {
|
||||
console.error('C++执行错误:', error);
|
||||
throw error;
|
||||
@@ -544,6 +583,16 @@ export class CppCodeExecutor {
|
||||
return !this.isRunning || window.isScriptRunOver;
|
||||
}
|
||||
|
||||
async withVariableScope(action, parent = this.variables) {
|
||||
const previous = this.variables;
|
||||
this.variables = new CppVariableScope(parent);
|
||||
try {
|
||||
return await action();
|
||||
} finally {
|
||||
this.variables = previous;
|
||||
}
|
||||
}
|
||||
|
||||
parseCode() {
|
||||
debugLog('🔍 开始解析C++代码,支持自定义函数');
|
||||
|
||||
@@ -1300,10 +1349,10 @@ export class CppCodeExecutor {
|
||||
await this.executeSimpleStatement(statement.content);
|
||||
break;
|
||||
case 'for':
|
||||
await this.executeForLoop(statement);
|
||||
await this.withVariableScope(() => this.executeForLoop(statement));
|
||||
break;
|
||||
case 'if':
|
||||
await this.executeIfStatement(statement);
|
||||
await this.withVariableScope(() => this.executeIfStatement(statement));
|
||||
break;
|
||||
case 'while':
|
||||
await this.executeWhileLoop(statement);
|
||||
@@ -1323,7 +1372,21 @@ export class CppCodeExecutor {
|
||||
|
||||
async executeSimpleStatement(content) {
|
||||
debugLog(`🔍 执行简单语句: ${content}`);
|
||||
|
||||
// 先识别输出语句,避免把字符串里的 =、++、游戏函数名当作代码执行。
|
||||
if (/^\s*(?:std\s*::\s*)?cout\s*<</.test(content)) {
|
||||
this.executeCoutStatement(content);
|
||||
return;
|
||||
}
|
||||
|
||||
// 声明必须留在当前作用域,不能按普通赋值覆盖外层同名变量。
|
||||
const declaration = content.match(/^\s*(int|bool|Position|string)\s+(\w+)\s*=\s*(.+);\s*$/);
|
||||
if (declaration) {
|
||||
const [, , name, value] = declaration;
|
||||
this.variables.declare(name, this.evaluateExpression(value));
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否是自定义函数调用(包括带括号的实参,如 f((n + 1));)
|
||||
const customCall = this.parseCustomFunctionCall(content);
|
||||
if (customCall && this.functions.has(customCall.functionName)) {
|
||||
@@ -1355,40 +1418,6 @@ export class CppCodeExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
// 变量声明
|
||||
if (content.includes('int ') && content.includes('=')) {
|
||||
const match = content.match(/int\s+(\w+)\s*=\s*(.+?);/);
|
||||
if (match) {
|
||||
const [, varName, value] = match;
|
||||
this.variables.set(varName, this.evaluateExpression(value));
|
||||
debugLog('声明int变量 ' + varName + ' = ' + this.variables.get(varName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// bool类型变量声明
|
||||
if (content.includes('bool ') && content.includes('=')) {
|
||||
const match = content.match(/bool\s+(\w+)\s*=\s*(.+?);/);
|
||||
if (match) {
|
||||
const [, varName, value] = match;
|
||||
this.variables.set(varName, this.evaluateExpression(value));
|
||||
debugLog('声明bool变量 ' + varName + ' = ' + this.variables.get(varName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Position类型变量声明
|
||||
if (content.includes('Position ') && content.includes('=')) {
|
||||
const match = content.match(/Position\s+(\w+)\s*=\s*(.+?);/);
|
||||
if (match) {
|
||||
const [, varName, value] = match;
|
||||
const position = this.evaluateExpression(value);
|
||||
this.variables.set(varName, position);
|
||||
debugLog(`声明Position变量 ${varName}:`, position);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 复合赋值运算符 (+=, -=, *=, /=)
|
||||
if (content.includes('+=')) {
|
||||
const match = content.match(/(\w+)\s*\+=\s*(.+?);/);
|
||||
@@ -1513,9 +1542,6 @@ export class CppCodeExecutor {
|
||||
}
|
||||
|
||||
|
||||
} else if (content.includes('cout')) {
|
||||
// 解析复杂的cout输出语句
|
||||
this.executeCoutStatement(content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1553,41 +1579,46 @@ export class CppCodeExecutor {
|
||||
|
||||
let shouldContinue = false;
|
||||
|
||||
for (const bodyStatement of forStatement.body) {
|
||||
if (this.shouldStop()) break;
|
||||
|
||||
// 检查是否是break或continue语句
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'break;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'break')) {
|
||||
debugLog('🔄 遇到break语句,退出for循环');
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'continue;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'continue')) {
|
||||
debugLog('🔄 遇到continue语句,跳过本次循环剩余部分');
|
||||
shouldContinue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// 使用预先计算好的精确行号,如果没有则使用调整后的行号
|
||||
let adjustedStatement;
|
||||
if (bodyStatement.exactLineNumber) {
|
||||
adjustedStatement = {
|
||||
...bodyStatement,
|
||||
lineNumber: bodyStatement.exactLineNumber
|
||||
};
|
||||
debugLog(`🎯 使用精确行号: "${bodyStatement.content}" -> 第${bodyStatement.exactLineNumber}行`);
|
||||
} else {
|
||||
adjustedStatement = this.adjustStatementLineNumber.call(this, bodyStatement);
|
||||
}
|
||||
await this.executeStatement(adjustedStatement);
|
||||
try {
|
||||
await this.withVariableScope(async () => {
|
||||
for (const bodyStatement of forStatement.body) {
|
||||
if (this.shouldStop()) break;
|
||||
|
||||
// 检查是否是break或continue语句
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'break;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'break')) {
|
||||
debugLog('🔄 遇到break语句,退出for循环');
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'continue;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'continue')) {
|
||||
debugLog('🔄 遇到continue语句,跳过本次循环剩余部分');
|
||||
shouldContinue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// 使用预先计算好的精确行号,如果没有则使用调整后的行号
|
||||
let adjustedStatement;
|
||||
if (bodyStatement.exactLineNumber) {
|
||||
adjustedStatement = {
|
||||
...bodyStatement,
|
||||
lineNumber: bodyStatement.exactLineNumber
|
||||
};
|
||||
debugLog(`🎯 使用精确行号: "${bodyStatement.content}" -> 第${bodyStatement.exactLineNumber}行`);
|
||||
} else {
|
||||
adjustedStatement = this.adjustStatementLineNumber.call(this, bodyStatement);
|
||||
}
|
||||
await this.executeStatement(adjustedStatement);
|
||||
}
|
||||
|
||||
});
|
||||
} finally {
|
||||
this.currentExecutionContext = oldContext;
|
||||
}
|
||||
|
||||
this.currentExecutionContext = oldContext;
|
||||
|
||||
if (this.shouldStop()) break;
|
||||
if (this.shouldStop() || shouldBreak) break;
|
||||
|
||||
// 如果遇到continue,跳过执行增量,直接进入下次循环
|
||||
if (shouldContinue) {
|
||||
@@ -1730,43 +1761,48 @@ export class CppCodeExecutor {
|
||||
|
||||
let shouldContinue = false;
|
||||
|
||||
for (const bodyStatement of whileStatement.body) {
|
||||
if (this.shouldStop()) break;
|
||||
|
||||
// 检查是否是break或continue语句
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'break;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'break')) {
|
||||
debugLog('🔄 遇到break语句,退出while循环');
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'continue;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'continue')) {
|
||||
debugLog('🔄 遇到continue语句,跳过本次循环剩余部分');
|
||||
shouldContinue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// 使用预先计算好的精确行号,如果没有则使用调整后的行号
|
||||
let adjustedStatement;
|
||||
if (bodyStatement.exactLineNumber) {
|
||||
adjustedStatement = {
|
||||
...bodyStatement,
|
||||
lineNumber: bodyStatement.exactLineNumber
|
||||
};
|
||||
debugLog(`🎯 使用精确行号: "${bodyStatement.content}" -> 第${bodyStatement.exactLineNumber}行`);
|
||||
} else {
|
||||
adjustedStatement = this.adjustStatementLineNumber.call(this, bodyStatement);
|
||||
}
|
||||
await this.executeStatement(adjustedStatement);
|
||||
|
||||
// 在每个语句执行后重新检查循环条件(特别重要!)
|
||||
debugLog(`🔍 语句执行后重新检查条件: ${whileStatement.condition} = ${this.evaluateCondition(whileStatement.condition)}`);
|
||||
try {
|
||||
await this.withVariableScope(async () => {
|
||||
for (const bodyStatement of whileStatement.body) {
|
||||
if (this.shouldStop()) break;
|
||||
|
||||
// 检查是否是break或continue语句
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'break;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'break')) {
|
||||
debugLog('🔄 遇到break语句,退出while循环');
|
||||
shouldBreak = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((bodyStatement.content && bodyStatement.content.trim() === 'continue;') ||
|
||||
(bodyStatement.type === 'control' && bodyStatement.subtype === 'continue')) {
|
||||
debugLog('🔄 遇到continue语句,跳过本次循环剩余部分');
|
||||
shouldContinue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// 使用预先计算好的精确行号,如果没有则使用调整后的行号
|
||||
let adjustedStatement;
|
||||
if (bodyStatement.exactLineNumber) {
|
||||
adjustedStatement = {
|
||||
...bodyStatement,
|
||||
lineNumber: bodyStatement.exactLineNumber
|
||||
};
|
||||
debugLog(`🎯 使用精确行号: "${bodyStatement.content}" -> 第${bodyStatement.exactLineNumber}行`);
|
||||
} else {
|
||||
adjustedStatement = this.adjustStatementLineNumber.call(this, bodyStatement);
|
||||
}
|
||||
await this.executeStatement(adjustedStatement);
|
||||
|
||||
// 在每个语句执行后重新检查循环条件(特别重要!)
|
||||
debugLog(`🔍 语句执行后重新检查条件: ${whileStatement.condition} = ${this.evaluateCondition(whileStatement.condition)}`);
|
||||
}
|
||||
|
||||
});
|
||||
} finally {
|
||||
this.currentExecutionContext = oldContext;
|
||||
}
|
||||
|
||||
this.currentExecutionContext = oldContext;
|
||||
|
||||
if (shouldContinue) {
|
||||
continue; // 跳过本次循环的剩余部分,重新开始
|
||||
}
|
||||
@@ -1804,6 +1840,11 @@ export class CppCodeExecutor {
|
||||
throw new Error(`函数调用栈溢出: ${functionName} (可能存在无限递归)`);
|
||||
}
|
||||
|
||||
// 所有实参先在调用者作用域求值,避免前一个形参覆盖后一个实参。
|
||||
const argumentValues = callArguments.map(arg => this.evaluateExpression(arg));
|
||||
const callerVariables = this.variables;
|
||||
this.variables = new CppVariableScope(this.globalVariables);
|
||||
|
||||
// 将函数调用信息压入调用栈
|
||||
this.callStack.push({
|
||||
functionName: functionName,
|
||||
@@ -1812,21 +1853,14 @@ export class CppCodeExecutor {
|
||||
});
|
||||
|
||||
try {
|
||||
// 最小改动:防递归数据污染,只备份会被覆盖的同名参数变量
|
||||
const savedParams = new Map();
|
||||
for (let i = 0; i < functionInfo.parameters.length; i++) {
|
||||
const pName = functionInfo.parameters[i].name;
|
||||
if (this.variables.has(pName)) savedParams.set(pName, this.variables.get(pName));
|
||||
}
|
||||
|
||||
// 设置函数参数变量
|
||||
for (let i = 0; i < functionInfo.parameters.length; i++) {
|
||||
const param = functionInfo.parameters[i];
|
||||
const argValue = this.evaluateExpression(callArguments[i]);
|
||||
const argValue = argumentValues[i];
|
||||
|
||||
// 类型检查和转换
|
||||
const convertedValue = this.convertArgumentToType(argValue, param.type);
|
||||
this.variables.set(param.name, convertedValue);
|
||||
this.variables.declare(param.name, convertedValue);
|
||||
|
||||
console.log(`📋 设置参数: ${param.name} (${param.type}) = ${convertedValue}`);
|
||||
}
|
||||
@@ -1859,19 +1893,10 @@ export class CppCodeExecutor {
|
||||
if (e.message !== 'RETURN_INTERRUPT') throw e;
|
||||
}
|
||||
|
||||
// 最小改动:仅恢复递归调用前的参数状态,保留全局变量的修改
|
||||
for (let i = 0; i < functionInfo.parameters.length; i++) {
|
||||
const pName = functionInfo.parameters[i].name;
|
||||
if (savedParams.has(pName)) {
|
||||
this.variables.set(pName, savedParams.get(pName));
|
||||
} else {
|
||||
this.variables.delete(pName);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`✅ 函数${functionName}执行完成`);
|
||||
|
||||
} finally {
|
||||
this.variables = callerVariables;
|
||||
// 从调用栈中弹出当前函数
|
||||
const callInfo = this.callStack.pop();
|
||||
const executionTime = Date.now() - callInfo.startTime;
|
||||
@@ -2201,7 +2226,7 @@ export class CppCodeExecutor {
|
||||
// 处理复杂的cout语句
|
||||
executeCoutStatement(content) {
|
||||
// 移除cout和分号,获取输出内容
|
||||
let coutContent = content.replace(/^\s*cout\s*/, '').replace(/;\s*$/, '');
|
||||
const coutContent = content.replace(/^\s*(?:std\s*::\s*)?cout\s*/, '').replace(/;\s*$/, '');
|
||||
|
||||
// 按 << 分割
|
||||
const parts = this.splitCoutParts(coutContent);
|
||||
@@ -2211,14 +2236,14 @@ export class CppCodeExecutor {
|
||||
for (const part of parts) {
|
||||
const trimmedPart = part.trim();
|
||||
|
||||
if (trimmedPart === 'endl') {
|
||||
if (/^(?:std\s*::\s*)?endl$/.test(trimmedPart)) {
|
||||
output += '\n';
|
||||
} else if (trimmedPart.startsWith('"') && trimmedPart.endsWith('"')) {
|
||||
// 字符串字面量
|
||||
output += trimmedPart.slice(1, -1);
|
||||
output += this.decodeStringLiteral(trimmedPart);
|
||||
} else if (trimmedPart.startsWith("'") && trimmedPart.endsWith("'")) {
|
||||
// 字符字面量
|
||||
output += trimmedPart.slice(1, -1);
|
||||
output += this.decodeStringLiteral(trimmedPart);
|
||||
} else if (trimmedPart.startsWith('(') && trimmedPart.endsWith(')')) {
|
||||
// 括号表达式
|
||||
const expr = trimmedPart.slice(1, -1);
|
||||
@@ -2233,7 +2258,13 @@ export class CppCodeExecutor {
|
||||
window.cppGameAPI.cmdPrint(output);
|
||||
}
|
||||
|
||||
// 智能分割cout的各个部分
|
||||
// 解码输出中的常用 C++ 转义字符。
|
||||
decodeStringLiteral(literal) {
|
||||
const escapes = {n: '\n', r: '\r', t: '\t', '0': '\0', '\\': '\\', '"': '"', "'": "'"};
|
||||
return literal.slice(1, -1).replace(/\\([nrt0\\"'])/g, (match, char) => escapes[char]);
|
||||
}
|
||||
|
||||
// 按字符串和括号边界分割输出流。
|
||||
splitCoutParts(content) {
|
||||
const parts = [];
|
||||
let current = '';
|
||||
@@ -2244,6 +2275,12 @@ export class CppCodeExecutor {
|
||||
for (let i = 0; i < content.length; i++) {
|
||||
const char = content[i];
|
||||
const nextChar = content[i + 1];
|
||||
|
||||
if (inString && char === '\\' && nextChar !== undefined) {
|
||||
current += char + nextChar;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inString && inParens === 0 && char === '<' && nextChar === '<') {
|
||||
// 遇到 << 分隔符
|
||||
@@ -2284,6 +2321,11 @@ export class CppCodeExecutor {
|
||||
expr = expr.trim().replace(/;$/, '');
|
||||
debugLog(`🔍 计算表达式: ${expr}`);
|
||||
|
||||
// 字符串中的 ++、-- 和函数名都是文本,不参与表达式运算。
|
||||
if (/^("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')$/.test(expr)) {
|
||||
return this.decodeStringLiteral(expr);
|
||||
}
|
||||
|
||||
// 布尔常量
|
||||
if (expr === 'true') {
|
||||
debugLog(`🔍 布尔常量: true = 1`);
|
||||
@@ -2338,7 +2380,7 @@ export class CppCodeExecutor {
|
||||
const newValue = currentValue + 1;
|
||||
this.variables.set(varName, newValue);
|
||||
console.log(`🔄 自增操作: ${expr} (${currentValue} -> ${newValue})`);
|
||||
return newValue;
|
||||
return expr.startsWith('++') ? newValue : currentValue;
|
||||
}
|
||||
|
||||
if (expr.includes('--')) {
|
||||
@@ -2356,7 +2398,7 @@ export class CppCodeExecutor {
|
||||
const newValue = currentValue - 1;
|
||||
this.variables.set(varName, newValue);
|
||||
console.log(`🔄 自减操作: ${expr} (${currentValue} -> ${newValue})`);
|
||||
return newValue;
|
||||
return expr.startsWith('--') ? newValue : currentValue;
|
||||
}
|
||||
|
||||
// 游戏API函数调用
|
||||
@@ -2386,12 +2428,6 @@ export class CppCodeExecutor {
|
||||
return position;
|
||||
}
|
||||
|
||||
// 整个表达式是字符串字面量时才当字符串;含引号的 API 调用走后面的算术解析
|
||||
if ((expr.startsWith('"') && expr.endsWith('"')) ||
|
||||
(expr.startsWith("'") && expr.endsWith("'"))) {
|
||||
return expr.slice(1, -1);
|
||||
}
|
||||
|
||||
return this.parseComplexExpression(expr);
|
||||
}
|
||||
|
||||
@@ -3720,4 +3756,4 @@ export const testCompleteIfElseIfElse = async () => {
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -645,17 +645,21 @@ const StageWrapperCppClang = () => {
|
||||
textStr = String(text);
|
||||
}
|
||||
|
||||
window.cmd_print_text += textStr + '\n';
|
||||
// cout 自己决定何时换行,连续输出应保持在同一行。
|
||||
window.cmd_print_text += textStr;
|
||||
const lines = window.cmd_print_text.split('\n');
|
||||
if (lines.length > 20) {
|
||||
window.cmd_print_text = lines.slice(lines.length - 20).join('\n');
|
||||
}
|
||||
|
||||
setCompilationOutput(prev => prev + textStr);
|
||||
if (window.unityInstance) {
|
||||
window.unityInstance.SendMessage("UIMain", "SetText", window.cmd_print_text);
|
||||
try {
|
||||
window.unityInstance.SendMessage("UIMain", "SetText", window.cmd_print_text);
|
||||
} catch (error) {
|
||||
console.warn('游戏画面输出失败,文本仍可在运行输出中查看', error);
|
||||
}
|
||||
}
|
||||
|
||||
setCompilationOutput(prev => prev + textStr + "\n");
|
||||
},
|
||||
|
||||
player_data: (direction) => {
|
||||
@@ -795,6 +799,7 @@ const StageWrapperCppClang = () => {
|
||||
setCompilationOutput(prev => prev + "语法检查通过!\n");
|
||||
|
||||
// 重置停止标志
|
||||
window.cmd_print_text = '';
|
||||
window.isScriptRunOver = false;
|
||||
setIsRunning(true);
|
||||
setOverlayActive(true);
|
||||
@@ -969,7 +974,7 @@ const StageWrapperCppClang = () => {
|
||||
<div className={styles.errorModalOverlay}>
|
||||
<div className={styles.errorModal}>
|
||||
<div className={styles.errorModalHeader}>
|
||||
<h3>编译信息</h3>
|
||||
<h3>运行输出</h3>
|
||||
<div style={{ display: 'flex', gap: '10px' }}>
|
||||
<button
|
||||
onClick={() => setCompilationOutput('')}
|
||||
@@ -1121,6 +1126,13 @@ const StageWrapperCppClang = () => {
|
||||
<div className={styles.apiDrawer}>
|
||||
<div className={styles.apiDrawerHeader}>
|
||||
<h3>🔧 C++ API参考</h3>
|
||||
<button
|
||||
type="button"
|
||||
className={styles.apiDrawerInsertButton}
|
||||
onClick={() => setCompilationModalVisible(true)}
|
||||
>
|
||||
查看输出
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className={styles.apiDrawerContent}>
|
||||
@@ -1353,4 +1365,4 @@ const StageWrapperCppClang = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default StageWrapperCppClang;
|
||||
export default StageWrapperCppClang;
|
||||
|
||||
@@ -11,7 +11,6 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js';
|
||||
// const friendToggle = new FriendToggle();
|
||||
window.RankBadgeGenerator = RankBadgeGenerator;
|
||||
window.CONFIG = CONFIG;
|
||||
import disableDevtool from 'disable-devtool';
|
||||
import { initDisableDevtool } from '../../playground/devtool-control.js';
|
||||
import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js';
|
||||
import { debug } from 'scratch-vm/src/util/log.js';
|
||||
@@ -561,7 +560,7 @@ const UnityComponent = function (props) {
|
||||
|
||||
useEffect(() => {
|
||||
if (CONFIG.disabledev) {
|
||||
disableDevtool({
|
||||
initDisableDevtool({
|
||||
ondevtoolopen: () => {
|
||||
|
||||
// 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗
|
||||
@@ -1892,4 +1891,4 @@ UnityComponent.propTypes = {
|
||||
vm: PropTypes.instanceOf(VM).isRequired
|
||||
};
|
||||
|
||||
export default UnityComponent;
|
||||
export default UnityComponent;
|
||||
|
||||
@@ -11,7 +11,6 @@ import RankBadgeGenerator from '../../playground/rank-badge-generator.js';
|
||||
// const friendToggle = new FriendToggle();
|
||||
window.RankBadgeGenerator = RankBadgeGenerator;
|
||||
window.CONFIG = CONFIG;
|
||||
import disableDevtool from 'disable-devtool';
|
||||
import { initDisableDevtool } from '../../playground/devtool-control.js';
|
||||
import { getUnityPlayerConfig, loadUnityLoaderScript } from '../../lib/unity-build-loader.js';
|
||||
import { debug } from 'scratch-vm/src/util/log.js';
|
||||
@@ -755,7 +754,7 @@ const UnityComponent = function (props) {
|
||||
|
||||
useEffect(() => {
|
||||
if (CONFIG.disabledev) {
|
||||
disableDevtool({
|
||||
initDisableDevtool({
|
||||
ondevtoolopen: () => {
|
||||
|
||||
// 临时禁用 onbeforeunload 事件监听,以防止弹出确认离开弹窗
|
||||
@@ -2162,4 +2161,4 @@ UnityComponent.propTypes = {
|
||||
vm: PropTypes.instanceOf(VM).isRequired
|
||||
};
|
||||
|
||||
export default UnityComponent;
|
||||
export default UnityComponent;
|
||||
|
||||
@@ -1325,7 +1325,7 @@
|
||||
<h2 class="cta-title">灵丌编程(001CODE)城市合伙人招募中</h2>
|
||||
</div>
|
||||
<div class="cta-grid">
|
||||
<a href="mailto:contact@001Code.com" class="contact-card">
|
||||
<a href="mailto:support@shxshf.com" class="contact-card">
|
||||
<div class="icon-box">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="2" y="4" width="20" height="16" rx="2"></rect>
|
||||
@@ -1334,11 +1334,11 @@
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<span class="card-label">邮箱地址</span>
|
||||
<span class="card-value">wangshenxing@shxshf.com</span>
|
||||
<span class="card-value">support@shxshf.com</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<button class="contact-card" onclick="navigator.clipboard.writeText('17380126742')">
|
||||
<button class="contact-card" onclick="navigator.clipboard.writeText('400-659-1659')">
|
||||
<div class="icon-box">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
@@ -1348,7 +1348,7 @@
|
||||
</div>
|
||||
<div class="card-info">
|
||||
<span class="card-label">咨询热线</span>
|
||||
<span class="card-value">135-2066-2111</span>
|
||||
<span class="card-value">400-659-1659</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// 导入配置信息
|
||||
import CONFIG from './config.js';
|
||||
import disableDevtool from 'disable-devtool';
|
||||
import { initDisableDevtool } from './devtool-control.js';
|
||||
|
||||
|
||||
// 获取 URL 参数的函数
|
||||
@@ -166,7 +166,7 @@ function showPlatformGuide() {
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (CONFIG.disabledev) {
|
||||
disableDevtool({
|
||||
initDisableDevtool({
|
||||
ondevtoolopen: () => {
|
||||
// window.location.href = '/index.html';
|
||||
// window.location.href = localStorage.getItem('returnUrl');
|
||||
@@ -3449,4 +3449,4 @@ function getLanguageName(t) {
|
||||
}
|
||||
|
||||
// 导出函数,以便其他模块可以使用
|
||||
export { getUrlParameter, fetchCompetitionInfo };
|
||||
export { getUrlParameter, fetchCompetitionInfo };
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import CONFIG from './config.js';
|
||||
import disableDevtool from 'disable-devtool';
|
||||
import { initDisableDevtool } from './devtool-control.js';
|
||||
let gamelvdata = {};
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
if (CONFIG.disabledev) {
|
||||
disableDevtool({
|
||||
initDisableDevtool({
|
||||
ondevtoolopen: () => {
|
||||
},
|
||||
interval: 500,
|
||||
|
||||
@@ -183,7 +183,7 @@ const CONFIG = {
|
||||
|
||||
|
||||
|
||||
disabledev: false,
|
||||
disabledev: true,
|
||||
usecdn: false,
|
||||
lvlock: false,
|
||||
lvlock_normal_learn: !(typeof localStorage !== 'undefined' &&
|
||||
|
||||
@@ -2,8 +2,10 @@ import disableDevtool from 'disable-devtool';
|
||||
import CONFIG from './config.js';
|
||||
|
||||
const STOP_DEV_KEY = 'stopDev';
|
||||
let stoppedForPage = false;
|
||||
|
||||
function isStopped() {
|
||||
if (stoppedForPage) return true;
|
||||
try {
|
||||
return sessionStorage.getItem(STOP_DEV_KEY) === '1';
|
||||
} catch (e) {
|
||||
@@ -16,6 +18,8 @@ function isStopped() {
|
||||
* 可在控制台直接执行:stopDev()
|
||||
*/
|
||||
export function stopDev() {
|
||||
// 即使浏览器拒绝写入 sessionStorage,当前页面仍应立即停止检测。
|
||||
stoppedForPage = true;
|
||||
try {
|
||||
sessionStorage.setItem(STOP_DEV_KEY, '1');
|
||||
} catch (e) {
|
||||
@@ -29,6 +33,8 @@ export function initDisableDevtool(options = {}) {
|
||||
|
||||
if (isStopped()) {
|
||||
disableDevtool.isSuspend = true;
|
||||
// F12 已打开时,库可能在初始化期间立即触发检测,不能继续初始化。
|
||||
return;
|
||||
}
|
||||
|
||||
if (!CONFIG.disabledev) {
|
||||
@@ -36,14 +42,19 @@ export function initDisableDevtool(options = {}) {
|
||||
}
|
||||
|
||||
const userIgnore = options.ignore;
|
||||
const onDevtoolOpen = options.ondevtoolopen || (() => {
|
||||
window.location.href = localStorage.getItem('returnUrl');
|
||||
});
|
||||
disableDevtool({
|
||||
ondevtoolopen: () => {
|
||||
window.location.href = localStorage.getItem('returnUrl');
|
||||
},
|
||||
interval: 500,
|
||||
clearLog: true,
|
||||
disableMenu: true,
|
||||
...options,
|
||||
ondevtoolopen: (...args) => {
|
||||
// stopDev() 之后,已排队的检测回调也不能清空代码或跳转。
|
||||
if (isStopped()) return;
|
||||
return onDevtoolOpen(...args);
|
||||
},
|
||||
ignore: () => {
|
||||
if (isStopped()) {
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user