When a C function terminates, it should not leave bogus elements
on the stack, or the stack can eventually overflow.
This is not as critical for C functions which are called by lua,
because they return an int explaining how many values on the stack
are important. But for C++ facing functions it is very important.
This reduces the code complexity quite a bit. Now all the lua api
defn's are in the scripting folder, and the generator object itself
needs only construct a kernel and ask it to do things, and catch /
rethrow its exceptions with appropriate type and additional
descriptive info.
read here: http://www.lua.org/manual/5.1/manual.html#lua_CFunction
When the C function returns with "1", all but the top entry are
discarded from the stack. If this function could be called again
and again without ever returning and without ever dumping the stack,
then there could be a stackoverflow, but in this case it's
not possible.
In initial commit of the new lua kernels, I introduced a problem
by trying to use luaW_pcall and lua_pcall interchangeably via
polymorphism. This doesn't work because their return types don't
match, and it's alot of work to change luaW_pcall syntax. Besides
this there's no reason we can't use the custom error handler
everywhere.
This commits adds protected_call and load_string functions to lua
kernel base. These are an intended replacement for luaW_pcall,
and replace the "run" function. They do better error reporting
and allow to specify an error handler.
The error reporting is very flexible -- by default we select a
an error reporting function associated polymorphically to the lua
kernel, so the in-game lua kernel can send chat messages, and
others can do something else. However an arbitrary handler may
be specified, and exceptions instead of logging may also be
requested.
If a lua script is passed as an argument to wesnoth, wesnoth will
actually instantiate the application_lua_kernel defined in the
previous commits, initialize it, and run the script in that
environment.
The application lua kernel is meant to interpret scripts to drive
the client. Its main features are, it stores a script in its
registry and provides a C++ function to call it with a config
as its argument. Its initialization also creates a "game_launcher"
object, which stands as a limited lua proxy for the C++
game_launcher object.
The game_launcher object is a table, holding a pointer to the
actual game_launcher it represents, and with metamethods to return
version info and the command line arguments. It also holds
callbacks to set the script for the current application lua kernel,
and to call the "play_multiplayer" function of game_launcher.
Currently it is readonly and you cannot write to its fields,
although that may change to allow the target server to be reset,
etc.
Some minor changes that are included in this commit:
- the actual C++ game launcher object provides an accessor to the
command line options.
- the scripting/lua_types.hpp file now has include guards
This includes the gettext and vconfig impl functions, and many
macros used to write lua callbacks. This code can't properly go in
the lua_kernel_base files, so it goes here.
The non-BFS version of create_directory_if_missing_recursive() handles
relative path names (e.g. "foo") correctly and doesn't attempt to create
a parent that is left unspecified in the path (i.e. empty), but the BFS
version does, predictably failing the whole operation.
This fixes an issue where `./wesnoth -p data foo` from the source tree
would fail with `error filesystem: Could not create parents to foo` if
`foo` did not already exist, when using the Boost.filesystem-based
implementation. `./wesnoth -p data ./foo` would succeed because there is
a visible parent directory '.' that already exists and needs not be
created again.
The non-BFS version of normalize_path() returns an empty string when
passed an empty string, but the BFS version returns the normalized
version of the current working dir for the Wesnoth process.
Due to the way editor::start()'s arguments are built from the process
command line, the result of normalize_path("") gets passed to it when
starting with the --editor switch and no map path argument. If the
result describes a directory, the editor brings up the filechooser
dialog on that path; otherwise, it attempts to open it as a map file.
Making the BFS version of normalize_path() follow the non-BFS behavior
fixes the editor unexpectedly bringing up the filechooser when started
from the command line.
When we are actually in the game, the image.cpp file uses an
elaborate collection of caches to make sure that all images are
cached and reloaded rather than redoing work (even scaling). It's
questionable whether the amount of caching going on there is
appropriate, it seems it might even be faster if we did less. But
one place that we don't do any caching and performance is bad is
in the mp create screen. There was a bug report in 1.12:
https://gna.org/bugs/?func=detailitem&item_id=21801
In this commit, I implement quick and dirty caching for scenario
minimap images. Each scenario record holds a surface (an SDL
reference counted pointer to image data), and when a minimap is
rendered this gets saved, along with the md5 hash of the map that
got rendered. Whenever a minimap is requested, we hash it first
and check if the cache is dirty. If so we recalculate, otherwise
we return the cached image.
The code is also cleaner and a bit less convoluted than the
previous code -- the previous author seemed to think that surfaces
are "object" types and not "pointer" types, that require an
additional layer of memory management with boost scoped pointer
etc. This was in fact redundant.
I don't know if this commit will actually help report 21801,
the profiling seemed to suggest that it's the minimap rendering
code that is actually slow. But it seems that this can't hurt,
and may at least mitigate the slowness, since except for random
maps it means the minimap calculation won't be repeated.
This preserves the way it was done previously, where we wouldn't
scan for terrain data until we actually load a map. This reduces
the wait you must endure when you click "campaign" or "multiplayer"
at the titlescreen.
This commit splits some of the functionality of the gamemap object
into a new class, the "terrain_type_data" object. This class is
intended to hold a record of known terrains and the terrain code ->
terrain type map. It handles merging in new terrain definitions,
and it is shared between map objects. It is also cached by the game
config manager, so that we only recalculate this data when we
change configs.
There is in fact a *semantic* change going on here, which is that
when a scenario introduces a new terrain type by merging, this gets
added to the global cache. The alternative is to make a copy of the
global cache, only for the this scenario, as soon as we have to
dirty the cache. However since I didn't see any downside to putting
the merged terrains together and carrying them across scenarios,
I opted not to do that here.
In case the same terrain definition had to be merged into a editor group
it already was in the issue was reported to the error channel.
The issue should only be a normal thing to happen thus I reduced the
severity of the output.
When the unit tests are running, the game_launcher, game_config
code is never involved, so the noaddons cmd line opt cannot be
ignored. This commit makes it so that regardless of game_config
value, the --noaddons command line flag is respected.
This reverts commit 7fd093d7c0bb425756ca3faa01798c67d9bc8cba.
Cores are now validated, invalid ones are discarded.
The failsave mechanism now tries to load without add-ons in case of a
fail before it falls back to the default core.
Core definitions are now read from a cores.cfg in every add-ons'
toplevel.
This will be used to switch addons off during runtime.
Used for fallback if loading fails.
Can later be used to give gui controll over loading the addons.
Tested to work with this test scenario, and the mainline defaults:
[label]
x = {X}
y = {Y}
text = {STRING}
[/label]
[multiplayer]
id=lua_map_gen
name= _ "Lua Map Gen Test Scenario"
description= _ "test test test of lua map gen"
map_generation="lua"
[generator]
id="test"
config_name="Test Lua Map Generator"
create_map = << local rng = Rng:create()
print(rng:draw())
print(rng:draw())
print(rng:draw())
local w = 50
local h = 40
map=""
for y=1,h do
local r = rng:draw() % 2
for x=1,w do
if x == 10 and y == 10 then
map = map .. " 1 "
end
if x == (w-10) and y == (h-10) then
map = map .. " 2 "
end
if ((x + y) % 2) == r then
map = map .. "Gg"
else
map = map .. "Md"
end
if x ~= w then
map = map .. ","
end
end
map = map .. "\n"
end
return map
>>
[/generator]
id = foo
random_start_time=yes
{DEFAULT_SCHEDULE}
[event]
name=prestart
{LABEL 25 20 ("Lua map generator")}
[/event]
[side]
[ai]
villages_per_scout=8
[/ai]
id=RBY_Side1
side=1
save_id=RBY_Side1
persistent=yes
color=red
team_name=Red
user_team_name= _ "teamname^Red"
controller=human
canrecruit=yes
shroud=no
fog=no
gold=1000000
[/side]
[side]
[ai]
villages_per_scout=8
[/ai]
id=RBY_Side2
side=2
save_id=RBY_Side2
persistent=yes
color=blue
team_name=Blue
user_team_name= _ "teamname^Blue"
controller=human
canrecruit=yes
shroud=no
fog=no
gold=1000000
[/side]
[/multiplayer]