(svn r13656) [NoAI] -Add: added suspend control. If an AI consumes N (default = 4000) opcodes, a sleep is forced (for 1 tick). This to give fair play for all AIs. Also, an infinite loop won't hang the GUI of the player. (Morloth)
--- a/src/ai/ai.cpp Mon Jun 30 12:15:10 2008 +0000
+++ b/src/ai/ai.cpp Mon Jun 30 12:27:24 2008 +0000
@@ -133,6 +133,11 @@
InvalidateWindowData(WC_AI_DEBUG, 0, -1);
}
+AIController *AI_GetPlayerController(PlayerID player)
+{
+ return _ai_player[player];
+}
+
/**
* Initialize some AI-related stuff.
*/
--- a/src/ai/ai.h Mon Jun 30 12:15:10 2008 +0000
+++ b/src/ai/ai.h Mon Jun 30 12:27:24 2008 +0000
@@ -22,4 +22,6 @@
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2);
+class AIController *AI_GetPlayerController(PlayerID player);
+
#endif /* AI_H */
--- a/src/ai/api/ai_controller.cpp Mon Jun 30 12:15:10 2008 +0000
+++ b/src/ai/api/ai_controller.cpp Mon Jun 30 12:27:24 2008 +0000
@@ -7,6 +7,7 @@
#include "../../player_func.h"
#include "../../core/alloc_func.hpp"
#include "../../string_func.h"
+#include "../../settings_type.h"
#include "table/strings.h"
#include <squirrel.h>
@@ -17,6 +18,7 @@
#include "ai_controller.hpp"
#include "../ai_threads.h"
#include "../ai_info.hpp"
+#include "../ai.h"
/* Convert all AI related classes to Squirrel data.
* Note: this line a marker in squirrel_export.sh. Do not change! */
@@ -76,6 +78,8 @@
AILog::Warning("Sleep() value should be > 0. Assuming value 1.");
ticks = 1;
}
+ AIController *controller = AI_GetPlayerController(_current_player);
+ controller->engine->ResetOpcodeCounter();
AI_SuspendPlayer(_current_player, ticks);
}
@@ -169,6 +173,11 @@
AIController::Print(error_msg, FS2OTTD(message));
}
+static void SquirrelSuspendControl()
+{
+ AIController::Sleep(1);
+}
+
AIController::AIController(const char *script, const char *class_name) :
tick(0),
engine(NULL),
@@ -205,6 +214,10 @@
this->engine->CallMethod(*this->SQ_instance, "constructor");
}
+ /* Set the maximum opcodes before suspend and suspend control */
+ this->engine->SetMaxOpcodes(_settings_game.ai.ai_max_opcode_till_suspend);
+ this->engine->SetSuspendControl(&SquirrelSuspendControl);
+
/* When that is done, start the Start() function */
this->engine->CallMethod(*this->SQ_instance, "Start");
}
--- a/src/lang/english.txt Mon Jun 30 12:15:10 2008 +0000
+++ b/src/lang/english.txt Mon Jun 30 12:27:24 2008 +0000
@@ -1149,6 +1149,7 @@
STR_CONFIG_PATCHES_AINEW_ACTIVE :{LTBLUE}Enable new AI (alpha): {ORANGE}{STRING1}
STR_CONFIG_PATCHES_AI_IN_MULTIPLAYER :{LTBLUE}Allow AIs in multiplayer (experimental): {ORANGE}{STRING1}
+STR_CONFIG_PATCHES_AI_MAX_OPCODES :{LTBLUE}#opcodes before AI is suspended: {ORANGE}{STRING1}
STR_CONFIG_PATCHES_SERVINT_TRAINS :{LTBLUE}Default service interval for trains: {ORANGE}{STRING1} days/%
STR_CONFIG_PATCHES_SERVINT_TRAINS_DISABLED :{LTBLUE}Default service interval for trains: {ORANGE}disabled
--- a/src/settings.cpp Mon Jun 30 12:15:10 2008 +0000
+++ b/src/settings.cpp Mon Jun 30 12:27:24 2008 +0000
@@ -1668,6 +1668,7 @@
SDT_BOOL(GameSettings, ai.ai_disable_veh_roadveh, 0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_ROADVEH, NULL),
SDT_BOOL(GameSettings, ai.ai_disable_veh_aircraft, 0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_AIRCRAFT, NULL),
SDT_BOOL(GameSettings, ai.ai_disable_veh_ship, 0, 0, false, STR_CONFIG_PATCHES_AI_BUILDS_SHIPS, NULL),
+ SDT_VAR(GameSettings, ai.ai_max_opcode_till_suspend, SLE_UINT32, 0, NG, 4000, 100, 40000, 100, STR_CONFIG_PATCHES_AI_MAX_OPCODES, NULL),
SDT_VAR(GameSettings, vehicle.extend_vehicle_life, SLE_UINT8, 0, 0, 0, 0, 100, 0, STR_NULL, NULL),
SDT_VAR(GameSettings, economy.dist_local_authority, SLE_UINT8, 0, 0, 20, 5, 60, 0, STR_NULL, NULL),
--- a/src/settings_gui.cpp Mon Jun 30 12:15:10 2008 +0000
+++ b/src/settings_gui.cpp Mon Jun 30 12:27:24 2008 +0000
@@ -667,6 +667,7 @@
"ai.ai_disable_veh_roadveh",
"ai.ai_disable_veh_aircraft",
"ai.ai_disable_veh_ship",
+ "ai.ai_max_opcode_till_suspend",
};
static const char *_patches_vehicles[] = {
--- a/src/settings_type.h Mon Jun 30 12:15:10 2008 +0000
+++ b/src/settings_type.h Mon Jun 30 12:27:24 2008 +0000
@@ -157,6 +157,7 @@
bool ai_disable_veh_roadveh; ///< disable types for AI
bool ai_disable_veh_aircraft; ///< disable types for AI
bool ai_disable_veh_ship; ///< disable types for AI
+ uint32 ai_max_opcode_till_suspend; ///< max opcode calls till the squirrel VM will be suspended
};
/** Settings related to the old pathfinder. */
--- a/src/squirrel.cpp Mon Jun 30 12:15:10 2008 +0000
+++ b/src/squirrel.cpp Mon Jun 30 12:27:24 2008 +0000
@@ -85,6 +85,11 @@
return 0;
}
+void Squirrel::SetSuspendControl(SQSuspendControlFunc func)
+{
+ sq_setsuspendcontrol(this->vm, func);
+}
+
void Squirrel::PrintFunc(HSQUIRRELVM vm, const SQChar *s, ...)
{
va_list arglist;
--- a/src/squirrel.hpp Mon Jun 30 12:15:10 2008 +0000
+++ b/src/squirrel.hpp Mon Jun 30 12:27:24 2008 +0000
@@ -155,6 +155,11 @@
void SetPrintFunction(SQPrintFunc *func) { this->print_func = func; }
/**
+ * Set a custom suspend function.
+ */
+ void SetSuspendControl(SQSuspendControlFunc func);
+
+ /**
* Throw a Squirrel error that will be nicely displayed to the user.
*/
void ThrowError(const char *error) { sq_throwerror(this->vm, OTTD2FS(error)); }
@@ -163,6 +168,17 @@
* Release a SQ object.
*/
void ReleaseObject(HSQOBJECT *ptr) { sq_release(this->vm, ptr); }
+
+ /**
+ * Reset the internal SQ counter which counts the opcodes executed and
+ * forces SQ to pause if the counter overflows.
+ */
+ void ResetOpcodeCounter() { sq_resetopcodecounter(this->vm); }
+
+ /**
+ * Set the maximum of opcodes before the suspend handler is called.
+ */
+ void SetMaxOpcodes(int32 opcodes) { sq_setmaxopcodes(this->vm, opcodes); }
};
#endif /* SQUIRREL_HPP */