mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 06:15:04 +00:00
Add: [Script] Framework for loading/saving selected ScriptObject
This commit is contained in:
parent
8d63aea929
commit
d6a261439b
@ -347,7 +347,7 @@ foreach(LINE IN LISTS SOURCE_LINES)
|
||||
string(APPEND SQUIRREL_EXPORT "\nvoid SQ${API_CLS}_Register(Squirrel *engine)")
|
||||
string(APPEND SQUIRREL_EXPORT "\n{")
|
||||
string(APPEND SQUIRREL_EXPORT "\n DefSQClass<${CLS}, ScriptType::${APIUC}> SQ${API_CLS}(\"${API_CLS}\");")
|
||||
if("${SUPER_CLS}" STREQUAL "Text" OR "${SUPER_CLS}" STREQUAL "ScriptObject")
|
||||
if("${SUPER_CLS}" STREQUAL "Text")
|
||||
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PreRegister(engine);")
|
||||
else()
|
||||
string(APPEND SQUIRREL_EXPORT "\n SQ${API_CLS}.PreRegister(engine, \"${API_SUPER_CLS}\");")
|
||||
|
@ -399,6 +399,7 @@ enum SaveLoadVersion : uint16_t {
|
||||
|
||||
SLV_ENCODED_STRING_FORMAT, ///< 350 PR#13499 Encoded String format changed.
|
||||
SLV_PROTECT_PLACED_HOUSES, ///< 351 PR#13270 Houses individually placed by players can be protected from town/AI removal.
|
||||
SLV_SCRIPT_SAVE_INSTANCES, ///< 352 PR#13556 Scripts are allowed to save instances.
|
||||
|
||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||
};
|
||||
|
@ -9,7 +9,17 @@
|
||||
|
||||
${SQUIRREL_INCLUDES}
|
||||
|
||||
static SQInteger ${APIUC}ObjectConstructor(HSQUIRRELVM vm)
|
||||
{
|
||||
return sq_throwerror(vm, "${APIUC}Object is not instantiable");
|
||||
}
|
||||
|
||||
void SQ${APIUC}_RegisterAll(Squirrel *engine)
|
||||
{
|
||||
DefSQClass<ScriptObject, ScriptType::${APIUC}> SQ${APIUC}Object("${APIUC}Object");
|
||||
SQ${APIUC}Object.PreRegister(engine);
|
||||
SQ${APIUC}Object.DefSQAdvancedStaticMethod(engine, &${APIUC}ObjectConstructor, "constructor");
|
||||
SQ${APIUC}Object.PostRegister(engine);
|
||||
|
||||
${SQUIRREL_REGISTER}
|
||||
}
|
||||
|
@ -84,6 +84,22 @@ protected:
|
||||
static ScriptInstance *active; ///< The global current active instance.
|
||||
};
|
||||
|
||||
/**
|
||||
* Save this object.
|
||||
* Must push 2 elements on the stack:
|
||||
* - the name (classname without "Script") of the object (OT_STRING)
|
||||
* - the data for the object (any supported types)
|
||||
* @return True iff saving this type is supported.
|
||||
*/
|
||||
virtual bool SaveObject(HSQUIRRELVM) { return false; }
|
||||
|
||||
/**
|
||||
* Load this object.
|
||||
* The data for the object must be pushed on the stack before the call.
|
||||
* @return True iff loading this type is supported.
|
||||
*/
|
||||
virtual bool LoadObject(HSQUIRRELVM) { return false; }
|
||||
|
||||
public:
|
||||
/**
|
||||
* Store the latest result of a DoCommand per company.
|
||||
|
@ -480,6 +480,27 @@ static const SaveLoad _script_byte[] = {
|
||||
return true;
|
||||
}
|
||||
|
||||
case OT_INSTANCE:{
|
||||
if (!test) {
|
||||
_script_sl_byte = SQSL_INSTANCE;
|
||||
SlObject(nullptr, _script_byte);
|
||||
}
|
||||
SQInteger top = sq_gettop(vm);
|
||||
try {
|
||||
ScriptObject *obj = static_cast<ScriptObject *>(Squirrel::GetRealInstance(vm, -1, "Object"));
|
||||
if (!obj->SaveObject(vm)) throw std::exception();
|
||||
if (sq_gettop(vm) != top + 2) throw std::exception();
|
||||
if (sq_gettype(vm, -2) != OT_STRING || !SaveObject(vm, -2, max_depth - 1, test)) throw std::exception();
|
||||
if (!SaveObject(vm, -1, max_depth - 1, test)) throw std::exception();
|
||||
sq_settop(vm, top);
|
||||
return true;
|
||||
} catch (...) {
|
||||
ScriptLog::Error("You tried to save an unsupported type. No data saved.");
|
||||
sq_settop(vm, top);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
ScriptLog::Error("You tried to save an unsupported type. No data saved.");
|
||||
return false;
|
||||
@ -588,7 +609,7 @@ bool ScriptInstance::IsPaused()
|
||||
case SQSL_INT: {
|
||||
int64_t value;
|
||||
SlCopy(&value, 1, IsSavegameVersionBefore(SLV_SCRIPT_INT64) ? SLE_FILE_I32 | SLE_VAR_I64 : SLE_INT64);
|
||||
if (data != nullptr) data->push_back((SQInteger)value);
|
||||
if (data != nullptr) data->push_back(static_cast<SQInteger>(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -602,24 +623,29 @@ bool ScriptInstance::IsPaused()
|
||||
|
||||
case SQSL_ARRAY:
|
||||
case SQSL_TABLE: {
|
||||
if (data != nullptr) data->push_back((SQSaveLoadType)_script_sl_byte);
|
||||
if (data != nullptr) data->push_back(static_cast<SQSaveLoadType>(_script_sl_byte));
|
||||
while (LoadObjects(data));
|
||||
return true;
|
||||
}
|
||||
|
||||
case SQSL_BOOL: {
|
||||
SlObject(nullptr, _script_byte);
|
||||
if (data != nullptr) data->push_back((SQBool)(_script_sl_byte != 0));
|
||||
if (data != nullptr) data->push_back(static_cast<SQBool>(_script_sl_byte != 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
case SQSL_NULL: {
|
||||
if (data != nullptr) data->push_back((SQSaveLoadType)_script_sl_byte);
|
||||
if (data != nullptr) data->push_back(static_cast<SQSaveLoadType>(_script_sl_byte));
|
||||
return true;
|
||||
}
|
||||
|
||||
case SQSL_INSTANCE: {
|
||||
if (data != nullptr) data->push_back(static_cast<SQSaveLoadType>(_script_sl_byte));
|
||||
return true;
|
||||
}
|
||||
|
||||
case SQSL_ARRAY_TABLE_END: {
|
||||
if (data != nullptr) data->push_back((SQSaveLoadType)_script_sl_byte);
|
||||
if (data != nullptr) data->push_back(static_cast<SQSaveLoadType>(_script_sl_byte));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -663,6 +689,31 @@ bool ScriptInstance::IsPaused()
|
||||
sq_pushnull(this->vm);
|
||||
return true;
|
||||
|
||||
case SQSL_INSTANCE: {
|
||||
SQInteger top = sq_gettop(this->vm);
|
||||
LoadObjects(this->vm, this->data);
|
||||
const SQChar *buf;
|
||||
sq_getstring(this->vm, -1, &buf);
|
||||
Squirrel *engine = static_cast<Squirrel *>(sq_getforeignptr(this->vm));
|
||||
std::string class_name = fmt::format("{}{}", engine->GetAPIName(), buf);
|
||||
sq_pushroottable(this->vm);
|
||||
sq_pushstring(this->vm, class_name);
|
||||
if (SQ_FAILED(sq_get(this->vm, -2))) throw Script_FatalError(fmt::format("'{}' doesn't exist", class_name));
|
||||
sq_pushroottable(vm);
|
||||
if (SQ_FAILED(sq_call(this->vm, 1, SQTrue, SQFalse))) throw Script_FatalError(fmt::format("Failed to instantiate '{}'", class_name));
|
||||
HSQOBJECT res;
|
||||
sq_getstackobj(vm, -1, &res);
|
||||
sq_addref(vm, &res);
|
||||
sq_settop(this->vm, top);
|
||||
sq_pushobject(vm, res);
|
||||
sq_release(vm, &res);
|
||||
ScriptObject *obj = static_cast<ScriptObject *>(Squirrel::GetRealInstance(vm, -1, "Object"));
|
||||
LoadObjects(this->vm, this->data);
|
||||
if (!obj->LoadObject(vm)) throw Script_FatalError(fmt::format("Failed to load '{}'", class_name));
|
||||
sq_pop(this->vm, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
case SQSL_ARRAY_TABLE_END:
|
||||
return false;
|
||||
|
||||
|
@ -32,6 +32,7 @@ private:
|
||||
SQSL_TABLE = 0x03, ///< The following data is an table.
|
||||
SQSL_BOOL = 0x04, ///< The following data is a boolean.
|
||||
SQSL_NULL = 0x05, ///< A null variable.
|
||||
SQSL_INSTANCE = 0x06, ///< The following data is an instance.
|
||||
SQSL_ARRAY_TABLE_END = 0xFF, ///< Marks the end of an array or table, no data follows.
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,7 @@ struct ScriptAllocator;
|
||||
|
||||
class Squirrel {
|
||||
friend class ScriptAllocatorScope;
|
||||
friend class ScriptInstance;
|
||||
|
||||
private:
|
||||
typedef void (SQPrintFunc)(bool error_msg, const std::string &message);
|
||||
|
Loading…
Reference in New Issue
Block a user