game.cpp 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214
  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 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. 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 Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser 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. #include "game.h"
  17. #include "irrlichttypes_extrabloated.h"
  18. #include <IGUICheckBox.h>
  19. #include <IGUIEditBox.h>
  20. #include <IGUIButton.h>
  21. #include <IGUIStaticText.h>
  22. #include <IGUIFont.h>
  23. #include <IMaterialRendererServices.h>
  24. #include "client.h"
  25. #include "server.h"
  26. #include "guiPauseMenu.h"
  27. #include "guiPasswordChange.h"
  28. #include "guiFormSpecMenu.h"
  29. #include "guiTextInputMenu.h"
  30. #include "guiDeathScreen.h"
  31. #include "tool.h"
  32. #include "guiChatConsole.h"
  33. #include "config.h"
  34. #include "clouds.h"
  35. #include "camera.h"
  36. #include "farmesh.h"
  37. #include "mapblock.h"
  38. #include "settings.h"
  39. #include "profiler.h"
  40. #include "mainmenumanager.h"
  41. #include "gettext.h"
  42. #include "log.h"
  43. #include "filesys.h"
  44. // Needed for determining pointing to nodes
  45. #include "nodedef.h"
  46. #include "nodemetadata.h"
  47. #include "main.h" // For g_settings
  48. #include "itemdef.h"
  49. #include "tile.h" // For TextureSource
  50. #include "shader.h" // For ShaderSource
  51. #include "logoutputbuffer.h"
  52. #include "subgame.h"
  53. #include "quicktune_shortcutter.h"
  54. #include "clientmap.h"
  55. #include "sky.h"
  56. #include "sound.h"
  57. #if USE_SOUND
  58. #include "sound_openal.h"
  59. #endif
  60. #include "event_manager.h"
  61. #include <list>
  62. #include "util/directiontables.h"
  63. /*
  64. Text input system
  65. */
  66. struct TextDestChat : public TextDest
  67. {
  68. TextDestChat(Client *client)
  69. {
  70. m_client = client;
  71. }
  72. void gotText(std::wstring text)
  73. {
  74. m_client->typeChatMessage(text);
  75. }
  76. void gotText(std::map<std::string, std::string> fields)
  77. {
  78. m_client->typeChatMessage(narrow_to_wide(fields["text"]));
  79. }
  80. Client *m_client;
  81. };
  82. struct TextDestNodeMetadata : public TextDest
  83. {
  84. TextDestNodeMetadata(v3s16 p, Client *client)
  85. {
  86. m_p = p;
  87. m_client = client;
  88. }
  89. // This is deprecated I guess? -celeron55
  90. void gotText(std::wstring text)
  91. {
  92. std::string ntext = wide_to_narrow(text);
  93. infostream<<"Submitting 'text' field of node at ("<<m_p.X<<","
  94. <<m_p.Y<<","<<m_p.Z<<"): "<<ntext<<std::endl;
  95. std::map<std::string, std::string> fields;
  96. fields["text"] = ntext;
  97. m_client->sendNodemetaFields(m_p, "", fields);
  98. }
  99. void gotText(std::map<std::string, std::string> fields)
  100. {
  101. m_client->sendNodemetaFields(m_p, "", fields);
  102. }
  103. v3s16 m_p;
  104. Client *m_client;
  105. };
  106. struct TextDestPlayerInventory : public TextDest
  107. {
  108. TextDestPlayerInventory(Client *client)
  109. {
  110. m_client = client;
  111. }
  112. void gotText(std::map<std::string, std::string> fields)
  113. {
  114. m_client->sendInventoryFields("", fields);
  115. }
  116. Client *m_client;
  117. };
  118. /* Respawn menu callback */
  119. class MainRespawnInitiator: public IRespawnInitiator
  120. {
  121. public:
  122. MainRespawnInitiator(bool *active, Client *client):
  123. m_active(active), m_client(client)
  124. {
  125. *m_active = true;
  126. }
  127. void respawn()
  128. {
  129. *m_active = false;
  130. m_client->sendRespawn();
  131. }
  132. private:
  133. bool *m_active;
  134. Client *m_client;
  135. };
  136. /* Form update callback */
  137. class NodeMetadataFormSource: public IFormSource
  138. {
  139. public:
  140. NodeMetadataFormSource(ClientMap *map, v3s16 p):
  141. m_map(map),
  142. m_p(p)
  143. {
  144. }
  145. std::string getForm()
  146. {
  147. NodeMetadata *meta = m_map->getNodeMetadata(m_p);
  148. if(!meta)
  149. return "";
  150. return meta->getString("formspec");
  151. }
  152. std::string resolveText(std::string str)
  153. {
  154. NodeMetadata *meta = m_map->getNodeMetadata(m_p);
  155. if(!meta)
  156. return str;
  157. return meta->resolveString(str);
  158. }
  159. ClientMap *m_map;
  160. v3s16 m_p;
  161. };
  162. class PlayerInventoryFormSource: public IFormSource
  163. {
  164. public:
  165. PlayerInventoryFormSource(Client *client):
  166. m_client(client)
  167. {
  168. }
  169. std::string getForm()
  170. {
  171. LocalPlayer* player = m_client->getEnv().getLocalPlayer();
  172. return player->inventory_formspec;
  173. }
  174. Client *m_client;
  175. };
  176. class FormspecFormSource: public IFormSource
  177. {
  178. public:
  179. FormspecFormSource(std::string formspec,FormspecFormSource** game_formspec)
  180. {
  181. m_formspec = formspec;
  182. m_game_formspec = game_formspec;
  183. }
  184. ~FormspecFormSource()
  185. {
  186. *m_game_formspec = 0;
  187. }
  188. void setForm(std::string formspec) {
  189. m_formspec = formspec;
  190. }
  191. std::string getForm()
  192. {
  193. return m_formspec;
  194. }
  195. std::string m_formspec;
  196. FormspecFormSource** m_game_formspec;
  197. };
  198. /*
  199. Hotbar draw routine
  200. */
  201. void draw_hotbar(video::IVideoDriver *driver, gui::IGUIFont *font,
  202. IGameDef *gamedef,
  203. v2s32 centerlowerpos, s32 imgsize, s32 itemcount,
  204. Inventory *inventory, s32 halfheartcount, u16 playeritem)
  205. {
  206. InventoryList *mainlist = inventory->getList("main");
  207. if(mainlist == NULL)
  208. {
  209. errorstream<<"draw_hotbar(): mainlist == NULL"<<std::endl;
  210. return;
  211. }
  212. s32 padding = imgsize/12;
  213. //s32 height = imgsize + padding*2;
  214. s32 width = itemcount*(imgsize+padding*2);
  215. // Position of upper left corner of bar
  216. v2s32 pos = centerlowerpos - v2s32(width/2, imgsize+padding*2);
  217. // Draw background color
  218. /*core::rect<s32> barrect(0,0,width,height);
  219. barrect += pos;
  220. video::SColor bgcolor(255,128,128,128);
  221. driver->draw2DRectangle(bgcolor, barrect, NULL);*/
  222. core::rect<s32> imgrect(0,0,imgsize,imgsize);
  223. for(s32 i=0; i<itemcount; i++)
  224. {
  225. const ItemStack &item = mainlist->getItem(i);
  226. core::rect<s32> rect = imgrect + pos
  227. + v2s32(padding+i*(imgsize+padding*2), padding);
  228. if(playeritem == i)
  229. {
  230. video::SColor c_outside(255,255,0,0);
  231. //video::SColor c_outside(255,0,0,0);
  232. //video::SColor c_inside(255,192,192,192);
  233. s32 x1 = rect.UpperLeftCorner.X;
  234. s32 y1 = rect.UpperLeftCorner.Y;
  235. s32 x2 = rect.LowerRightCorner.X;
  236. s32 y2 = rect.LowerRightCorner.Y;
  237. // Black base borders
  238. driver->draw2DRectangle(c_outside,
  239. core::rect<s32>(
  240. v2s32(x1 - padding, y1 - padding),
  241. v2s32(x2 + padding, y1)
  242. ), NULL);
  243. driver->draw2DRectangle(c_outside,
  244. core::rect<s32>(
  245. v2s32(x1 - padding, y2),
  246. v2s32(x2 + padding, y2 + padding)
  247. ), NULL);
  248. driver->draw2DRectangle(c_outside,
  249. core::rect<s32>(
  250. v2s32(x1 - padding, y1),
  251. v2s32(x1, y2)
  252. ), NULL);
  253. driver->draw2DRectangle(c_outside,
  254. core::rect<s32>(
  255. v2s32(x2, y1),
  256. v2s32(x2 + padding, y2)
  257. ), NULL);
  258. /*// Light inside borders
  259. driver->draw2DRectangle(c_inside,
  260. core::rect<s32>(
  261. v2s32(x1 - padding/2, y1 - padding/2),
  262. v2s32(x2 + padding/2, y1)
  263. ), NULL);
  264. driver->draw2DRectangle(c_inside,
  265. core::rect<s32>(
  266. v2s32(x1 - padding/2, y2),
  267. v2s32(x2 + padding/2, y2 + padding/2)
  268. ), NULL);
  269. driver->draw2DRectangle(c_inside,
  270. core::rect<s32>(
  271. v2s32(x1 - padding/2, y1),
  272. v2s32(x1, y2)
  273. ), NULL);
  274. driver->draw2DRectangle(c_inside,
  275. core::rect<s32>(
  276. v2s32(x2, y1),
  277. v2s32(x2 + padding/2, y2)
  278. ), NULL);
  279. */
  280. }
  281. video::SColor bgcolor2(128,0,0,0);
  282. driver->draw2DRectangle(bgcolor2, rect, NULL);
  283. drawItemStack(driver, font, item, rect, NULL, gamedef);
  284. }
  285. /*
  286. Draw hearts
  287. */
  288. video::ITexture *heart_texture =
  289. gamedef->getTextureSource()->getTextureRaw("heart.png");
  290. if(heart_texture)
  291. {
  292. v2s32 p = pos + v2s32(0, -20);
  293. for(s32 i=0; i<halfheartcount/2; i++)
  294. {
  295. const video::SColor color(255,255,255,255);
  296. const video::SColor colors[] = {color,color,color,color};
  297. core::rect<s32> rect(0,0,16,16);
  298. rect += p;
  299. driver->draw2DImage(heart_texture, rect,
  300. core::rect<s32>(core::position2d<s32>(0,0),
  301. core::dimension2di(heart_texture->getOriginalSize())),
  302. NULL, colors, true);
  303. p += v2s32(16,0);
  304. }
  305. if(halfheartcount % 2 == 1)
  306. {
  307. const video::SColor color(255,255,255,255);
  308. const video::SColor colors[] = {color,color,color,color};
  309. core::rect<s32> rect(0,0,16/2,16);
  310. rect += p;
  311. core::dimension2di srcd(heart_texture->getOriginalSize());
  312. srcd.Width /= 2;
  313. driver->draw2DImage(heart_texture, rect,
  314. core::rect<s32>(core::position2d<s32>(0,0), srcd),
  315. NULL, colors, true);
  316. p += v2s32(16,0);
  317. }
  318. }
  319. }
  320. /*
  321. Check if a node is pointable
  322. */
  323. inline bool isPointableNode(const MapNode& n,
  324. Client *client, bool liquids_pointable)
  325. {
  326. const ContentFeatures &features = client->getNodeDefManager()->get(n);
  327. return features.pointable ||
  328. (liquids_pointable && features.isLiquid());
  329. }
  330. /*
  331. Find what the player is pointing at
  332. */
  333. PointedThing getPointedThing(Client *client, v3f player_position,
  334. v3f camera_direction, v3f camera_position,
  335. core::line3d<f32> shootline, f32 d,
  336. bool liquids_pointable,
  337. bool look_for_object,
  338. std::vector<aabb3f> &hilightboxes,
  339. ClientActiveObject *&selected_object)
  340. {
  341. PointedThing result;
  342. hilightboxes.clear();
  343. selected_object = NULL;
  344. INodeDefManager *nodedef = client->getNodeDefManager();
  345. ClientMap &map = client->getEnv().getClientMap();
  346. // First try to find a pointed at active object
  347. if(look_for_object)
  348. {
  349. selected_object = client->getSelectedActiveObject(d*BS,
  350. camera_position, shootline);
  351. if(selected_object != NULL)
  352. {
  353. if(selected_object->doShowSelectionBox())
  354. {
  355. aabb3f *selection_box = selected_object->getSelectionBox();
  356. // Box should exist because object was
  357. // returned in the first place
  358. assert(selection_box);
  359. v3f pos = selected_object->getPosition();
  360. hilightboxes.push_back(aabb3f(
  361. selection_box->MinEdge + pos,
  362. selection_box->MaxEdge + pos));
  363. }
  364. result.type = POINTEDTHING_OBJECT;
  365. result.object_id = selected_object->getId();
  366. return result;
  367. }
  368. }
  369. // That didn't work, try to find a pointed at node
  370. f32 mindistance = BS * 1001;
  371. v3s16 pos_i = floatToInt(player_position, BS);
  372. /*infostream<<"pos_i=("<<pos_i.X<<","<<pos_i.Y<<","<<pos_i.Z<<")"
  373. <<std::endl;*/
  374. s16 a = d;
  375. s16 ystart = pos_i.Y + 0 - (camera_direction.Y<0 ? a : 1);
  376. s16 zstart = pos_i.Z - (camera_direction.Z<0 ? a : 1);
  377. s16 xstart = pos_i.X - (camera_direction.X<0 ? a : 1);
  378. s16 yend = pos_i.Y + 1 + (camera_direction.Y>0 ? a : 1);
  379. s16 zend = pos_i.Z + (camera_direction.Z>0 ? a : 1);
  380. s16 xend = pos_i.X + (camera_direction.X>0 ? a : 1);
  381. // Prevent signed number overflow
  382. if(yend==32767)
  383. yend=32766;
  384. if(zend==32767)
  385. zend=32766;
  386. if(xend==32767)
  387. xend=32766;
  388. for(s16 y = ystart; y <= yend; y++)
  389. for(s16 z = zstart; z <= zend; z++)
  390. for(s16 x = xstart; x <= xend; x++)
  391. {
  392. MapNode n;
  393. try
  394. {
  395. n = map.getNode(v3s16(x,y,z));
  396. }
  397. catch(InvalidPositionException &e)
  398. {
  399. continue;
  400. }
  401. if(!isPointableNode(n, client, liquids_pointable))
  402. continue;
  403. std::vector<aabb3f> boxes = n.getSelectionBoxes(nodedef);
  404. v3s16 np(x,y,z);
  405. v3f npf = intToFloat(np, BS);
  406. for(std::vector<aabb3f>::const_iterator
  407. i = boxes.begin();
  408. i != boxes.end(); i++)
  409. {
  410. aabb3f box = *i;
  411. box.MinEdge += npf;
  412. box.MaxEdge += npf;
  413. for(u16 j=0; j<6; j++)
  414. {
  415. v3s16 facedir = g_6dirs[j];
  416. aabb3f facebox = box;
  417. f32 d = 0.001*BS;
  418. if(facedir.X > 0)
  419. facebox.MinEdge.X = facebox.MaxEdge.X-d;
  420. else if(facedir.X < 0)
  421. facebox.MaxEdge.X = facebox.MinEdge.X+d;
  422. else if(facedir.Y > 0)
  423. facebox.MinEdge.Y = facebox.MaxEdge.Y-d;
  424. else if(facedir.Y < 0)
  425. facebox.MaxEdge.Y = facebox.MinEdge.Y+d;
  426. else if(facedir.Z > 0)
  427. facebox.MinEdge.Z = facebox.MaxEdge.Z-d;
  428. else if(facedir.Z < 0)
  429. facebox.MaxEdge.Z = facebox.MinEdge.Z+d;
  430. v3f centerpoint = facebox.getCenter();
  431. f32 distance = (centerpoint - camera_position).getLength();
  432. if(distance >= mindistance)
  433. continue;
  434. if(!facebox.intersectsWithLine(shootline))
  435. continue;
  436. v3s16 np_above = np + facedir;
  437. result.type = POINTEDTHING_NODE;
  438. result.node_undersurface = np;
  439. result.node_abovesurface = np_above;
  440. mindistance = distance;
  441. hilightboxes.clear();
  442. for(std::vector<aabb3f>::const_iterator
  443. i2 = boxes.begin();
  444. i2 != boxes.end(); i2++)
  445. {
  446. aabb3f box = *i2;
  447. box.MinEdge += npf + v3f(-d,-d,-d);
  448. box.MaxEdge += npf + v3f(d,d,d);
  449. hilightboxes.push_back(box);
  450. }
  451. }
  452. }
  453. } // for coords
  454. return result;
  455. }
  456. /*
  457. Draws a screen with a single text on it.
  458. Text will be removed when the screen is drawn the next time.
  459. */
  460. /*gui::IGUIStaticText **/
  461. void draw_load_screen(const std::wstring &text,
  462. video::IVideoDriver* driver, gui::IGUIFont* font)
  463. {
  464. v2u32 screensize = driver->getScreenSize();
  465. const wchar_t *loadingtext = text.c_str();
  466. core::vector2d<u32> textsize_u = font->getDimension(loadingtext);
  467. core::vector2d<s32> textsize(textsize_u.X,textsize_u.Y);
  468. core::vector2d<s32> center(screensize.X/2, screensize.Y/2);
  469. core::rect<s32> textrect(center - textsize/2, center + textsize/2);
  470. gui::IGUIStaticText *guitext = guienv->addStaticText(
  471. loadingtext, textrect, false, false);
  472. guitext->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
  473. driver->beginScene(true, true, video::SColor(255,0,0,0));
  474. guienv->drawAll();
  475. driver->endScene();
  476. guitext->remove();
  477. //return guitext;
  478. }
  479. /* Profiler display */
  480. void update_profiler_gui(gui::IGUIStaticText *guitext_profiler,
  481. gui::IGUIFont *font, u32 text_height,
  482. u32 show_profiler, u32 show_profiler_max)
  483. {
  484. if(show_profiler == 0)
  485. {
  486. guitext_profiler->setVisible(false);
  487. }
  488. else
  489. {
  490. std::ostringstream os(std::ios_base::binary);
  491. g_profiler->printPage(os, show_profiler, show_profiler_max);
  492. std::wstring text = narrow_to_wide(os.str());
  493. guitext_profiler->setText(text.c_str());
  494. guitext_profiler->setVisible(true);
  495. s32 w = font->getDimension(text.c_str()).Width;
  496. if(w < 400)
  497. w = 400;
  498. core::rect<s32> rect(6, 4+(text_height+5)*2, 12+w,
  499. 8+(text_height+5)*2 +
  500. font->getDimension(text.c_str()).Height);
  501. guitext_profiler->setRelativePosition(rect);
  502. guitext_profiler->setVisible(true);
  503. }
  504. }
  505. class ProfilerGraph
  506. {
  507. private:
  508. struct Piece{
  509. Profiler::GraphValues values;
  510. };
  511. struct Meta{
  512. float min;
  513. float max;
  514. video::SColor color;
  515. Meta(float initial=0, video::SColor color=
  516. video::SColor(255,255,255,255)):
  517. min(initial),
  518. max(initial),
  519. color(color)
  520. {}
  521. };
  522. std::list<Piece> m_log;
  523. public:
  524. u32 m_log_max_size;
  525. ProfilerGraph():
  526. m_log_max_size(200)
  527. {}
  528. void put(const Profiler::GraphValues &values)
  529. {
  530. Piece piece;
  531. piece.values = values;
  532. m_log.push_back(piece);
  533. while(m_log.size() > m_log_max_size)
  534. m_log.erase(m_log.begin());
  535. }
  536. void draw(s32 x_left, s32 y_bottom, video::IVideoDriver *driver,
  537. gui::IGUIFont* font) const
  538. {
  539. std::map<std::string, Meta> m_meta;
  540. for(std::list<Piece>::const_iterator k = m_log.begin();
  541. k != m_log.end(); k++)
  542. {
  543. const Piece &piece = *k;
  544. for(Profiler::GraphValues::const_iterator i = piece.values.begin();
  545. i != piece.values.end(); i++){
  546. const std::string &id = i->first;
  547. const float &value = i->second;
  548. std::map<std::string, Meta>::iterator j =
  549. m_meta.find(id);
  550. if(j == m_meta.end()){
  551. m_meta[id] = Meta(value);
  552. continue;
  553. }
  554. if(value < j->second.min)
  555. j->second.min = value;
  556. if(value > j->second.max)
  557. j->second.max = value;
  558. }
  559. }
  560. // Assign colors
  561. static const video::SColor usable_colors[] = {
  562. video::SColor(255,255,100,100),
  563. video::SColor(255,90,225,90),
  564. video::SColor(255,100,100,255),
  565. video::SColor(255,255,150,50),
  566. video::SColor(255,220,220,100)
  567. };
  568. static const u32 usable_colors_count =
  569. sizeof(usable_colors) / sizeof(*usable_colors);
  570. u32 next_color_i = 0;
  571. for(std::map<std::string, Meta>::iterator i = m_meta.begin();
  572. i != m_meta.end(); i++){
  573. Meta &meta = i->second;
  574. video::SColor color(255,200,200,200);
  575. if(next_color_i < usable_colors_count)
  576. color = usable_colors[next_color_i++];
  577. meta.color = color;
  578. }
  579. s32 graphh = 50;
  580. s32 textx = x_left + m_log_max_size + 15;
  581. s32 textx2 = textx + 200 - 15;
  582. // Draw background
  583. /*{
  584. u32 num_graphs = m_meta.size();
  585. core::rect<s32> rect(x_left, y_bottom - num_graphs*graphh,
  586. textx2, y_bottom);
  587. video::SColor bgcolor(120,0,0,0);
  588. driver->draw2DRectangle(bgcolor, rect, NULL);
  589. }*/
  590. s32 meta_i = 0;
  591. for(std::map<std::string, Meta>::const_iterator i = m_meta.begin();
  592. i != m_meta.end(); i++){
  593. const std::string &id = i->first;
  594. const Meta &meta = i->second;
  595. s32 x = x_left;
  596. s32 y = y_bottom - meta_i * 50;
  597. float show_min = meta.min;
  598. float show_max = meta.max;
  599. if(show_min >= -0.0001 && show_max >= -0.0001){
  600. if(show_min <= show_max * 0.5)
  601. show_min = 0;
  602. }
  603. s32 texth = 15;
  604. char buf[10];
  605. snprintf(buf, 10, "%.3g", show_max);
  606. font->draw(narrow_to_wide(buf).c_str(),
  607. core::rect<s32>(textx, y - graphh,
  608. textx2, y - graphh + texth),
  609. meta.color);
  610. snprintf(buf, 10, "%.3g", show_min);
  611. font->draw(narrow_to_wide(buf).c_str(),
  612. core::rect<s32>(textx, y - texth,
  613. textx2, y),
  614. meta.color);
  615. font->draw(narrow_to_wide(id).c_str(),
  616. core::rect<s32>(textx, y - graphh/2 - texth/2,
  617. textx2, y - graphh/2 + texth/2),
  618. meta.color);
  619. s32 graph1y = y;
  620. s32 graph1h = graphh;
  621. bool relativegraph = (show_min != 0 && show_min != show_max);
  622. float lastscaledvalue = 0.0;
  623. bool lastscaledvalue_exists = false;
  624. for(std::list<Piece>::const_iterator j = m_log.begin();
  625. j != m_log.end(); j++)
  626. {
  627. const Piece &piece = *j;
  628. float value = 0;
  629. bool value_exists = false;
  630. Profiler::GraphValues::const_iterator k =
  631. piece.values.find(id);
  632. if(k != piece.values.end()){
  633. value = k->second;
  634. value_exists = true;
  635. }
  636. if(!value_exists){
  637. x++;
  638. lastscaledvalue_exists = false;
  639. continue;
  640. }
  641. float scaledvalue = 1.0;
  642. if(show_max != show_min)
  643. scaledvalue = (value - show_min) / (show_max - show_min);
  644. if(scaledvalue == 1.0 && value == 0){
  645. x++;
  646. lastscaledvalue_exists = false;
  647. continue;
  648. }
  649. if(relativegraph){
  650. if(lastscaledvalue_exists){
  651. s32 ivalue1 = lastscaledvalue * graph1h;
  652. s32 ivalue2 = scaledvalue * graph1h;
  653. driver->draw2DLine(v2s32(x-1, graph1y - ivalue1),
  654. v2s32(x, graph1y - ivalue2), meta.color);
  655. }
  656. lastscaledvalue = scaledvalue;
  657. lastscaledvalue_exists = true;
  658. } else{
  659. s32 ivalue = scaledvalue * graph1h;
  660. driver->draw2DLine(v2s32(x, graph1y),
  661. v2s32(x, graph1y - ivalue), meta.color);
  662. }
  663. x++;
  664. }
  665. meta_i++;
  666. }
  667. }
  668. };
  669. class NodeDugEvent: public MtEvent
  670. {
  671. public:
  672. v3s16 p;
  673. MapNode n;
  674. NodeDugEvent(v3s16 p, MapNode n):
  675. p(p),
  676. n(n)
  677. {}
  678. const char* getType() const
  679. {return "NodeDug";}
  680. };
  681. class SoundMaker
  682. {
  683. ISoundManager *m_sound;
  684. INodeDefManager *m_ndef;
  685. public:
  686. float m_player_step_timer;
  687. SimpleSoundSpec m_player_step_sound;
  688. SimpleSoundSpec m_player_leftpunch_sound;
  689. SimpleSoundSpec m_player_rightpunch_sound;
  690. SoundMaker(ISoundManager *sound, INodeDefManager *ndef):
  691. m_sound(sound),
  692. m_ndef(ndef),
  693. m_player_step_timer(0)
  694. {
  695. }
  696. void playPlayerStep()
  697. {
  698. if(m_player_step_timer <= 0 && m_player_step_sound.exists()){
  699. m_player_step_timer = 0.03;
  700. m_sound->playSound(m_player_step_sound, false);
  701. }
  702. }
  703. static void viewBobbingStep(MtEvent *e, void *data)
  704. {
  705. SoundMaker *sm = (SoundMaker*)data;
  706. sm->playPlayerStep();
  707. }
  708. static void playerRegainGround(MtEvent *e, void *data)
  709. {
  710. SoundMaker *sm = (SoundMaker*)data;
  711. sm->playPlayerStep();
  712. }
  713. static void playerJump(MtEvent *e, void *data)
  714. {
  715. //SoundMaker *sm = (SoundMaker*)data;
  716. }
  717. static void cameraPunchLeft(MtEvent *e, void *data)
  718. {
  719. SoundMaker *sm = (SoundMaker*)data;
  720. sm->m_sound->playSound(sm->m_player_leftpunch_sound, false);
  721. }
  722. static void cameraPunchRight(MtEvent *e, void *data)
  723. {
  724. SoundMaker *sm = (SoundMaker*)data;
  725. sm->m_sound->playSound(sm->m_player_rightpunch_sound, false);
  726. }
  727. static void nodeDug(MtEvent *e, void *data)
  728. {
  729. SoundMaker *sm = (SoundMaker*)data;
  730. NodeDugEvent *nde = (NodeDugEvent*)e;
  731. sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false);
  732. }
  733. void registerReceiver(MtEventManager *mgr)
  734. {
  735. mgr->reg("ViewBobbingStep", SoundMaker::viewBobbingStep, this);
  736. mgr->reg("PlayerRegainGround", SoundMaker::playerRegainGround, this);
  737. mgr->reg("PlayerJump", SoundMaker::playerJump, this);
  738. mgr->reg("CameraPunchLeft", SoundMaker::cameraPunchLeft, this);
  739. mgr->reg("CameraPunchRight", SoundMaker::cameraPunchRight, this);
  740. mgr->reg("NodeDug", SoundMaker::nodeDug, this);
  741. }
  742. void step(float dtime)
  743. {
  744. m_player_step_timer -= dtime;
  745. }
  746. };
  747. // Locally stored sounds don't need to be preloaded because of this
  748. class GameOnDemandSoundFetcher: public OnDemandSoundFetcher
  749. {
  750. std::set<std::string> m_fetched;
  751. public:
  752. void fetchSounds(const std::string &name,
  753. std::set<std::string> &dst_paths,
  754. std::set<std::string> &dst_datas)
  755. {
  756. if(m_fetched.count(name))
  757. return;
  758. m_fetched.insert(name);
  759. std::string base = porting::path_share + DIR_DELIM + "testsounds";
  760. dst_paths.insert(base + DIR_DELIM + name + ".ogg");
  761. dst_paths.insert(base + DIR_DELIM + name + ".0.ogg");
  762. dst_paths.insert(base + DIR_DELIM + name + ".1.ogg");
  763. dst_paths.insert(base + DIR_DELIM + name + ".2.ogg");
  764. dst_paths.insert(base + DIR_DELIM + name + ".3.ogg");
  765. dst_paths.insert(base + DIR_DELIM + name + ".4.ogg");
  766. dst_paths.insert(base + DIR_DELIM + name + ".5.ogg");
  767. dst_paths.insert(base + DIR_DELIM + name + ".6.ogg");
  768. dst_paths.insert(base + DIR_DELIM + name + ".7.ogg");
  769. dst_paths.insert(base + DIR_DELIM + name + ".8.ogg");
  770. dst_paths.insert(base + DIR_DELIM + name + ".9.ogg");
  771. }
  772. };
  773. class GameGlobalShaderConstantSetter : public IShaderConstantSetter
  774. {
  775. Sky *m_sky;
  776. bool *m_force_fog_off;
  777. f32 *m_fog_range;
  778. Client *m_client;
  779. public:
  780. GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
  781. f32 *fog_range, Client *client):
  782. m_sky(sky),
  783. m_force_fog_off(force_fog_off),
  784. m_fog_range(fog_range),
  785. m_client(client)
  786. {}
  787. ~GameGlobalShaderConstantSetter() {}
  788. virtual void onSetConstants(video::IMaterialRendererServices *services,
  789. bool is_highlevel)
  790. {
  791. if(!is_highlevel)
  792. return;
  793. // Background color
  794. video::SColor bgcolor = m_sky->getBgColor();
  795. video::SColorf bgcolorf(bgcolor);
  796. float bgcolorfa[4] = {
  797. bgcolorf.r,
  798. bgcolorf.g,
  799. bgcolorf.b,
  800. bgcolorf.a,
  801. };
  802. services->setPixelShaderConstant("skyBgColor", bgcolorfa, 4);
  803. // Fog distance
  804. float fog_distance = *m_fog_range;
  805. if(*m_force_fog_off)
  806. fog_distance = 10000*BS;
  807. services->setPixelShaderConstant("fogDistance", &fog_distance, 1);
  808. // Day-night ratio
  809. u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
  810. float daynight_ratio_f = (float)daynight_ratio / 1000.0;
  811. services->setPixelShaderConstant("dayNightRatio", &daynight_ratio_f, 1);
  812. }
  813. };
  814. void the_game(
  815. bool &kill,
  816. bool random_input,
  817. InputHandler *input,
  818. IrrlichtDevice *device,
  819. gui::IGUIFont* font,
  820. std::string map_dir,
  821. std::string playername,
  822. std::string password,
  823. std::string address, // If "", local server is used
  824. u16 port,
  825. std::wstring &error_message,
  826. std::string configpath,
  827. ChatBackend &chat_backend,
  828. const SubgameSpec &gamespec, // Used for local game,
  829. bool simple_singleplayer_mode
  830. )
  831. {
  832. FormspecFormSource* current_formspec = 0;
  833. video::IVideoDriver* driver = device->getVideoDriver();
  834. scene::ISceneManager* smgr = device->getSceneManager();
  835. // Calculate text height using the font
  836. u32 text_height = font->getDimension(L"Random test string").Height;
  837. v2u32 screensize(0,0);
  838. v2u32 last_screensize(0,0);
  839. screensize = driver->getScreenSize();
  840. const s32 hotbar_itemcount = 8;
  841. //const s32 hotbar_imagesize = 36;
  842. //const s32 hotbar_imagesize = 64;
  843. s32 hotbar_imagesize = 48;
  844. /*
  845. Draw "Loading" screen
  846. */
  847. draw_load_screen(L"Loading...", driver, font);
  848. // Create texture source
  849. IWritableTextureSource *tsrc = createTextureSource(device);
  850. // Create shader source
  851. IWritableShaderSource *shsrc = createShaderSource(device);
  852. // These will be filled by data received from the server
  853. // Create item definition manager
  854. IWritableItemDefManager *itemdef = createItemDefManager();
  855. // Create node definition manager
  856. IWritableNodeDefManager *nodedef = createNodeDefManager();
  857. // Sound fetcher (useful when testing)
  858. GameOnDemandSoundFetcher soundfetcher;
  859. // Sound manager
  860. ISoundManager *sound = NULL;
  861. bool sound_is_dummy = false;
  862. #if USE_SOUND
  863. if(g_settings->getBool("enable_sound")){
  864. infostream<<"Attempting to use OpenAL audio"<<std::endl;
  865. sound = createOpenALSoundManager(&soundfetcher);
  866. if(!sound)
  867. infostream<<"Failed to initialize OpenAL audio"<<std::endl;
  868. } else {
  869. infostream<<"Sound disabled."<<std::endl;
  870. }
  871. #endif
  872. if(!sound){
  873. infostream<<"Using dummy audio."<<std::endl;
  874. sound = &dummySoundManager;
  875. sound_is_dummy = true;
  876. }
  877. // Event manager
  878. EventManager eventmgr;
  879. // Sound maker
  880. SoundMaker soundmaker(sound, nodedef);
  881. soundmaker.registerReceiver(&eventmgr);
  882. // Add chat log output for errors to be shown in chat
  883. LogOutputBuffer chat_log_error_buf(LMT_ERROR);
  884. // Create UI for modifying quicktune values
  885. QuicktuneShortcutter quicktune;
  886. /*
  887. Create server.
  888. SharedPtr will delete it when it goes out of scope.
  889. */
  890. SharedPtr<Server> server;
  891. if(address == ""){
  892. draw_load_screen(L"Creating server...", driver, font);
  893. infostream<<"Creating server"<<std::endl;
  894. server = new Server(map_dir, configpath, gamespec,
  895. simple_singleplayer_mode);
  896. server->start(port);
  897. }
  898. try{
  899. do{ // Client scope (breakable do-while(0))
  900. /*
  901. Create client
  902. */
  903. draw_load_screen(L"Creating client...", driver, font);
  904. infostream<<"Creating client"<<std::endl;
  905. MapDrawControl draw_control;
  906. Client client(device, playername.c_str(), password, draw_control,
  907. tsrc, shsrc, itemdef, nodedef, sound, &eventmgr);
  908. // Client acts as our GameDef
  909. IGameDef *gamedef = &client;
  910. draw_load_screen(L"Resolving address...", driver, font);
  911. Address connect_address(0,0,0,0, port);
  912. try{
  913. if(address == "")
  914. //connect_address.Resolve("localhost");
  915. connect_address.setAddress(127,0,0,1);
  916. else
  917. connect_address.Resolve(address.c_str());
  918. }
  919. catch(ResolveError &e)
  920. {
  921. error_message = L"Couldn't resolve address";
  922. errorstream<<wide_to_narrow(error_message)<<std::endl;
  923. // Break out of client scope
  924. break;
  925. }
  926. /*
  927. Attempt to connect to the server
  928. */
  929. infostream<<"Connecting to server at ";
  930. connect_address.print(&infostream);
  931. infostream<<std::endl;
  932. client.connect(connect_address);
  933. /*
  934. Wait for server to accept connection
  935. */
  936. bool could_connect = false;
  937. bool connect_aborted = false;
  938. try{
  939. float frametime = 0.033;
  940. float time_counter = 0.0;
  941. input->clear();
  942. while(device->run())
  943. {
  944. // Update client and server
  945. client.step(frametime);
  946. if(server != NULL)
  947. server->step(frametime);
  948. // End condition
  949. if(client.connectedAndInitialized()){
  950. could_connect = true;
  951. break;
  952. }
  953. // Break conditions
  954. if(client.accessDenied()){
  955. error_message = L"Access denied. Reason: "
  956. +client.accessDeniedReason();
  957. errorstream<<wide_to_narrow(error_message)<<std::endl;
  958. break;
  959. }
  960. if(input->wasKeyDown(EscapeKey)){
  961. connect_aborted = true;
  962. infostream<<"Connect aborted [Escape]"<<std::endl;
  963. break;
  964. }
  965. // Display status
  966. std::wostringstream ss;
  967. ss<<L"Connecting to server... (press Escape to cancel)\n";
  968. std::wstring animation = L"/-\\|";
  969. ss<<animation[(int)(time_counter/0.2)%4];
  970. draw_load_screen(ss.str(), driver, font);
  971. // Delay a bit
  972. sleep_ms(1000*frametime);
  973. time_counter += frametime;
  974. }
  975. }
  976. catch(con::PeerNotFoundException &e)
  977. {}
  978. /*
  979. Handle failure to connect
  980. */
  981. if(!could_connect){
  982. if(error_message == L"" && !connect_aborted){
  983. error_message = L"Connection failed";
  984. errorstream<<wide_to_narrow(error_message)<<std::endl;
  985. }
  986. // Break out of client scope
  987. break;
  988. }
  989. /*
  990. Wait until content has been received
  991. */
  992. bool got_content = false;
  993. bool content_aborted = false;
  994. {
  995. float frametime = 0.033;
  996. float time_counter = 0.0;
  997. input->clear();
  998. while(device->run())
  999. {
  1000. // Update client and server
  1001. client.step(frametime);
  1002. if(server != NULL)
  1003. server->step(frametime);
  1004. // End condition
  1005. if(client.texturesReceived() &&
  1006. client.itemdefReceived() &&
  1007. client.nodedefReceived()){
  1008. got_content = true;
  1009. break;
  1010. }
  1011. // Break conditions
  1012. if(!client.connectedAndInitialized()){
  1013. error_message = L"Client disconnected";
  1014. errorstream<<wide_to_narrow(error_message)<<std::endl;
  1015. break;
  1016. }
  1017. if(input->wasKeyDown(EscapeKey)){
  1018. content_aborted = true;
  1019. infostream<<"Connect aborted [Escape]"<<std::endl;
  1020. break;
  1021. }
  1022. // Display status
  1023. std::wostringstream ss;
  1024. ss<<L"Waiting content... (press Escape to cancel)\n";
  1025. ss<<(client.itemdefReceived()?L"[X]":L"[ ]");
  1026. ss<<L" Item definitions\n";
  1027. ss<<(client.nodedefReceived()?L"[X]":L"[ ]");
  1028. ss<<L" Node definitions\n";
  1029. ss<<L"["<<(int)(client.mediaReceiveProgress()*100+0.5)<<L"%] ";
  1030. ss<<L" Media\n";
  1031. draw_load_screen(ss.str(), driver, font);
  1032. // Delay a bit
  1033. sleep_ms(1000*frametime);
  1034. time_counter += frametime;
  1035. }
  1036. }
  1037. if(!got_content){
  1038. if(error_message == L"" && !content_aborted){
  1039. error_message = L"Something failed";
  1040. errorstream<<wide_to_narrow(error_message)<<std::endl;
  1041. }
  1042. // Break out of client scope
  1043. break;
  1044. }
  1045. /*
  1046. After all content has been received:
  1047. Update cached textures, meshes and materials
  1048. */
  1049. client.afterContentReceived();
  1050. /*
  1051. Create the camera node
  1052. */
  1053. Camera camera(smgr, draw_control, gamedef);
  1054. if (!camera.successfullyCreated(error_message))
  1055. return;
  1056. f32 camera_yaw = 0; // "right/left"
  1057. f32 camera_pitch = 0; // "up/down"
  1058. /*
  1059. Clouds
  1060. */
  1061. Clouds *clouds = NULL;
  1062. if(g_settings->getBool("enable_clouds"))
  1063. {
  1064. clouds = new Clouds(smgr->getRootSceneNode(), smgr, -1, time(0));
  1065. }
  1066. /*
  1067. Skybox thingy
  1068. */
  1069. Sky *sky = NULL;
  1070. sky = new Sky(smgr->getRootSceneNode(), smgr, -1);
  1071. /*
  1072. FarMesh
  1073. */
  1074. FarMesh *farmesh = NULL;
  1075. if(g_settings->getBool("enable_farmesh"))
  1076. {
  1077. farmesh = new FarMesh(smgr->getRootSceneNode(), smgr, -1, client.getMapSeed(), &client);
  1078. }
  1079. /*
  1080. A copy of the local inventory
  1081. */
  1082. Inventory local_inventory(itemdef);
  1083. /*
  1084. Find out size of crack animation
  1085. */
  1086. int crack_animation_length = 5;
  1087. {
  1088. video::ITexture *t = tsrc->getTextureRaw("crack_anylength.png");
  1089. v2u32 size = t->getOriginalSize();
  1090. crack_animation_length = size.Y / size.X;
  1091. }
  1092. /*
  1093. Add some gui stuff
  1094. */
  1095. // First line of debug text
  1096. gui::IGUIStaticText *guitext = guienv->addStaticText(
  1097. L"Minetest",
  1098. core::rect<s32>(5, 5, 795, 5+text_height),
  1099. false, false);
  1100. // Second line of debug text
  1101. gui::IGUIStaticText *guitext2 = guienv->addStaticText(
  1102. L"",
  1103. core::rect<s32>(5, 5+(text_height+5)*1, 795, (5+text_height)*2),
  1104. false, false);
  1105. // At the middle of the screen
  1106. // Object infos are shown in this
  1107. gui::IGUIStaticText *guitext_info = guienv->addStaticText(
  1108. L"",
  1109. core::rect<s32>(0,0,400,text_height*5+5) + v2s32(100,200),
  1110. false, false);
  1111. // Status text (displays info when showing and hiding GUI stuff, etc.)
  1112. gui::IGUIStaticText *guitext_status = guienv->addStaticText(
  1113. L"<Status>",
  1114. core::rect<s32>(0,0,0,0),
  1115. false, false);
  1116. guitext_status->setVisible(false);
  1117. std::wstring statustext;
  1118. float statustext_time = 0;
  1119. // Chat text
  1120. gui::IGUIStaticText *guitext_chat = guienv->addStaticText(
  1121. L"",
  1122. core::rect<s32>(0,0,0,0),
  1123. //false, false); // Disable word wrap as of now
  1124. false, true);
  1125. // Remove stale "recent" chat messages from previous connections
  1126. chat_backend.clearRecentChat();
  1127. // Chat backend and console
  1128. GUIChatConsole *gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(), -1, &chat_backend, &client);
  1129. // Profiler text (size is updated when text is updated)
  1130. gui::IGUIStaticText *guitext_profiler = guienv->addStaticText(
  1131. L"<Profiler>",
  1132. core::rect<s32>(0,0,0,0),
  1133. false, false);
  1134. guitext_profiler->setBackgroundColor(video::SColor(120,0,0,0));
  1135. guitext_profiler->setVisible(false);
  1136. /*
  1137. Some statistics are collected in these
  1138. */
  1139. u32 drawtime = 0;
  1140. u32 beginscenetime = 0;
  1141. u32 scenetime = 0;
  1142. u32 endscenetime = 0;
  1143. float recent_turn_speed = 0.0;
  1144. ProfilerGraph graph;
  1145. // Initially clear the profiler
  1146. Profiler::GraphValues dummyvalues;
  1147. g_profiler->graphGet(dummyvalues);
  1148. float nodig_delay_timer = 0.0;
  1149. float dig_time = 0.0;
  1150. u16 dig_index = 0;
  1151. PointedThing pointed_old;
  1152. bool digging = false;
  1153. bool ldown_for_dig = false;
  1154. float damage_flash = 0;
  1155. s16 farmesh_range = 20*MAP_BLOCKSIZE;
  1156. float jump_timer = 0;
  1157. bool reset_jump_timer = false;
  1158. const float object_hit_delay = 0.2;
  1159. float object_hit_delay_timer = 0.0;
  1160. float time_from_last_punch = 10;
  1161. float update_draw_list_timer = 0.0;
  1162. v3f update_draw_list_last_cam_dir;
  1163. bool invert_mouse = g_settings->getBool("invert_mouse");
  1164. bool respawn_menu_active = false;
  1165. bool update_wielded_item_trigger = false;
  1166. bool show_hud = true;
  1167. bool show_chat = true;
  1168. bool force_fog_off = false;
  1169. f32 fog_range = 100*BS;
  1170. bool disable_camera_update = false;
  1171. bool show_debug = g_settings->getBool("show_debug");
  1172. bool show_profiler_graph = false;
  1173. u32 show_profiler = 0;
  1174. u32 show_profiler_max = 3; // Number of pages
  1175. float time_of_day = 0;
  1176. float time_of_day_smooth = 0;
  1177. float repeat_rightclick_timer = 0;
  1178. /*
  1179. Shader constants
  1180. */
  1181. shsrc->addGlobalConstantSetter(new GameGlobalShaderConstantSetter(
  1182. sky, &force_fog_off, &fog_range, &client));
  1183. /*
  1184. Main loop
  1185. */
  1186. bool first_loop_after_window_activation = true;
  1187. // TODO: Convert the static interval timers to these
  1188. // Interval limiter for profiler
  1189. IntervalLimiter m_profiler_interval;
  1190. // Time is in milliseconds
  1191. // NOTE: getRealTime() causes strange problems in wine (imprecision?)
  1192. // NOTE: So we have to use getTime() and call run()s between them
  1193. u32 lasttime = device->getTimer()->getTime();
  1194. LocalPlayer* player = client.getEnv().getLocalPlayer();
  1195. player->hurt_tilt_timer = 0;
  1196. player->hurt_tilt_strength = 0;
  1197. for(;;)
  1198. {
  1199. if(device->run() == false || kill == true)
  1200. break;
  1201. // Time of frame without fps limit
  1202. float busytime;
  1203. u32 busytime_u32;
  1204. {
  1205. // not using getRealTime is necessary for wine
  1206. u32 time = device->getTimer()->getTime();
  1207. if(time > lasttime)
  1208. busytime_u32 = time - lasttime;
  1209. else
  1210. busytime_u32 = 0;
  1211. busytime = busytime_u32 / 1000.0;
  1212. }
  1213. g_profiler->graphAdd("mainloop_other", busytime - (float)drawtime/1000.0f);
  1214. // Necessary for device->getTimer()->getTime()
  1215. device->run();
  1216. /*
  1217. FPS limiter
  1218. */
  1219. {
  1220. float fps_max = g_settings->getFloat("fps_max");
  1221. u32 frametime_min = 1000./fps_max;
  1222. if(busytime_u32 < frametime_min)
  1223. {
  1224. u32 sleeptime = frametime_min - busytime_u32;
  1225. device->sleep(sleeptime);
  1226. g_profiler->graphAdd("mainloop_sleep", (float)sleeptime/1000.0f);
  1227. }
  1228. }
  1229. // Necessary for device->getTimer()->getTime()
  1230. device->run();
  1231. /*
  1232. Time difference calculation
  1233. */
  1234. f32 dtime; // in seconds
  1235. u32 time = device->getTimer()->getTime();
  1236. if(time > lasttime)
  1237. dtime = (time - lasttime) / 1000.0;
  1238. else
  1239. dtime = 0;
  1240. lasttime = time;
  1241. g_profiler->graphAdd("mainloop_dtime", dtime);
  1242. /* Run timers */
  1243. if(nodig_delay_timer >= 0)
  1244. nodig_delay_timer -= dtime;
  1245. if(object_hit_delay_timer >= 0)
  1246. object_hit_delay_timer -= dtime;
  1247. time_from_last_punch += dtime;
  1248. g_profiler->add("Elapsed time", dtime);
  1249. g_profiler->avg("FPS", 1./dtime);
  1250. /*
  1251. Time average and jitter calculation
  1252. */
  1253. static f32 dtime_avg1 = 0.0;
  1254. dtime_avg1 = dtime_avg1 * 0.96 + dtime * 0.04;
  1255. f32 dtime_jitter1 = dtime - dtime_avg1;
  1256. static f32 dtime_jitter1_max_sample = 0.0;
  1257. static f32 dtime_jitter1_max_fraction = 0.0;
  1258. {
  1259. static f32 jitter1_max = 0.0;
  1260. static f32 counter = 0.0;
  1261. if(dtime_jitter1 > jitter1_max)
  1262. jitter1_max = dtime_jitter1;
  1263. counter += dtime;
  1264. if(counter > 0.0)
  1265. {
  1266. counter -= 3.0;
  1267. dtime_jitter1_max_sample = jitter1_max;
  1268. dtime_jitter1_max_fraction
  1269. = dtime_jitter1_max_sample / (dtime_avg1+0.001);
  1270. jitter1_max = 0.0;
  1271. }
  1272. }
  1273. /*
  1274. Busytime average and jitter calculation
  1275. */
  1276. static f32 busytime_avg1 = 0.0;
  1277. busytime_avg1 = busytime_avg1 * 0.98 + busytime * 0.02;
  1278. f32 busytime_jitter1 = busytime - busytime_avg1;
  1279. static f32 busytime_jitter1_max_sample = 0.0;
  1280. static f32 busytime_jitter1_min_sample = 0.0;
  1281. {
  1282. static f32 jitter1_max = 0.0;
  1283. static f32 jitter1_min = 0.0;
  1284. static f32 counter = 0.0;
  1285. if(busytime_jitter1 > jitter1_max)
  1286. jitter1_max = busytime_jitter1;
  1287. if(busytime_jitter1 < jitter1_min)
  1288. jitter1_min = busytime_jitter1;
  1289. counter += dtime;
  1290. if(counter > 0.0){
  1291. counter -= 3.0;
  1292. busytime_jitter1_max_sample = jitter1_max;
  1293. busytime_jitter1_min_sample = jitter1_min;
  1294. jitter1_max = 0.0;
  1295. jitter1_min = 0.0;
  1296. }
  1297. }
  1298. /*
  1299. Handle miscellaneous stuff
  1300. */
  1301. if(client.accessDenied())
  1302. {
  1303. error_message = L"Access denied. Reason: "
  1304. +client.accessDeniedReason();
  1305. errorstream<<wide_to_narrow(error_message)<<std::endl;
  1306. break;
  1307. }
  1308. if(g_gamecallback->disconnect_requested)
  1309. {
  1310. g_gamecallback->disconnect_requested = false;
  1311. break;
  1312. }
  1313. if(g_gamecallback->changepassword_requested)
  1314. {
  1315. (new GUIPasswordChange(guienv, guiroot, -1,
  1316. &g_menumgr, &client))->drop();
  1317. g_gamecallback->changepassword_requested = false;
  1318. }
  1319. /* Process TextureSource's queue */
  1320. tsrc->processQueue();
  1321. /* Process ItemDefManager's queue */
  1322. itemdef->processQueue(gamedef);
  1323. /*
  1324. Process ShaderSource's queue
  1325. */
  1326. shsrc->processQueue();
  1327. /*
  1328. Random calculations
  1329. */
  1330. last_screensize = screensize;
  1331. screensize = driver->getScreenSize();
  1332. v2s32 displaycenter(screensize.X/2,screensize.Y/2);
  1333. //bool screensize_changed = screensize != last_screensize;
  1334. // Resize hotbar
  1335. if(screensize.Y <= 800)
  1336. hotbar_imagesize = 32;
  1337. else if(screensize.Y <= 1280)
  1338. hotbar_imagesize = 48;
  1339. else
  1340. hotbar_imagesize = 64;
  1341. // Hilight boxes collected during the loop and displayed
  1342. std::vector<aabb3f> hilightboxes;
  1343. // Info text
  1344. std::wstring infotext;
  1345. /*
  1346. Debug info for client
  1347. */
  1348. {
  1349. static float counter = 0.0;
  1350. counter -= dtime;
  1351. if(counter < 0)
  1352. {
  1353. counter = 30.0;
  1354. client.printDebugInfo(infostream);
  1355. }
  1356. }
  1357. /*
  1358. Profiler
  1359. */
  1360. float profiler_print_interval =
  1361. g_settings->getFloat("profiler_print_interval");
  1362. bool print_to_log = true;
  1363. if(profiler_print_interval == 0){
  1364. print_to_log = false;
  1365. profiler_print_interval = 5;
  1366. }
  1367. if(m_profiler_interval.step(dtime, profiler_print_interval))
  1368. {
  1369. if(print_to_log){
  1370. infostream<<"Profiler:"<<std::endl;
  1371. g_profiler->print(infostream);
  1372. }
  1373. update_profiler_gui(guitext_profiler, font, text_height,
  1374. show_profiler, show_profiler_max);
  1375. g_profiler->clear();
  1376. }
  1377. /*
  1378. Direct handling of user input
  1379. */
  1380. // Reset input if window not active or some menu is active
  1381. if(device->isWindowActive() == false
  1382. || noMenuActive() == false
  1383. || guienv->hasFocus(gui_chat_console))
  1384. {
  1385. input->clear();
  1386. }
  1387. // Input handler step() (used by the random input generator)
  1388. input->step(dtime);
  1389. // Increase timer for doubleclick of "jump"
  1390. if(g_settings->getBool("doubletap_jump") && jump_timer <= 0.2)
  1391. jump_timer += dtime;
  1392. /*
  1393. Launch menus and trigger stuff according to keys
  1394. */
  1395. if(input->wasKeyDown(getKeySetting("keymap_drop")))
  1396. {
  1397. // drop selected item
  1398. IDropAction *a = new IDropAction();
  1399. a->count = 0;
  1400. a->from_inv.setCurrentPlayer();
  1401. a->from_list = "main";
  1402. a->from_i = client.getPlayerItem();
  1403. client.inventoryAction(a);
  1404. }
  1405. else if(input->wasKeyDown(getKeySetting("keymap_inventory")))
  1406. {
  1407. infostream<<"the_game: "
  1408. <<"Launching inventory"<<std::endl;
  1409. GUIFormSpecMenu *menu =
  1410. new GUIFormSpecMenu(device, guiroot, -1,
  1411. &g_menumgr,
  1412. &client, gamedef);
  1413. InventoryLocation inventoryloc;
  1414. inventoryloc.setCurrentPlayer();
  1415. PlayerInventoryFormSource *src = new PlayerInventoryFormSource(&client);
  1416. assert(src);
  1417. menu->setFormSpec(src->getForm(), inventoryloc);
  1418. menu->setFormSource(src);
  1419. menu->setTextDest(new TextDestPlayerInventory(&client));
  1420. menu->drop();
  1421. }
  1422. else if(input->wasKeyDown(EscapeKey))
  1423. {
  1424. infostream<<"the_game: "
  1425. <<"Launching pause menu"<<std::endl;
  1426. // It will delete itself by itself
  1427. (new GUIPauseMenu(guienv, guiroot, -1, g_gamecallback,
  1428. &g_menumgr, simple_singleplayer_mode))->drop();
  1429. // Move mouse cursor on top of the disconnect button
  1430. if(simple_singleplayer_mode)
  1431. input->setMousePos(displaycenter.X, displaycenter.Y+0);
  1432. else
  1433. input->setMousePos(displaycenter.X, displaycenter.Y+25);
  1434. }
  1435. else if(input->wasKeyDown(getKeySetting("keymap_chat")))
  1436. {
  1437. TextDest *dest = new TextDestChat(&client);
  1438. (new GUITextInputMenu(guienv, guiroot, -1,
  1439. &g_menumgr, dest,
  1440. L""))->drop();
  1441. }
  1442. else if(input->wasKeyDown(getKeySetting("keymap_cmd")))
  1443. {
  1444. TextDest *dest = new TextDestChat(&client);
  1445. (new GUITextInputMenu(guienv, guiroot, -1,
  1446. &g_menumgr, dest,
  1447. L"/"))->drop();
  1448. }
  1449. else if(input->wasKeyDown(getKeySetting("keymap_console")))
  1450. {
  1451. if (!gui_chat_console->isOpenInhibited())
  1452. {
  1453. // Open up to over half of the screen
  1454. gui_chat_console->openConsole(0.6);
  1455. guienv->setFocus(gui_chat_console);
  1456. }
  1457. }
  1458. else if(input->wasKeyDown(getKeySetting("keymap_freemove")))
  1459. {
  1460. if(g_settings->getBool("free_move"))
  1461. {
  1462. g_settings->set("free_move","false");
  1463. statustext = L"free_move disabled";
  1464. statustext_time = 0;
  1465. }
  1466. else
  1467. {
  1468. g_settings->set("free_move","true");
  1469. statustext = L"free_move enabled";
  1470. statustext_time = 0;
  1471. if(!client.checkPrivilege("fly"))
  1472. statustext += L" (note: no 'fly' privilege)";
  1473. }
  1474. }
  1475. else if(input->wasKeyDown(getKeySetting("keymap_jump")))
  1476. {
  1477. if(g_settings->getBool("doubletap_jump") && jump_timer < 0.2)
  1478. {
  1479. if(g_settings->getBool("free_move"))
  1480. {
  1481. g_settings->set("free_move","false");
  1482. statustext = L"free_move disabled";
  1483. statustext_time = 0;
  1484. }
  1485. else
  1486. {
  1487. g_settings->set("free_move","true");
  1488. statustext = L"free_move enabled";
  1489. statustext_time = 0;
  1490. if(!client.checkPrivilege("fly"))
  1491. statustext += L" (note: no 'fly' privilege)";
  1492. }
  1493. }
  1494. reset_jump_timer = true;
  1495. }
  1496. else if(input->wasKeyDown(getKeySetting("keymap_fastmove")))
  1497. {
  1498. if(g_settings->getBool("fast_move"))
  1499. {
  1500. g_settings->set("fast_move","false");
  1501. statustext = L"fast_move disabled";
  1502. statustext_time = 0;
  1503. }
  1504. else
  1505. {
  1506. g_settings->set("fast_move","true");
  1507. statustext = L"fast_move enabled";
  1508. statustext_time = 0;
  1509. if(!client.checkPrivilege("fast"))
  1510. statustext += L" (note: no 'fast' privilege)";
  1511. }
  1512. }
  1513. else if(input->wasKeyDown(getKeySetting("keymap_noclip")))
  1514. {
  1515. if(g_settings->getBool("noclip"))
  1516. {
  1517. g_settings->set("noclip","false");
  1518. statustext = L"noclip disabled";
  1519. statustext_time = 0;
  1520. }
  1521. else
  1522. {
  1523. g_settings->set("noclip","true");
  1524. statustext = L"noclip enabled";
  1525. statustext_time = 0;
  1526. if(!client.checkPrivilege("noclip"))
  1527. statustext += L" (note: no 'noclip' privilege)";
  1528. }
  1529. }
  1530. else if(input->wasKeyDown(getKeySetting("keymap_screenshot")))
  1531. {
  1532. irr::video::IImage* const image = driver->createScreenShot();
  1533. if (image) {
  1534. irr::c8 filename[256];
  1535. snprintf(filename, 256, "%s" DIR_DELIM "screenshot_%u.png",
  1536. g_settings->get("screenshot_path").c_str(),
  1537. device->getTimer()->getRealTime());
  1538. if (driver->writeImageToFile(image, filename)) {
  1539. std::wstringstream sstr;
  1540. sstr<<"Saved screenshot to '"<<filename<<"'";
  1541. infostream<<"Saved screenshot to '"<<filename<<"'"<<std::endl;
  1542. statustext = sstr.str();
  1543. statustext_time = 0;
  1544. } else{
  1545. infostream<<"Failed to save screenshot '"<<filename<<"'"<<std::endl;
  1546. }
  1547. image->drop();
  1548. }
  1549. }
  1550. else if(input->wasKeyDown(getKeySetting("keymap_toggle_hud")))
  1551. {
  1552. show_hud = !show_hud;
  1553. if(show_hud)
  1554. statustext = L"HUD shown";
  1555. else
  1556. statustext = L"HUD hidden";
  1557. statustext_time = 0;
  1558. }
  1559. else if(input->wasKeyDown(getKeySetting("keymap_toggle_chat")))
  1560. {
  1561. show_chat = !show_chat;
  1562. if(show_chat)
  1563. statustext = L"Chat shown";
  1564. else
  1565. statustext = L"Chat hidden";
  1566. statustext_time = 0;
  1567. }
  1568. else if(input->wasKeyDown(getKeySetting("keymap_toggle_force_fog_off")))
  1569. {
  1570. force_fog_off = !force_fog_off;
  1571. if(force_fog_off)
  1572. statustext = L"Fog disabled";
  1573. else
  1574. statustext = L"Fog enabled";
  1575. statustext_time = 0;
  1576. }
  1577. else if(input->wasKeyDown(getKeySetting("keymap_toggle_update_camera")))
  1578. {
  1579. disable_camera_update = !disable_camera_update;
  1580. if(disable_camera_update)
  1581. statustext = L"Camera update disabled";
  1582. else
  1583. statustext = L"Camera update enabled";
  1584. statustext_time = 0;
  1585. }
  1586. else if(input->wasKeyDown(getKeySetting("keymap_toggle_debug")))
  1587. {
  1588. // Initial / 3x toggle: Chat only
  1589. // 1x toggle: Debug text with chat
  1590. // 2x toggle: Debug text with profiler graph
  1591. if(!show_debug)
  1592. {
  1593. show_debug = true;
  1594. show_profiler_graph = false;
  1595. statustext = L"Debug info shown";
  1596. statustext_time = 0;
  1597. }
  1598. else if(show_profiler_graph)
  1599. {
  1600. show_debug = false;
  1601. show_profiler_graph = false;
  1602. statustext = L"Debug info and profiler graph hidden";
  1603. statustext_time = 0;
  1604. }
  1605. else
  1606. {
  1607. show_profiler_graph = true;
  1608. statustext = L"Profiler graph shown";
  1609. statustext_time = 0;
  1610. }
  1611. }
  1612. else if(input->wasKeyDown(getKeySetting("keymap_toggle_profiler")))
  1613. {
  1614. show_profiler = (show_profiler + 1) % (show_profiler_max + 1);
  1615. // FIXME: This updates the profiler with incomplete values
  1616. update_profiler_gui(guitext_profiler, font, text_height,
  1617. show_profiler, show_profiler_max);
  1618. if(show_profiler != 0)
  1619. {
  1620. std::wstringstream sstr;
  1621. sstr<<"Profiler shown (page "<<show_profiler
  1622. <<" of "<<show_profiler_max<<")";
  1623. statustext = sstr.str();
  1624. statustext_time = 0;
  1625. }
  1626. else
  1627. {
  1628. statustext = L"Profiler hidden";
  1629. statustext_time = 0;
  1630. }
  1631. }
  1632. else if(input->wasKeyDown(getKeySetting("keymap_increase_viewing_range_min")))
  1633. {
  1634. s16 range = g_settings->getS16("viewing_range_nodes_min");
  1635. s16 range_new = range + 10;
  1636. g_settings->set("viewing_range_nodes_min", itos(range_new));
  1637. statustext = narrow_to_wide(
  1638. "Minimum viewing range changed to "
  1639. + itos(range_new));
  1640. statustext_time = 0;
  1641. }
  1642. else if(input->wasKeyDown(getKeySetting("keymap_decrease_viewing_range_min")))
  1643. {
  1644. s16 range = g_settings->getS16("viewing_range_nodes_min");
  1645. s16 range_new = range - 10;
  1646. if(range_new < 0)
  1647. range_new = range;
  1648. g_settings->set("viewing_range_nodes_min",
  1649. itos(range_new));
  1650. statustext = narrow_to_wide(
  1651. "Minimum viewing range changed to "
  1652. + itos(range_new));
  1653. statustext_time = 0;
  1654. }
  1655. // Reset jump_timer
  1656. if(!input->isKeyDown(getKeySetting("keymap_jump")) && reset_jump_timer)
  1657. {
  1658. reset_jump_timer = false;
  1659. jump_timer = 0.0;
  1660. }
  1661. // Handle QuicktuneShortcutter
  1662. if(input->wasKeyDown(getKeySetting("keymap_quicktune_next")))
  1663. quicktune.next();
  1664. if(input->wasKeyDown(getKeySetting("keymap_quicktune_prev")))
  1665. quicktune.prev();
  1666. if(input->wasKeyDown(getKeySetting("keymap_quicktune_inc")))
  1667. quicktune.inc();
  1668. if(input->wasKeyDown(getKeySetting("keymap_quicktune_dec")))
  1669. quicktune.dec();
  1670. {
  1671. std::string msg = quicktune.getMessage();
  1672. if(msg != ""){
  1673. statustext = narrow_to_wide(msg);
  1674. statustext_time = 0;
  1675. }
  1676. }
  1677. // Item selection with mouse wheel
  1678. u16 new_playeritem = client.getPlayerItem();
  1679. {
  1680. s32 wheel = input->getMouseWheel();
  1681. u16 max_item = MYMIN(PLAYER_INVENTORY_SIZE-1,
  1682. hotbar_itemcount-1);
  1683. if(wheel < 0)
  1684. {
  1685. if(new_playeritem < max_item)
  1686. new_playeritem++;
  1687. else
  1688. new_playeritem = 0;
  1689. }
  1690. else if(wheel > 0)
  1691. {
  1692. if(new_playeritem > 0)
  1693. new_playeritem--;
  1694. else
  1695. new_playeritem = max_item;
  1696. }
  1697. }
  1698. // Item selection
  1699. for(u16 i=0; i<10; i++)
  1700. {
  1701. const KeyPress *kp = NumberKey + (i + 1) % 10;
  1702. if(input->wasKeyDown(*kp))
  1703. {
  1704. if(i < PLAYER_INVENTORY_SIZE && i < hotbar_itemcount)
  1705. {
  1706. new_playeritem = i;
  1707. infostream<<"Selected item: "
  1708. <<new_playeritem<<std::endl;
  1709. }
  1710. }
  1711. }
  1712. // Viewing range selection
  1713. if(input->wasKeyDown(getKeySetting("keymap_rangeselect")))
  1714. {
  1715. draw_control.range_all = !draw_control.range_all;
  1716. if(draw_control.range_all)
  1717. {
  1718. infostream<<"Enabled full viewing range"<<std::endl;
  1719. statustext = L"Enabled full viewing range";
  1720. statustext_time = 0;
  1721. }
  1722. else
  1723. {
  1724. infostream<<"Disabled full viewing range"<<std::endl;
  1725. statustext = L"Disabled full viewing range";
  1726. statustext_time = 0;
  1727. }
  1728. }
  1729. // Print debug stacks
  1730. if(input->wasKeyDown(getKeySetting("keymap_print_debug_stacks")))
  1731. {
  1732. dstream<<"-----------------------------------------"
  1733. <<std::endl;
  1734. dstream<<DTIME<<"Printing debug stacks:"<<std::endl;
  1735. dstream<<"-----------------------------------------"
  1736. <<std::endl;
  1737. debug_stacks_print();
  1738. }
  1739. /*
  1740. Mouse and camera control
  1741. NOTE: Do this before client.setPlayerControl() to not cause a camera lag of one frame
  1742. */
  1743. float turn_amount = 0;
  1744. if((device->isWindowActive() && noMenuActive()) || random_input)
  1745. {
  1746. if(!random_input)
  1747. {
  1748. // Mac OSX gets upset if this is set every frame
  1749. if(device->getCursorControl()->isVisible())
  1750. device->getCursorControl()->setVisible(false);
  1751. }
  1752. if(first_loop_after_window_activation){
  1753. //infostream<<"window active, first loop"<<std::endl;
  1754. first_loop_after_window_activation = false;
  1755. }
  1756. else{
  1757. s32 dx = input->getMousePos().X - displaycenter.X;
  1758. s32 dy = input->getMousePos().Y - displaycenter.Y;
  1759. if(invert_mouse)
  1760. dy = -dy;
  1761. //infostream<<"window active, pos difference "<<dx<<","<<dy<<std::endl;
  1762. /*const float keyspeed = 500;
  1763. if(input->isKeyDown(irr::KEY_UP))
  1764. dy -= dtime * keyspeed;
  1765. if(input->isKeyDown(irr::KEY_DOWN))
  1766. dy += dtime * keyspeed;
  1767. if(input->isKeyDown(irr::KEY_LEFT))
  1768. dx -= dtime * keyspeed;
  1769. if(input->isKeyDown(irr::KEY_RIGHT))
  1770. dx += dtime * keyspeed;*/
  1771. float d = 0.2;
  1772. camera_yaw -= dx*d;
  1773. camera_pitch += dy*d;
  1774. if(camera_pitch < -89.5) camera_pitch = -89.5;
  1775. if(camera_pitch > 89.5) camera_pitch = 89.5;
  1776. turn_amount = v2f(dx, dy).getLength() * d;
  1777. }
  1778. input->setMousePos(displaycenter.X, displaycenter.Y);
  1779. }
  1780. else{
  1781. // Mac OSX gets upset if this is set every frame
  1782. if(device->getCursorControl()->isVisible() == false)
  1783. device->getCursorControl()->setVisible(true);
  1784. //infostream<<"window inactive"<<std::endl;
  1785. first_loop_after_window_activation = true;
  1786. }
  1787. recent_turn_speed = recent_turn_speed * 0.9 + turn_amount * 0.1;
  1788. //std::cerr<<"recent_turn_speed = "<<recent_turn_speed<<std::endl;
  1789. /*
  1790. Player speed control
  1791. */
  1792. {
  1793. /*bool a_up,
  1794. bool a_down,
  1795. bool a_left,
  1796. bool a_right,
  1797. bool a_jump,
  1798. bool a_superspeed,
  1799. bool a_sneak,
  1800. bool a_LMB,
  1801. bool a_RMB,
  1802. float a_pitch,
  1803. float a_yaw*/
  1804. PlayerControl control(
  1805. input->isKeyDown(getKeySetting("keymap_forward")),
  1806. input->isKeyDown(getKeySetting("keymap_backward")),
  1807. input->isKeyDown(getKeySetting("keymap_left")),
  1808. input->isKeyDown(getKeySetting("keymap_right")),
  1809. input->isKeyDown(getKeySetting("keymap_jump")),
  1810. input->isKeyDown(getKeySetting("keymap_special1")),
  1811. input->isKeyDown(getKeySetting("keymap_sneak")),
  1812. input->getLeftState(),
  1813. input->getRightState(),
  1814. camera_pitch,
  1815. camera_yaw
  1816. );
  1817. client.setPlayerControl(control);
  1818. u32 keyPressed=
  1819. 1*(int)input->isKeyDown(getKeySetting("keymap_forward"))+
  1820. 2*(int)input->isKeyDown(getKeySetting("keymap_backward"))+
  1821. 4*(int)input->isKeyDown(getKeySetting("keymap_left"))+
  1822. 8*(int)input->isKeyDown(getKeySetting("keymap_right"))+
  1823. 16*(int)input->isKeyDown(getKeySetting("keymap_jump"))+
  1824. 32*(int)input->isKeyDown(getKeySetting("keymap_special1"))+
  1825. 64*(int)input->isKeyDown(getKeySetting("keymap_sneak"))+
  1826. 128*(int)input->getLeftState()+
  1827. 256*(int)input->getRightState();
  1828. LocalPlayer* player = client.getEnv().getLocalPlayer();
  1829. player->keyPressed=keyPressed;
  1830. }
  1831. /*
  1832. Run server
  1833. */
  1834. if(server != NULL)
  1835. {
  1836. //TimeTaker timer("server->step(dtime)");
  1837. server->step(dtime);
  1838. }
  1839. /*
  1840. Process environment
  1841. */
  1842. {
  1843. //TimeTaker timer("client.step(dtime)");
  1844. client.step(dtime);
  1845. //client.step(dtime_avg1);
  1846. }
  1847. {
  1848. // Read client events
  1849. for(;;)
  1850. {
  1851. ClientEvent event = client.getClientEvent();
  1852. if(event.type == CE_NONE)
  1853. {
  1854. break;
  1855. }
  1856. else if(event.type == CE_PLAYER_DAMAGE)
  1857. {
  1858. //u16 damage = event.player_damage.amount;
  1859. //infostream<<"Player damage: "<<damage<<std::endl;
  1860. damage_flash += 100.0;
  1861. damage_flash += 8.0 * event.player_damage.amount;
  1862. player->hurt_tilt_timer = 1.5;
  1863. player->hurt_tilt_strength = event.player_damage.amount/2;
  1864. player->hurt_tilt_strength = rangelim(player->hurt_tilt_strength, 2.0, 10.0);
  1865. }
  1866. else if(event.type == CE_PLAYER_FORCE_MOVE)
  1867. {
  1868. camera_yaw = event.player_force_move.yaw;
  1869. camera_pitch = event.player_force_move.pitch;
  1870. }
  1871. else if(event.type == CE_DEATHSCREEN)
  1872. {
  1873. if(respawn_menu_active)
  1874. continue;
  1875. /*bool set_camera_point_target =
  1876. event.deathscreen.set_camera_point_target;
  1877. v3f camera_point_target;
  1878. camera_point_target.X = event.deathscreen.camera_point_target_x;
  1879. camera_point_target.Y = event.deathscreen.camera_point_target_y;
  1880. camera_point_target.Z = event.deathscreen.camera_point_target_z;*/
  1881. MainRespawnInitiator *respawner =
  1882. new MainRespawnInitiator(
  1883. &respawn_menu_active, &client);
  1884. GUIDeathScreen *menu =
  1885. new GUIDeathScreen(guienv, guiroot, -1,
  1886. &g_menumgr, respawner);
  1887. menu->drop();
  1888. chat_backend.addMessage(L"", L"You died.");
  1889. /* Handle visualization */
  1890. damage_flash = 0;
  1891. LocalPlayer* player = client.getEnv().getLocalPlayer();
  1892. player->hurt_tilt_timer = 0;
  1893. player->hurt_tilt_strength = 0;
  1894. /*LocalPlayer* player = client.getLocalPlayer();
  1895. player->setPosition(player->getPosition() + v3f(0,-BS,0));
  1896. camera.update(player, busytime, screensize);*/
  1897. }
  1898. else if (event.type == CE_SHOW_FORMSPEC)
  1899. {
  1900. if (current_formspec == 0)
  1901. {
  1902. /* Create menu */
  1903. current_formspec = new FormspecFormSource(*(event.show_formspec.formspec),&current_formspec);
  1904. GUIFormSpecMenu *menu =
  1905. new GUIFormSpecMenu(device, guiroot, -1,
  1906. &g_menumgr,
  1907. &client, gamedef);
  1908. menu->setFormSource(current_formspec);
  1909. menu->drop();
  1910. }
  1911. else
  1912. {
  1913. /* update menu */
  1914. current_formspec->setForm(*(event.show_formspec.formspec));
  1915. }
  1916. delete(event.show_formspec.formspec);
  1917. }
  1918. else if(event.type == CE_TEXTURES_UPDATED)
  1919. {
  1920. update_wielded_item_trigger = true;
  1921. }
  1922. }
  1923. }
  1924. //TimeTaker //timer2("//timer2");
  1925. /*
  1926. For interaction purposes, get info about the held item
  1927. - What item is it?
  1928. - Is it a usable item?
  1929. - Can it point to liquids?
  1930. */
  1931. ItemStack playeritem;
  1932. bool playeritem_usable = false;
  1933. bool playeritem_liquids_pointable = false;
  1934. {
  1935. InventoryList *mlist = local_inventory.getList("main");
  1936. if(mlist != NULL)
  1937. {
  1938. playeritem = mlist->getItem(client.getPlayerItem());
  1939. playeritem_usable = playeritem.getDefinition(itemdef).usable;
  1940. playeritem_liquids_pointable = playeritem.getDefinition(itemdef).liquids_pointable;
  1941. }
  1942. }
  1943. ToolCapabilities playeritem_toolcap =
  1944. playeritem.getToolCapabilities(itemdef);
  1945. /*
  1946. Update camera
  1947. */
  1948. LocalPlayer* player = client.getEnv().getLocalPlayer();
  1949. float full_punch_interval = playeritem_toolcap.full_punch_interval;
  1950. float tool_reload_ratio = time_from_last_punch / full_punch_interval;
  1951. tool_reload_ratio = MYMIN(tool_reload_ratio, 1.0);
  1952. camera.update(player, busytime, screensize, tool_reload_ratio);
  1953. camera.step(dtime);
  1954. v3f player_position = player->getPosition();
  1955. v3f camera_position = camera.getPosition();
  1956. v3f camera_direction = camera.getDirection();
  1957. f32 camera_fov = camera.getFovMax();
  1958. if(!disable_camera_update){
  1959. client.getEnv().getClientMap().updateCamera(camera_position,
  1960. camera_direction, camera_fov);
  1961. }
  1962. // Update sound listener
  1963. sound->updateListener(camera.getCameraNode()->getPosition(),
  1964. v3f(0,0,0), // velocity
  1965. camera.getDirection(),
  1966. camera.getCameraNode()->getUpVector());
  1967. sound->setListenerGain(g_settings->getFloat("sound_volume"));
  1968. /*
  1969. Update sound maker
  1970. */
  1971. {
  1972. soundmaker.step(dtime);
  1973. ClientMap &map = client.getEnv().getClientMap();
  1974. MapNode n = map.getNodeNoEx(player->getStandingNodePos());
  1975. soundmaker.m_player_step_sound = nodedef->get(n).sound_footstep;
  1976. }
  1977. /*
  1978. Calculate what block is the crosshair pointing to
  1979. */
  1980. //u32 t1 = device->getTimer()->getRealTime();
  1981. f32 d = 4; // max. distance
  1982. core::line3d<f32> shootline(camera_position,
  1983. camera_position + camera_direction * BS * (d+1));
  1984. ClientActiveObject *selected_object = NULL;
  1985. PointedThing pointed = getPointedThing(
  1986. // input
  1987. &client, player_position, camera_direction,
  1988. camera_position, shootline, d,
  1989. playeritem_liquids_pointable, !ldown_for_dig,
  1990. // output
  1991. hilightboxes,
  1992. selected_object);
  1993. if(pointed != pointed_old)
  1994. {
  1995. infostream<<"Pointing at "<<pointed.dump()<<std::endl;
  1996. //dstream<<"Pointing at "<<pointed.dump()<<std::endl;
  1997. }
  1998. /*
  1999. Stop digging when
  2000. - releasing left mouse button
  2001. - pointing away from node
  2002. */
  2003. if(digging)
  2004. {
  2005. if(input->getLeftReleased())
  2006. {
  2007. infostream<<"Left button released"
  2008. <<" (stopped digging)"<<std::endl;
  2009. digging = false;
  2010. }
  2011. else if(pointed != pointed_old)
  2012. {
  2013. if (pointed.type == POINTEDTHING_NODE
  2014. && pointed_old.type == POINTEDTHING_NODE
  2015. && pointed.node_undersurface == pointed_old.node_undersurface)
  2016. {
  2017. // Still pointing to the same node,
  2018. // but a different face. Don't reset.
  2019. }
  2020. else
  2021. {
  2022. infostream<<"Pointing away from node"
  2023. <<" (stopped digging)"<<std::endl;
  2024. digging = false;
  2025. }
  2026. }
  2027. if(!digging)
  2028. {
  2029. client.interact(1, pointed_old);
  2030. client.setCrack(-1, v3s16(0,0,0));
  2031. dig_time = 0.0;
  2032. }
  2033. }
  2034. if(!digging && ldown_for_dig && !input->getLeftState())
  2035. {
  2036. ldown_for_dig = false;
  2037. }
  2038. bool left_punch = false;
  2039. soundmaker.m_player_leftpunch_sound.name = "";
  2040. if(input->getRightState())
  2041. repeat_rightclick_timer += dtime;
  2042. if(playeritem_usable && input->getLeftState())
  2043. {
  2044. if(input->getLeftClicked())
  2045. client.interact(4, pointed);
  2046. }
  2047. else if(pointed.type == POINTEDTHING_NODE)
  2048. {
  2049. v3s16 nodepos = pointed.node_undersurface;
  2050. v3s16 neighbourpos = pointed.node_abovesurface;
  2051. /*
  2052. Check information text of node
  2053. */
  2054. ClientMap &map = client.getEnv().getClientMap();
  2055. NodeMetadata *meta = map.getNodeMetadata(nodepos);
  2056. if(meta){
  2057. infotext = narrow_to_wide(meta->getString("infotext"));
  2058. } else {
  2059. MapNode n = map.getNode(nodepos);
  2060. if(nodedef->get(n).tiledef[0].name == "unknown_block.png"){
  2061. infotext = L"Unknown node: ";
  2062. infotext += narrow_to_wide(nodedef->get(n).name);
  2063. }
  2064. }
  2065. // We can't actually know, but assume the sound of right-clicking
  2066. // to be the sound of placing a node
  2067. soundmaker.m_player_rightpunch_sound.gain = 0.5;
  2068. soundmaker.m_player_rightpunch_sound.name = "default_place_node";
  2069. /*
  2070. Handle digging
  2071. */
  2072. if(nodig_delay_timer <= 0.0 && input->getLeftState())
  2073. {
  2074. if(!digging)
  2075. {
  2076. infostream<<"Started digging"<<std::endl;
  2077. client.interact(0, pointed);
  2078. digging = true;
  2079. ldown_for_dig = true;
  2080. }
  2081. MapNode n = client.getEnv().getClientMap().getNode(nodepos);
  2082. // NOTE: Similar piece of code exists on the server side for
  2083. // cheat detection.
  2084. // Get digging parameters
  2085. DigParams params = getDigParams(nodedef->get(n).groups,
  2086. &playeritem_toolcap);
  2087. // If can't dig, try hand
  2088. if(!params.diggable){
  2089. const ItemDefinition &hand = itemdef->get("");
  2090. const ToolCapabilities *tp = hand.tool_capabilities;
  2091. if(tp)
  2092. params = getDigParams(nodedef->get(n).groups, tp);
  2093. }
  2094. SimpleSoundSpec sound_dig = nodedef->get(n).sound_dig;
  2095. if(sound_dig.exists()){
  2096. if(sound_dig.name == "__group"){
  2097. if(params.main_group != ""){
  2098. soundmaker.m_player_leftpunch_sound.gain = 0.5;
  2099. soundmaker.m_player_leftpunch_sound.name =
  2100. std::string("default_dig_") +
  2101. params.main_group;
  2102. }
  2103. } else{
  2104. soundmaker.m_player_leftpunch_sound = sound_dig;
  2105. }
  2106. }
  2107. float dig_time_complete = 0.0;
  2108. if(params.diggable == false)
  2109. {
  2110. // I guess nobody will wait for this long
  2111. dig_time_complete = 10000000.0;
  2112. }
  2113. else
  2114. {
  2115. dig_time_complete = params.time;
  2116. }
  2117. if(dig_time_complete >= 0.001)
  2118. {
  2119. dig_index = (u16)((float)crack_animation_length
  2120. * dig_time/dig_time_complete);
  2121. }
  2122. // This is for torches
  2123. else
  2124. {
  2125. dig_index = crack_animation_length;
  2126. }
  2127. // Don't show cracks if not diggable
  2128. if(dig_time_complete >= 100000.0)
  2129. {
  2130. }
  2131. else if(dig_index < crack_animation_length)
  2132. {
  2133. //TimeTaker timer("client.setTempMod");
  2134. //infostream<<"dig_index="<<dig_index<<std::endl;
  2135. client.setCrack(dig_index, nodepos);
  2136. }
  2137. else
  2138. {
  2139. infostream<<"Digging completed"<<std::endl;
  2140. client.interact(2, pointed);
  2141. client.setCrack(-1, v3s16(0,0,0));
  2142. MapNode wasnode = map.getNode(nodepos);
  2143. client.removeNode(nodepos);
  2144. dig_time = 0;
  2145. digging = false;
  2146. nodig_delay_timer = dig_time_complete
  2147. / (float)crack_animation_length;
  2148. // We don't want a corresponding delay to
  2149. // very time consuming nodes
  2150. if(nodig_delay_timer > 0.3)
  2151. nodig_delay_timer = 0.3;
  2152. // We want a slight delay to very little
  2153. // time consuming nodes
  2154. float mindelay = 0.15;
  2155. if(nodig_delay_timer < mindelay)
  2156. nodig_delay_timer = mindelay;
  2157. // Send event to trigger sound
  2158. MtEvent *e = new NodeDugEvent(nodepos, wasnode);
  2159. gamedef->event()->put(e);
  2160. }
  2161. dig_time += dtime;
  2162. camera.setDigging(0); // left click animation
  2163. }
  2164. if(input->getRightClicked() ||
  2165. repeat_rightclick_timer >= g_settings->getFloat("repeat_rightclick_time"))
  2166. {
  2167. repeat_rightclick_timer = 0;
  2168. infostream<<"Ground right-clicked"<<std::endl;
  2169. // Sign special case, at least until formspec is properly implemented.
  2170. // Deprecated?
  2171. if(meta && meta->getString("formspec") == "hack:sign_text_input" && !random_input)
  2172. {
  2173. infostream<<"Launching metadata text input"<<std::endl;
  2174. // Get a new text for it
  2175. TextDest *dest = new TextDestNodeMetadata(nodepos, &client);
  2176. std::wstring wtext = narrow_to_wide(meta->getString("text"));
  2177. (new GUITextInputMenu(guienv, guiroot, -1,
  2178. &g_menumgr, dest,
  2179. wtext))->drop();
  2180. }
  2181. // If metadata provides an inventory view, activate it
  2182. else if(meta && meta->getString("formspec") != "" && !random_input)
  2183. {
  2184. infostream<<"Launching custom inventory view"<<std::endl;
  2185. InventoryLocation inventoryloc;
  2186. inventoryloc.setNodeMeta(nodepos);
  2187. /* Create menu */
  2188. GUIFormSpecMenu *menu =
  2189. new GUIFormSpecMenu(device, guiroot, -1,
  2190. &g_menumgr,
  2191. &client, gamedef);
  2192. menu->setFormSpec(meta->getString("formspec"),
  2193. inventoryloc);
  2194. menu->setFormSource(new NodeMetadataFormSource(
  2195. &client.getEnv().getClientMap(), nodepos));
  2196. menu->setTextDest(new TextDestNodeMetadata(nodepos, &client));
  2197. menu->drop();
  2198. }
  2199. // Otherwise report right click to server
  2200. else
  2201. {
  2202. // Report to server
  2203. client.interact(3, pointed);
  2204. camera.setDigging(1); // right click animation
  2205. // If the wielded item has node placement prediction,
  2206. // make that happen
  2207. const ItemDefinition &def =
  2208. playeritem.getDefinition(itemdef);
  2209. if(def.node_placement_prediction != "")
  2210. do{ // breakable
  2211. verbosestream<<"Node placement prediction for "
  2212. <<playeritem.name<<" is "
  2213. <<def.node_placement_prediction<<std::endl;
  2214. v3s16 p = neighbourpos;
  2215. // Place inside node itself if buildable_to
  2216. try{
  2217. MapNode n_under = map.getNode(nodepos);
  2218. if(nodedef->get(n_under).buildable_to)
  2219. p = nodepos;
  2220. }catch(InvalidPositionException &e){}
  2221. // Find id of predicted node
  2222. content_t id;
  2223. bool found =
  2224. nodedef->getId(def.node_placement_prediction, id);
  2225. if(!found){
  2226. errorstream<<"Node placement prediction failed for "
  2227. <<playeritem.name<<" (places "
  2228. <<def.node_placement_prediction
  2229. <<") - Name not known"<<std::endl;
  2230. break;
  2231. }
  2232. MapNode n(id);
  2233. try{
  2234. // This triggers the required mesh update too
  2235. client.addNode(p, n);
  2236. }catch(InvalidPositionException &e){
  2237. errorstream<<"Node placement prediction failed for "
  2238. <<playeritem.name<<" (places "
  2239. <<def.node_placement_prediction
  2240. <<") - Position not loaded"<<std::endl;
  2241. }
  2242. }while(0);
  2243. }
  2244. }
  2245. }
  2246. else if(pointed.type == POINTEDTHING_OBJECT)
  2247. {
  2248. infotext = narrow_to_wide(selected_object->infoText());
  2249. if(infotext == L"" && show_debug){
  2250. infotext = narrow_to_wide(selected_object->debugInfoText());
  2251. }
  2252. //if(input->getLeftClicked())
  2253. if(input->getLeftState())
  2254. {
  2255. bool do_punch = false;
  2256. bool do_punch_damage = false;
  2257. if(object_hit_delay_timer <= 0.0){
  2258. do_punch = true;
  2259. do_punch_damage = true;
  2260. object_hit_delay_timer = object_hit_delay;
  2261. }
  2262. if(input->getLeftClicked()){
  2263. do_punch = true;
  2264. }
  2265. if(do_punch){
  2266. infostream<<"Left-clicked object"<<std::endl;
  2267. left_punch = true;
  2268. }
  2269. if(do_punch_damage){
  2270. // Report direct punch
  2271. v3f objpos = selected_object->getPosition();
  2272. v3f dir = (objpos - player_position).normalize();
  2273. bool disable_send = selected_object->directReportPunch(
  2274. dir, &playeritem, time_from_last_punch);
  2275. time_from_last_punch = 0;
  2276. if(!disable_send)
  2277. client.interact(0, pointed);
  2278. }
  2279. }
  2280. else if(input->getRightClicked())
  2281. {
  2282. infostream<<"Right-clicked object"<<std::endl;
  2283. client.interact(3, pointed); // place
  2284. }
  2285. }
  2286. else if(input->getLeftState())
  2287. {
  2288. // When button is held down in air, show continuous animation
  2289. left_punch = true;
  2290. }
  2291. pointed_old = pointed;
  2292. if(left_punch || input->getLeftClicked())
  2293. {
  2294. camera.setDigging(0); // left click animation
  2295. }
  2296. input->resetLeftClicked();
  2297. input->resetRightClicked();
  2298. input->resetLeftReleased();
  2299. input->resetRightReleased();
  2300. /*
  2301. Calculate stuff for drawing
  2302. */
  2303. /*
  2304. Fog range
  2305. */
  2306. if(farmesh)
  2307. {
  2308. fog_range = BS*farmesh_range;
  2309. }
  2310. else
  2311. {
  2312. fog_range = draw_control.wanted_range*BS + 0.0*MAP_BLOCKSIZE*BS;
  2313. fog_range *= 0.9;
  2314. if(draw_control.range_all)
  2315. fog_range = 100000*BS;
  2316. }
  2317. /*
  2318. Calculate general brightness
  2319. */
  2320. u32 daynight_ratio = client.getEnv().getDayNightRatio();
  2321. float time_brightness = decode_light_f((float)daynight_ratio/1000.0);
  2322. float direct_brightness = 0;
  2323. bool sunlight_seen = false;
  2324. if(g_settings->getBool("free_move")){
  2325. direct_brightness = time_brightness;
  2326. sunlight_seen = true;
  2327. } else {
  2328. ScopeProfiler sp(g_profiler, "Detecting background light", SPT_AVG);
  2329. float old_brightness = sky->getBrightness();
  2330. direct_brightness = (float)client.getEnv().getClientMap()
  2331. .getBackgroundBrightness(MYMIN(fog_range*1.2, 60*BS),
  2332. daynight_ratio, (int)(old_brightness*255.5), &sunlight_seen)
  2333. / 255.0;
  2334. }
  2335. time_of_day = client.getEnv().getTimeOfDayF();
  2336. float maxsm = 0.05;
  2337. if(fabs(time_of_day - time_of_day_smooth) > maxsm &&
  2338. fabs(time_of_day - time_of_day_smooth + 1.0) > maxsm &&
  2339. fabs(time_of_day - time_of_day_smooth - 1.0) > maxsm)
  2340. time_of_day_smooth = time_of_day;
  2341. float todsm = 0.05;
  2342. if(time_of_day_smooth > 0.8 && time_of_day < 0.2)
  2343. time_of_day_smooth = time_of_day_smooth * (1.0-todsm)
  2344. + (time_of_day+1.0) * todsm;
  2345. else
  2346. time_of_day_smooth = time_of_day_smooth * (1.0-todsm)
  2347. + time_of_day * todsm;
  2348. sky->update(time_of_day_smooth, time_brightness, direct_brightness,
  2349. sunlight_seen);
  2350. float brightness = sky->getBrightness();
  2351. video::SColor bgcolor = sky->getBgColor();
  2352. video::SColor skycolor = sky->getSkyColor();
  2353. /*
  2354. Update clouds
  2355. */
  2356. if(clouds){
  2357. if(sky->getCloudsVisible()){
  2358. clouds->setVisible(true);
  2359. clouds->step(dtime);
  2360. clouds->update(v2f(player_position.X, player_position.Z),
  2361. sky->getCloudColor());
  2362. } else{
  2363. clouds->setVisible(false);
  2364. }
  2365. }
  2366. /*
  2367. Update farmesh
  2368. */
  2369. if(farmesh)
  2370. {
  2371. farmesh_range = draw_control.wanted_range * 10;
  2372. if(draw_control.range_all && farmesh_range < 500)
  2373. farmesh_range = 500;
  2374. if(farmesh_range > 1000)
  2375. farmesh_range = 1000;
  2376. farmesh->step(dtime);
  2377. farmesh->update(v2f(player_position.X, player_position.Z),
  2378. brightness, farmesh_range);
  2379. }
  2380. /*
  2381. Fog
  2382. */
  2383. if(g_settings->getBool("enable_fog") == true && !force_fog_off)
  2384. {
  2385. driver->setFog(
  2386. bgcolor,
  2387. video::EFT_FOG_LINEAR,
  2388. fog_range*0.4,
  2389. fog_range*1.0,
  2390. 0.01,
  2391. false, // pixel fog
  2392. false // range fog
  2393. );
  2394. }
  2395. else
  2396. {
  2397. driver->setFog(
  2398. bgcolor,
  2399. video::EFT_FOG_LINEAR,
  2400. 100000*BS,
  2401. 110000*BS,
  2402. 0.01,
  2403. false, // pixel fog
  2404. false // range fog
  2405. );
  2406. }
  2407. /*
  2408. Update gui stuff (0ms)
  2409. */
  2410. //TimeTaker guiupdatetimer("Gui updating");
  2411. const char program_name_and_version[] =
  2412. "Minetest " VERSION_STRING;
  2413. if(show_debug)
  2414. {
  2415. static float drawtime_avg = 0;
  2416. drawtime_avg = drawtime_avg * 0.95 + (float)drawtime*0.05;
  2417. /*static float beginscenetime_avg = 0;
  2418. beginscenetime_avg = beginscenetime_avg * 0.95 + (float)beginscenetime*0.05;
  2419. static float scenetime_avg = 0;
  2420. scenetime_avg = scenetime_avg * 0.95 + (float)scenetime*0.05;
  2421. static float endscenetime_avg = 0;
  2422. endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;*/
  2423. char temptext[300];
  2424. snprintf(temptext, 300, "%s ("
  2425. "R: range_all=%i"
  2426. ")"
  2427. " drawtime=%.0f, dtime_jitter = % .1f %%"
  2428. ", v_range = %.1f, RTT = %.3f",
  2429. program_name_and_version,
  2430. draw_control.range_all,
  2431. drawtime_avg,
  2432. dtime_jitter1_max_fraction * 100.0,
  2433. draw_control.wanted_range,
  2434. client.getRTT()
  2435. );
  2436. guitext->setText(narrow_to_wide(temptext).c_str());
  2437. guitext->setVisible(true);
  2438. }
  2439. else if(show_hud || show_chat)
  2440. {
  2441. guitext->setText(narrow_to_wide(program_name_and_version).c_str());
  2442. guitext->setVisible(true);
  2443. }
  2444. else
  2445. {
  2446. guitext->setVisible(false);
  2447. }
  2448. if(show_debug)
  2449. {
  2450. char temptext[300];
  2451. snprintf(temptext, 300,
  2452. "(% .1f, % .1f, % .1f)"
  2453. " (yaw = %.1f) (seed = %lli)",
  2454. player_position.X/BS,
  2455. player_position.Y/BS,
  2456. player_position.Z/BS,
  2457. wrapDegrees_0_360(camera_yaw),
  2458. client.getMapSeed());
  2459. guitext2->setText(narrow_to_wide(temptext).c_str());
  2460. guitext2->setVisible(true);
  2461. }
  2462. else
  2463. {
  2464. guitext2->setVisible(false);
  2465. }
  2466. {
  2467. guitext_info->setText(infotext.c_str());
  2468. guitext_info->setVisible(show_hud && g_menumgr.menuCount() == 0);
  2469. }
  2470. {
  2471. float statustext_time_max = 1.5;
  2472. if(!statustext.empty())
  2473. {
  2474. statustext_time += dtime;
  2475. if(statustext_time >= statustext_time_max)
  2476. {
  2477. statustext = L"";
  2478. statustext_time = 0;
  2479. }
  2480. }
  2481. guitext_status->setText(statustext.c_str());
  2482. guitext_status->setVisible(!statustext.empty());
  2483. if(!statustext.empty())
  2484. {
  2485. s32 status_y = screensize.Y - 130;
  2486. core::rect<s32> rect(
  2487. 10,
  2488. status_y - guitext_status->getTextHeight(),
  2489. screensize.X - 10,
  2490. status_y
  2491. );
  2492. guitext_status->setRelativePosition(rect);
  2493. // Fade out
  2494. video::SColor initial_color(255,0,0,0);
  2495. if(guienv->getSkin())
  2496. initial_color = guienv->getSkin()->getColor(gui::EGDC_BUTTON_TEXT);
  2497. video::SColor final_color = initial_color;
  2498. final_color.setAlpha(0);
  2499. video::SColor fade_color =
  2500. initial_color.getInterpolated_quadratic(
  2501. initial_color,
  2502. final_color,
  2503. pow(statustext_time / (float)statustext_time_max, 2.0f));
  2504. guitext_status->setOverrideColor(fade_color);
  2505. guitext_status->enableOverrideColor(true);
  2506. }
  2507. }
  2508. /*
  2509. Get chat messages from client
  2510. */
  2511. {
  2512. // Get new messages from error log buffer
  2513. while(!chat_log_error_buf.empty())
  2514. {
  2515. chat_backend.addMessage(L"", narrow_to_wide(
  2516. chat_log_error_buf.get()));
  2517. }
  2518. // Get new messages from client
  2519. std::wstring message;
  2520. while(client.getChatMessage(message))
  2521. {
  2522. chat_backend.addUnparsedMessage(message);
  2523. }
  2524. // Remove old messages
  2525. chat_backend.step(dtime);
  2526. // Display all messages in a static text element
  2527. u32 recent_chat_count = chat_backend.getRecentBuffer().getLineCount();
  2528. std::wstring recent_chat = chat_backend.getRecentChat();
  2529. guitext_chat->setText(recent_chat.c_str());
  2530. // Update gui element size and position
  2531. s32 chat_y = 5+(text_height+5);
  2532. if(show_debug)
  2533. chat_y += (text_height+5);
  2534. core::rect<s32> rect(
  2535. 10,
  2536. chat_y,
  2537. screensize.X - 10,
  2538. chat_y + guitext_chat->getTextHeight()
  2539. );
  2540. guitext_chat->setRelativePosition(rect);
  2541. // Don't show chat if disabled or empty or profiler is enabled
  2542. guitext_chat->setVisible(show_chat && recent_chat_count != 0
  2543. && !show_profiler);
  2544. }
  2545. /*
  2546. Inventory
  2547. */
  2548. if(client.getPlayerItem() != new_playeritem)
  2549. {
  2550. client.selectPlayerItem(new_playeritem);
  2551. }
  2552. if(client.getLocalInventoryUpdated())
  2553. {
  2554. //infostream<<"Updating local inventory"<<std::endl;
  2555. client.getLocalInventory(local_inventory);
  2556. update_wielded_item_trigger = true;
  2557. }
  2558. if(update_wielded_item_trigger)
  2559. {
  2560. update_wielded_item_trigger = false;
  2561. // Update wielded tool
  2562. InventoryList *mlist = local_inventory.getList("main");
  2563. ItemStack item;
  2564. if(mlist != NULL)
  2565. item = mlist->getItem(client.getPlayerItem());
  2566. camera.wield(item);
  2567. }
  2568. /*
  2569. Update block draw list every 200ms or when camera direction has
  2570. changed much
  2571. */
  2572. update_draw_list_timer += dtime;
  2573. if(update_draw_list_timer >= 0.2 ||
  2574. update_draw_list_last_cam_dir.getDistanceFrom(camera_direction) > 0.2){
  2575. update_draw_list_timer = 0;
  2576. client.getEnv().getClientMap().updateDrawList(driver);
  2577. update_draw_list_last_cam_dir = camera_direction;
  2578. }
  2579. /*
  2580. Drawing begins
  2581. */
  2582. TimeTaker tt_draw("mainloop: draw");
  2583. {
  2584. TimeTaker timer("beginScene");
  2585. //driver->beginScene(false, true, bgcolor);
  2586. //driver->beginScene(true, true, bgcolor);
  2587. driver->beginScene(true, true, skycolor);
  2588. beginscenetime = timer.stop(true);
  2589. }
  2590. //timer3.stop();
  2591. //infostream<<"smgr->drawAll()"<<std::endl;
  2592. {
  2593. TimeTaker timer("smgr");
  2594. smgr->drawAll();
  2595. if(g_settings->getBool("anaglyph"))
  2596. {
  2597. irr::core::vector3df oldPosition = camera.getCameraNode()->getPosition();
  2598. irr::core::vector3df oldTarget = camera.getCameraNode()->getTarget();
  2599. irr::core::matrix4 startMatrix = camera.getCameraNode()->getAbsoluteTransformation();
  2600. irr::core::vector3df focusPoint = (camera.getCameraNode()->getTarget() -
  2601. camera.getCameraNode()->getAbsolutePosition()).setLength(1) +
  2602. camera.getCameraNode()->getAbsolutePosition() ;
  2603. //Left eye...
  2604. irr::core::vector3df leftEye;
  2605. irr::core::matrix4 leftMove;
  2606. leftMove.setTranslation( irr::core::vector3df(-g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
  2607. leftEye=(startMatrix*leftMove).getTranslation();
  2608. //clear the depth buffer, and color
  2609. driver->beginScene( true, true, irr::video::SColor(0,200,200,255) );
  2610. driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED;
  2611. driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
  2612. driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
  2613. irr::scene::ESNRP_SOLID +
  2614. irr::scene::ESNRP_TRANSPARENT +
  2615. irr::scene::ESNRP_TRANSPARENT_EFFECT +
  2616. irr::scene::ESNRP_SHADOW;
  2617. camera.getCameraNode()->setPosition( leftEye );
  2618. camera.getCameraNode()->setTarget( focusPoint );
  2619. smgr->drawAll(); // 'smgr->drawAll();' may go here
  2620. //Right eye...
  2621. irr::core::vector3df rightEye;
  2622. irr::core::matrix4 rightMove;
  2623. rightMove.setTranslation( irr::core::vector3df(g_settings->getFloat("anaglyph_strength"),0.0f,0.0f) );
  2624. rightEye=(startMatrix*rightMove).getTranslation();
  2625. //clear the depth buffer
  2626. driver->clearZBuffer();
  2627. driver->getOverrideMaterial().Material.ColorMask = irr::video::ECP_GREEN + irr::video::ECP_BLUE;
  2628. driver->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK;
  2629. driver->getOverrideMaterial().EnablePasses = irr::scene::ESNRP_SKY_BOX +
  2630. irr::scene::ESNRP_SOLID +
  2631. irr::scene::ESNRP_TRANSPARENT +
  2632. irr::scene::ESNRP_TRANSPARENT_EFFECT +
  2633. irr::scene::ESNRP_SHADOW;
  2634. camera.getCameraNode()->setPosition( rightEye );
  2635. camera.getCameraNode()->setTarget( focusPoint );
  2636. smgr->drawAll(); // 'smgr->drawAll();' may go here
  2637. //driver->endScene();
  2638. driver->getOverrideMaterial().Material.ColorMask=irr::video::ECP_ALL;
  2639. driver->getOverrideMaterial().EnableFlags=0;
  2640. driver->getOverrideMaterial().EnablePasses=0;
  2641. camera.getCameraNode()->setPosition( oldPosition );
  2642. camera.getCameraNode()->setTarget( oldTarget );
  2643. }
  2644. scenetime = timer.stop(true);
  2645. }
  2646. {
  2647. //TimeTaker timer9("auxiliary drawings");
  2648. // 0ms
  2649. //timer9.stop();
  2650. //TimeTaker //timer10("//timer10");
  2651. video::SMaterial m;
  2652. //m.Thickness = 10;
  2653. m.Thickness = 3;
  2654. m.Lighting = false;
  2655. driver->setMaterial(m);
  2656. driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
  2657. if(show_hud)
  2658. {
  2659. v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
  2660. u32 selectionbox_color_r = rangelim(myround(selectionbox_color.X), 0, 255);
  2661. u32 selectionbox_color_g = rangelim(myround(selectionbox_color.Y), 0, 255);
  2662. u32 selectionbox_color_b = rangelim(myround(selectionbox_color.Z), 0, 255);
  2663. for(std::vector<aabb3f>::const_iterator
  2664. i = hilightboxes.begin();
  2665. i != hilightboxes.end(); i++)
  2666. {
  2667. /*infostream<<"hilightbox min="
  2668. <<"("<<i->MinEdge.X<<","<<i->MinEdge.Y<<","<<i->MinEdge.Z<<")"
  2669. <<" max="
  2670. <<"("<<i->MaxEdge.X<<","<<i->MaxEdge.Y<<","<<i->MaxEdge.Z<<")"
  2671. <<std::endl;*/
  2672. driver->draw3DBox(*i, video::SColor(255,selectionbox_color_r,selectionbox_color_g,selectionbox_color_b));
  2673. }
  2674. }
  2675. /*
  2676. Wielded tool
  2677. */
  2678. if(show_hud)
  2679. {
  2680. // Warning: This clears the Z buffer.
  2681. camera.drawWieldedTool();
  2682. }
  2683. /*
  2684. Post effects
  2685. */
  2686. {
  2687. client.getEnv().getClientMap().renderPostFx();
  2688. }
  2689. /*
  2690. Profiler graph
  2691. */
  2692. if(show_profiler_graph)
  2693. {
  2694. graph.draw(10, screensize.Y - 10, driver, font);
  2695. }
  2696. /*
  2697. Draw crosshair
  2698. */
  2699. if(show_hud)
  2700. {
  2701. v3f crosshair_color = g_settings->getV3F("crosshair_color");
  2702. u32 crosshair_color_r = rangelim(myround(crosshair_color.X), 0, 255);
  2703. u32 crosshair_color_g = rangelim(myround(crosshair_color.Y), 0, 255);
  2704. u32 crosshair_color_b = rangelim(myround(crosshair_color.Z), 0, 255);
  2705. u32 crosshair_alpha = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
  2706. driver->draw2DLine(displaycenter - core::vector2d<s32>(10,0),
  2707. displaycenter + core::vector2d<s32>(10,0),
  2708. video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b));
  2709. driver->draw2DLine(displaycenter - core::vector2d<s32>(0,10),
  2710. displaycenter + core::vector2d<s32>(0,10),
  2711. video::SColor(crosshair_alpha,crosshair_color_r,crosshair_color_g,crosshair_color_b));
  2712. }
  2713. } // timer
  2714. //timer10.stop();
  2715. //TimeTaker //timer11("//timer11");
  2716. /*
  2717. Draw hotbar
  2718. */
  2719. if(show_hud)
  2720. {
  2721. draw_hotbar(driver, font, gamedef,
  2722. v2s32(displaycenter.X, screensize.Y),
  2723. hotbar_imagesize, hotbar_itemcount, &local_inventory,
  2724. client.getHP(), client.getPlayerItem());
  2725. }
  2726. /*
  2727. Damage flash
  2728. */
  2729. if(damage_flash > 0.0)
  2730. {
  2731. video::SColor color(std::min(damage_flash, 180.0f),180,0,0);
  2732. driver->draw2DRectangle(color,
  2733. core::rect<s32>(0,0,screensize.X,screensize.Y),
  2734. NULL);
  2735. damage_flash -= 100.0*dtime;
  2736. }
  2737. /*
  2738. Damage camera tilt
  2739. */
  2740. if(player->hurt_tilt_timer > 0.0)
  2741. {
  2742. player->hurt_tilt_timer -= dtime*5;
  2743. if(player->hurt_tilt_timer < 0)
  2744. player->hurt_tilt_strength = 0;
  2745. }
  2746. /*
  2747. Draw gui
  2748. */
  2749. // 0-1ms
  2750. guienv->drawAll();
  2751. /*
  2752. End scene
  2753. */
  2754. {
  2755. TimeTaker timer("endScene");
  2756. endSceneX(driver);
  2757. endscenetime = timer.stop(true);
  2758. }
  2759. drawtime = tt_draw.stop(true);
  2760. g_profiler->graphAdd("mainloop_draw", (float)drawtime/1000.0f);
  2761. /*
  2762. End of drawing
  2763. */
  2764. static s16 lastFPS = 0;
  2765. //u16 fps = driver->getFPS();
  2766. u16 fps = (1.0/dtime_avg1);
  2767. if (lastFPS != fps)
  2768. {
  2769. core::stringw str = L"Minetest [";
  2770. str += driver->getName();
  2771. str += "] FPS=";
  2772. str += fps;
  2773. device->setWindowCaption(str.c_str());
  2774. lastFPS = fps;
  2775. }
  2776. /*
  2777. Log times and stuff for visualization
  2778. */
  2779. Profiler::GraphValues values;
  2780. g_profiler->graphGet(values);
  2781. graph.put(values);
  2782. }
  2783. /*
  2784. Drop stuff
  2785. */
  2786. if(clouds)
  2787. clouds->drop();
  2788. if(gui_chat_console)
  2789. gui_chat_console->drop();
  2790. /*
  2791. Draw a "shutting down" screen, which will be shown while the map
  2792. generator and other stuff quits
  2793. */
  2794. {
  2795. /*gui::IGUIStaticText *gui_shuttingdowntext = */
  2796. draw_load_screen(L"Shutting down stuff...", driver, font);
  2797. /*driver->beginScene(true, true, video::SColor(255,0,0,0));
  2798. guienv->drawAll();
  2799. driver->endScene();
  2800. gui_shuttingdowntext->remove();*/
  2801. }
  2802. chat_backend.addMessage(L"", L"# Disconnected.");
  2803. chat_backend.addMessage(L"", L"");
  2804. // Client scope (client is destructed before destructing *def and tsrc)
  2805. }while(0);
  2806. } // try-catch
  2807. catch(SerializationError &e)
  2808. {
  2809. error_message = L"A serialization error occurred:\n"
  2810. + narrow_to_wide(e.what()) + L"\n\nThe server is probably "
  2811. L" running a different version of Minetest.";
  2812. errorstream<<wide_to_narrow(error_message)<<std::endl;
  2813. }
  2814. if(!sound_is_dummy)
  2815. delete sound;
  2816. delete tsrc;
  2817. delete shsrc;
  2818. delete nodedef;
  2819. delete itemdef;
  2820. }