main.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633
  1. /*
  2. Minetest-c55
  3. Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. /*
  17. =============================== NOTES ==============================
  18. NOTE: Things starting with TODO are sometimes only suggestions.
  19. NOTE: iostream.imbue(std::locale("C")) is very slow
  20. NOTE: Global locale is now set at initialization
  21. NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the
  22. hardware buffer (it is not freed automatically)
  23. Old, wild and random suggestions that probably won't be done:
  24. -------------------------------------------------------------
  25. SUGG: If player is on ground, mainly fetch ground-level blocks
  26. SUGG: Expose Connection's seqnums and ACKs to server and client.
  27. - This enables saving many packets and making a faster connection
  28. - This also enables server to check if client has received the
  29. most recent block sent, for example.
  30. SUGG: Add a sane bandwidth throttling system to Connection
  31. SUGG: More fine-grained control of client's dumping of blocks from
  32. memory
  33. - ...What does this mean in the first place?
  34. SUGG: A map editing mode (similar to dedicated server mode)
  35. SUGG: Transfer more blocks in a single packet
  36. SUGG: A blockdata combiner class, to which blocks are added and at
  37. destruction it sends all the stuff in as few packets as possible.
  38. SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize
  39. it by sending more stuff in a single packet.
  40. - Add a packet queue to RemoteClient, from which packets will be
  41. combined with object data packets
  42. - This is not exactly trivial: the object data packets are
  43. sometimes very big by themselves
  44. - This might not give much network performance gain though.
  45. SUGG: Precalculate lighting translation table at runtime (at startup)
  46. - This is not doable because it is currently hand-made and not
  47. based on some mathematical function.
  48. - Note: This has been changing lately
  49. SUGG: A version number to blocks, which increments when the block is
  50. modified (node add/remove, water update, lighting update)
  51. - This can then be used to make sure the most recent version of
  52. a block has been sent to client, for example
  53. SUGG: Make the amount of blocks sending to client and the total
  54. amount of blocks dynamically limited. Transferring blocks is the
  55. main network eater of this system, so it is the one that has
  56. to be throttled so that RTTs stay low.
  57. SUGG: Meshes of blocks could be split into 6 meshes facing into
  58. different directions and then only those drawn that need to be
  59. SUGG: Calculate lighting per vertex to get a lighting effect like in
  60. bartwe's game
  61. SUGG: Background music based on cellular automata?
  62. http://www.earslap.com/projectslab/otomata
  63. SUGG: Simple light color information to air
  64. SUGG: Server-side objects could be moved based on nodes to enable very
  65. lightweight operation and simple AI
  66. - Not practical; client would still need to show smooth movement.
  67. SUGG: Make a system for pregenerating quick information for mapblocks, so
  68. that the client can show them as cubes before they are actually sent
  69. or even generated.
  70. Gaming ideas:
  71. -------------
  72. - Aim for something like controlling a single dwarf in Dwarf Fortress
  73. - The player could go faster by a crafting a boat, or riding an animal
  74. - Random NPC traders. what else?
  75. Game content:
  76. -------------
  77. - When furnace is destroyed, move items to player's inventory
  78. - Add lots of stuff
  79. - Glass blocks
  80. - Growing grass, decaying leaves
  81. - This can be done in the active blocks I guess.
  82. - Lots of stuff can be done in the active blocks.
  83. - Uh, is there an active block list somewhere? I think not. Add it.
  84. - Breaking weak structures
  85. - This can probably be accomplished in the same way as grass
  86. - Player health points
  87. - When player dies, throw items on map (needs better item-on-map
  88. implementation)
  89. - Cobble to get mossy if near water
  90. - More slots in furnace source list, so that multiple ingredients
  91. are possible.
  92. - Keys to chests?
  93. - The Treasure Guard; a big monster with a hammer
  94. - The hammer does great damage, shakes the ground and removes a block
  95. - You can drop on top of it, and have some time to attack there
  96. before he shakes you off
  97. - Maybe the difficulty could come from monsters getting tougher in
  98. far-away places, and the player starting to need something from
  99. there when time goes by.
  100. - The player would have some of that stuff at the beginning, and
  101. would need new supplies of it when it runs out
  102. - A bomb
  103. - A spread-items-on-map routine for the bomb, and for dying players
  104. - Fighting:
  105. - Proper sword swing simulation
  106. - Player should get damage from colliding to a wall at high speed
  107. Documentation:
  108. --------------
  109. Build system / running:
  110. -----------------------
  111. Networking and serialization:
  112. -----------------------------
  113. SUGG: Fix address to be ipv6 compatible
  114. User Interface:
  115. ---------------
  116. Graphics:
  117. ---------
  118. SUGG: Combine MapBlock's face caches to so big pieces that VBO
  119. can be used
  120. - That is >500 vertices
  121. - This is not easy; all the MapBlocks close to the player would
  122. still need to be drawn separately and combining the blocks
  123. would have to happen in a background thread
  124. SUGG: Make fetching sector's blocks more efficient when rendering
  125. sectors that have very large amounts of blocks (on client)
  126. - Is this necessary at all?
  127. TODO: Flowing water animation
  128. SUGG: Draw cubes in inventory directly with 3D drawing commands, so that
  129. animating them is easier.
  130. SUGG: Option for enabling proper alpha channel for textures
  131. TODO: A setting for enabling bilinear filtering for textures
  132. TODO: Better control of draw_control.wanted_max_blocks
  133. TODO: Block mesh generator to tile properly on smooth lighting
  134. TODO: Further investigate the use of GPU lighting in addition to the
  135. current one
  136. TODO: Quick drawing of huge distances according to heightmap has to be
  137. tested once again.
  138. Configuration:
  139. --------------
  140. Client:
  141. -------
  142. TODO: Untie client network operations from framerate
  143. - Needs some input queues or something
  144. - This won't give much performance boost because calculating block
  145. meshes takes so long
  146. SUGG: Make morning and evening transition more smooth and maybe shorter
  147. TODO: Don't update all meshes always on single node changes, but
  148. check which ones should be updated
  149. - implement Map::updateNodeMeshes() and the usage of it
  150. - It will give almost always a 4x boost in mesh update performance.
  151. - A weapon engine
  152. - Tool/weapon visualization
  153. FIXME: When disconnected to the menu, memory is not freed properly
  154. Server:
  155. -------
  156. SUGG: Make an option to the server to disable building and digging near
  157. the starting position
  158. FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
  159. * Fix the problem with the server constantly saving one or a few
  160. blocks? List the first saved block, maybe it explains.
  161. - It is probably caused by oscillating water
  162. * Make a small history check to transformLiquids to detect and log
  163. continuous oscillations, in such detail that they can be fixed.
  164. FIXME: The new optimized map sending doesn't sometimes send enough blocks
  165. from big caves and such
  166. * Take player's walking direction into account in GetNextBlocks
  167. TODO: Map saving should be done by EmergeThread
  168. Environment:
  169. ------------
  170. TODO: A list of "active blocks" in which stuff happens.
  171. + Add a never-resetted game timer to the server
  172. + Add a timestamp value to blocks
  173. + The simple rule: All blocks near some player are "active"
  174. - Do stuff in real time in active blocks
  175. + Handle objects
  176. TODO: Make proper hooks in here
  177. - Grow grass, delete leaves without a tree
  178. - Spawn some mobs based on some rules
  179. - Transform cobble to mossy cobble near water
  180. - Run a custom script
  181. - ...And all kinds of other dynamic stuff
  182. + Keep track of when a block becomes active and becomes inactive
  183. + When a block goes inactive:
  184. + Store objects statically to block
  185. + Store timer value as the timestamp
  186. + When a block goes active:
  187. + Create active objects out of static objects
  188. TODO: Make proper hooks in here
  189. - Simulate the results of what would have happened if it would have
  190. been active for all the time
  191. - Grow a lot of grass and so on
  192. + Initially it is fine to send information about every active object
  193. to every player. Eventually it should be modified to only send info
  194. about the nearest ones.
  195. + This was left to be done by the old system and it sends only the
  196. nearest ones.
  197. Objects:
  198. --------
  199. TODO: Get rid of MapBlockObjects and use only ActiveObjects
  200. - Skipping the MapBlockObject data is nasty - there is no "total
  201. length" stored; have to make a SkipMBOs function which contains
  202. enough of the current code to skip them properly.
  203. SUGG: MovingObject::move and Player::move are basically the same.
  204. combine them.
  205. - NOTE: Player::move is more up-to-date.
  206. - NOTE: There is a simple move implementation now in collision.{h,cpp}
  207. - NOTE: MovingObject will be deleted (MapBlockObject)
  208. TODO: Add a long step function to objects that is called with the time
  209. difference when block activates
  210. Map:
  211. ----
  212. TODO: Mineral and ground material properties
  213. - This way mineral ground toughness can be calculated with just
  214. some formula, as well as tool strengths
  215. TODO: Flowing water to actually contain flow direction information
  216. - There is a space for this - it just has to be implemented.
  217. SUGG: Erosion simulation at map generation time
  218. - Simulate water flows, which would carve out dirt fast and
  219. then turn stone into gravel and sand and relocate it.
  220. - How about relocating minerals, too? Coal and gold in
  221. downstream sand and gravel would be kind of cool
  222. - This would need a better way of handling minerals, mainly
  223. to have mineral content as a separate field. the first
  224. parameter field is free for this.
  225. - Simulate rock falling from cliffs when water has removed
  226. enough solid rock from the bottom
  227. SUGG: Try out the notch way of generating maps, that is, make bunches
  228. of low-res 3d noise and interpolate linearly.
  229. Mapgen v2:
  230. * Possibly add some kind of erosion and other stuff
  231. * Better water generation (spread it to underwater caverns but don't
  232. fill dungeons that don't touch big water masses)
  233. * When generating a chunk and the neighboring chunk doesn't have mud
  234. and stuff yet and the ground is fairly flat, the mud will flow to
  235. the other chunk making nasty straight walls when the other chunk
  236. is generated. Fix it. Maybe just a special case if the ground is
  237. flat?
  238. Misc. stuff:
  239. ------------
  240. * Move digging property stuff from material.{h,cpp} to mapnode.cpp
  241. - ...Or maybe move content_features to material.{h,cpp}?
  242. Making it more portable:
  243. ------------------------
  244. Stuff to do before release:
  245. ---------------------------
  246. Fixes to the current release:
  247. -----------------------------
  248. Stuff to do after release:
  249. ---------------------------
  250. - Make sure server handles removing grass when a block is placed (etc)
  251. - The client should not do it by itself
  252. - Block cube placement around player's head
  253. - Protocol version field
  254. - Consider getting some textures from cisoun's texture pack
  255. - Ask from Cisoun
  256. - Make sure the fence implementation and data format is good
  257. - Think about using same bits for material for fences and doors, for
  258. example
  259. - Finish the ActiveBlockModifier stuff and use it for something
  260. - Move mineral to param2, increment map serialization version, add conversion
  261. ======================================================================
  262. */
  263. #ifdef NDEBUG
  264. #ifdef _WIN32
  265. #pragma message ("Disabling unit tests")
  266. #else
  267. #warning "Disabling unit tests"
  268. #endif
  269. // Disable unit tests
  270. #define ENABLE_TESTS 0
  271. #else
  272. // Enable unit tests
  273. #define ENABLE_TESTS 1
  274. #endif
  275. #ifdef _MSC_VER
  276. #pragma comment(lib, "Irrlicht.lib")
  277. //#pragma comment(lib, "jthread.lib")
  278. #pragma comment(lib, "zlibwapi.lib")
  279. #pragma comment(lib, "Shell32.lib")
  280. // This would get rid of the console window
  281. //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
  282. #endif
  283. #include <iostream>
  284. #include <fstream>
  285. //#include <jmutexautolock.h>
  286. #include <locale.h>
  287. #include "main.h"
  288. #include "common_irrlicht.h"
  289. #include "debug.h"
  290. //#include "map.h"
  291. //#include "player.h"
  292. #include "test.h"
  293. #include "server.h"
  294. //#include "client.h"
  295. #include "constants.h"
  296. #include "porting.h"
  297. #include "gettime.h"
  298. #include "guiMessageMenu.h"
  299. #include "filesys.h"
  300. #include "config.h"
  301. #include "guiMainMenu.h"
  302. #include "mineral.h"
  303. //#include "noise.h"
  304. //#include "tile.h"
  305. #include "materials.h"
  306. #include "game.h"
  307. #include "keycode.h"
  308. // This makes textures
  309. ITextureSource *g_texturesource = NULL;
  310. /*
  311. Settings.
  312. These are loaded from the config file.
  313. */
  314. Settings g_settings;
  315. // This is located in defaultsettings.cpp
  316. extern void set_default_settings();
  317. // Global profiler
  318. Profiler g_profiler;
  319. /*
  320. Random stuff
  321. */
  322. /*
  323. GUI Stuff
  324. */
  325. gui::IGUIEnvironment* guienv = NULL;
  326. gui::IGUIStaticText *guiroot = NULL;
  327. MainMenuManager g_menumgr;
  328. bool noMenuActive()
  329. {
  330. return (g_menumgr.menuCount() == 0);
  331. }
  332. // Passed to menus to allow disconnecting and exiting
  333. MainGameCallback *g_gamecallback = NULL;
  334. /*
  335. Debug streams
  336. */
  337. // Connection
  338. std::ostream *dout_con_ptr = &dummyout;
  339. std::ostream *derr_con_ptr = &dstream_no_stderr;
  340. //std::ostream *dout_con_ptr = &dstream_no_stderr;
  341. //std::ostream *derr_con_ptr = &dstream_no_stderr;
  342. //std::ostream *dout_con_ptr = &dstream;
  343. //std::ostream *derr_con_ptr = &dstream;
  344. // Server
  345. std::ostream *dout_server_ptr = &dstream;
  346. std::ostream *derr_server_ptr = &dstream;
  347. // Client
  348. std::ostream *dout_client_ptr = &dstream;
  349. std::ostream *derr_client_ptr = &dstream;
  350. /*
  351. gettime.h implementation
  352. */
  353. // A small helper class
  354. class TimeGetter
  355. {
  356. public:
  357. virtual u32 getTime() = 0;
  358. };
  359. // A precise irrlicht one
  360. class IrrlichtTimeGetter: public TimeGetter
  361. {
  362. public:
  363. IrrlichtTimeGetter(IrrlichtDevice *device):
  364. m_device(device)
  365. {}
  366. u32 getTime()
  367. {
  368. if(m_device == NULL)
  369. return 0;
  370. return m_device->getTimer()->getRealTime();
  371. }
  372. private:
  373. IrrlichtDevice *m_device;
  374. };
  375. // Not so precise one which works without irrlicht
  376. class SimpleTimeGetter: public TimeGetter
  377. {
  378. public:
  379. u32 getTime()
  380. {
  381. return porting::getTimeMs();
  382. }
  383. };
  384. // A pointer to a global instance of the time getter
  385. // TODO: why?
  386. TimeGetter *g_timegetter = NULL;
  387. u32 getTimeMs()
  388. {
  389. if(g_timegetter == NULL)
  390. return 0;
  391. return g_timegetter->getTime();
  392. }
  393. /*
  394. Event handler for Irrlicht
  395. NOTE: Everything possible should be moved out from here,
  396. probably to InputHandler and the_game
  397. */
  398. class MyEventReceiver : public IEventReceiver
  399. {
  400. public:
  401. // This is the one method that we have to implement
  402. virtual bool OnEvent(const SEvent& event)
  403. {
  404. /*
  405. React to nothing here if a menu is active
  406. */
  407. if(noMenuActive() == false)
  408. {
  409. return false;
  410. }
  411. // Remember whether each key is down or up
  412. if(event.EventType == irr::EET_KEY_INPUT_EVENT)
  413. {
  414. keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
  415. if(event.KeyInput.PressedDown)
  416. keyWasDown[event.KeyInput.Key] = true;
  417. }
  418. if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)
  419. {
  420. if(noMenuActive() == false)
  421. {
  422. left_active = false;
  423. middle_active = false;
  424. right_active = false;
  425. }
  426. else
  427. {
  428. //dstream<<"MyEventReceiver: mouse input"<<std::endl;
  429. left_active = event.MouseInput.isLeftPressed();
  430. middle_active = event.MouseInput.isMiddlePressed();
  431. right_active = event.MouseInput.isRightPressed();
  432. if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
  433. {
  434. leftclicked = true;
  435. }
  436. if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
  437. {
  438. rightclicked = true;
  439. }
  440. if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
  441. {
  442. leftreleased = true;
  443. }
  444. if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
  445. {
  446. rightreleased = true;
  447. }
  448. if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
  449. {
  450. mouse_wheel += event.MouseInput.Wheel;
  451. }
  452. }
  453. }
  454. return false;
  455. }
  456. bool IsKeyDown(EKEY_CODE keyCode) const
  457. {
  458. return keyIsDown[keyCode];
  459. }
  460. // Checks whether a key was down and resets the state
  461. bool WasKeyDown(EKEY_CODE keyCode)
  462. {
  463. bool b = keyWasDown[keyCode];
  464. keyWasDown[keyCode] = false;
  465. return b;
  466. }
  467. s32 getMouseWheel()
  468. {
  469. s32 a = mouse_wheel;
  470. mouse_wheel = 0;
  471. return a;
  472. }
  473. void clearInput()
  474. {
  475. for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)
  476. {
  477. keyIsDown[i] = false;
  478. keyWasDown[i] = false;
  479. }
  480. leftclicked = false;
  481. rightclicked = false;
  482. leftreleased = false;
  483. rightreleased = false;
  484. left_active = false;
  485. middle_active = false;
  486. right_active = false;
  487. mouse_wheel = 0;
  488. }
  489. MyEventReceiver()
  490. {
  491. clearInput();
  492. }
  493. bool leftclicked;
  494. bool rightclicked;
  495. bool leftreleased;
  496. bool rightreleased;
  497. bool left_active;
  498. bool middle_active;
  499. bool right_active;
  500. s32 mouse_wheel;
  501. private:
  502. IrrlichtDevice *m_device;
  503. // The current state of keys
  504. bool keyIsDown[KEY_KEY_CODES_COUNT];
  505. // Whether a key has been pressed or not
  506. bool keyWasDown[KEY_KEY_CODES_COUNT];
  507. };
  508. /*
  509. Separated input handler
  510. */
  511. class RealInputHandler : public InputHandler
  512. {
  513. public:
  514. RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):
  515. m_device(device),
  516. m_receiver(receiver)
  517. {
  518. }
  519. virtual bool isKeyDown(EKEY_CODE keyCode)
  520. {
  521. return m_receiver->IsKeyDown(keyCode);
  522. }
  523. virtual bool wasKeyDown(EKEY_CODE keyCode)
  524. {
  525. return m_receiver->WasKeyDown(keyCode);
  526. }
  527. virtual v2s32 getMousePos()
  528. {
  529. return m_device->getCursorControl()->getPosition();
  530. }
  531. virtual void setMousePos(s32 x, s32 y)
  532. {
  533. m_device->getCursorControl()->setPosition(x, y);
  534. }
  535. virtual bool getLeftState()
  536. {
  537. return m_receiver->left_active;
  538. }
  539. virtual bool getRightState()
  540. {
  541. return m_receiver->right_active;
  542. }
  543. virtual bool getLeftClicked()
  544. {
  545. return m_receiver->leftclicked;
  546. }
  547. virtual bool getRightClicked()
  548. {
  549. return m_receiver->rightclicked;
  550. }
  551. virtual void resetLeftClicked()
  552. {
  553. m_receiver->leftclicked = false;
  554. }
  555. virtual void resetRightClicked()
  556. {
  557. m_receiver->rightclicked = false;
  558. }
  559. virtual bool getLeftReleased()
  560. {
  561. return m_receiver->leftreleased;
  562. }
  563. virtual bool getRightReleased()
  564. {
  565. return m_receiver->rightreleased;
  566. }
  567. virtual void resetLeftReleased()
  568. {
  569. m_receiver->leftreleased = false;
  570. }
  571. virtual void resetRightReleased()
  572. {
  573. m_receiver->rightreleased = false;
  574. }
  575. virtual s32 getMouseWheel()
  576. {
  577. return m_receiver->getMouseWheel();
  578. }
  579. void clear()
  580. {
  581. m_receiver->clearInput();
  582. }
  583. private:
  584. IrrlichtDevice *m_device;
  585. MyEventReceiver *m_receiver;
  586. };
  587. class RandomInputHandler : public InputHandler
  588. {
  589. public:
  590. RandomInputHandler()
  591. {
  592. leftdown = false;
  593. rightdown = false;
  594. leftclicked = false;
  595. rightclicked = false;
  596. leftreleased = false;
  597. rightreleased = false;
  598. for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
  599. keydown[i] = false;
  600. }
  601. virtual bool isKeyDown(EKEY_CODE keyCode)
  602. {
  603. return keydown[keyCode];
  604. }
  605. virtual bool wasKeyDown(EKEY_CODE keyCode)
  606. {
  607. return false;
  608. }
  609. virtual v2s32 getMousePos()
  610. {
  611. return mousepos;
  612. }
  613. virtual void setMousePos(s32 x, s32 y)
  614. {
  615. mousepos = v2s32(x,y);
  616. }
  617. virtual bool getLeftState()
  618. {
  619. return leftdown;
  620. }
  621. virtual bool getRightState()
  622. {
  623. return rightdown;
  624. }
  625. virtual bool getLeftClicked()
  626. {
  627. return leftclicked;
  628. }
  629. virtual bool getRightClicked()
  630. {
  631. return rightclicked;
  632. }
  633. virtual void resetLeftClicked()
  634. {
  635. leftclicked = false;
  636. }
  637. virtual void resetRightClicked()
  638. {
  639. rightclicked = false;
  640. }
  641. virtual bool getLeftReleased()
  642. {
  643. return leftreleased;
  644. }
  645. virtual bool getRightReleased()
  646. {
  647. return rightreleased;
  648. }
  649. virtual void resetLeftReleased()
  650. {
  651. leftreleased = false;
  652. }
  653. virtual void resetRightReleased()
  654. {
  655. rightreleased = false;
  656. }
  657. virtual s32 getMouseWheel()
  658. {
  659. return 0;
  660. }
  661. virtual void step(float dtime)
  662. {
  663. {
  664. static float counter1 = 0;
  665. counter1 -= dtime;
  666. if(counter1 < 0.0)
  667. {
  668. counter1 = 0.1*Rand(1, 40);
  669. keydown[getKeySetting("keymap_jump")] =
  670. !keydown[getKeySetting("keymap_jump")];
  671. }
  672. }
  673. {
  674. static float counter1 = 0;
  675. counter1 -= dtime;
  676. if(counter1 < 0.0)
  677. {
  678. counter1 = 0.1*Rand(1, 40);
  679. keydown[getKeySetting("keymap_special1")] =
  680. !keydown[getKeySetting("keymap_special1")];
  681. }
  682. }
  683. {
  684. static float counter1 = 0;
  685. counter1 -= dtime;
  686. if(counter1 < 0.0)
  687. {
  688. counter1 = 0.1*Rand(1, 40);
  689. keydown[getKeySetting("keymap_forward")] =
  690. !keydown[getKeySetting("keymap_forward")];
  691. }
  692. }
  693. {
  694. static float counter1 = 0;
  695. counter1 -= dtime;
  696. if(counter1 < 0.0)
  697. {
  698. counter1 = 0.1*Rand(1, 40);
  699. keydown[getKeySetting("keymap_left")] =
  700. !keydown[getKeySetting("keymap_left")];
  701. }
  702. }
  703. {
  704. static float counter1 = 0;
  705. counter1 -= dtime;
  706. if(counter1 < 0.0)
  707. {
  708. counter1 = 0.1*Rand(1, 20);
  709. mousespeed = v2s32(Rand(-20,20), Rand(-15,20));
  710. }
  711. }
  712. {
  713. static float counter1 = 0;
  714. counter1 -= dtime;
  715. if(counter1 < 0.0)
  716. {
  717. counter1 = 0.1*Rand(1, 30);
  718. leftdown = !leftdown;
  719. if(leftdown)
  720. leftclicked = true;
  721. if(!leftdown)
  722. leftreleased = true;
  723. }
  724. }
  725. {
  726. static float counter1 = 0;
  727. counter1 -= dtime;
  728. if(counter1 < 0.0)
  729. {
  730. counter1 = 0.1*Rand(1, 15);
  731. rightdown = !rightdown;
  732. if(rightdown)
  733. rightclicked = true;
  734. if(!rightdown)
  735. rightreleased = true;
  736. }
  737. }
  738. mousepos += mousespeed;
  739. }
  740. s32 Rand(s32 min, s32 max)
  741. {
  742. return (myrand()%(max-min+1))+min;
  743. }
  744. private:
  745. bool keydown[KEY_KEY_CODES_COUNT];
  746. v2s32 mousepos;
  747. v2s32 mousespeed;
  748. bool leftdown;
  749. bool rightdown;
  750. bool leftclicked;
  751. bool rightclicked;
  752. bool leftreleased;
  753. bool rightreleased;
  754. };
  755. // These are defined global so that they're not optimized too much.
  756. // Can't change them to volatile.
  757. s16 temp16;
  758. f32 tempf;
  759. v3f tempv3f1;
  760. v3f tempv3f2;
  761. std::string tempstring;
  762. std::string tempstring2;
  763. void SpeedTests()
  764. {
  765. {
  766. dstream<<"The following test should take around 20ms."<<std::endl;
  767. TimeTaker timer("Testing std::string speed");
  768. const u32 jj = 10000;
  769. for(u32 j=0; j<jj; j++)
  770. {
  771. tempstring = "";
  772. tempstring2 = "";
  773. const u32 ii = 10;
  774. for(u32 i=0; i<ii; i++){
  775. tempstring2 += "asd";
  776. }
  777. for(u32 i=0; i<ii+1; i++){
  778. tempstring += "asd";
  779. if(tempstring == tempstring2)
  780. break;
  781. }
  782. }
  783. }
  784. dstream<<"All of the following tests should take around 100ms each."
  785. <<std::endl;
  786. {
  787. TimeTaker timer("Testing floating-point conversion speed");
  788. tempf = 0.001;
  789. for(u32 i=0; i<4000000; i++){
  790. temp16 += tempf;
  791. tempf += 0.001;
  792. }
  793. }
  794. {
  795. TimeTaker timer("Testing floating-point vector speed");
  796. tempv3f1 = v3f(1,2,3);
  797. tempv3f2 = v3f(4,5,6);
  798. for(u32 i=0; i<10000000; i++){
  799. tempf += tempv3f1.dotProduct(tempv3f2);
  800. tempv3f2 += v3f(7,8,9);
  801. }
  802. }
  803. {
  804. TimeTaker timer("Testing core::map speed");
  805. core::map<v2s16, f32> map1;
  806. tempf = -324;
  807. const s16 ii=300;
  808. for(s16 y=0; y<ii; y++){
  809. for(s16 x=0; x<ii; x++){
  810. map1.insert(v2s16(x,y), tempf);
  811. tempf += 1;
  812. }
  813. }
  814. for(s16 y=ii-1; y>=0; y--){
  815. for(s16 x=0; x<ii; x++){
  816. tempf = map1[v2s16(x,y)];
  817. }
  818. }
  819. }
  820. {
  821. dstream<<"Around 5000/ms should do well here."<<std::endl;
  822. TimeTaker timer("Testing mutex speed");
  823. JMutex m;
  824. m.Init();
  825. u32 n = 0;
  826. u32 i = 0;
  827. do{
  828. n += 10000;
  829. for(; i<n; i++){
  830. m.Lock();
  831. m.Unlock();
  832. }
  833. }
  834. // Do at least 10ms
  835. while(timer.getTime() < 10);
  836. u32 dtime = timer.stop();
  837. u32 per_ms = n / dtime;
  838. std::cout<<"Done. "<<dtime<<"ms, "
  839. <<per_ms<<"/ms"<<std::endl;
  840. }
  841. }
  842. void drawMenuBackground(video::IVideoDriver* driver)
  843. {
  844. core::dimension2d<u32> screensize = driver->getScreenSize();
  845. video::ITexture *bgtexture =
  846. driver->getTexture(getTexturePath("mud.png").c_str());
  847. if(bgtexture)
  848. {
  849. s32 texturesize = 128;
  850. s32 tiled_y = screensize.Height / texturesize + 1;
  851. s32 tiled_x = screensize.Width / texturesize + 1;
  852. for(s32 y=0; y<tiled_y; y++)
  853. for(s32 x=0; x<tiled_x; x++)
  854. {
  855. core::rect<s32> rect(0,0,texturesize,texturesize);
  856. rect += v2s32(x*texturesize, y*texturesize);
  857. driver->draw2DImage(bgtexture, rect,
  858. core::rect<s32>(core::position2d<s32>(0,0),
  859. core::dimension2di(bgtexture->getSize())),
  860. NULL, NULL, true);
  861. }
  862. }
  863. video::ITexture *logotexture =
  864. driver->getTexture(getTexturePath("menulogo.png").c_str());
  865. if(logotexture)
  866. {
  867. v2s32 logosize(logotexture->getOriginalSize().Width,
  868. logotexture->getOriginalSize().Height);
  869. logosize *= 4;
  870. video::SColor bgcolor(255,50,50,50);
  871. core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,
  872. screensize.Width, screensize.Height);
  873. driver->draw2DRectangle(bgcolor, bgrect, NULL);
  874. core::rect<s32> rect(0,0,logosize.X,logosize.Y);
  875. rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);
  876. rect -= v2s32(logosize.X/2, 0);
  877. driver->draw2DImage(logotexture, rect,
  878. core::rect<s32>(core::position2d<s32>(0,0),
  879. core::dimension2di(logotexture->getSize())),
  880. NULL, NULL, true);
  881. }
  882. }
  883. int main(int argc, char *argv[])
  884. {
  885. /*
  886. Initialization
  887. */
  888. // Set locale. This is for forcing '.' as the decimal point.
  889. std::locale::global(std::locale("C"));
  890. // This enables printing all characters in bitmap font
  891. setlocale(LC_CTYPE, "en_US");
  892. /*
  893. Parse command line
  894. */
  895. // List all allowed options
  896. core::map<std::string, ValueSpec> allowed_options;
  897. allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));
  898. allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,
  899. "Run server directly"));
  900. allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,
  901. "Load configuration from specified file"));
  902. allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));
  903. allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));
  904. allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));
  905. allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));
  906. allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));
  907. allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));
  908. #ifdef _WIN32
  909. allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));
  910. #endif
  911. allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));
  912. Settings cmd_args;
  913. bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);
  914. if(ret == false || cmd_args.getFlag("help"))
  915. {
  916. dstream<<"Allowed options:"<<std::endl;
  917. for(core::map<std::string, ValueSpec>::Iterator
  918. i = allowed_options.getIterator();
  919. i.atEnd() == false; i++)
  920. {
  921. dstream<<" --"<<i.getNode()->getKey();
  922. if(i.getNode()->getValue().type == VALUETYPE_FLAG)
  923. {
  924. }
  925. else
  926. {
  927. dstream<<" <value>";
  928. }
  929. dstream<<std::endl;
  930. if(i.getNode()->getValue().help != NULL)
  931. {
  932. dstream<<" "<<i.getNode()->getValue().help
  933. <<std::endl;
  934. }
  935. }
  936. return cmd_args.getFlag("help") ? 0 : 1;
  937. }
  938. /*
  939. Low-level initialization
  940. */
  941. bool disable_stderr = false;
  942. #ifdef _WIN32
  943. if(cmd_args.getFlag("dstream-on-stderr") == false)
  944. disable_stderr = true;
  945. #endif
  946. porting::signal_handler_init();
  947. bool &kill = *porting::signal_handler_killstatus();
  948. // Initialize porting::path_data and porting::path_userdata
  949. porting::initializePaths();
  950. // Initialize debug streams
  951. #ifdef RUN_IN_PLACE
  952. std::string debugfile = DEBUGFILE;
  953. #else
  954. std::string debugfile = porting::path_userdata+"/"+DEBUGFILE;
  955. #endif
  956. debugstreams_init(disable_stderr, debugfile.c_str());
  957. // Initialize debug stacks
  958. debug_stacks_init();
  959. DSTACK(__FUNCTION_NAME);
  960. // Create user data directory
  961. fs::CreateDir(porting::path_userdata);
  962. // Init material properties table
  963. initializeMaterialProperties();
  964. // Debug handler
  965. BEGIN_DEBUG_EXCEPTION_HANDLER
  966. // Print startup message
  967. dstream<<DTIME<<"minetest-c55"
  968. " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
  969. <<", "<<BUILD_INFO
  970. <<std::endl;
  971. /*
  972. Basic initialization
  973. */
  974. // Initialize default settings
  975. set_default_settings();
  976. // Initialize sockets
  977. sockets_init();
  978. atexit(sockets_cleanup);
  979. /*
  980. Read config file
  981. */
  982. // Path of configuration file in use
  983. std::string configpath = "";
  984. if(cmd_args.exists("config"))
  985. {
  986. bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());
  987. if(r == false)
  988. {
  989. dstream<<"Could not read configuration from \""
  990. <<cmd_args.get("config")<<"\""<<std::endl;
  991. return 1;
  992. }
  993. configpath = cmd_args.get("config");
  994. }
  995. else
  996. {
  997. core::array<std::string> filenames;
  998. filenames.push_back(porting::path_userdata + "/minetest.conf");
  999. #ifdef RUN_IN_PLACE
  1000. filenames.push_back(porting::path_userdata + "/../minetest.conf");
  1001. #endif
  1002. for(u32 i=0; i<filenames.size(); i++)
  1003. {
  1004. bool r = g_settings.readConfigFile(filenames[i].c_str());
  1005. if(r)
  1006. {
  1007. configpath = filenames[i];
  1008. break;
  1009. }
  1010. }
  1011. // If no path found, use the first one (menu creates the file)
  1012. if(configpath == "")
  1013. configpath = filenames[0];
  1014. }
  1015. // Initialize random seed
  1016. srand(time(0));
  1017. mysrand(time(0));
  1018. /*
  1019. Pre-initialize some stuff with a dummy irrlicht wrapper.
  1020. These are needed for unit tests at least.
  1021. */
  1022. // Initial call with g_texturesource not set.
  1023. init_mapnode();
  1024. /*
  1025. Run unit tests
  1026. */
  1027. if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
  1028. || cmd_args.getFlag("enable-unittests") == true)
  1029. {
  1030. run_tests();
  1031. }
  1032. /*for(s16 y=-100; y<100; y++)
  1033. for(s16 x=-100; x<100; x++)
  1034. {
  1035. std::cout<<noise2d_gradient((double)x/10,(double)y/10, 32415)<<std::endl;
  1036. }
  1037. return 0;*/
  1038. /*
  1039. Game parameters
  1040. */
  1041. // Port
  1042. u16 port = 30000;
  1043. if(cmd_args.exists("port"))
  1044. port = cmd_args.getU16("port");
  1045. else if(g_settings.exists("port"))
  1046. port = g_settings.getU16("port");
  1047. if(port == 0)
  1048. port = 30000;
  1049. // Map directory
  1050. std::string map_dir = porting::path_userdata+"/world";
  1051. if(cmd_args.exists("map-dir"))
  1052. map_dir = cmd_args.get("map-dir");
  1053. else if(g_settings.exists("map-dir"))
  1054. map_dir = g_settings.get("map-dir");
  1055. // Run dedicated server if asked to
  1056. if(cmd_args.getFlag("server"))
  1057. {
  1058. DSTACK("Dedicated server branch");
  1059. // Create time getter
  1060. g_timegetter = new SimpleTimeGetter();
  1061. // Create server
  1062. Server server(map_dir.c_str());
  1063. server.start(port);
  1064. // Run server
  1065. dedicated_server_loop(server, kill);
  1066. return 0;
  1067. }
  1068. /*
  1069. More parameters
  1070. */
  1071. // Address to connect to
  1072. std::string address = "";
  1073. if(cmd_args.exists("address"))
  1074. {
  1075. address = cmd_args.get("address");
  1076. }
  1077. else
  1078. {
  1079. address = g_settings.get("address");
  1080. }
  1081. std::string playername = g_settings.get("name");
  1082. /*
  1083. Device initialization
  1084. */
  1085. // Resolution selection
  1086. bool fullscreen = false;
  1087. u16 screenW = g_settings.getU16("screenW");
  1088. u16 screenH = g_settings.getU16("screenH");
  1089. // Determine driver
  1090. video::E_DRIVER_TYPE driverType;
  1091. std::string driverstring = g_settings.get("video_driver");
  1092. if(driverstring == "null")
  1093. driverType = video::EDT_NULL;
  1094. else if(driverstring == "software")
  1095. driverType = video::EDT_SOFTWARE;
  1096. else if(driverstring == "burningsvideo")
  1097. driverType = video::EDT_BURNINGSVIDEO;
  1098. else if(driverstring == "direct3d8")
  1099. driverType = video::EDT_DIRECT3D8;
  1100. else if(driverstring == "direct3d9")
  1101. driverType = video::EDT_DIRECT3D9;
  1102. else if(driverstring == "opengl")
  1103. driverType = video::EDT_OPENGL;
  1104. else
  1105. {
  1106. dstream<<"WARNING: Invalid video_driver specified; defaulting "
  1107. "to opengl"<<std::endl;
  1108. driverType = video::EDT_OPENGL;
  1109. }
  1110. /*
  1111. Create device and exit if creation failed
  1112. */
  1113. MyEventReceiver receiver;
  1114. IrrlichtDevice *device;
  1115. device = createDevice(driverType,
  1116. core::dimension2d<u32>(screenW, screenH),
  1117. 16, fullscreen, false, false, &receiver);
  1118. if (device == 0)
  1119. return 1; // could not create selected driver.
  1120. // Set device in game parameters
  1121. device = device;
  1122. // Create time getter
  1123. g_timegetter = new IrrlichtTimeGetter(device);
  1124. // Create game callback for menus
  1125. g_gamecallback = new MainGameCallback(device);
  1126. // Create texture source
  1127. g_texturesource = new TextureSource(device);
  1128. /*
  1129. Speed tests (done after irrlicht is loaded to get timer)
  1130. */
  1131. if(cmd_args.getFlag("speedtests"))
  1132. {
  1133. dstream<<"Running speed tests"<<std::endl;
  1134. SpeedTests();
  1135. return 0;
  1136. }
  1137. device->setResizable(true);
  1138. bool random_input = g_settings.getBool("random_input")
  1139. || cmd_args.getFlag("random-input");
  1140. InputHandler *input = NULL;
  1141. if(random_input)
  1142. input = new RandomInputHandler();
  1143. else
  1144. input = new RealInputHandler(device, &receiver);
  1145. /*
  1146. Continue initialization
  1147. */
  1148. //video::IVideoDriver* driver = device->getVideoDriver();
  1149. /*
  1150. This changes the minimum allowed number of vertices in a VBO.
  1151. Default is 500.
  1152. */
  1153. //driver->setMinHardwareBufferVertexCount(50);
  1154. scene::ISceneManager* smgr = device->getSceneManager();
  1155. guienv = device->getGUIEnvironment();
  1156. gui::IGUISkin* skin = guienv->getSkin();
  1157. gui::IGUIFont* font = guienv->getFont(getTexturePath("fontlucida.png").c_str());
  1158. if(font)
  1159. skin->setFont(font);
  1160. else
  1161. dstream<<"WARNING: Font file was not found."
  1162. " Using default font."<<std::endl;
  1163. // If font was not found, this will get us one
  1164. font = skin->getFont();
  1165. assert(font);
  1166. u32 text_height = font->getDimension(L"Hello, world!").Height;
  1167. dstream<<"text_height="<<text_height<<std::endl;
  1168. //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));
  1169. skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));
  1170. //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));
  1171. //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));
  1172. skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));
  1173. skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));
  1174. /*
  1175. Preload some textures and stuff
  1176. */
  1177. init_content_inventory_texture_paths();
  1178. init_mapnode(); // Second call with g_texturesource set
  1179. init_mineral();
  1180. /*
  1181. GUI stuff
  1182. */
  1183. /*
  1184. If an error occurs, this is set to something and the
  1185. menu-game loop is restarted. It is then displayed before
  1186. the menu.
  1187. */
  1188. std::wstring error_message = L"";
  1189. // The password entered during the menu screen,
  1190. std::string password;
  1191. /*
  1192. Menu-game loop
  1193. */
  1194. while(device->run() && kill == false)
  1195. {
  1196. // This is used for catching disconnects
  1197. try
  1198. {
  1199. /*
  1200. Clear everything from the GUIEnvironment
  1201. */
  1202. guienv->clear();
  1203. /*
  1204. We need some kind of a root node to be able to add
  1205. custom gui elements directly on the screen.
  1206. Otherwise they won't be automatically drawn.
  1207. */
  1208. guiroot = guienv->addStaticText(L"",
  1209. core::rect<s32>(0, 0, 10000, 10000));
  1210. /*
  1211. Out-of-game menu loop.
  1212. Loop quits when menu returns proper parameters.
  1213. */
  1214. while(kill == false)
  1215. {
  1216. // Cursor can be non-visible when coming from the game
  1217. device->getCursorControl()->setVisible(true);
  1218. // Some stuff are left to scene manager when coming from the game
  1219. // (map at least?)
  1220. smgr->clear();
  1221. // Reset or hide the debug gui texts
  1222. /*guitext->setText(L"Minetest-c55");
  1223. guitext2->setVisible(false);
  1224. guitext_info->setVisible(false);
  1225. guitext_chat->setVisible(false);*/
  1226. // Initialize menu data
  1227. MainMenuData menudata;
  1228. menudata.address = narrow_to_wide(address);
  1229. menudata.name = narrow_to_wide(playername);
  1230. menudata.port = narrow_to_wide(itos(port));
  1231. menudata.fancy_trees = g_settings.getBool("new_style_leaves");
  1232. menudata.smooth_lighting = g_settings.getBool("smooth_lighting");
  1233. menudata.creative_mode = g_settings.getBool("creative_mode");
  1234. menudata.enable_damage = g_settings.getBool("enable_damage");
  1235. GUIMainMenu *menu =
  1236. new GUIMainMenu(guienv, guiroot, -1,
  1237. &g_menumgr, &menudata, g_gamecallback);
  1238. menu->allowFocusRemoval(true);
  1239. if(error_message != L"")
  1240. {
  1241. dstream<<"WARNING: error_message = "
  1242. <<wide_to_narrow(error_message)<<std::endl;
  1243. GUIMessageMenu *menu2 =
  1244. new GUIMessageMenu(guienv, guiroot, -1,
  1245. &g_menumgr, error_message.c_str());
  1246. menu2->drop();
  1247. error_message = L"";
  1248. }
  1249. video::IVideoDriver* driver = device->getVideoDriver();
  1250. dstream<<"Created main menu"<<std::endl;
  1251. while(device->run() && kill == false)
  1252. {
  1253. if(menu->getStatus() == true)
  1254. break;
  1255. //driver->beginScene(true, true, video::SColor(255,0,0,0));
  1256. driver->beginScene(true, true, video::SColor(255,128,128,128));
  1257. drawMenuBackground(driver);
  1258. guienv->drawAll();
  1259. driver->endScene();
  1260. // On some computers framerate doesn't seem to be
  1261. // automatically limited
  1262. sleep_ms(25);
  1263. }
  1264. // Break out of menu-game loop to shut down cleanly
  1265. if(device->run() == false || kill == true)
  1266. break;
  1267. dstream<<"Dropping main menu"<<std::endl;
  1268. menu->drop();
  1269. // Delete map if requested
  1270. if(menudata.delete_map)
  1271. {
  1272. bool r = fs::RecursiveDeleteContent(map_dir);
  1273. if(r == false)
  1274. error_message = L"Delete failed";
  1275. continue;
  1276. }
  1277. playername = wide_to_narrow(menudata.name);
  1278. password = translatePassword(playername, menudata.password);
  1279. address = wide_to_narrow(menudata.address);
  1280. int newport = stoi(wide_to_narrow(menudata.port));
  1281. if(newport != 0)
  1282. port = newport;
  1283. g_settings.set("new_style_leaves", itos(menudata.fancy_trees));
  1284. g_settings.set("smooth_lighting", itos(menudata.smooth_lighting));
  1285. g_settings.set("creative_mode", itos(menudata.creative_mode));
  1286. g_settings.set("enable_damage", itos(menudata.enable_damage));
  1287. // NOTE: These are now checked server side; no need to do it
  1288. // here, so let's not do it here.
  1289. /*// Check for valid parameters, restart menu if invalid.
  1290. if(playername == "")
  1291. {
  1292. error_message = L"Name required.";
  1293. continue;
  1294. }
  1295. // Check that name has only valid chars
  1296. if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
  1297. {
  1298. error_message = L"Characters allowed: "
  1299. +narrow_to_wide(PLAYERNAME_ALLOWED_CHARS);
  1300. continue;
  1301. }*/
  1302. // Save settings
  1303. g_settings.set("name", playername);
  1304. g_settings.set("address", address);
  1305. g_settings.set("port", itos(port));
  1306. // Update configuration file
  1307. if(configpath != "")
  1308. g_settings.updateConfigFile(configpath.c_str());
  1309. // Continue to game
  1310. break;
  1311. }
  1312. // Break out of menu-game loop to shut down cleanly
  1313. if(device->run() == false)
  1314. break;
  1315. // Initialize mapnode again to enable changed graphics settings
  1316. init_mapnode();
  1317. /*
  1318. Run game
  1319. */
  1320. the_game(
  1321. kill,
  1322. random_input,
  1323. input,
  1324. device,
  1325. font,
  1326. map_dir,
  1327. playername,
  1328. password,
  1329. address,
  1330. port,
  1331. error_message
  1332. );
  1333. } //try
  1334. catch(con::PeerNotFoundException &e)
  1335. {
  1336. dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;
  1337. error_message = L"Connection error (timed out?)";
  1338. }
  1339. catch(SocketException &e)
  1340. {
  1341. dstream<<DTIME<<"Socket error (port already in use?)"<<std::endl;
  1342. error_message = L"Socket error (port already in use?)";
  1343. }
  1344. #ifdef NDEBUG
  1345. catch(std::exception &e)
  1346. {
  1347. std::string narrow_message = "Some exception, what()=\"";
  1348. narrow_message += e.what();
  1349. narrow_message += "\"";
  1350. dstream<<DTIME<<narrow_message<<std::endl;
  1351. error_message = narrow_to_wide(narrow_message);
  1352. }
  1353. #endif
  1354. } // Menu-game loop
  1355. delete input;
  1356. /*
  1357. In the end, delete the Irrlicht device.
  1358. */
  1359. device->drop();
  1360. END_DEBUG_EXCEPTION_HANDLER
  1361. debugstreams_deinit();
  1362. return 0;
  1363. }
  1364. //END