Merge lp:~widelands-dev/widelands/autosave_on_objectives into lp:widelands
- autosave_on_objectives
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 6639 | ||||
Proposed branch: | lp:~widelands-dev/widelands/autosave_on_objectives | ||||
Merge into: | lp:widelands | ||||
Diff against target: |
902 lines (+263/-216) 8 files modified
campaigns/tutorial01.wmf/scripting/init.lua (+48/-48) src/logic/game.h (+0/-4) src/save_handler.cc (+33/-17) src/save_handler.h (+12/-4) src/scripting/lua_game.cc (+19/-4) src/scripting/lua_root.cc (+27/-27) src/scripting/lua_root.h (+2/-0) test/lua/persistence.wmf/scripting/init.lua (+122/-112) |
||||
To merge this branch: | bzr merge lp:~widelands-dev/widelands/autosave_on_objectives | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
SirVer | Approve | ||
Review via email: mp+174546@code.launchpad.net |
Commit message
Description of the change
I just applied the patch provided in the bug report and removed the option checkbox.
Concerning the new lua function, i added it to the const static struct luaL_reg wlgame [] and was able to use it in a newly created win condition, so i guess this was ok?
cghislai (charlyghislain) wrote : | # |
I'm a bit lost in the lua tests. It appears I cannot make it run even with trunk code :
"could not load "test/lua/
Could you check it? I will try to make a save-in-corountine test afterwards.
I refactored m_allow_autosaving to m_allow_saving, because i guess we have to prevent manual saves as well then, right?
I removed some comments i grasped, and left some that may still be useful
SirVer (sirver) wrote : | # |
I looked over the code again and removed more of my comments that you adressed or that I made up my mind about :). One more thing: If you change a Lua method make sure that you update where it is used in the code (i.e. in all *.lua files) and add in a backwards compatible version (I did this for this change). The reason for this is that the Lua interface is a kind of public API that people should rely on and that should not change to quickly so that they have time to adapt - there is no proper deprecation warning for this yet, for now I just simply added a comment.
These methods must be around for at least three builds - the reason is that the lua code is saved into savegames, so if the API changes and a player tries to reload a scenario with older code, the API calls must still be around.
About the test running, the comments in the file where slightly outdated. I updated them to this:
$PATH_TO_
of course a rm -rf ~/.widelands/
Could you try again if this works for you? You have to be in the root directory of the repository for this to work.
cghislai (charlyghislain) wrote : | # |
Running the coroutine test I get a PANIC: unprotected error in call to Lua API (Attempt to persist a C function) which I'm unable to track down...
I'm not very familiar with lua or scripting at that low level (yet).
In the meantime, the former persistence test passed, I think i was trying with the system executable.
SirVer (sirver) wrote : | # |
This is the error you get when Lua tries to persist a running coroutine. So this is precisely the error you want to fix :).
In trunk, the save routine must only be called when no coroutine is running, i.e. outside of any coroutine, i.e. when the script is run the first time. This is not very flexible and means that you can essentially not save from inside Lua. I did it because I needed a save routine for the persistence test and this did the job.
Your code now should be able to handle this though, because as soon as you hit the main loop and poll if the game should be saved, there cannot be a Lua coroutine running anymore, so saving should work.
cghislai (charlyghislain) wrote : | # |
The autosave seems to work as expected in campaign. Also calling wl.Game(
SirVer (sirver) wrote : | # |
I did slight modifications to the test and added a bunch of comments - I found the reason why the test did work for you and then didn't and did again: lunit did define some handles to cfunctions, so it needs to be pulled in after loading :).
I will merge this as soon as i get good internet again - seems impossible in this train right now.
Preview Diff
1 | === modified file 'campaigns/tutorial01.wmf/scripting/init.lua' | |||
2 | --- campaigns/tutorial01.wmf/scripting/init.lua 2010-11-12 12:42:11 +0000 | |||
3 | +++ campaigns/tutorial01.wmf/scripting/init.lua 2013-07-19 21:32:25 +0000 | |||
4 | @@ -32,7 +32,7 @@ | |||
5 | 32 | use("map", "texts") | 32 | use("map", "texts") |
6 | 33 | 33 | ||
7 | 34 | -- ================= | 34 | -- ================= |
9 | 35 | -- Helper functions | 35 | -- Helper functions |
10 | 36 | -- ================= | 36 | -- ================= |
11 | 37 | 37 | ||
12 | 38 | -- A small helper class to disable/enable autosaving and user interaction | 38 | -- A small helper class to disable/enable autosaving and user interaction |
13 | @@ -49,14 +49,14 @@ | |||
14 | 49 | function UserInputDisabler:establish_blocks() | 49 | function UserInputDisabler:establish_blocks() |
15 | 50 | self._ui_state = wl.ui.get_user_input_allowed() | 50 | self._ui_state = wl.ui.get_user_input_allowed() |
16 | 51 | local game = wl.Game() | 51 | local game = wl.Game() |
18 | 52 | self._as_state = game.allow_autosaving | 52 | self._as_state = game.allow_saving |
19 | 53 | 53 | ||
20 | 54 | wl.ui.set_user_input_allowed(false) | 54 | wl.ui.set_user_input_allowed(false) |
22 | 55 | wl.Game().allow_autosaving = false | 55 | wl.Game().allow_saving = false |
23 | 56 | end | 56 | end |
24 | 57 | function UserInputDisabler:lift_blocks() | 57 | function UserInputDisabler:lift_blocks() |
25 | 58 | wl.ui.set_user_input_allowed(self._ui_state) | 58 | wl.ui.set_user_input_allowed(self._ui_state) |
27 | 59 | wl.Game().allow_autosaving= self._as_state | 59 | wl.Game().allow_saving = self._as_state |
28 | 60 | end | 60 | end |
29 | 61 | 61 | ||
30 | 62 | function _try_add_objective(i) | 62 | function _try_add_objective(i) |
31 | @@ -108,7 +108,7 @@ | |||
32 | 108 | sleep(130) | 108 | sleep(130) |
33 | 109 | return o | 109 | return o |
34 | 110 | end | 110 | end |
36 | 111 | 111 | ||
37 | 112 | function click_on_field(f, g_T, g_sleeptime) | 112 | function click_on_field(f, g_T, g_sleeptime) |
38 | 113 | local sleeptime = g_sleeptime or 500 | 113 | local sleeptime = g_sleeptime or 500 |
39 | 114 | 114 | ||
40 | @@ -125,7 +125,7 @@ | |||
41 | 125 | 125 | ||
42 | 126 | function click_on_panel(panel, g_T, g_sleeptime) | 126 | function click_on_panel(panel, g_T, g_sleeptime) |
43 | 127 | local sleeptime = g_sleeptime or 500 | 127 | local sleeptime = g_sleeptime or 500 |
45 | 128 | 128 | ||
46 | 129 | local blocker = UserInputDisabler:new() | 129 | local blocker = UserInputDisabler:new() |
47 | 130 | 130 | ||
48 | 131 | sleep(sleeptime) | 131 | sleep(sleeptime) |
49 | @@ -143,7 +143,7 @@ | |||
50 | 143 | function warp_houses(descriptions) | 143 | function warp_houses(descriptions) |
51 | 144 | local blocker = UserInputDisabler:new() | 144 | local blocker = UserInputDisabler:new() |
52 | 145 | 145 | ||
54 | 146 | for idx, d in ipairs(descriptions) do | 146 | for idx, d in ipairs(descriptions) do |
55 | 147 | local name, x, y = d[1], d[2], d[3] | 147 | local name, x, y = d[1], d[2], d[3] |
56 | 148 | mouse_smoothly_to(wl.Game().map:get_field(x, y)) | 148 | mouse_smoothly_to(wl.Game().map:get_field(x, y)) |
57 | 149 | sleep(300) | 149 | sleep(300) |
58 | @@ -167,7 +167,7 @@ | |||
59 | 167 | 167 | ||
60 | 168 | function build_road(field, ...) | 168 | function build_road(field, ...) |
61 | 169 | -- Build a road by clicking the UI. A little faster than before | 169 | -- Build a road by clicking the UI. A little faster than before |
63 | 170 | 170 | ||
64 | 171 | -- Make sure that there is room for the road: Rip all immovables | 171 | -- Make sure that there is room for the road: Rip all immovables |
65 | 172 | local cf = field | 172 | local cf = field |
66 | 173 | for idx, d in ipairs{...} do | 173 | for idx, d in ipairs{...} do |
67 | @@ -206,11 +206,11 @@ | |||
68 | 206 | end | 206 | end |
69 | 207 | end | 207 | end |
70 | 208 | end | 208 | end |
72 | 209 | 209 | ||
73 | 210 | function build_eastern_trainings_area(citadel_field) | 210 | function build_eastern_trainings_area(citadel_field) |
74 | 211 | -- Build some infrastructure as another example | 211 | -- Build some infrastructure as another example |
75 | 212 | local blocker = UserInputDisabler:new() | 212 | local blocker = UserInputDisabler:new() |
77 | 213 | 213 | ||
78 | 214 | plr:reveal_fields(citadel_field:region(8)) | 214 | plr:reveal_fields(citadel_field:region(8)) |
79 | 215 | scroll_smoothly_to(wl.Game().map:get_field(21,9)) | 215 | scroll_smoothly_to(wl.Game().map:get_field(21,9)) |
80 | 216 | scroll_smoothly_to(citadel_field) | 216 | scroll_smoothly_to(citadel_field) |
81 | @@ -262,16 +262,16 @@ | |||
82 | 262 | -- add buildwares to the warehouse | 262 | -- add buildwares to the warehouse |
83 | 263 | local ts = map:get_field(31,56).immovable | 263 | local ts = map:get_field(31,56).immovable |
84 | 264 | ts:set_wares(ts.valid_wares) | 264 | ts:set_wares(ts.valid_wares) |
86 | 265 | 265 | ||
87 | 266 | scroll_smoothly_to(citadel_field) | 266 | scroll_smoothly_to(citadel_field) |
88 | 267 | 267 | ||
89 | 268 | blocker:lift_blocks() | 268 | blocker:lift_blocks() |
90 | 269 | end | 269 | end |
92 | 270 | 270 | ||
93 | 271 | -- Remove all stones in a given environment. This is done | 271 | -- Remove all stones in a given environment. This is done |
94 | 272 | -- in a loop for a nice optical effect | 272 | -- in a loop for a nice optical effect |
95 | 273 | function remove_all_stones(fields, g_sleeptime) | 273 | function remove_all_stones(fields, g_sleeptime) |
97 | 274 | local sleeptime = g_sleeptime or 150 | 274 | local sleeptime = g_sleeptime or 150 |
98 | 275 | local map = wl.Game().map | 275 | local map = wl.Game().map |
99 | 276 | while #fields > 0 do | 276 | while #fields > 0 do |
100 | 277 | local idx = math.random(#fields) | 277 | local idx = math.random(#fields) |
101 | @@ -283,7 +283,7 @@ | |||
102 | 283 | if n then | 283 | if n then |
103 | 284 | n = tonumber(n) | 284 | n = tonumber(n) |
104 | 285 | f.immovable:remove() | 285 | f.immovable:remove() |
106 | 286 | if n > 1 then | 286 | if n > 1 then |
107 | 287 | remove_field = false | 287 | remove_field = false |
108 | 288 | map:place_immovable("stones" .. n-1, f) | 288 | map:place_immovable("stones" .. n-1, f) |
109 | 289 | end | 289 | end |
110 | @@ -298,7 +298,7 @@ | |||
111 | 298 | end | 298 | end |
112 | 299 | 299 | ||
113 | 300 | -- ============== | 300 | -- ============== |
115 | 301 | -- Sentry Thread | 301 | -- Sentry Thread |
116 | 302 | -- ============== | 302 | -- ============== |
117 | 303 | -- This thread makes sure that the player does not build stuff where he | 303 | -- This thread makes sure that the player does not build stuff where he |
118 | 304 | -- is not supposed to. He gets a message box when he tries and what he build | 304 | -- is not supposed to. He gets a message box when he tries and what he build |
119 | @@ -345,7 +345,7 @@ | |||
120 | 345 | sleep(1000) | 345 | sleep(1000) |
121 | 346 | end | 346 | end |
122 | 347 | end | 347 | end |
124 | 348 | 348 | ||
125 | 349 | -- Allows constructionsites for the given buildings, all others are invalid | 349 | -- Allows constructionsites for the given buildings, all others are invalid |
126 | 350 | -- as is any other immovable build by the player | 350 | -- as is any other immovable build by the player |
127 | 351 | function allow_constructionsite(i, buildings) | 351 | function allow_constructionsite(i, buildings) |
128 | @@ -366,7 +366,7 @@ | |||
129 | 366 | end | 366 | end |
130 | 367 | 367 | ||
131 | 368 | -- ================ | 368 | -- ================ |
133 | 369 | -- Message threads | 369 | -- Message threads |
134 | 370 | -- ================ | 370 | -- ================ |
135 | 371 | function starting_infos() | 371 | function starting_infos() |
136 | 372 | sleep(100) | 372 | sleep(100) |
137 | @@ -418,7 +418,7 @@ | |||
138 | 418 | click_on_field(wl.Game().map.player_slots[1].starting_field.brn) | 418 | click_on_field(wl.Game().map.player_slots[1].starting_field.brn) |
139 | 419 | 419 | ||
140 | 420 | msg_box(lumberjack_message_04) | 420 | msg_box(lumberjack_message_04) |
142 | 421 | 421 | ||
143 | 422 | register_immovable_as_allowed(first_lumberjack_field.immovable) -- hut + flag | 422 | register_immovable_as_allowed(first_lumberjack_field.immovable) -- hut + flag |
144 | 423 | 423 | ||
145 | 424 | local f = wl.Game().map:get_field(14,11) | 424 | local f = wl.Game().map:get_field(14,11) |
146 | @@ -429,25 +429,25 @@ | |||
147 | 429 | blocker:lift_blocks() | 429 | blocker:lift_blocks() |
148 | 430 | 430 | ||
149 | 431 | sleep(15000) | 431 | sleep(15000) |
151 | 432 | 432 | ||
152 | 433 | local o = msg_box(lumberjack_message_05) | 433 | local o = msg_box(lumberjack_message_05) |
153 | 434 | 434 | ||
154 | 435 | local blocker = UserInputDisabler:new() | 435 | local blocker = UserInputDisabler:new() |
156 | 436 | 436 | ||
157 | 437 | local f = wl.Game().map:get_field(14,11) | 437 | local f = wl.Game().map:get_field(14,11) |
158 | 438 | scroll_smoothly_to(f) | 438 | scroll_smoothly_to(f) |
159 | 439 | mouse_smoothly_to(f) | 439 | mouse_smoothly_to(f) |
161 | 440 | 440 | ||
162 | 441 | blocker:lift_blocks() | 441 | blocker:lift_blocks() |
164 | 442 | 442 | ||
165 | 443 | -- Wait for flag | 443 | -- Wait for flag |
166 | 444 | while not (f.immovable and f.immovable.type == "flag") do sleep(300) end | 444 | while not (f.immovable and f.immovable.type == "flag") do sleep(300) end |
167 | 445 | o.done = true | 445 | o.done = true |
168 | 446 | 446 | ||
169 | 447 | sleep(300) | 447 | sleep(300) |
171 | 448 | 448 | ||
172 | 449 | msg_box(lumberjack_message_06) | 449 | msg_box(lumberjack_message_06) |
174 | 450 | 450 | ||
175 | 451 | while #plr:get_buildings("lumberjacks_hut") < 1 do sleep(300) end | 451 | while #plr:get_buildings("lumberjacks_hut") < 1 do sleep(300) end |
176 | 452 | 452 | ||
177 | 453 | msg_box(lumberjack_message_07) | 453 | msg_box(lumberjack_message_07) |
178 | @@ -458,7 +458,7 @@ | |||
179 | 458 | function learn_to_move() | 458 | function learn_to_move() |
180 | 459 | -- Teaching the user how to scroll on the map | 459 | -- Teaching the user how to scroll on the map |
181 | 460 | local o = msg_box(inform_about_stones) | 460 | local o = msg_box(inform_about_stones) |
183 | 461 | 461 | ||
184 | 462 | function _wait_for_move() | 462 | function _wait_for_move() |
185 | 463 | local cx = wl.ui.MapView().viewpoint_x | 463 | local cx = wl.ui.MapView().viewpoint_x |
186 | 464 | local cy = wl.ui.MapView().viewpoint_y | 464 | local cy = wl.ui.MapView().viewpoint_y |
187 | @@ -477,12 +477,12 @@ | |||
188 | 477 | _wait_for_move() | 477 | _wait_for_move() |
189 | 478 | o.done = true | 478 | o.done = true |
190 | 479 | sleep(3000) -- Give the player a chance to try this some more | 479 | sleep(3000) -- Give the player a chance to try this some more |
192 | 480 | 480 | ||
193 | 481 | msg_box(congratulate_and_on_to_quarry) | 481 | msg_box(congratulate_and_on_to_quarry) |
194 | 482 | 482 | ||
195 | 483 | build_a_quarry() | 483 | build_a_quarry() |
196 | 484 | end | 484 | end |
198 | 485 | 485 | ||
199 | 486 | function build_a_quarry() | 486 | function build_a_quarry() |
200 | 487 | sleep(200) | 487 | sleep(200) |
201 | 488 | 488 | ||
202 | @@ -505,12 +505,12 @@ | |||
203 | 505 | 505 | ||
204 | 506 | local function _rip_road() | 506 | local function _rip_road() |
205 | 507 | for idx,f in ipairs(cs.fields[1].brn:region(2)) do | 507 | for idx,f in ipairs(cs.fields[1].brn:region(2)) do |
207 | 508 | if f.immovable and f.immovable.type == "road" then | 508 | if f.immovable and f.immovable.type == "road" then |
208 | 509 | click_on_field(f) | 509 | click_on_field(f) |
209 | 510 | click_on_panel(wl.ui.MapView().windows. | 510 | click_on_panel(wl.ui.MapView().windows. |
210 | 511 | field_action.buttons.destroy_road, 300) | 511 | field_action.buttons.destroy_road, 300) |
211 | 512 | sleep(200) | 512 | sleep(200) |
213 | 513 | return | 513 | return |
214 | 514 | end | 514 | end |
215 | 515 | end | 515 | end |
216 | 516 | end | 516 | end |
217 | @@ -527,17 +527,17 @@ | |||
218 | 527 | click_on_field(map:get_field(11,12)) | 527 | click_on_field(map:get_field(11,12)) |
219 | 528 | click_on_field(map:get_field(12,12)) | 528 | click_on_field(map:get_field(12,12)) |
220 | 529 | click_on_field(map:get_field(12,11)) | 529 | click_on_field(map:get_field(12,11)) |
222 | 530 | 530 | ||
223 | 531 | sleep(3000) | 531 | sleep(3000) |
224 | 532 | 532 | ||
225 | 533 | _rip_road() | 533 | _rip_road() |
227 | 534 | 534 | ||
228 | 535 | msg_box(talk_about_roadbuilding_01) | 535 | msg_box(talk_about_roadbuilding_01) |
229 | 536 | -- Showoff direct roadbuilding | 536 | -- Showoff direct roadbuilding |
230 | 537 | click_on_field(cs.fields[1].brn) | 537 | click_on_field(cs.fields[1].brn) |
231 | 538 | click_on_panel(wl.ui.MapView().windows.field_action.buttons.build_road, 300) | 538 | click_on_panel(wl.ui.MapView().windows.field_action.buttons.build_road, 300) |
232 | 539 | click_on_field(map.player_slots[1].starting_field.brn) | 539 | click_on_field(map.player_slots[1].starting_field.brn) |
234 | 540 | 540 | ||
235 | 541 | sleep(3000) | 541 | sleep(3000) |
236 | 542 | 542 | ||
237 | 543 | _rip_road() | 543 | _rip_road() |
238 | @@ -545,12 +545,12 @@ | |||
239 | 545 | blocker:lift_blocks() | 545 | blocker:lift_blocks() |
240 | 546 | 546 | ||
241 | 547 | local o = msg_box(talk_about_roadbuilding_02) | 547 | local o = msg_box(talk_about_roadbuilding_02) |
243 | 548 | 548 | ||
244 | 549 | -- From now on, the player can build whatever he wants | 549 | -- From now on, the player can build whatever he wants |
245 | 550 | terminate_bad_boy_sentinel = true | 550 | terminate_bad_boy_sentinel = true |
247 | 551 | 551 | ||
248 | 552 | -- Wait a while | 552 | -- Wait a while |
250 | 553 | sleep( 100*1000 ) | 553 | sleep( 100*1000 ) |
251 | 554 | 554 | ||
252 | 555 | -- Interludium: talk about census and statistics | 555 | -- Interludium: talk about census and statistics |
253 | 556 | census_and_statistics(cs.fields[1]) | 556 | census_and_statistics(cs.fields[1]) |
254 | @@ -560,17 +560,17 @@ | |||
255 | 560 | 560 | ||
256 | 561 | messages() | 561 | messages() |
257 | 562 | end | 562 | end |
259 | 563 | 563 | ||
260 | 564 | function census_and_statistics(field) | 564 | function census_and_statistics(field) |
261 | 565 | sleep(15000) | 565 | sleep(15000) |
263 | 566 | 566 | ||
264 | 567 | local blocker = UserInputDisabler:new() | 567 | local blocker = UserInputDisabler:new() |
265 | 568 | 568 | ||
266 | 569 | wl.ui.MapView().census = false | 569 | wl.ui.MapView().census = false |
267 | 570 | wl.ui.MapView().statistics = false | 570 | wl.ui.MapView().statistics = false |
269 | 571 | 571 | ||
270 | 572 | wl.ui.MapView():abort_road_building() | 572 | wl.ui.MapView():abort_road_building() |
272 | 573 | 573 | ||
273 | 574 | msg_box(census_and_statistics_00) | 574 | msg_box(census_and_statistics_00) |
274 | 575 | -- Pick any empty field | 575 | -- Pick any empty field |
275 | 576 | local function _pick_empty_field() | 576 | local function _pick_empty_field() |
276 | @@ -591,7 +591,7 @@ | |||
277 | 591 | click_on_panel(wl.ui.MapView().windows.field_action.buttons.statistics) | 591 | click_on_panel(wl.ui.MapView().windows.field_action.buttons.statistics) |
278 | 592 | 592 | ||
279 | 593 | msg_box(census_and_statistics_01) | 593 | msg_box(census_and_statistics_01) |
281 | 594 | 594 | ||
282 | 595 | blocker:lift_blocks() | 595 | blocker:lift_blocks() |
283 | 596 | end | 596 | end |
284 | 597 | 597 | ||
285 | @@ -611,7 +611,7 @@ | |||
286 | 611 | -- Wait for messages window to close | 611 | -- Wait for messages window to close |
287 | 612 | while wl.ui.MapView().windows.messages do sleep(300) end | 612 | while wl.ui.MapView().windows.messages do sleep(300) end |
288 | 613 | o.done = true | 613 | o.done = true |
290 | 614 | 614 | ||
291 | 615 | msg_box(closing_msg_window_01) | 615 | msg_box(closing_msg_window_01) |
292 | 616 | 616 | ||
293 | 617 | -- Remove all stones | 617 | -- Remove all stones |
294 | @@ -627,10 +627,10 @@ | |||
295 | 627 | expansion() | 627 | expansion() |
296 | 628 | end | 628 | end |
297 | 629 | 629 | ||
299 | 630 | function expansion() | 630 | function expansion() |
300 | 631 | -- Teach about expanding your territory. | 631 | -- Teach about expanding your territory. |
301 | 632 | sleep(10) | 632 | sleep(10) |
303 | 633 | 633 | ||
304 | 634 | -- This is not really needed since the stones are already removed, but if | 634 | -- This is not really needed since the stones are already removed, but if |
305 | 635 | -- we're debugging and we start with this function it is most useful to have | 635 | -- we're debugging and we start with this function it is most useful to have |
306 | 636 | -- the stones away already | 636 | -- the stones away already |
307 | @@ -655,7 +655,7 @@ | |||
308 | 655 | while #fields > 0 do | 655 | while #fields > 0 do |
309 | 656 | local idx = math.random(#fields) | 656 | local idx = math.random(#fields) |
310 | 657 | local f = fields[idx] | 657 | local f = fields[idx] |
312 | 658 | 658 | ||
313 | 659 | if f.terr:match("berg%d+") and f.terd:match("berg%d+") then | 659 | if f.terr:match("berg%d+") and f.terd:match("berg%d+") then |
314 | 660 | if pcall(function() plr:place_flag(f) end) then | 660 | if pcall(function() plr:place_flag(f) end) then |
315 | 661 | f.immovable:remove() | 661 | f.immovable:remove() |
316 | @@ -678,7 +678,7 @@ | |||
317 | 678 | end | 678 | end |
318 | 679 | 679 | ||
319 | 680 | scroll_smoothly_to(conquer_field) | 680 | scroll_smoothly_to(conquer_field) |
321 | 681 | 681 | ||
322 | 682 | local dest = _find_good_flag_position() | 682 | local dest = _find_good_flag_position() |
323 | 683 | local start = _find_nearby_flag() | 683 | local start = _find_nearby_flag() |
324 | 684 | 684 | ||
325 | @@ -699,7 +699,7 @@ | |||
326 | 699 | local function _wait_for_some_resi(wanted) | 699 | local function _wait_for_some_resi(wanted) |
327 | 700 | while 1 do | 700 | while 1 do |
328 | 701 | local cnt = 0 | 701 | local cnt = 0 |
330 | 702 | for idx, f in ipairs(dest:region(6)) do | 702 | for idx, f in ipairs(dest:region(6)) do |
331 | 703 | if f.immovable and f.immovable.name:sub(1,4) == "resi" then | 703 | if f.immovable and f.immovable.name:sub(1,4) == "resi" then |
332 | 704 | cnt = cnt + 1 | 704 | cnt = cnt + 1 |
333 | 705 | if cnt >= wanted then return end | 705 | if cnt >= wanted then return end |
334 | @@ -720,7 +720,7 @@ | |||
335 | 720 | function training() | 720 | function training() |
336 | 721 | -- Teach about trainingsites and soldiers | 721 | -- Teach about trainingsites and soldiers |
337 | 722 | sleep(300) | 722 | sleep(300) |
339 | 723 | 723 | ||
340 | 724 | msg_box(warfare_and_training_00) | 724 | msg_box(warfare_and_training_00) |
341 | 725 | 725 | ||
342 | 726 | local citadel_field = wl.Game().map:get_field(31, 63) | 726 | local citadel_field = wl.Game().map:get_field(31, 63) |
343 | @@ -734,7 +734,7 @@ | |||
344 | 734 | scroll_smoothly_to(citadel_field) | 734 | scroll_smoothly_to(citadel_field) |
345 | 735 | 735 | ||
346 | 736 | local o = msg_box(enhance_fortress) | 736 | local o = msg_box(enhance_fortress) |
348 | 737 | while not (citadel_field.immovable and | 737 | while not (citadel_field.immovable and |
349 | 738 | citadel_field.immovable.name == "citadel") do sleep(800) end | 738 | citadel_field.immovable.name == "citadel") do sleep(800) end |
350 | 739 | o.done = true | 739 | o.done = true |
351 | 740 | 740 | ||
352 | 741 | 741 | ||
353 | === modified file 'src/logic/game.h' | |||
354 | --- src/logic/game.h 2013-07-14 17:05:25 +0000 | |||
355 | +++ src/logic/game.h 2013-07-19 21:32:25 +0000 | |||
356 | @@ -90,10 +90,6 @@ | |||
357 | 90 | friend struct ::Game_Main_Menu_Load_Game; | 90 | friend struct ::Game_Main_Menu_Load_Game; |
358 | 91 | friend struct ::WLApplication; | 91 | friend struct ::WLApplication; |
359 | 92 | 92 | ||
360 | 93 | // This friend is for legacy reasons and should probably be removed | ||
361 | 94 | // at least after summer 2008, maybe even earlier. | ||
362 | 95 | friend struct Game_Interactive_Player_Data_Packet; | ||
363 | 96 | |||
364 | 97 | Game(); | 93 | Game(); |
365 | 98 | ~Game(); | 94 | ~Game(); |
366 | 99 | 95 | ||
367 | 100 | 96 | ||
368 | === modified file 'src/save_handler.cc' | |||
369 | --- src/save_handler.cc 2013-07-16 13:26:14 +0000 | |||
370 | +++ src/save_handler.cc 2013-07-19 21:32:25 +0000 | |||
371 | @@ -39,19 +39,35 @@ | |||
372 | 39 | */ | 39 | */ |
373 | 40 | void SaveHandler::think(Widelands::Game & game, int32_t realtime) { | 40 | void SaveHandler::think(Widelands::Game & game, int32_t realtime) { |
374 | 41 | initialize(realtime); | 41 | initialize(realtime); |
388 | 42 | 42 | std::string filename = "wl_autosave"; | |
389 | 43 | if (not m_allow_autosaving) // Is autosaving allowed atm? | 43 | |
390 | 44 | return; | 44 | if (!m_allow_saving) { |
391 | 45 | 45 | return; | |
392 | 46 | int32_t const autosaveInterval = | 46 | } |
393 | 47 | g_options.pull_section("global").get_int | 47 | |
394 | 48 | ("autosave", DEFAULT_AUTOSAVE_INTERVAL * 60); | 48 | if (m_save_requested) { |
395 | 49 | if (autosaveInterval <= 0) | 49 | if (!m_save_filename.empty()) { |
396 | 50 | return; // no autosave requested | 50 | filename = m_save_filename; |
397 | 51 | 51 | } | |
398 | 52 | int32_t const elapsed = (realtime - m_last_saved_time) / 1000; | 52 | |
399 | 53 | if (elapsed < autosaveInterval) | 53 | log("Autosave: save requested : %s\n", filename.c_str()); |
400 | 54 | return; | 54 | m_save_requested = false; |
401 | 55 | m_save_filename = ""; | ||
402 | 56 | } else { | ||
403 | 57 | const int32_t autosave_interval_in_seconds = | ||
404 | 58 | g_options.pull_section("global").get_int | ||
405 | 59 | ("autosave", DEFAULT_AUTOSAVE_INTERVAL * 60); | ||
406 | 60 | if (autosave_interval_in_seconds <= 0) { | ||
407 | 61 | return; // no autosave requested | ||
408 | 62 | } | ||
409 | 63 | |||
410 | 64 | const int32_t elapsed = (realtime - m_last_saved_time) / 1000; | ||
411 | 65 | if (elapsed < autosave_interval_in_seconds) { | ||
412 | 66 | return; | ||
413 | 67 | } | ||
414 | 68 | |||
415 | 69 | log("Autosave: interval elapsed (%d s), saving\n", elapsed); | ||
416 | 70 | } | ||
417 | 55 | 71 | ||
418 | 56 | // TODO: defer saving to next tick so that this message is shown | 72 | // TODO: defer saving to next tick so that this message is shown |
419 | 57 | // before the actual save, or put the saving logic in another thread | 73 | // before the actual save, or put the saving logic in another thread |
420 | @@ -59,20 +75,20 @@ | |||
421 | 59 | (_("Saving game...")); | 75 | (_("Saving game...")); |
422 | 60 | 76 | ||
423 | 61 | // save the game | 77 | // save the game |
426 | 62 | std::string complete_filename = | 78 | const std::string complete_filename = create_file_name(get_base_dir(), filename); |
425 | 63 | create_file_name (get_base_dir(), "wl_autosave"); | ||
427 | 64 | std::string backup_filename; | 79 | std::string backup_filename; |
428 | 65 | 80 | ||
429 | 66 | // always overwrite a file | 81 | // always overwrite a file |
430 | 67 | if (g_fs->FileExists(complete_filename)) { | 82 | if (g_fs->FileExists(complete_filename)) { |
432 | 68 | backup_filename = create_file_name (get_base_dir(), "wl_autosave2"); | 83 | filename += "2"; |
433 | 84 | backup_filename = create_file_name (get_base_dir(), filename); | ||
434 | 69 | if (g_fs->FileExists(backup_filename)) { | 85 | if (g_fs->FileExists(backup_filename)) { |
435 | 70 | g_fs->Unlink(backup_filename); | 86 | g_fs->Unlink(backup_filename); |
436 | 71 | } | 87 | } |
437 | 72 | g_fs->Rename(complete_filename, backup_filename); | 88 | g_fs->Rename(complete_filename, backup_filename); |
438 | 73 | } | 89 | } |
439 | 74 | 90 | ||
441 | 75 | static std::string error; | 91 | std::string error; |
442 | 76 | if (!save_game(game, complete_filename, &error)) { | 92 | if (!save_game(game, complete_filename, &error)) { |
443 | 77 | log("Autosave: ERROR! - %s\n", error.c_str()); | 93 | log("Autosave: ERROR! - %s\n", error.c_str()); |
444 | 78 | game.get_ipl()->get_chat_provider()->send_local | 94 | game.get_ipl()->get_chat_provider()->send_local |
445 | 79 | 95 | ||
446 | === modified file 'src/save_handler.h' | |||
447 | --- src/save_handler.h 2013-07-14 11:48:13 +0000 | |||
448 | +++ src/save_handler.h 2013-07-19 21:32:25 +0000 | |||
449 | @@ -32,7 +32,8 @@ | |||
450 | 32 | 32 | ||
451 | 33 | class SaveHandler { | 33 | class SaveHandler { |
452 | 34 | public: | 34 | public: |
454 | 35 | SaveHandler() : m_last_saved_time(0), m_initialized(false), m_allow_autosaving(true) {} | 35 | SaveHandler() : m_last_saved_time(0), m_initialized(false), m_allow_saving(true), |
455 | 36 | m_save_requested(false), m_save_filename("") {} | ||
456 | 36 | void think(Widelands::Game &, int32_t currenttime); | 37 | void think(Widelands::Game &, int32_t currenttime); |
457 | 37 | std::string create_file_name(std::string dir, std::string filename); | 38 | std::string create_file_name(std::string dir, std::string filename); |
458 | 38 | bool save_game | 39 | bool save_game |
459 | @@ -43,13 +44,20 @@ | |||
460 | 43 | static std::string get_base_dir() {return "save";} | 44 | static std::string get_base_dir() {return "save";} |
461 | 44 | const std::string get_cur_filename() {return m_current_filename;} | 45 | const std::string get_cur_filename() {return m_current_filename;} |
462 | 45 | void set_current_filename(std::string filename) {m_current_filename = filename;} | 46 | void set_current_filename(std::string filename) {m_current_filename = filename;} |
465 | 46 | void set_allow_autosaving(bool t) {m_allow_autosaving = t;} | 47 | void set_allow_saving(bool t) {m_allow_saving = t;} |
466 | 47 | bool get_allow_autosaving() {return m_allow_autosaving;} | 48 | bool get_allow_saving() {return m_allow_saving;} |
467 | 49 | void request_save(std::string filename = "") | ||
468 | 50 | { | ||
469 | 51 | m_save_requested = true; | ||
470 | 52 | m_save_filename = filename; | ||
471 | 53 | } | ||
472 | 48 | 54 | ||
473 | 49 | private: | 55 | private: |
474 | 50 | int32_t m_last_saved_time; | 56 | int32_t m_last_saved_time; |
475 | 51 | bool m_initialized; | 57 | bool m_initialized; |
477 | 52 | bool m_allow_autosaving; | 58 | bool m_allow_saving; |
478 | 59 | bool m_save_requested; | ||
479 | 60 | std::string m_save_filename; | ||
480 | 53 | std::string m_current_filename; | 61 | std::string m_current_filename; |
481 | 54 | 62 | ||
482 | 55 | void initialize(int32_t currenttime); | 63 | void initialize(int32_t currenttime); |
483 | 56 | 64 | ||
484 | === modified file 'src/scripting/lua_game.cc' | |||
485 | --- src/scripting/lua_game.cc 2013-07-15 05:18:12 +0000 | |||
486 | +++ src/scripting/lua_game.cc 2013-07-19 21:32:25 +0000 | |||
487 | @@ -470,7 +470,7 @@ | |||
488 | 470 | uint32_t cspeed = game.gameController()->desiredSpeed(); | 470 | uint32_t cspeed = game.gameController()->desiredSpeed(); |
489 | 471 | game.gameController()->setDesiredSpeed(0); | 471 | game.gameController()->setDesiredSpeed(0); |
490 | 472 | 472 | ||
492 | 473 | game.save_handler().set_allow_autosaving(false); | 473 | game.save_handler().set_allow_saving(false); |
493 | 474 | 474 | ||
494 | 475 | Story_Message_Box * mb = | 475 | Story_Message_Box * mb = |
495 | 476 | new Story_Message_Box | 476 | new Story_Message_Box |
496 | @@ -486,7 +486,7 @@ | |||
497 | 486 | 486 | ||
498 | 487 | game.gameController()->setDesiredSpeed(cspeed); | 487 | game.gameController()->setDesiredSpeed(cspeed); |
499 | 488 | 488 | ||
501 | 489 | game.save_handler().set_allow_autosaving(true); | 489 | game.save_handler().set_allow_saving(true); |
502 | 490 | 490 | ||
503 | 491 | return 1; | 491 | return 1; |
504 | 492 | } | 492 | } |
505 | @@ -1062,8 +1062,10 @@ | |||
506 | 1062 | .. attribute:: done | 1062 | .. attribute:: done |
507 | 1063 | 1063 | ||
508 | 1064 | (RW) defines if this objective is already fulfilled. If done is | 1064 | (RW) defines if this objective is already fulfilled. If done is |
511 | 1065 | :const`true`, the objective will not be shown to the user, no matter what | 1065 | :const`true`, the objective will not be shown to the user, no matter what. |
512 | 1066 | :attr:`visible` is set to. | 1066 | :attr:`visible` is set to. A savegame will be created when this attribute |
513 | 1067 | is changed to :const`true`. | ||
514 | 1068 | |||
515 | 1067 | */ | 1069 | */ |
516 | 1068 | int L_Objective::get_done(lua_State * L) { | 1070 | int L_Objective::get_done(lua_State * L) { |
517 | 1069 | Objective & o = get(L, get_game(L)); | 1071 | Objective & o = get(L, get_game(L)); |
518 | @@ -1073,6 +1075,19 @@ | |||
519 | 1073 | int L_Objective::set_done(lua_State * L) { | 1075 | int L_Objective::set_done(lua_State * L) { |
520 | 1074 | Objective & o = get(L, get_game(L)); | 1076 | Objective & o = get(L, get_game(L)); |
521 | 1075 | o.set_done(luaL_checkboolean(L, -1)); | 1077 | o.set_done(luaL_checkboolean(L, -1)); |
522 | 1078 | |||
523 | 1079 | const int32_t autosave = g_options.pull_section("global").get_int("autosave", 0); | ||
524 | 1080 | if (autosave <= 0) { | ||
525 | 1081 | return 0; | ||
526 | 1082 | } | ||
527 | 1083 | |||
528 | 1084 | if (o.done()) { | ||
529 | 1085 | std::string filename = get_egbase(L).get_map()->get_name(); | ||
530 | 1086 | char buffer[128]; | ||
531 | 1087 | snprintf(buffer, sizeof(buffer), _(" (achieved %s)"), o.descname().c_str()); | ||
532 | 1088 | filename.append(buffer); | ||
533 | 1089 | get_game(L).save_handler().request_save(filename); | ||
534 | 1090 | } | ||
535 | 1076 | return 0; | 1091 | return 0; |
536 | 1077 | } | 1092 | } |
537 | 1078 | 1093 | ||
538 | 1079 | 1094 | ||
539 | === modified file 'src/scripting/lua_root.cc' | |||
540 | --- src/scripting/lua_root.cc 2012-06-08 22:33:16 +0000 | |||
541 | +++ src/scripting/lua_root.cc 2013-07-19 21:32:25 +0000 | |||
542 | @@ -82,6 +82,7 @@ | |||
543 | 82 | PROP_RO(L_Game, time), | 82 | PROP_RO(L_Game, time), |
544 | 83 | PROP_RW(L_Game, desired_speed), | 83 | PROP_RW(L_Game, desired_speed), |
545 | 84 | PROP_RW(L_Game, allow_autosaving), | 84 | PROP_RW(L_Game, allow_autosaving), |
546 | 85 | PROP_RW(L_Game, allow_saving), | ||
547 | 85 | {0, 0, 0}, | 86 | {0, 0, 0}, |
548 | 86 | }; | 87 | }; |
549 | 87 | 88 | ||
550 | @@ -131,22 +132,33 @@ | |||
551 | 131 | } | 132 | } |
552 | 132 | 133 | ||
553 | 133 | /* RST | 134 | /* RST |
555 | 134 | .. attribute:: allow_autosaving | 135 | .. attribute:: allow_saving |
556 | 135 | 136 | ||
559 | 136 | (RW) Disable or enable auto-saving. When you show off UI features in a | 137 | (RW) Disable or enable saving. When you show off UI features in a |
560 | 137 | tutorial or scenario, you have to disallow auto-saving because UI | 138 | tutorial or scenario, you have to disallow saving because UI |
561 | 138 | elements can not be saved and therefore reloading a game saved in the | 139 | elements can not be saved and therefore reloading a game saved in the |
562 | 139 | meantime would crash the game. | 140 | meantime would crash the game. |
563 | 140 | */ | 141 | */ |
564 | 141 | // UNTESTED | 142 | // UNTESTED |
565 | 143 | int L_Game::set_allow_saving(lua_State * L) { | ||
566 | 144 | get_game(L).save_handler().set_allow_saving | ||
567 | 145 | (luaL_checkboolean(L, -1)); | ||
568 | 146 | return 0; | ||
569 | 147 | } | ||
570 | 148 | // UNTESTED | ||
571 | 149 | int L_Game::get_allow_saving(lua_State * L) { | ||
572 | 150 | lua_pushboolean(L, get_game(L).save_handler().get_allow_saving()); | ||
573 | 151 | return 1; | ||
574 | 152 | } | ||
575 | 142 | int L_Game::set_allow_autosaving(lua_State * L) { | 153 | int L_Game::set_allow_autosaving(lua_State * L) { |
577 | 143 | get_game(L).save_handler().set_allow_autosaving | 154 | // WAS_DEPRECATED_BEFORE(build18), use allow_saving |
578 | 155 | get_game(L).save_handler().set_allow_saving | ||
579 | 144 | (luaL_checkboolean(L, -1)); | 156 | (luaL_checkboolean(L, -1)); |
580 | 145 | return 0; | 157 | return 0; |
581 | 146 | } | 158 | } |
582 | 147 | // UNTESTED | ||
583 | 148 | int L_Game::get_allow_autosaving(lua_State * L) { | 159 | int L_Game::get_allow_autosaving(lua_State * L) { |
585 | 149 | lua_pushboolean(L, get_game(L).save_handler().get_allow_autosaving()); | 160 | // WAS_DEPRECATED_BEFORE(build18), use allow_saving |
586 | 161 | lua_pushboolean(L, get_game(L).save_handler().get_allow_saving()); | ||
587 | 150 | return 1; | 162 | return 1; |
588 | 151 | } | 163 | } |
589 | 152 | 164 | ||
590 | @@ -192,35 +204,23 @@ | |||
591 | 192 | /* RST | 204 | /* RST |
592 | 193 | .. method:: save(name) | 205 | .. method:: save(name) |
593 | 194 | 206 | ||
598 | 195 | Saves the game exactly as if the player had entered the save dialog and | 207 | Requests a savegame. Note that the actual save will be performed |
599 | 196 | entered name as an argument. If some error occurred while saving, this | 208 | later, and that you have no control over any error that may happen |
600 | 197 | will throw an Lua error. Note that this currently doesn't work when | 209 | by then currently. |
597 | 198 | called from inside a Coroutine. | ||
601 | 199 | 210 | ||
604 | 200 | :arg name: name of save game. If this game already exists, it will be | 211 | :arg name: name of save game, as if entered in the save dialog. |
605 | 201 | silently overwritten | 212 | If this game already exists, it will be silently overwritten. |
606 | 213 | If empty, the autosave name will be used. | ||
607 | 202 | :type name: :class:`string` | 214 | :type name: :class:`string` |
608 | 203 | :returns: :const:`nil` | 215 | :returns: :const:`nil` |
609 | 204 | */ | 216 | */ |
624 | 205 | int L_Game::save(lua_State * const L) { | 217 | int L_Game::save(lua_State * L) { |
625 | 206 | Widelands::Game & game = get_game(L); | 218 | std::string filename = luaL_checkstring(L, -1); |
626 | 207 | 219 | get_game(L).save_handler().request_save(filename); | |
613 | 208 | std::string const complete_filename = | ||
614 | 209 | game.save_handler().create_file_name | ||
615 | 210 | (SaveHandler::get_base_dir(), luaL_checkstring(L, -1)); | ||
616 | 211 | |||
617 | 212 | lua_pop(L, 2); // Make stack empty before persistence starts. | ||
618 | 213 | |||
619 | 214 | if (g_fs->FileExists(complete_filename)) | ||
620 | 215 | g_fs->Unlink(complete_filename); | ||
621 | 216 | std::string error; | ||
622 | 217 | if (!game.save_handler().save_game(game, complete_filename, &error)) | ||
623 | 218 | return report_error(L, "save error: %s", error.c_str()); | ||
627 | 219 | 220 | ||
628 | 220 | return 0; | 221 | return 0; |
629 | 221 | } | 222 | } |
630 | 222 | 223 | ||
631 | 223 | |||
632 | 224 | /* | 224 | /* |
633 | 225 | ========================================================== | 225 | ========================================================== |
634 | 226 | C METHODS | 226 | C METHODS |
635 | 227 | 227 | ||
636 | === modified file 'src/scripting/lua_root.h' | |||
637 | --- src/scripting/lua_root.h 2012-02-15 21:25:34 +0000 | |||
638 | +++ src/scripting/lua_root.h 2013-07-19 21:32:25 +0000 | |||
639 | @@ -53,6 +53,8 @@ | |||
640 | 53 | int set_desired_speed(lua_State *); | 53 | int set_desired_speed(lua_State *); |
641 | 54 | int get_allow_autosaving(lua_State *); | 54 | int get_allow_autosaving(lua_State *); |
642 | 55 | int set_allow_autosaving(lua_State *); | 55 | int set_allow_autosaving(lua_State *); |
643 | 56 | int get_allow_saving(lua_State *); | ||
644 | 57 | int set_allow_saving(lua_State *); | ||
645 | 56 | 58 | ||
646 | 57 | /* | 59 | /* |
647 | 58 | * Lua methods | 60 | * Lua methods |
648 | 59 | 61 | ||
649 | === modified file 'test/lua/persistence.wmf/scripting/init.lua' | |||
650 | --- test/lua/persistence.wmf/scripting/init.lua 2011-02-21 20:36:10 +0000 | |||
651 | +++ test/lua/persistence.wmf/scripting/init.lua 2013-07-19 21:32:25 +0000 | |||
652 | @@ -1,128 +1,138 @@ | |||
653 | 1 | -- ======================================================================= | 1 | -- ======================================================================= |
655 | 2 | -- LOADING/SAVING TESTS | 2 | -- LOADING/SAVING TESTS |
656 | 3 | -- ======================================================================= | 3 | -- ======================================================================= |
658 | 4 | -- This tests saving and loading of various Lua objects in the global | 4 | -- This tests saving and loading of various Lua objects in the global |
659 | 5 | -- environment. | 5 | -- environment. |
660 | 6 | -- | 6 | -- |
665 | 7 | -- To run this test use: | 7 | -- To run this test, go to the top level directory, set the path to your |
666 | 8 | -- ./widelands --nozip --scenario=src/scripting/test/persistence.wmf && | 8 | -- widelands binary and run: |
667 | 9 | -- ./widelands --loadgame=~/.widelands/save/lua_persistence.wgf | 9 | -- |
668 | 10 | 10 | -- $PATH_TO_WIDELANDS_BINARY --datadir="." --nozip --scenario=test/lua/persistence.wmf && \ | |
669 | 11 | -- $PATH_TO_WIDELANDS_BINARY --datadir="." --loadgame=~/.widelands/save/lua_persistence.wgf | ||
670 | 11 | 12 | ||
671 | 12 | -- ==================== | 13 | -- ==================== |
673 | 13 | -- Test Data to persist | 14 | -- Test Data to persist |
674 | 14 | -- ==================== | 15 | -- ==================== |
675 | 15 | use("aux", "set") | 16 | use("aux", "set") |
676 | 16 | |||
677 | 17 | my_name = "SirVer" | ||
678 | 18 | pi = 3.1415 | ||
679 | 19 | eight = 8 | ||
680 | 20 | is_true = true | ||
681 | 21 | is_false = false | ||
682 | 22 | |||
683 | 23 | game = wl.Game() | 17 | game = wl.Game() |
775 | 24 | p = game.players[1] | 18 | |
776 | 25 | map = game.map | 19 | function save_coroutine() |
777 | 26 | a = { "Hallo", "Welt" } | 20 | game = wl.Game() |
778 | 27 | c = { func = function(a) return "I say " .. a .. "!" end } | 21 | |
779 | 28 | field = map:get_field(32,34) | 22 | my_name = "SirVer" |
780 | 29 | tree = map:place_immovable("tree3", field) | 23 | pi = 3.1415 |
781 | 30 | removed_tree = map:place_immovable("tree4", map:get_field(34,34)) | 24 | eight = 8 |
782 | 31 | removed_tree:remove() | 25 | is_true = true |
783 | 32 | corout = coroutine.create(function() | 26 | is_false = false |
784 | 33 | local a = 100 | 27 | |
785 | 34 | coroutine.yield("What cool is that?") | 28 | game = wl.Game() |
786 | 35 | coroutine.yield(a) | 29 | p = game.players[1] |
787 | 36 | end) | 30 | map = game.map |
788 | 37 | objective = p:add_objective("lumber", "House", "Ship!") | 31 | a = { "Hallo", "Welt" } |
789 | 38 | objective.done = true | 32 | c = { func = function(a) return "I say " .. a .. "!" end } |
790 | 39 | 33 | field = map:get_field(32,34) | |
791 | 40 | p:send_message("dummy msg1", "dummy msg 1") | 34 | tree = map:place_immovable("tree3", field) |
792 | 41 | msg = p:send_message("hello nice", "World", {sender="blah", field = field }) | 35 | removed_tree = map:place_immovable("tree4", map:get_field(34,34)) |
793 | 42 | player_slot = map.player_slots[1] | 36 | removed_tree:remove() |
794 | 43 | 37 | ||
795 | 44 | myset = Set:new{ | 38 | corout = coroutine.create(function() |
796 | 45 | map:get_field(10,10), map:get_field(10,10), map:get_field(10,11) | 39 | local a = 100 |
797 | 46 | } | 40 | coroutine.yield("What cool is that?") |
798 | 47 | 41 | coroutine.yield(a) | |
799 | 48 | -- ======================== | 42 | end) |
800 | 49 | -- Test after unpersisting | 43 | objective = p:add_objective("lumber", "House", "Ship!") |
801 | 50 | -- ======================== | 44 | objective.done = true |
802 | 51 | function check_persistence() | 45 | |
803 | 52 | coroutine.yield(wl.Game().time + 2000) | 46 | p:send_message("dummy msg1", "dummy msg 1") |
804 | 53 | 47 | msg = p:send_message("hello nice", "World", {sender="blah", field = field }) | |
805 | 54 | use("map", "lunit") | 48 | player_slot = map.player_slots[1] |
806 | 55 | lunit.import "assertions" | 49 | |
807 | 56 | 50 | myset = Set:new{ | |
808 | 57 | print("###################### CHECKING FOR CORRECT PERSISTENCE") | 51 | map:get_field(10,10), map:get_field(10,10), map:get_field(10,11) |
809 | 58 | assert_equal("SirVer", my_name) | 52 | } |
810 | 59 | assert_equal(3.1415, pi) | 53 | |
811 | 60 | assert_equal(8, eight) | 54 | game:save("lua_persistence") |
812 | 61 | assert_equal(true, is_true) | 55 | print("Save requested\n"); |
813 | 62 | assert_equal(false, is_false) | 56 | |
814 | 63 | 57 | -- Stick around, so that we are needed to get loaded too. | |
815 | 64 | assert_equal(1, p.number) | 58 | coroutine.yield(wl.Game().time + 8000) |
816 | 65 | 59 | end | |
817 | 66 | assert_table(a) | 60 | |
818 | 67 | assert_equal(a[1], "Hallo") | 61 | function check_coroutine() |
819 | 68 | assert_equal(a[2], "Welt") | 62 | -- Sleep till the save routine has done its job. |
820 | 69 | 63 | coroutine.yield(wl.Game().time + 2000) | |
821 | 70 | assert_table(c) | 64 | |
822 | 71 | assert_function(c.func) | 65 | -- Attention, lunit contains code that can not be persisted (c functions), |
823 | 72 | assert_equal("I say zonk!", c.func("zonk")) | 66 | -- so it must be imported after reload. |
824 | 73 | 67 | use("map", "lunit") | |
825 | 74 | assert_equal("tree3", tree.name) | 68 | lunit.import "assertions" |
826 | 75 | 69 | ||
827 | 76 | assert_equal(32, field.x) | 70 | print("###################### CHECKING FOR CORRECT PERSISTENCE") |
828 | 77 | assert_equal(34, field.y) | 71 | assert_equal("SirVer", my_name) |
829 | 78 | assert_equal(tree, field.immovable) | 72 | assert_equal(3.1415, pi) |
830 | 79 | 73 | assert_equal(8, eight) | |
831 | 80 | assert_thread(corout) | 74 | assert_equal(true, is_true) |
832 | 81 | _,rv = coroutine.resume(corout) | 75 | assert_equal(false, is_false) |
833 | 82 | assert_equal("What cool is that?", rv) | 76 | |
834 | 83 | _,rv = coroutine.resume(corout) | 77 | assert_equal(1, p.number) |
835 | 84 | assert_equal(100, rv) | 78 | |
836 | 85 | 79 | assert_table(a) | |
837 | 86 | assert_table(objective) | 80 | assert_equal(a[1], "Hallo") |
838 | 87 | assert_equal("lumber", objective.name) | 81 | assert_equal(a[2], "Welt") |
839 | 88 | assert_equal("House", objective.title) | 82 | |
840 | 89 | assert_equal("Ship!", objective.body) | 83 | assert_table(c) |
841 | 90 | assert_equal(true, objective.done) | 84 | assert_function(c.func) |
842 | 91 | 85 | assert_equal("I say zonk!", c.func("zonk")) | |
843 | 92 | assert_table(msg) | 86 | |
844 | 93 | assert_equal("hello nice", msg.title) | 87 | assert_equal("tree3", tree.name) |
845 | 94 | assert_equal("World", msg.body) | 88 | |
846 | 95 | assert_equal("blah", msg.sender) | 89 | assert_equal(32, field.x) |
847 | 96 | assert_equal(field, msg.field) | 90 | assert_equal(34, field.y) |
848 | 97 | 91 | assert_equal(tree, field.immovable) | |
849 | 98 | assert_table(map) | 92 | |
850 | 99 | assert_equal(64, map.width) | 93 | assert_thread(corout) |
851 | 100 | assert_equal(64, map.height) | 94 | _,rv = coroutine.resume(corout) |
852 | 101 | 95 | assert_equal("What cool is that?", rv) | |
853 | 102 | assert_table(player_slot) | 96 | _,rv = coroutine.resume(corout) |
854 | 103 | assert_equal("barbarians", player_slot.tribe_name) | 97 | assert_equal(100, rv) |
855 | 104 | assert_equal("Player 1", player_slot.name) | 98 | |
856 | 105 | assert_equal(player_slot.name, map.player_slots[1].name) | 99 | assert_table(objective) |
857 | 106 | assert_equal(player_slot.tribe_name, map.player_slots[1].tribe_name) | 100 | assert_equal("lumber", objective.name) |
858 | 107 | 101 | assert_equal("House", objective.title) | |
859 | 108 | assert_equal(2, myset.size) | 102 | assert_equal("Ship!", objective.body) |
860 | 109 | assert_true(myset:contains(map:get_field(10,10))) | 103 | assert_equal(true, objective.done) |
861 | 110 | assert_true(myset:contains(map:get_field(10,11))) | 104 | |
862 | 111 | 105 | assert_table(msg) | |
863 | 112 | print("################### ALL TEST PASS!") | 106 | assert_equal("hello nice", msg.title) |
864 | 113 | 107 | assert_equal("World", msg.body) | |
865 | 114 | wl.ui.MapView():close() | 108 | assert_equal("blah", msg.sender) |
866 | 109 | assert_equal(field, msg.field) | ||
867 | 110 | |||
868 | 111 | assert_table(map) | ||
869 | 112 | assert_equal(64, map.width) | ||
870 | 113 | assert_equal(64, map.height) | ||
871 | 114 | |||
872 | 115 | assert_table(player_slot) | ||
873 | 116 | assert_equal("barbarians", player_slot.tribe_name) | ||
874 | 117 | assert_equal("Player 1", player_slot.name) | ||
875 | 118 | assert_equal(player_slot.name, map.player_slots[1].name) | ||
876 | 119 | assert_equal(player_slot.tribe_name, map.player_slots[1].tribe_name) | ||
877 | 120 | |||
878 | 121 | assert_equal(2, myset.size) | ||
879 | 122 | assert_true(myset:contains(map:get_field(10,10))) | ||
880 | 123 | assert_true(myset:contains(map:get_field(10,11))) | ||
881 | 124 | |||
882 | 125 | print("################### ALL TEST PASS!") | ||
883 | 126 | |||
884 | 127 | wl.ui.MapView():close() | ||
885 | 115 | end | 128 | end |
886 | 116 | 129 | ||
887 | 117 | 130 | ||
888 | 118 | -- ========== | 131 | -- ========== |
890 | 119 | -- Main Code | 132 | -- Main Code |
891 | 120 | -- ========== | 133 | -- ========== |
892 | 121 | -- This starts the test routine, saves the game and exits. | 134 | -- This starts the test routine, saves the game and exits. |
894 | 122 | -- Loading the saved game will check that all objects are | 135 | -- Loading the saved game will check that all objects are |
895 | 123 | -- correctly unpersisted | 136 | -- correctly unpersisted |
901 | 124 | game = wl.Game() | 137 | game:launch_coroutine(coroutine.create(check_coroutine)) |
902 | 125 | game:launch_coroutine(coroutine.create(check_persistence)) | 138 | game:launch_coroutine(coroutine.create(save_coroutine)) |
898 | 126 | game:save("lua_persistence") | ||
899 | 127 | wl.ui.MapView():close() | ||
900 | 128 |
I pushed my review of this branch in r6613. You can find all my comments by grep-ing for #cghislai. I changed some nits around (see the diff) and added a short comment when I found it appropriate - feel free to just delete them again, they are for your eyes only :). I did not touch anything that would affect the logic because you are more suited to do this as you know your code better.
I think the code looks very reasonable already. The biggest issues is that we now have wl.Game():save and wl.game.save_game - the first one is only used in the persistence.wmf test (see tests/lua/ persistence. wmf/scripting/ init.lua) . I think you should move your logic to the method that is already there and make sure that its new features are exercised in the persistence tests - comments are in the source code as well.