mirror of
https://github.com/edubart/otclient.git
synced 2025-10-14 11:34:54 +02:00
a lot of changes in modules
This commit is contained in:
@@ -33,7 +33,7 @@ public:
|
||||
Event(const SimpleCallback& callback) : m_callback(callback), m_canceled(false), m_executed(false) { }
|
||||
|
||||
void execute() {
|
||||
if(!m_canceled && !m_executed) {
|
||||
if(!m_canceled && !m_executed && m_callback) {
|
||||
m_callback();
|
||||
m_executed = true;
|
||||
}
|
||||
|
@@ -52,8 +52,10 @@ bool Module::load()
|
||||
if(m_loadCallback)
|
||||
m_loadCallback();
|
||||
|
||||
logInfo("Loaded module '", m_name, "'");
|
||||
m_loaded = true;
|
||||
logInfo("Loaded module '", m_name, "'");
|
||||
g_modules.updateModuleLoadOrder(asModule());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -63,9 +65,33 @@ void Module::unload()
|
||||
if(m_unloadCallback)
|
||||
m_unloadCallback();
|
||||
m_loaded = false;
|
||||
logInfo("Unloaded module '", m_name, "'");
|
||||
g_modules.updateModuleLoadOrder(asModule());
|
||||
}
|
||||
}
|
||||
|
||||
bool Module::reload()
|
||||
{
|
||||
unload();
|
||||
return load();
|
||||
}
|
||||
|
||||
bool Module::isDependent()
|
||||
{
|
||||
for(const ModulePtr& module : g_modules.getModules()) {
|
||||
if(module->isLoaded() && module->hasDependency(m_name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Module::hasDependency(const std::string& name)
|
||||
{
|
||||
if(std::find(m_dependencies.begin(), m_dependencies.end(), name) != m_dependencies.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Module::discover(const OTMLNodePtr& moduleNode)
|
||||
{
|
||||
const static std::string none = "none";
|
||||
@@ -73,8 +99,9 @@ void Module::discover(const OTMLNodePtr& moduleNode)
|
||||
m_author = moduleNode->valueAt("author", none);
|
||||
m_website = moduleNode->valueAt("website", none);
|
||||
m_version = moduleNode->valueAt("version", none);
|
||||
m_autoLoad = moduleNode->valueAt<bool>("autoLoad", false);
|
||||
m_autoLoadAntecedence = moduleNode->valueAt<int>("autoLoadAntecedence", 100);
|
||||
m_autoLoad = moduleNode->valueAt<bool>("autoload", false);
|
||||
m_unloadable = moduleNode->valueAt<bool>("unloadable", true);
|
||||
m_autoLoadAntecedence = moduleNode->valueAt<int>("autoload-antecedence", 9999);
|
||||
|
||||
if(OTMLNodePtr node = moduleNode->get("dependencies")) {
|
||||
for(const OTMLNodePtr& tmp : node->children())
|
||||
@@ -95,4 +122,3 @@ void Module::discover(const OTMLNodePtr& moduleNode)
|
||||
m_unloadCallback = g_lua.polymorphicPop<SimpleCallback>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -35,8 +35,12 @@ public:
|
||||
|
||||
bool load();
|
||||
void unload();
|
||||
bool reload();
|
||||
|
||||
bool canUnload() { return m_loaded && m_unloadable && !isDependent(); }
|
||||
bool isLoaded() { return m_loaded; }
|
||||
bool isDependent();
|
||||
bool hasDependency(const std::string& name);
|
||||
|
||||
std::string getDescription() { return m_description; }
|
||||
std::string getName() { return m_name; }
|
||||
@@ -46,6 +50,8 @@ public:
|
||||
bool isAutoLoad() { return m_autoLoad; }
|
||||
int getAutoLoadAntecedence() { return m_autoLoadAntecedence; }
|
||||
|
||||
ModulePtr asModule() { return std::static_pointer_cast<Module>(shared_from_this()); }
|
||||
|
||||
protected:
|
||||
void discover(const OTMLNodePtr& moduleNode);
|
||||
friend class ModuleManager;
|
||||
@@ -53,6 +59,7 @@ protected:
|
||||
private:
|
||||
Boolean<false> m_loaded;
|
||||
Boolean<false> m_autoLoad;
|
||||
Boolean<true> m_unloadable;
|
||||
int m_autoLoadAntecedence;
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
|
@@ -61,13 +61,13 @@ void ModuleManager::autoLoadModules(int maxAntecedence)
|
||||
void ModuleManager::discoverModulesPath()
|
||||
{
|
||||
// search for modules directory
|
||||
std::string possibleDirs[] = { "modules",
|
||||
g_resources.getBaseDir() + "modules",
|
||||
g_resources.getBaseDir() + "../modules",
|
||||
g_resources.getBaseDir() + "../share/" + g_app->getAppName() + "/modules",
|
||||
"" };
|
||||
std::string possibleModulesDirs[] = { "modules",
|
||||
g_resources.getBaseDir() + "modules",
|
||||
g_resources.getBaseDir() + "../modules",
|
||||
g_resources.getBaseDir() + "../share/" + g_app->getAppName() + "/modules",
|
||||
"" };
|
||||
bool found = false;
|
||||
for(const std::string& dir : possibleDirs) {
|
||||
for(const std::string& dir : possibleModulesDirs) {
|
||||
// try to add module directory
|
||||
if(g_resources.addToSearchPath(dir, false)) {
|
||||
logInfo("Using modules directory '", dir.c_str(), "'");
|
||||
@@ -78,6 +78,21 @@ void ModuleManager::discoverModulesPath()
|
||||
|
||||
if(!found)
|
||||
logFatal("Could not find modules directory");
|
||||
|
||||
// search for addons directory
|
||||
std::string possibleAddonsDirs[] = { "addons",
|
||||
g_resources.getBaseDir() + "addons",
|
||||
g_resources.getBaseDir() + "../addons",
|
||||
g_resources.getBaseDir() + "../addons/" + g_app->getAppName() + "/modules",
|
||||
"" };
|
||||
for(const std::string& dir : possibleAddonsDirs) {
|
||||
// try to add module directory
|
||||
if(g_resources.addToSearchPath(dir, false)) {
|
||||
logInfo("Using addons directory '", dir.c_str(), "'");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModulePtr ModuleManager::discoverModule(const std::string& moduleFile)
|
||||
@@ -99,6 +114,7 @@ ModulePtr ModuleManager::discoverModule(const std::string& moduleFile)
|
||||
}
|
||||
module->discover(moduleNode);
|
||||
|
||||
// not loaded modules are always in back
|
||||
if(push)
|
||||
m_modules.push_back(module);
|
||||
} catch(Exception& e) {
|
||||
@@ -116,10 +132,30 @@ void ModuleManager::ensureModuleLoaded(const std::string& moduleName)
|
||||
|
||||
void ModuleManager::unloadModules()
|
||||
{
|
||||
for(const ModulePtr& module : m_modules)
|
||||
auto modulesBackup = m_modules;
|
||||
for(const ModulePtr& module : modulesBackup)
|
||||
module->unload();
|
||||
}
|
||||
|
||||
void ModuleManager::reloadModules()
|
||||
{
|
||||
std::deque<ModulePtr> toLoadList;
|
||||
|
||||
// unload in the reverse direction, try to unload upto 10 times (because of dependencies)
|
||||
for(int i=0;i<10;++i) {
|
||||
auto modulesBackup = m_modules;
|
||||
for(const ModulePtr& module : modulesBackup) {
|
||||
if(module->isLoaded() && module->canUnload()) {
|
||||
module->unload();
|
||||
toLoadList.push_front(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(const ModulePtr& module : toLoadList)
|
||||
module->load();
|
||||
}
|
||||
|
||||
ModulePtr ModuleManager::getModule(const std::string& moduleName)
|
||||
{
|
||||
for(const ModulePtr& module : m_modules)
|
||||
@@ -127,3 +163,14 @@ ModulePtr ModuleManager::getModule(const std::string& moduleName)
|
||||
return module;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ModuleManager::updateModuleLoadOrder(ModulePtr module)
|
||||
{
|
||||
auto it = std::find(m_modules.begin(), m_modules.end(), module);
|
||||
if(it != m_modules.end())
|
||||
m_modules.erase(it);
|
||||
if(module->isLoaded())
|
||||
m_modules.push_front(module);
|
||||
else
|
||||
m_modules.push_back(module);
|
||||
}
|
||||
|
@@ -34,12 +34,18 @@ public:
|
||||
ModulePtr discoverModule(const std::string& moduleFile);
|
||||
void ensureModuleLoaded(const std::string& moduleName);
|
||||
void unloadModules();
|
||||
void reloadModules();
|
||||
|
||||
ModulePtr getModule(const std::string& moduleName);
|
||||
std::vector<ModulePtr> getModules() { return m_modules; }
|
||||
std::deque<ModulePtr> getModules() { return m_modules; }
|
||||
|
||||
protected:
|
||||
void updateModuleLoadOrder(ModulePtr module);
|
||||
|
||||
friend class Module;
|
||||
|
||||
private:
|
||||
std::vector<ModulePtr> m_modules;
|
||||
std::deque<ModulePtr> m_modules;
|
||||
std::multimap<int, ModulePtr> m_autoLoadModules;
|
||||
};
|
||||
|
||||
|
@@ -48,8 +48,16 @@ bool FontManager::importFont(std::string fontFile)
|
||||
OTMLNodePtr fontNode = doc->at("Font");
|
||||
|
||||
std::string name = fontNode->valueAt("name");
|
||||
if(fontExists(name))
|
||||
Fw::throwException("font '", name, "' already exists, cannot have duplicate font names");
|
||||
//if(fontExists(name))
|
||||
// Fw::throwException("font '", name, "' already exists, cannot have duplicate font names");
|
||||
|
||||
// remove any font with the same name
|
||||
for(auto it = m_fonts.begin(); it != m_fonts.end(); ++it) {
|
||||
if((*it)->getName() == name) {
|
||||
m_fonts.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FontPtr font(new Font(name));
|
||||
font->load(fontNode);
|
||||
|
@@ -47,11 +47,15 @@ void Application::registerLuaFunctions()
|
||||
|
||||
// Event
|
||||
g_lua.registerClass<Event>();
|
||||
g_lua.bindClassMemberFunction<Event>("cancel", &Event::cancel);
|
||||
g_lua.bindClassMemberFunction<Event>("execute", &Event::execute);
|
||||
g_lua.bindClassMemberFunction<Event>("isCanceled", &Event::isCanceled);
|
||||
g_lua.bindClassMemberFunction<Event>("isExecuted", &Event::isExecuted);
|
||||
|
||||
// ScheduledEvent
|
||||
g_lua.registerClass<ScheduledEvent, Event>();
|
||||
g_lua.bindClassMemberFunction<ScheduledEvent>("reamaningTicks", &ScheduledEvent::reamaningTicks);
|
||||
g_lua.bindClassMemberFunction<ScheduledEvent>("ticks", &ScheduledEvent::ticks);
|
||||
|
||||
// UIWidget
|
||||
g_lua.registerClass<UIWidget>();
|
||||
@@ -370,6 +374,8 @@ void Application::registerLuaFunctions()
|
||||
g_lua.registerClass<Module>();
|
||||
g_lua.bindClassMemberFunction<Module>("load", &Module::load);
|
||||
g_lua.bindClassMemberFunction<Module>("unload", &Module::unload);
|
||||
g_lua.bindClassMemberFunction<Module>("reload", &Module::reload);
|
||||
g_lua.bindClassMemberFunction<Module>("canUnload", &Module::canUnload);
|
||||
g_lua.bindClassMemberFunction<Module>("isLoaded", &Module::isLoaded);
|
||||
g_lua.bindClassMemberFunction<Module>("getDescription", &Module::getDescription);
|
||||
g_lua.bindClassMemberFunction<Module>("getName", &Module::getName);
|
||||
@@ -397,6 +403,8 @@ void Application::registerLuaFunctions()
|
||||
// Application
|
||||
g_lua.registerStaticClass("g_app");
|
||||
g_lua.bindClassStaticFunction("g_app", "exit", std::bind(&Application::exit, g_app));
|
||||
g_lua.bindClassStaticFunction("g_app", "isRunning", std::bind(&Application::isRunning, g_app));
|
||||
g_lua.bindClassStaticFunction("g_app", "isStopping", std::bind(&Application::isStopping, g_app));
|
||||
|
||||
// ConfigManager
|
||||
g_lua.registerStaticClass("g_configs");
|
||||
@@ -477,6 +485,7 @@ void Application::registerLuaFunctions()
|
||||
g_lua.bindClassStaticFunction("g_modules", "discoverModule", std::bind(&ModuleManager::discoverModule, &g_modules, _1));
|
||||
g_lua.bindClassStaticFunction("g_modules", "ensureModuleLoaded", std::bind(&ModuleManager::ensureModuleLoaded, &g_modules, _1));
|
||||
g_lua.bindClassStaticFunction("g_modules", "unloadModules", std::bind(&ModuleManager::unloadModules, &g_modules));
|
||||
g_lua.bindClassStaticFunction("g_modules", "reloadModules", std::bind(&ModuleManager::reloadModules, &g_modules));
|
||||
g_lua.bindClassStaticFunction("g_modules", "getModule", std::bind(&ModuleManager::getModule, &g_modules, _1));
|
||||
g_lua.bindClassStaticFunction("g_modules", "getModules", std::bind(&ModuleManager::getModules, &g_modules));
|
||||
|
||||
|
@@ -132,6 +132,9 @@ bool luavalue_cast(int index, std::vector<T>& vec);
|
||||
template<class T>
|
||||
void push_luavalue(const std::deque<T>& vec);
|
||||
|
||||
template<typename T>
|
||||
bool luavalue_cast(int index, std::deque<T>& vec);
|
||||
|
||||
// tuple
|
||||
template<typename... Args>
|
||||
void push_luavalue(const std::tuple<Args...>& tuple);
|
||||
@@ -279,6 +282,22 @@ void push_luavalue(const std::deque<T>& vec) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool luavalue_cast(int index, std::deque<T>& vec)
|
||||
{
|
||||
if(g_lua.isTable(index)) {
|
||||
g_lua.pushNil();
|
||||
while(g_lua.next(index < 0 ? index-1 : index)) {
|
||||
T value;
|
||||
if(luavalue_cast(-1, value))
|
||||
vec.push_back(value);
|
||||
g_lua.pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<int N>
|
||||
struct push_tuple_luavalue {
|
||||
template<typename Tuple>
|
||||
|
@@ -554,15 +554,17 @@ void UIWidget::destroy()
|
||||
|
||||
#ifdef DEBUG
|
||||
auto self = asUIWidget();
|
||||
g_lua.collectGarbage();
|
||||
g_dispatcher.addEvent([self] {
|
||||
if(self != g_ui.getRootWidget()) {
|
||||
g_lua.collectGarbage();
|
||||
g_dispatcher.addEvent([self] {
|
||||
g_lua.collectGarbage();
|
||||
if(self->getUseCount() != 1)
|
||||
logWarning("widget '", self->getId(), "' destroyed but still have ", self->getUseCount()-1, " reference(s) left");
|
||||
g_dispatcher.addEvent([self] {
|
||||
g_lua.collectGarbage();
|
||||
if(self->getUseCount() != 1)
|
||||
logWarning("widget '", self->getId(), "' destroyed but still have ", self->getUseCount()-1, " reference(s) left");
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
#endif
|
||||
|
||||
m_destroyed = true;
|
||||
@@ -853,9 +855,9 @@ UIWidgetPtr UIWidget::getChildById(const std::string& childId)
|
||||
UIWidgetPtr UIWidget::getChildByPos(const Point& childPos)
|
||||
{
|
||||
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
||||
const UIWidgetPtr& widget = (*it);
|
||||
if(widget->isExplicitlyVisible() && widget->containsPoint(childPos))
|
||||
return widget;
|
||||
const UIWidgetPtr& child = (*it);
|
||||
if(child->isExplicitlyVisible() && child->containsPoint(childPos))
|
||||
return child;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -884,7 +886,8 @@ UIWidgetPtr UIWidget::recursiveGetChildById(const std::string& id)
|
||||
|
||||
UIWidgetPtr UIWidget::recursiveGetChildByPos(const Point& childPos)
|
||||
{
|
||||
for(const UIWidgetPtr& child : m_children) {
|
||||
for(auto it = m_children.rbegin(); it != m_children.rend(); ++it) {
|
||||
const UIWidgetPtr& child = (*it);
|
||||
if(child->isExplicitlyVisible() && child->containsPoint(childPos)) {
|
||||
if(UIWidgetPtr subChild = child->recursiveGetChildByPos(childPos))
|
||||
return subChild;
|
||||
@@ -1280,9 +1283,9 @@ bool UIWidget::propagateOnKeyPress(uchar keyCode, int keyboardModifiers, int aut
|
||||
return true;
|
||||
}
|
||||
|
||||
if(autoRepeatTicks == 0 || autoRepeatTicks >= m_autoRepeatDelay) {
|
||||
if(autoRepeatTicks == 0 || autoRepeatTicks >= m_autoRepeatDelay)
|
||||
return onKeyPress(keyCode, keyboardModifiers, autoRepeatTicks);
|
||||
} else
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -86,7 +86,7 @@ void UIWidget::onFontChange(const std::string& font)
|
||||
|
||||
void UIWidget::wrapText()
|
||||
{
|
||||
setText(m_font->wrapText(m_text, getWidth()));
|
||||
setText(m_font->wrapText(m_text, getWidth() - m_textOffset.x));
|
||||
}
|
||||
|
||||
void UIWidget::setText(const std::string& text)
|
||||
|
@@ -37,11 +37,18 @@ void OTClient::init(const std::vector<std::string>& args)
|
||||
Application::init(args, Fw::AppEnableAll);
|
||||
|
||||
g_modules.discoverModules();
|
||||
g_modules.autoLoadModules(100);
|
||||
g_modules.ensureModuleLoaded("client");
|
||||
g_modules.autoLoadModules(1000);
|
||||
|
||||
//g_map.load();
|
||||
// core modules 0-99
|
||||
g_modules.autoLoadModules(99);
|
||||
g_modules.ensureModuleLoaded("core_lib");
|
||||
// client modules 100-499
|
||||
g_modules.autoLoadModules(499);
|
||||
g_modules.ensureModuleLoaded("client_main");
|
||||
// game modules 500-999
|
||||
g_modules.autoLoadModules(999);
|
||||
g_modules.ensureModuleLoaded("game");
|
||||
// addons 1000-9999
|
||||
g_modules.autoLoadModules(9999);
|
||||
|
||||
// load otclientrc.lua
|
||||
if(g_resources.fileExists("/otclientrc.lua")) {
|
||||
|
Reference in New Issue
Block a user