8#include <simplesquirrel/simplesquirrel.hpp>
16#include "physfs/physfs.h"
23bool readViaPhysFS(
const char*
path, std::string& out) {
24 if (!PHYSFS_isInit() || !PHYSFS_exists(
path))
return false;
25 PHYSFS_file*
f = PHYSFS_openRead(
path);
27 const PHYSFS_uint64 len = PHYSFS_fileLength(
f);
28 out.resize(
static_cast<size_t>(len));
29 if (len > 0 && PHYSFS_readBytes(
f, out.data(), len) !=
static_cast<PHYSFS_sint64
>(len)) {
38bool readViaOS(
const char*
path, std::string& out) {
39 std::ifstream ifs(
path, std::ios::binary);
40 if (!ifs)
return false;
41 out.assign(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
45bool readFileContent(
const char*
path, std::string& out) {
46 if (readViaPhysFS(
path, out) && !out.empty())
return true;
48 return readViaOS(
path, out);
55std::string scriptUriFromPath(
const char*
path) {
57 for (
char& ch :
uri) {
58 if (ch ==
'\\') ch =
'/';
60 const size_t scheme =
uri.find(
":/");
61 const bool drive =
uri.size() >= 2 &&
uri[1] ==
':';
62 if (scheme != std::string::npos && !drive)
return uri;
63 while (
uri.rfind(
"./", 0) == 0)
uri.erase(0, 2);
64 while (!
uri.empty() &&
uri.front() ==
'/')
uri.erase(0, 1);
65 return "game:/" +
uri;
70 const SQChar*
path =
nullptr;
71 if (SQ_FAILED(sq_getstring(
vm, 2, &
path)) || !
path)
72 return sq_throwerror(
vm,
"expected a script filename");
75 if (!readFileContent(
path, content))
76 return sq_throwerror(
vm,
"cannot open script");
79 if (content.size() >= 3 && (
unsigned char)content[0] == 0xEF &&
80 (
unsigned char)content[1] == 0xBB && (
unsigned char)content[2] == 0xBF)
83 const std::string
uri = scriptUriFromPath(
path);
85 static_cast<SQInteger
>(content.size()),
86 uri.c_str(), SQTrue)))
93 rt->scriptModules().instantiateDependencies(
uri);
94 }
catch (
const std::exception&
error) {
96 return sq_throwerror(
vm,
error.what());
102 sq_pushroottable(
vm);
103 if (SQ_FAILED(sq_call(
vm, 1, SQFalse, SQTrue)))
return SQ_ERROR;
108SQInteger sq_dofile(
HSQUIRRELVM vm) {
return compileAndMaybeRun(
vm,
true); }
109SQInteger sq_loadfile(
HSQUIRRELVM vm) {
return compileAndMaybeRun(
vm,
false); }
113bool getThisStr(
HSQUIRRELVM vm,
const SQChar* field, std::string& out) {
114 sq_pushstring(
vm, field, -1);
115 if (SQ_SUCCEEDED(sq_get(
vm, 1))) {
116 const SQChar*
s =
nullptr;
117 if (SQ_SUCCEEDED(sq_getstring(
vm, -1, &
s)) &&
s) out =
s;
131 if (!getThisStr(
vm, _SC(
"_data"), data))
return sq_throwerror(
vm,
"file not readable");
132 sq_pushstring(
vm, data.c_str(),
static_cast<SQInteger
>(data.size()));
138 if (!getThisStr(
vm, _SC(
"_data"), data))
return sq_throwerror(
vm,
"file not readable");
139 sq_pushinteger(
vm,
static_cast<SQInteger
>(data.size()));
144 sq_pushbool(
vm, SQTrue);
149 sq_pushinteger(
vm, 0);
154 sq_pushbool(
vm, SQTrue);
160 getThisStr(
vm, _SC(
"_path"),
path);
161 sq_pushstring(
vm,
path.c_str(),
static_cast<SQInteger
>(
path.size()));
166 const SQChar*
path =
nullptr;
167 const SQChar* mode =
nullptr;
168 if (SQ_FAILED(sq_getstring(
vm, 2, &
path)) || SQ_FAILED(sq_getstring(
vm, 3, &mode)))
169 return sq_throwerror(
vm,
"file: expected (path, mode)");
171 std::string
m(mode ? mode :
"");
172 const bool writing =
m.find(
'w') != std::string::npos ||
m.find(
'a') != std::string::npos;
178 if (!readFileContent(
path, content))
179 return sq_throwerror(
vm,
"cannot open file");
186 sq_pushstring(
vm,
"_path", -1);
187 sq_pushstring(
vm,
path, -1);
188 sq_newslot(
vm, -3, SQFalse);
189 sq_pushstring(
vm,
"_data", -1);
190 sq_pushstring(
vm, content.c_str(),
static_cast<SQInteger
>(content.size()));
191 sq_newslot(
vm, -3, SQFalse);
193 struct {
const SQChar*
name; SQFUNCTION
fn; } methods[] = {
194 {_SC(
"close"), sq_f_close},
195 {_SC(
"read"), sq_f_read},
196 {_SC(
"readString"), sq_f_read},
197 {_SC(
"getSize"), sq_f_getSize},
198 {_SC(
"isEOF"), sq_f_isEOF},
199 {_SC(
"tell"), sq_f_tell},
200 {_SC(
"seek"), sq_f_seek},
201 {_SC(
"getFilename"), sq_f_getFilename},
203 for (
const auto& mth : methods) {
204 sq_pushstring(
vm, mth.name, -1);
205 sq_newclosure(
vm, mth.fn, 0);
206 sq_newslot(
vm, -3, SQFalse);
215 const SQInteger
top = sq_gettop(
h);
217 struct {
const SQChar*
name; SQFUNCTION
fn; } globals[] = {
218 {_SC(
"dofile"), sq_dofile},
219 {_SC(
"loadfile"), sq_loadfile},
220 {_SC(
"file"), sq_file},
222 for (
const auto&
g : globals) {
224 sq_pushstring(
h,
g.name, -1);
225 sq_newclosure(
h,
g.fn, 0);
226 sq_newslot(
h, -3, SQTrue);
struct SQVM * HSQUIRRELVM
static Runtime * runtime()
Active runtime associated with the last expose() call, or nullptr. @ownership Borrowed; the embedding...
static Runtime * current() noexcept
The runtime currently at the top of this thread's runtime stack, or nullptr.
static SQRESULT compileBuffer(HSQUIRRELVM vm, const SQChar *source, SQInteger size, const SQChar *sourceName, SQBool raiseError)
Unified raw-VM entry used by REPL, debugger, MCP, and editor adapters.
void installScriptFileApi(ssq::VM &vm)
用 PhysFS 版本覆盖 Squirrel 的 file / dofile / loadfile 全局, 使脚本与资源从已挂载的游戏源(真实目录或内存挂载的 .eve 归档)解析; PhysFS 中不...
Build metadata (engine git commit, build time, third-party version).
SettlementPipeline::Stage fn