Files
lity3d/Engine/VisualScript/block_executor.c
T
shuiyu1123 0669d102ce feat: major engine overhaul - scene demo with lighting, sphere, ground
- Scene Demo: cube + sphere + ground plane with proper lighting
- Audio: XAudio2 dynamic loading + WAV playback
- Physics: expanded collision system
- Renderer: improved pipeline with materials
- UI: extended widget system
- VisualScript: enhanced serializer + block interactions
- ASM: optimized math/memory/profiling routines
- Window: mouse input + scroll support
2026-07-12 08:21:07 +08:00

466 lines
16 KiB
C

// ============================================================================
// block_executor.c - 积木执行引擎 (完整实现)
// ============================================================================
#include "block_executor.h"
#include "block_types.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
// 日志回调
typedef void (*LogCallback)(const char* msg, int level);
static LogCallback g_log_cb = NULL;
static void log_info(const char* fmt, ...) {
char buf[512]; va_list args; va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args); va_end(args);
if (g_log_cb) g_log_cb(buf, 0); else printf("[INFO] %s\n", buf);
}
static void log_error(const char* fmt, ...) {
char buf[512]; va_list args; va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args); va_end(args);
if (g_log_cb) g_log_cb(buf, 2); else printf("[ERROR] %s\n", buf);
}
void executor_set_log_callback(LogCallback cb) { g_log_cb = cb; }
// 值辅助
static SlotValue make_number(double v) { SlotValue v2; v2.type = SLOT_VALUE_NUMBER; v2.as.number = v; return v2; }
static SlotValue make_string(const char* s) { SlotValue v; v.type = SLOT_VALUE_STRING; strncpy(v.as.string, s, 255); return v; }
static SlotValue make_bool(int b) { SlotValue v; v.type = SLOT_VALUE_BOOLEAN; v.as.boolean = b; return v; }
static SlotValue make_vec3(float x, float y, float z) { SlotValue v; v.type = SLOT_VALUE_VECTOR3; v.as.vector3.x = x; v.as.vector3.y = y; v.as.vector3.z = z; return v; }
// 连接追踪:获取槽位的输入值(通过连线回溯)
static SlotValue get_connected_value(BlockSlot* slot) {
if (slot->connected) return slot->connected->value;
return slot->value;
}
BlockExecutor* executor_create(BlockWorkspace* ws) {
BlockExecutor* exec = (BlockExecutor*)calloc(1, sizeof(BlockExecutor));
if (!exec) return NULL;
exec->workspace = ws;
return exec;
}
void executor_destroy(BlockExecutor* exec) { free(exec); }
void executor_start(BlockExecutor* exec) {
exec->state = EXEC_RUNNING;
exec->call_stack_top = 0;
exec->loop_stack_top = 0;
exec->current_block = NULL;
for (int i = 0; i < exec->workspace->block_count; i++) {
Block* block = exec->workspace->blocks[i];
if (block->type == BLOCK_EVENT_START) {
exec->current_block = block;
log_info("执行器启动: 找到 on_start 事件");
return;
}
}
log_error("未找到 on_start 事件积木");
exec->state = EXEC_IDLE;
}
void executor_stop(BlockExecutor* exec) { exec->state = EXEC_IDLE; exec->current_block = NULL; }
void executor_pause(BlockExecutor* exec) { if (exec->state == EXEC_RUNNING) exec->state = EXEC_PAUSED; }
void executor_resume(BlockExecutor* exec) { if (exec->state == EXEC_PAUSED) exec->state = EXEC_RUNNING; }
// 获取下一个执行的积木(通过输出端口连接)
static Block* next_from_output(Block* block, int output_index) {
if (output_index >= block->output_count) return NULL;
BlockSlot* out = &block->outputs[output_index];
if (out->connected && out->connected->owner) return out->connected->owner;
return NULL;
}
// 查找循环体链的最后一个积木(用于确定循环结束后应跳转到的积木)
static Block* find_loop_body_end(Block* loop_block) {
if (!loop_block || loop_block->output_count == 0 || !loop_block->outputs[0].connected) return NULL;
Block* cur = loop_block->outputs[0].connected->owner;
Block* prev = loop_block;
int guard = 0;
while (cur && guard < 1000) {
guard++;
if (cur == loop_block) return prev; // 回到循环头,则前一个为体尾
Block* next = NULL;
if (cur->output_count > 0 && cur->outputs[0].connected) {
next = cur->outputs[0].connected->owner;
}
if (!next) return cur;
prev = cur;
cur = next;
}
return cur;
}
// 获取值输入
static SlotValue get_input(Block* block, int idx) {
if (idx >= block->input_count) return make_number(0);
return get_connected_value(&block->inputs[idx]);
}
void executor_step(BlockExecutor* exec) {
if (!exec->current_block) { exec->state = EXEC_IDLE; return; }
Block* cur = exec->current_block;
Block* next = NULL;
switch (cur->type) {
// === 事件 ===
case BLOCK_EVENT_START:
case BLOCK_EVENT_UPDATE:
case BLOCK_EVENT_COLLISION:
case BLOCK_EVENT_MOUSE_CLICK:
next = next_from_output(cur, 0);
break;
case BLOCK_EVENT_KEY_PRESSED: {
const char* key = get_input(cur, 0).as.string;
log_info("事件: 按键 '%s' (需要引擎集成)", key);
next = next_from_output(cur, 0);
break;
}
case BLOCK_EVENT_TIMER: {
double interval = get_input(cur, 0).as.number;
log_info("事件: 定时器 %.1fs (需要引擎集成)", interval);
next = next_from_output(cur, 0);
break;
}
// === 动作 ===
case BLOCK_ACTION_MOVE: {
double x = get_input(cur, 1).as.number;
double y = get_input(cur, 2).as.number;
double z = get_input(cur, 3).as.number;
log_info("移动物体: (%.2f, %.2f, %.2f)", x, y, z);
next = next_from_output(cur, 0);
break;
}
case BLOCK_ACTION_ROTATE: {
double x = get_input(cur, 1).as.number;
double y = get_input(cur, 2).as.number;
double z = get_input(cur, 3).as.number;
log_info("旋转物体: (%.2f, %.2f, %.2f)", x, y, z);
next = next_from_output(cur, 0);
break;
}
case BLOCK_ACTION_SCALE: {
double x = get_input(cur, 1).as.number;
double y = get_input(cur, 2).as.number;
double z = get_input(cur, 3).as.number;
log_info("缩放物体: (%.2f, %.2f, %.2f)", x, y, z);
next = next_from_output(cur, 0);
break;
}
case BLOCK_ACTION_SET_POSITION: {
double x = get_input(cur, 1).as.number;
double y = get_input(cur, 2).as.number;
double z = get_input(cur, 3).as.number;
log_info("设置位置: (%.2f, %.2f, %.2f)", x, y, z);
next = next_from_output(cur, 0);
break;
}
case BLOCK_ACTION_SET_ROTATION: {
double x = get_input(cur, 1).as.number;
double y = get_input(cur, 2).as.number;
double z = get_input(cur, 3).as.number;
log_info("设置旋转: (%.2f, %.2f, %.2f)", x, y, z);
next = next_from_output(cur, 0);
break;
}
case BLOCK_ACTION_PLAY_SOUND: {
const char* name = get_input(cur, 1).as.string;
log_info("播放音效: '%s'", name);
next = next_from_output(cur, 0);
break;
}
case BLOCK_ACTION_DESTROY:
log_info("销毁物体");
next = next_from_output(cur, 0);
break;
case BLOCK_ACTION_INSTANTIATE: {
const char* prefab = get_input(cur, 1).as.string;
log_info("实例化预制体: '%s'", prefab);
next = next_from_output(cur, 0);
break;
}
// === 控制流 ===
case BLOCK_CONTROL_IF:
case BLOCK_CONTROL_IF_ELSE: {
int cond = get_input(cur, 1).as.boolean;
log_info("如果 %s", cond ? "真 -> Then" : "假 -> Else");
next = next_from_output(cur, cond ? 0 : 1);
break;
}
case BLOCK_CONTROL_REPEAT:
case BLOCK_CONTROL_WHILE: {
int cond = get_input(cur, 1).as.boolean;
LoopFrame* frame = NULL;
if (exec->loop_stack_top > 0 && exec->loop_stack[exec->loop_stack_top - 1].loop_block == cur) {
frame = &exec->loop_stack[exec->loop_stack_top - 1];
} else {
if (exec->loop_stack_top < MAX_LOOP_STACK) {
frame = &exec->loop_stack[exec->loop_stack_top++];
frame->loop_block = cur;
frame->counter = 0;
frame->target = 0;
Block* body_end = find_loop_body_end(cur);
frame->after_block = body_end ? next_from_output(body_end, 0) : NULL;
}
}
if (frame && cond) {
frame->counter++;
next = next_from_output(cur, 0);
} else {
if (frame) exec->loop_stack_top--;
next = frame ? frame->after_block : next_from_output(cur, 0);
}
break;
}
case BLOCK_CONTROL_REPEAT_TIMES: {
double times = get_input(cur, 1).as.number;
LoopFrame* frame = NULL;
if (exec->loop_stack_top > 0 && exec->loop_stack[exec->loop_stack_top - 1].loop_block == cur) {
frame = &exec->loop_stack[exec->loop_stack_top - 1];
frame->counter++;
} else {
if (exec->loop_stack_top < MAX_LOOP_STACK) {
frame = &exec->loop_stack[exec->loop_stack_top++];
frame->loop_block = cur;
frame->counter = 0;
frame->target = (int)times;
Block* body_end = find_loop_body_end(cur);
frame->after_block = body_end ? next_from_output(body_end, 0) : NULL;
}
}
if (frame && frame->counter < frame->target) {
log_info("循环 %d / %d", frame->counter + 1, frame->target);
next = next_from_output(cur, 0);
} else {
if (frame) exec->loop_stack_top--;
next = frame ? frame->after_block : next_from_output(cur, 0);
}
break;
}
case BLOCK_CONTROL_WAIT: {
double secs = get_input(cur, 1).as.number;
log_info("等待 %.1f 秒", secs);
exec->wait_timer = secs;
exec->state = EXEC_WAITING;
exec->current_block = next_from_output(cur, 0);
return;
}
case BLOCK_CONTROL_FUNCTION_DEF:
log_info("函数定义 (跳过)");
next = next_from_output(cur, 0);
break;
// === 运算 ===
case BLOCK_OP_ADD: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_number(a + b);
log_info("%.1f + %.1f = %.1f", a, b, a + b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_SUB: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_number(a - b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_MUL: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_number(a * b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_DIV: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_number(b != 0 ? a / b : 0);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_MOD: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_number(b != 0 ? fmod(a, b) : 0);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_EQUALS: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_bool(a == b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_NOT_EQUALS: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_bool(a != b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_GREATER: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_bool(a > b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_LESS: {
double a = get_input(cur, 0).as.number;
double b = get_input(cur, 1).as.number;
cur->outputs[0].value = make_bool(a < b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_AND: {
int a = get_input(cur, 0).as.boolean;
int b = get_input(cur, 1).as.boolean;
cur->outputs[0].value = make_bool(a && b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_OR: {
int a = get_input(cur, 0).as.boolean;
int b = get_input(cur, 1).as.boolean;
cur->outputs[0].value = make_bool(a || b);
next = next_from_output(cur, 0);
break;
}
case BLOCK_OP_NOT: {
int a = get_input(cur, 0).as.boolean;
cur->outputs[0].value = make_bool(!a);
next = next_from_output(cur, 0);
break;
}
// === 变量 ===
case BLOCK_VAR_GET: {
const char* name = cur->label;
SlotValue val = executor_get_variable(exec, name);
cur->outputs[0].value = val;
log_info("读取变量 '%s' = %.2f", name, val.as.number);
next = next_from_output(cur, 0);
break;
}
case BLOCK_VAR_SET: {
const char* name = cur->label;
SlotValue val = get_input(cur, 1);
executor_set_variable(exec, name, val);
log_info("设置变量 '%s' = %.2f", name, val.as.number);
next = next_from_output(cur, 0);
break;
}
case BLOCK_VAR_CREATE: {
const char* name = cur->label;
executor_create_variable(exec, name);
log_info("创建变量 '%s' = 0", name);
next = next_from_output(cur, 0);
break;
}
// === 函数 ===
case BLOCK_FUNC_CALL: {
const char* fname = get_input(cur, 1).as.string;
log_info("调用函数 '%s'", fname);
// 在工作区中查找同名函数定义积木
Block* def = NULL;
for (int i = 0; i < exec->workspace->block_count; i++) {
Block* b = exec->workspace->blocks[i];
if (b->type == BLOCK_CONTROL_FUNCTION_DEF && strcmp(b->label, fname) == 0) {
def = b;
break;
}
}
if (def && exec->call_stack_top < MAX_CALL_STACK) {
exec->call_stack[exec->call_stack_top].block = cur;
exec->call_stack[exec->call_stack_top].return_block = next_from_output(cur, 0);
exec->call_stack_top++;
next = next_from_output(def, 0);
} else {
if (!def) log_error("未找到函数定义: '%s'", fname);
next = next_from_output(cur, 0);
}
break;
}
case BLOCK_FUNC_RETURN: {
if (exec->call_stack_top > 0) {
exec->call_stack_top--;
next = exec->call_stack[exec->call_stack_top].return_block;
}
break;
}
default:
log_error("未知积木类型: %d", cur->type);
next = next_from_output(cur, 0);
break;
}
// 若当前 next 是某个活跃循环的 after_block,则跳转回循环头继续判断
if (next && exec->loop_stack_top > 0) {
LoopFrame* frame = &exec->loop_stack[exec->loop_stack_top - 1];
if (next == frame->after_block) {
next = frame->loop_block;
}
}
exec->current_block = next;
if (!exec->current_block) {
log_info("执行完成");
exec->state = EXEC_IDLE;
}
}
void executor_update(BlockExecutor* exec, double delta_time) {
if (exec->state == EXEC_WAITING) {
exec->wait_timer -= delta_time;
if (exec->wait_timer <= 0) exec->state = EXEC_RUNNING;
return;
}
if (exec->state != EXEC_RUNNING) return;
int steps = 0;
while (exec->current_block && exec->state == EXEC_RUNNING && steps < 1000) {
executor_step(exec);
steps++;
}
}
void executor_set_variable(BlockExecutor* exec, const char* name, SlotValue value) {
for (int i = 0; i < exec->variable_count; i++) {
if (strcmp(exec->variables[i].name, name) == 0) {
exec->variables[i].value = value;
return;
}
}
if (exec->variable_count < MAX_VARIABLES) {
Variable* var = &exec->variables[exec->variable_count++];
strncpy(var->name, name, 63);
var->value = value;
var->used = 1;
}
}
SlotValue executor_get_variable(BlockExecutor* exec, const char* name) {
for (int i = 0; i < exec->variable_count; i++) {
if (strcmp(exec->variables[i].name, name) == 0) return exec->variables[i].value;
}
return make_number(0);
}
void executor_create_variable(BlockExecutor* exec, const char* name) {
executor_set_variable(exec, name, make_number(0));
}