]> git.lizzy.rs Git - minetest.git/blob - builtin/modstore.lua
Fix settings to honor numeric conversion errors
[minetest.git] / builtin / modstore.lua
1 --Minetest
2 --Copyright (C) 2013 sapier
3 --
4 --This program is free software; you can redistribute it and/or modify
5 --it under the terms of the GNU Lesser General Public License as published by
6 --the Free Software Foundation; either version 2.1 of the License, or
7 --(at your option) any later version.
8 --
9 --This program is distributed in the hope that it will be useful,
10 --but WITHOUT ANY WARRANTY; without even the implied warranty of
11 --MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 --GNU Lesser General Public License for more details.
13 --
14 --You should have received a copy of the GNU Lesser General Public License along
15 --with this program; if not, write to the Free Software Foundation, Inc.,
16 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 --------------------------------------------------------------------------------
19
20 --modstore implementation
21 modstore = {}
22
23 --------------------------------------------------------------------------------
24 -- @function [parent=#modstore] init
25 function modstore.init()
26         modstore.tabnames = {}
27
28         table.insert(modstore.tabnames,"dialog_modstore_unsorted")
29         table.insert(modstore.tabnames,"dialog_modstore_search")
30
31         modstore.modsperpage = 5
32
33         modstore.basetexturedir = engine.get_texturepath() .. DIR_DELIM .. "base" ..
34                                                 DIR_DELIM .. "pack" .. DIR_DELIM
35
36         modstore.lastmodtitle = ""
37         modstore.last_search = ""
38         
39         modstore.searchlist = filterlist.create(
40                 function()
41                         if modstore.modlist_unsorted ~= nil and
42                                 modstore.modlist_unsorted.data ~= nil then
43                                 return modstore.modlist_unsorted.data
44                         end
45                         return {}
46                 end,
47                 function(element,modid)
48                         if element.id == modid then
49                                 return true
50                         end
51                         return false
52                 end, --compare fct
53                 nil, --uid match fct
54                 function(element,substring)
55                         if substring == nil or
56                                 substring == "" then
57                                 return false
58                         end
59                         substring = substring:upper()
60                         
61                         if element.title ~= nil and
62                                 element.title:upper():find(substring) ~= nil then
63                                 return true
64                         end
65                         
66                         if element.details ~= nil and
67                                 element.details.author ~= nil and
68                                 element.details.author:upper():find(substring) ~= nil then
69                                 return true
70                         end
71                         
72                         if element.details ~= nil and
73                                 element.details.description ~= nil and
74                                 element.details.description:upper():find(substring) ~= nil then
75                                 return true
76                         end
77                         return false
78                 end --filter fct
79                 )
80
81         modstore.current_list = nil
82 end
83
84 --------------------------------------------------------------------------------
85 -- @function [parent=#modstore] nametoindex
86 function modstore.nametoindex(name)
87
88         for i=1,#modstore.tabnames,1 do
89                 if modstore.tabnames[i] == name then
90                         return i
91                 end
92         end
93
94         return 1
95 end
96
97 --------------------------------------------------------------------------------
98 -- @function [parent=#modstore] getsuccessfuldialog
99 function modstore.getsuccessfuldialog()
100         local retval = ""
101         retval = retval .. "size[6,2]"
102         if modstore.lastmodentry ~= nil then
103                 retval = retval .. "label[0,0.25;" .. fgettext("Successfully installed:") .. "]"
104                 retval = retval .. "label[3,0.25;" .. modstore.lastmodentry.moddetails.title .. "]"
105         
106                 
107                 retval = retval .. "label[0,0.75;" .. fgettext("Shortname:") .. "]"
108                 retval = retval .. "label[3,0.75;" .. engine.formspec_escape(modstore.lastmodentry.moddetails.basename) .. "]"
109
110         end
111         retval = retval .. "button[2.5,1.5;1,0.5;btn_confirm_mod_successfull;" .. fgettext("ok") .. "]"
112                                 
113                                 
114         return retval
115 end
116
117 --------------------------------------------------------------------------------
118 -- @function [parent=#modstore] gettab
119 function modstore.gettab(tabname)
120         local retval = ""
121
122         local is_modstore_tab = false
123
124         if tabname == "dialog_modstore_unsorted" then
125                 modstore.modsperpage = 5
126                 retval = modstore.getmodlist(modstore.modlist_unsorted)
127                 is_modstore_tab = true
128         end
129
130         if tabname == "dialog_modstore_search" then
131                 retval = modstore.getsearchpage()
132                 is_modstore_tab = true
133         end
134
135         if is_modstore_tab then
136                 return modstore.tabheader(tabname) .. retval
137         end
138
139         if tabname == "modstore_mod_installed" then
140                 return modstore.getsuccessfuldialog()
141         end
142
143         if tabname == "modstore_downloading" then
144                 return "size[6,2]label[0.25,0.75;" .. fgettext("Downloading") ..
145                                 " " .. modstore.lastmodtitle .. " " ..
146                                 fgettext("please wait...") .. "]"
147         end
148
149         return ""
150 end
151
152 --------------------------------------------------------------------------------
153 -- @function [parent=#modstore] tabheader
154 function modstore.tabheader(tabname)
155         local retval  = "size[12,10.25]"
156         retval = retval .. "tabheader[-0.3,-0.99;modstore_tab;" ..
157                                 "Unsorted,Search;" ..
158                                 modstore.nametoindex(tabname) .. ";true;false]" ..
159                                 "button[4,9.9;4,0.5;btn_modstore_close;" ..
160                                 fgettext("Close modstore") .. "]"
161
162         return retval
163 end
164
165 --------------------------------------------------------------------------------
166 -- @function [parent=#modstore] handle_buttons
167 function modstore.handle_buttons(current_tab,fields)
168
169         if fields["modstore_tab"] then
170                 local index = tonumber(fields["modstore_tab"])
171
172                 if index > 0 and
173                         index <= #modstore.tabnames then
174                         if modstore.tabnames[index] == "dialog_modstore_search" then
175                                 filterlist.set_filtercriteria(modstore.searchlist,modstore.last_search)
176                                 filterlist.refresh(modstore.searchlist)
177                                 modstore.modsperpage = 4
178                                 modstore.currentlist = {
179                                         page = 0,
180                                         pagecount =
181                                                 math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
182                                         data = filterlist.get_list(modstore.searchlist),
183                                 }
184                         end
185                         
186                         return {
187                                         current_tab = modstore.tabnames[index],
188                                         is_dialog = true,
189                                         show_buttons = false
190                         }
191                 end
192                 
193         end
194
195         if fields["btn_modstore_page_up"] then
196                 if modstore.current_list ~= nil and modstore.current_list.page > 0 then
197                         modstore.current_list.page = modstore.current_list.page - 1
198                 end
199         end
200
201         if fields["btn_modstore_page_down"] then
202                 if modstore.current_list ~= nil and
203                         modstore.current_list.page <modstore.current_list.pagecount-1 then
204                         modstore.current_list.page = modstore.current_list.page +1
205                 end
206         end
207
208         if fields["btn_hidden_close_download"] ~= nil then
209                 if fields["btn_hidden_close_download"].successfull then
210                         modstore.lastmodentry = fields["btn_hidden_close_download"]
211                         return {
212                                         current_tab = "modstore_mod_installed",
213                                         is_dialog = true,
214                                         show_buttons = false
215                         }
216                 else
217                         modstore.lastmodtitle = ""
218                         return {
219                                                 current_tab = modstore.tabnames[1],
220                                                 is_dialog = true,
221                                                 show_buttons = false
222                                 }
223                 end
224         end
225
226         if fields["btn_confirm_mod_successfull"] then
227                 modstore.lastmodentry = nil
228                 modstore.lastmodtitle = ""
229                 return {
230                                         current_tab = modstore.tabnames[1],
231                                         is_dialog = true,
232                                         show_buttons = false
233                         }
234         end
235
236         if fields["btn_modstore_search"] or
237                 (fields["key_enter"] and fields["te_modstore_search"] ~= nil) then
238                 modstore.last_search = fields["te_modstore_search"]
239                 filterlist.set_filtercriteria(modstore.searchlist,fields["te_modstore_search"])
240                 filterlist.refresh(modstore.searchlist)
241                 modstore.currentlist = {
242                         page = 0,
243                         pagecount =  math.ceil(filterlist.size(modstore.searchlist) / modstore.modsperpage),
244                         data = filterlist.get_list(modstore.searchlist),
245                 }
246         end
247         
248         
249         if fields["btn_modstore_close"] then
250                 return {
251                         is_dialog = false,
252                         show_buttons = true,
253                         current_tab = engine.setting_get("main_menu_tab")
254                 }
255         end
256         
257         for key,value in pairs(fields) do
258                 local foundat = key:find("btn_install_mod_")
259                 if ( foundat == 1) then
260                         local modid = tonumber(key:sub(17))
261                         for i=1,#modstore.modlist_unsorted.data,1 do
262                                 if modstore.modlist_unsorted.data[i].id == modid then
263                                         local moddetails = modstore.modlist_unsorted.data[i].details
264
265                                         if modstore.lastmodtitle ~= "" then
266                                                 modstore.lastmodtitle = modstore.lastmodtitle .. ", "
267                                         end
268         
269                                         modstore.lastmodtitle = modstore.lastmodtitle .. moddetails.title
270         
271                                         engine.handle_async(
272                                                 function(param)
273                                                 
274                                                         local fullurl = engine.setting_get("modstore_download_url") ..
275                                                                                         param.moddetails.download_url
276                                                                                         
277                                                         if param.version ~= nil then
278                                                                 local found = false
279                                                                 for i=1,#param.moddetails.versions, 1 do
280                                                                         if param.moddetails.versions[i].date:sub(1,10) == param.version then
281                                                                                 fullurl = engine.setting_get("modstore_download_url") ..
282                                                                                                                 param.moddetails.versions[i].download_url
283                                                                                 found = true
284                                                                         end
285                                                                 end
286                                                                 
287                                                                 if not found then
288                                                                         return {
289                                                                                 moddetails = param.moddetails,
290                                                                                 successfull = false
291                                                                         }
292                                                                 end
293                                                         end
294         
295                                                         if engine.download_file(fullurl,param.filename) then
296                                                                 return {
297                                                                         texturename = param.texturename,
298                                                                         moddetails = param.moddetails,
299                                                                         filename = param.filename,
300                                                                         successfull = true
301                                                                 }
302                                                         else
303                                                                 return {
304                                                                         moddetails = param.moddetails,
305                                                                         successfull = false
306                                                                 }
307                                                         end
308                                                 end,
309                                                 {
310                                                         moddetails = moddetails,
311                                                         version = fields["dd_version" .. modid],
312                                                         filename = os.tempfolder() .. "_MODNAME_" .. moddetails.basename .. ".zip",
313                                                         texturename = modstore.modlist_unsorted.data[i].texturename
314                                                 },
315                                                 function(result)
316                                                         if result.successfull then
317                                                                 modmgr.installmod(result.filename,result.moddetails.basename)
318                                                                 os.remove(result.filename)
319                                                         else
320                                                                 gamedata.errormessage = "Failed to download " .. result.moddetails.title
321                                                         end
322         
323                                                         if gamedata.errormessage == nil then
324                                                                 engine.button_handler({btn_hidden_close_download=result})
325                                                         else
326                                                                 engine.button_handler({btn_hidden_close_download={successfull=false}})
327                                                         end
328                                                 end
329                                         )
330         
331                                         return {
332                                                 current_tab = "modstore_downloading",
333                                                 is_dialog = true,
334                                                 show_buttons = false,
335                                                 ignore_menu_quit = true
336                                         }
337                                 end
338                         end
339                         break
340                 end
341         end
342 end
343
344 --------------------------------------------------------------------------------
345 -- @function [parent=#modstore] update_modlist
346 function modstore.update_modlist()
347         modstore.modlist_unsorted = {}
348         modstore.modlist_unsorted.data = {}
349         modstore.modlist_unsorted.pagecount = 1
350         modstore.modlist_unsorted.page = 0
351
352         engine.handle_async(
353                 function(param)
354                         return engine.get_modstore_list()
355                 end,
356                 nil,
357                 function(result)
358                         if result ~= nil then
359                                 modstore.modlist_unsorted = {}
360                                 modstore.modlist_unsorted.data = result
361
362                                 if modstore.modlist_unsorted.data ~= nil then
363                                         modstore.modlist_unsorted.pagecount =
364                                                 math.ceil((#modstore.modlist_unsorted.data / modstore.modsperpage))
365                                 else
366                                         modstore.modlist_unsorted.data = {}
367                                         modstore.modlist_unsorted.pagecount = 1
368                                 end
369                                 modstore.modlist_unsorted.page = 0
370                                 modstore.fetchdetails()
371                                 engine.event_handler("Refresh")
372                         end
373                 end
374         )
375 end
376
377 --------------------------------------------------------------------------------
378 -- @function [parent=#modstore] fetchdetails
379 function modstore.fetchdetails()
380
381         for i=1,#modstore.modlist_unsorted.data,1 do
382                 engine.handle_async(
383                 function(param)
384                         param.details = engine.get_modstore_details(tostring(param.modid))
385                         return param
386                 end,
387                 {
388                         modid=modstore.modlist_unsorted.data[i].id,
389                         listindex=i
390                 },
391                 function(result)
392                         if result ~= nil and
393                                 modstore.modlist_unsorted ~= nil
394                                 and modstore.modlist_unsorted.data ~= nil and
395                                 modstore.modlist_unsorted.data[result.listindex] ~= nil and
396                                 modstore.modlist_unsorted.data[result.listindex].id ~= nil then
397
398                                 modstore.modlist_unsorted.data[result.listindex].details = result.details
399                                 engine.event_handler("Refresh")
400                         end
401                 end
402                 )
403         end
404 end
405
406 --------------------------------------------------------------------------------
407 -- @function [parent=#modstore] getscreenshot
408 function modstore.getscreenshot(ypos,listentry)
409
410         if      listentry.details ~= nil and
411                 (listentry.details.screenshot_url == nil or
412                 listentry.details.screenshot_url == "") then
413                 
414                 if listentry.texturename == nil then
415                         listentry.texturename = modstore.basetexturedir .. "no_screenshot.png"
416                 end
417                 
418                 return "image[0,".. ypos .. ";3,2;" ..
419                         engine.formspec_escape(listentry.texturename) .. "]"
420         end
421         
422         if listentry.details ~= nil and
423                 listentry.texturename == nil then
424                 --make sure we don't download multiple times
425                 listentry.texturename = "in progress"
426         
427                 --prepare url and filename
428                 local fullurl = engine.setting_get("modstore_download_url") ..
429                                         listentry.details.screenshot_url
430                 local filename = os.tempfolder() .. "_MID_" .. listentry.id
431                 
432                 --trigger download
433                 engine.handle_async(
434                         --first param is downloadfct
435                         function(param)
436                                 param.successfull = engine.download_file(param.fullurl,param.filename)
437                                 return param
438                         end,
439                         --second parameter is data passed to async job
440                         {
441                                 fullurl = fullurl,
442                                 filename = filename,
443                                 modid = listentry.id
444                         },
445                         --integrate result to raw list
446                         function(result)
447                                 if result.successfull then
448                                         local found = false
449                                         for i=1,#modstore.modlist_unsorted.data,1 do
450                                                 if modstore.modlist_unsorted.data[i].id == result.modid then
451                                                         found = true
452                                                         modstore.modlist_unsorted.data[i].texturename = result.filename
453                                                         break
454                                                 end
455                                         end
456                                         if found then
457                                                 engine.event_handler("Refresh")
458                                         else
459                                                 engine.log("error","got screenshot but didn't find matching mod: " .. result.modid)
460                                         end
461                                 end
462                         end
463                 )
464         end
465
466         if listentry.texturename ~= nil and
467                 listentry.texturename ~= "in progress" then
468                 return "image[0,".. ypos .. ";3,2;" ..
469                         engine.formspec_escape(listentry.texturename) .. "]"
470         end
471         
472         return ""
473 end
474
475 --------------------------------------------------------------------------------
476 --@function [parent=#modstore] getshortmodinfo
477 function modstore.getshortmodinfo(ypos,listentry,details)
478         local retval = ""
479         
480         retval = retval .. "box[0," .. ypos .. ";11.4,1.75;#FFFFFF]"
481
482         --screenshot
483         retval = retval .. modstore.getscreenshot(ypos,listentry)
484
485         --title + author
486         retval = retval .."label[2.75," .. ypos .. ";" ..
487                 engine.formspec_escape(details.title) .. " (" .. details.author .. ")]"
488
489         --description
490         local descriptiony = ypos + 0.5
491         retval = retval .. "textarea[3," .. descriptiony .. ";6.5,1.55;;" ..
492                 engine.formspec_escape(details.description) .. ";]"
493                 
494         --rating
495         local ratingy = ypos
496         retval = retval .."label[7," .. ratingy .. ";" ..
497                                         fgettext("Rating") .. ":]"
498         retval = retval .. "label[8.7," .. ratingy .. ";" .. details.rating .."]"
499         
500         --versions (IMPORTANT has to be defined AFTER rating)
501         if details.versions ~= nil and
502                 #details.versions > 1 then
503                 local versiony = ypos + 0.05
504                 retval = retval .. "dropdown[9.1," .. versiony .. ";2.48,0.25;dd_version" .. details.id .. ";"
505                 local versions = ""
506                 for i=1,#details.versions , 1 do
507                         if versions ~= "" then
508                                 versions = versions .. ","
509                         end
510                         
511                         versions = versions .. details.versions[i].date:sub(1,10)
512                 end
513                 retval = retval .. versions .. ";1]"
514         end
515
516         if details.basename then
517                 --install button
518                 local buttony = ypos + 1.2
519                 retval = retval .."button[9.1," .. buttony .. ";2.5,0.5;btn_install_mod_" .. details.id .. ";"
520
521                 if modmgr.mod_exists(details.basename) then
522                         retval = retval .. fgettext("re-Install") .."]"
523                 else
524                         retval = retval .. fgettext("Install") .."]"
525                 end
526         end
527         
528         return retval
529 end
530
531 --------------------------------------------------------------------------------
532 --@function [parent=#modstore] getmodlist
533 function modstore.getmodlist(list,yoffset)
534
535         modstore.current_list = list
536         
537         if #list.data == 0 then
538                 return ""
539         end
540         
541         if yoffset == nil then
542                 yoffset = 0
543         end
544
545         local scrollbar = ""
546         scrollbar = scrollbar .. "label[0.1,9.5;"
547                                 .. fgettext("Page $1 of $2", list.page+1, list.pagecount) .. "]"
548         scrollbar = scrollbar .. "box[11.6," .. (yoffset + 0.35) .. ";0.28,"
549                                 .. (8.6 - yoffset) .. ";#000000]"
550         local scrollbarpos = (yoffset + 0.75) +
551                                 ((7.7 -yoffset)/(list.pagecount-1)) * list.page
552         scrollbar = scrollbar .. "box[11.6," ..scrollbarpos .. ";0.28,0.5;#32CD32]"
553         scrollbar = scrollbar .. "button[11.6," .. (yoffset + (0.3))
554                                 .. ";0.5,0.5;btn_modstore_page_up;^]"
555         scrollbar = scrollbar .. "button[11.6," .. 9.0
556                                 .. ";0.5,0.5;btn_modstore_page_down;v]"
557
558         local retval = ""
559
560         local endmod = (list.page * modstore.modsperpage) + modstore.modsperpage
561
562         if (endmod > #list.data) then
563                 endmod = #list.data
564         end
565
566         for i=(list.page * modstore.modsperpage) +1, endmod, 1 do
567                 --getmoddetails
568                 local details = list.data[i].details
569
570                 if details == nil then
571                         details = {}
572                         details.title = list.data[i].title
573                         details.author = ""
574                         details.rating = -1
575                         details.description = ""
576                 end
577
578                 if details ~= nil then
579                         local screenshot_ypos =
580                                 yoffset +(i-1 - (list.page * modstore.modsperpage))*1.9 +0.2
581                                 
582                         retval = retval .. modstore.getshortmodinfo(screenshot_ypos,
583                                                                                                                 list.data[i],
584                                                                                                                 details)
585                 end
586         end
587         
588         return retval .. scrollbar
589 end
590
591 --------------------------------------------------------------------------------
592 --@function [parent=#modstore] getsearchpage
593 function modstore.getsearchpage()
594         local retval = ""
595         local search = ""
596         
597         if modstore.last_search ~= nil then
598                 search = modstore.last_search
599         end
600
601         retval = retval ..
602                 "button[9.5,0.2;2.5,0.5;btn_modstore_search;".. fgettext("Search") .. "]" ..
603                 "field[0.5,0.5;9,0.5;te_modstore_search;;" .. search .. "]"
604
605         
606         --show 4 mods only
607         modstore.modsperpage = 4
608         retval = retval ..
609                 modstore.getmodlist(
610                         modstore.currentlist,
611                         1.75)
612
613         return retval;
614 end
615