the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "Minecraft.h"
3#include "GameMode.h"
4#include "Timer.h"
5#include "ProgressRenderer.h"
6#include "LevelRenderer.h"
7#include "ParticleEngine.h"
8#include "MultiPlayerLocalPlayer.h"
9#include "User.h"
10#include "Textures.h"
11#include "GameRenderer.h"
12#include "HumanoidModel.h"
13#include "Options.h"
14#include "TexturePackRepository.h"
15#include "StatsCounter.h"
16#include "EntityRenderDispatcher.h"
17#include "TileEntityRenderDispatcher.h"
18#include "SurvivalMode.h"
19#include "Chunk.h"
20#include "CreativeMode.h"
21#include "DemoLevel.h"
22#include "MultiPlayerLevel.h"
23#include "MultiPlayerLocalPlayer.h"
24#include "DemoUser.h"
25#include "GuiParticles.h"
26#include "Screen.h"
27#include "DeathScreen.h"
28#include "ErrorScreen.h"
29#include "TitleScreen.h"
30#include "InventoryScreen.h"
31#include "InBedChatScreen.h"
32#include "AchievementPopup.h"
33#include "Input.h"
34#include "FrustumCuller.h"
35#include "Camera.h"
36
37#include "..\Minecraft.World\MobEffect.h"
38#include "..\Minecraft.World\Difficulty.h"
39#include "..\Minecraft.World\net.minecraft.world.level.h"
40#include "..\Minecraft.World\net.minecraft.world.entity.h"
41#include "..\Minecraft.World\net.minecraft.world.entity.player.h"
42#include "..\Minecraft.World\net.minecraft.world.entity.item.h"
43#include "..\Minecraft.World\net.minecraft.world.phys.h"
44#include "..\Minecraft.World\File.h"
45#include "..\Minecraft.World\net.minecraft.world.level.storage.h"
46#include "..\Minecraft.World\net.minecraft.h"
47#include "..\Minecraft.World\net.minecraft.stats.h"
48#include "..\Minecraft.World\System.h"
49#include "..\Minecraft.World\ByteBuffer.h"
50#include "..\Minecraft.World\net.minecraft.world.level.tile.h"
51#include "..\Minecraft.World\net.minecraft.world.level.chunk.h"
52#include "..\Minecraft.World\net.minecraft.world.level.dimension.h"
53#include "..\Minecraft.World\net.minecraft.world.item.h"
54#include "..\Minecraft.World\Minecraft.World.h"
55#include "ClientConnection.h"
56#include "..\Minecraft.World\HellRandomLevelSource.h"
57#include "..\Minecraft.World\net.minecraft.world.entity.animal.h"
58#include "..\Minecraft.World\net.minecraft.world.entity.monster.h"
59#include "..\Minecraft.World\StrongholdFeature.h"
60#include "..\Minecraft.World\IntCache.h"
61#include "..\Minecraft.World\Villager.h"
62#include "..\Minecraft.World\SparseLightStorage.h"
63#include "..\Minecraft.World\SparseDataStorage.h"
64#include "..\Minecraft.World\ChestTileEntity.h"
65#include "TextureManager.h"
66#ifdef _XBOX
67#include "Xbox\Network\NetworkPlayerXbox.h"
68#endif
69#include "Common\UI\IUIScene_CreativeMenu.h"
70#include "Common\UI\UIFontData.h"
71#include "DLCTexturePack.h"
72
73#ifdef __ORBIS__
74#include "Orbis\Network\PsPlusUpsellWrapper_Orbis.h"
75#endif
76
77// #define DISABLE_SPU_CODE
78// 4J Turning this on will change the graph at the bottom of the debug overlay to show the number of packets of each type added per fram
79//#define DEBUG_RENDER_SHOWS_PACKETS 1
80//#define SPLITSCREEN_TEST
81
82// If not disabled, this creates an event queue on a seperate thread so that the Level::tick calls can be offloaded
83// from the main thread, and have longer to run, since it's called at 20Hz instead of 60
84#define DISABLE_LEVELTICK_THREAD
85
86Minecraft *Minecraft::m_instance = NULL;
87__int64 Minecraft::frameTimes[512];
88__int64 Minecraft::tickTimes[512];
89int Minecraft::frameTimePos = 0;
90__int64 Minecraft::warezTime = 0;
91File Minecraft::workDir = File(L"");
92
93#ifdef __PSVITA__
94
95TOUCHSCREENRECT QuickSelectRect[3]=
96{
97 { 560, 890, 1360, 980 },
98 { 450, 840, 1449, 960 },
99 { 320, 840, 1600, 970 },
100};
101
102int QuickSelectBoxWidth[3]=
103{
104 89,
105 111,
106 142
107};
108
109// 4J - TomK ToDo: these really shouldn't be magic numbers, it should read the hud position from flash.
110int iToolTipOffset = 85;
111
112#endif
113
114ResourceLocation Minecraft::DEFAULT_FONT_LOCATION = ResourceLocation(TN_DEFAULT_FONT);
115ResourceLocation Minecraft::ALT_FONT_LOCATION = ResourceLocation(TN_ALT_FONT);
116
117
118Minecraft::Minecraft(Component *mouseComponent, Canvas *parent, MinecraftApplet *minecraftApplet, int width, int height, bool fullscreen)
119{
120 // 4J - added this block of initialisers
121 gameMode = NULL;
122 hasCrashed = false;
123 timer = new Timer(SharedConstants::TICKS_PER_SECOND);
124 oldLevel = NULL; //4J Stu added
125 level = NULL;
126 levels = MultiPlayerLevelArray(3); // 4J Added
127 levelRenderer = NULL;
128 player = nullptr;
129 cameraTargetPlayer = nullptr;
130 particleEngine = NULL;
131 user = NULL;
132 parent = NULL;
133 pause = false;
134 textures = NULL;
135 font = NULL;
136 screen = NULL;
137 localPlayerIdx = 0;
138 rightClickDelay = 0;
139
140 // 4J Stu Added
141 InitializeCriticalSection( &ProgressRenderer::s_progress );
142 InitializeCriticalSection(&m_setLevelCS);
143 //m_hPlayerRespawned = CreateEvent(NULL, FALSE, FALSE, NULL);
144
145 progressRenderer = NULL;
146 gameRenderer = NULL;
147 bgLoader = NULL;
148
149 ticks = 0;
150 // 4J-PB - moved into the local player
151 //missTime = 0;
152 //lastClickTick = 0;
153 //isRaining = false;
154 // 4J-PB - end
155
156 orgWidth = orgHeight = 0;
157 achievementPopup = new AchievementPopup(this);
158 gui = NULL;
159 noRender = false;
160 humanoidModel = new HumanoidModel(0);
161 hitResult = 0;
162 options = NULL;
163 soundEngine = new SoundEngine();
164 mouseHandler = NULL;
165 skins = NULL;
166 workingDirectory = File(L"");
167 levelSource = NULL;
168 stats[0] = NULL;
169 stats[1] = NULL;
170 stats[2] = NULL;
171 stats[3] = NULL;
172 connectToPort = 0;
173 workDir = File(L"");
174 // 4J removed
175 //wasDown = false;
176 lastTimer = -1;
177
178 // 4J removed
179 //lastTickTime = System::currentTimeMillis();
180 recheckPlayerIn = 0;
181 running = true;
182 unoccupiedQuadrant = -1;
183
184 Stats::init();
185
186 orgHeight = height;
187 this->fullscreen = fullscreen;
188 this->minecraftApplet = NULL;
189
190 this->parent = parent;
191 // 4J - Our actual physical frame buffer is always 1280x720 ie in a 16:9 ratio. If we want to do a 4:3 mode, we are telling the original minecraft code
192 // that the width is 3/4 what it actually is, to correctly present a 4:3 image. Have added width_phys and height_phys for any code we add that requires
193 // to know the real physical dimensions of the frame buffer.
194 if( RenderManager.IsWidescreen() )
195 {
196 this->width = width;
197 }
198 else
199 {
200 this->width = (width * 3 ) / 4;
201 }
202 this->height = height;
203 this->width_phys = width;
204 this->height_phys = height;
205
206 this->fullscreen = fullscreen;
207
208 appletMode = false;
209
210 Minecraft::m_instance = this;
211 TextureManager::createInstance();
212
213 for(int i=0;i<XUSER_MAX_COUNT;i++)
214 {
215 m_pendingLocalConnections[i] = NULL;
216 m_connectionFailed[i] = false;
217 localgameModes[i]=NULL;
218 }
219
220 animateTickLevel = NULL; // 4J added
221 m_inFullTutorialBits = 0; // 4J Added
222 reloadTextures = false;
223
224 // initialise the audio before any textures are loaded - to avoid the problem in win64 of the Miles audio causing the codec for textures to be unloaded
225
226 // 4J-PB - Removed it from here on Orbis due to it causing a crash with the network init.
227 // We should work out why...
228#ifndef __ORBIS__
229 this->soundEngine->init(NULL);
230#endif
231
232#ifndef DISABLE_LEVELTICK_THREAD
233 levelTickEventQueue = new C4JThread::EventQueue(levelTickUpdateFunc, levelTickThreadInitFunc, "LevelTick_EventQueuePoll");
234 levelTickEventQueue->setProcessor(3);
235 levelTickEventQueue->setPriority(THREAD_PRIORITY_NORMAL);
236#endif // DISABLE_LEVELTICK_THREAD
237}
238
239void Minecraft::clearConnectionFailed()
240{
241 for(int i=0;i<XUSER_MAX_COUNT;i++)
242 {
243 m_connectionFailed[i] = false;
244 m_connectionFailedReason[i] = DisconnectPacket::eDisconnect_None;
245 }
246 app.SetDisconnectReason(DisconnectPacket::eDisconnect_None);
247}
248
249void Minecraft::connectTo(const wstring& server, int port)
250{
251 connectToIp = server;
252 connectToPort = port;
253}
254
255void Minecraft::init()
256{
257#if 0 // 4J - removed
258 if (parent != null)
259 {
260 Graphics g = parent.getGraphics();
261 if (g != null) {
262 g.setColor(Color.BLACK);
263 g.fillRect(0, 0, width, height);
264 g.dispose();
265 }
266 Display.setParent(parent);
267 } else {
268 if (fullscreen) {
269 Display.setFullscreen(true);
270 width = Display.getDisplayMode().getWidth();
271 height = Display.getDisplayMode().getHeight();
272 if (width <= 0) width = 1;
273 if (height <= 0) height = 1;
274 } else {
275 Display.setDisplayMode(new DisplayMode(width, height));
276 }
277 }
278
279 Display.setTitle("Minecraft " + VERSION_STRING);
280 try {
281 Display.create();
282 /*
283 * System.out.println("LWJGL version: " + Sys.getVersion());
284 * System.out.println("GL RENDERER: " +
285 * GL11.glGetString(GL11.GL_RENDERER));
286 * System.out.println("GL VENDOR: " +
287 * GL11.glGetString(GL11.GL_VENDOR));
288 * System.out.println("GL VERSION: " +
289 * GL11.glGetString(GL11.GL_VERSION)); ContextCapabilities caps =
290 * GLContext.getCapabilities(); System.out.println("OpenGL 3.0: " +
291 * caps.OpenGL30); System.out.println("OpenGL 3.1: " +
292 * caps.OpenGL31); System.out.println("OpenGL 3.2: " +
293 * caps.OpenGL32); System.out.println("ARB_compatibility: " +
294 * caps.GL_ARB_compatibility); if (caps.OpenGL32) { IntBuffer buffer
295 * = ByteBuffer.allocateDirect(16 *
296 * 4).order(ByteOrder.nativeOrder()).asIntBuffer();
297 * GL11.glGetInteger(GL32.GL_CONTEXT_PROFILE_MASK, buffer); int
298 * profileMask = buffer.get(0); System.out.println("PROFILE MASK: "
299 * + Integer.toBinaryString(profileMask));
300 * System.out.println("CORE PROFILE: " + ((profileMask &
301 * GL32.GL_CONTEXT_CORE_PROFILE_BIT) != 0));
302 * System.out.println("COMPATIBILITY PROFILE: " + ((profileMask &
303 * GL32.GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0)); }
304 */
305 } catch (LWJGLException e) {
306 // This COULD be because of a bug! A delay followed by a new attempt
307 // is supposed getWorkingDirectoryto fix it.
308 e.printStackTrace();
309 try {
310 Thread.sleep(1000);
311 } catch (InterruptedException e1) {
312 }
313 Display.create();
314 }
315
316 if (Minecraft.FLYBY_MODE) {
317 glPixelStorei(GL_PACK_ALIGNMENT, 1);
318 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
319 }
320#endif
321
322 // glClearColor(0.2f, 0.2f, 0.2f, 1);
323
324 workingDirectory = File(L"");//getWorkingDirectory();
325 levelSource = new McRegionLevelStorageSource(File(workingDirectory, L"saves"));
326 // levelSource = new MemoryLevelStorageSource();
327 options = new Options(this, workingDirectory);
328 skins = new TexturePackRepository(workingDirectory, this);
329 skins->addDebugPacks();
330 textures = new Textures(skins, options);
331 //renderLoadingScreen();
332
333 font = new Font(options, L"font/Default.png", textures, false, &DEFAULT_FONT_LOCATION, 23, 20, 8, 8, SFontData::Codepoints);
334 altFont = new Font(options, L"font/alternate.png", textures, false, &ALT_FONT_LOCATION, 16, 16, 8, 8);
335
336 //if (options.languageCode != null) {
337 // Language.getInstance().loadLanguage(options.languageCode);
338 // // font.setEnforceUnicodeSheet("true".equalsIgnoreCase(I18n.get("language.enforceUnicode")));
339 // font.setEnforceUnicodeSheet(Language.getInstance().isSelectedLanguageIsUnicode());
340 // font.setBidirectional(Language.isBidirectional(options.languageCode));
341 //}
342
343 // 4J Stu - Not using these any more
344 //WaterColor::init(textures->loadTexturePixels(L"misc/watercolor.png"));
345 //GrassColor::init(textures->loadTexturePixels(L"misc/grasscolor.png"));
346 //FoliageColor::init(textures->loadTexturePixels(L"misc/foliagecolor.png"));
347
348 gameRenderer = new GameRenderer(this);
349 EntityRenderDispatcher::instance->itemInHandRenderer = new ItemInHandRenderer(this,false);
350
351 for( int i=0 ; i<4 ; ++i )
352 stats[i] = new StatsCounter();
353
354 /* 4J - TODO, 4J-JEV: Unnecessary.
355 Achievements::openInventory->setDescFormatter(NULL);
356 Achievements.openInventory.setDescFormatter(new DescFormatter(){
357 public String format(String i18nValue) {
358 return String.format(i18nValue, Keyboard.getKeyName(options.keyBuild.key));
359 }
360 });
361 */
362
363 // 4J-PB - We'll do this in a xui intro
364 //renderLoadingScreen();
365
366 //Keyboard::create();
367 Mouse::create();
368#if 0 // 4J - removed
369 mouseHandler = new MouseHandler(parent);
370 try {
371 Controllers.create();
372 } catch (Exception e) {
373 e.printStackTrace();
374 }
375#endif
376
377 MemSect(31);
378 checkGlError(L"Pre startup");
379 MemSect(0);
380
381 // width = Display.getDisplayMode().getWidth();
382 // height = Display.getDisplayMode().getHeight();
383
384 glEnable(GL_TEXTURE_2D);
385 glShadeModel(GL_SMOOTH);
386 glClearDepth(1.0);
387 glEnable(GL_DEPTH_TEST);
388 glDepthFunc(GL_LEQUAL);
389 glEnable(GL_ALPHA_TEST);
390 glAlphaFunc(GL_GREATER, 0.1f);
391 glCullFace(GL_BACK);
392
393 glMatrixMode(GL_PROJECTION);
394 glLoadIdentity();
395 glMatrixMode(GL_MODELVIEW);
396 MemSect(31);
397 checkGlError(L"Startup");
398 MemSect(0);
399
400 // openGLCapabilities = new OpenGLCapabilities(); // 4J - removed
401
402 levelRenderer = new LevelRenderer(this, textures);
403 //textures->register(&TextureAtlas::LOCATION_BLOCKS, new TextureAtlas(Icon::TYPE_TERRAIN, TN_TERRAIN));
404 //textures->register(&TextureAtlas::LOCATION_ITEMS, new TextureAtlas(Icon::TYPE_ITEM, TN_GUI_ITEMS));
405 textures->stitch();
406
407 glViewport(0, 0, width, height);
408
409 particleEngine = new ParticleEngine(level, textures);
410
411 MemSect(31);
412 checkGlError(L"Post startup");
413 MemSect(0);
414 gui = new Gui(this);
415
416 if (connectToIp != L"") // 4J - was NULL comparison
417 {
418 // setScreen(new ConnectScreen(this, connectToIp, connectToPort)); // 4J TODO - put back in
419 }
420 else
421 {
422 setScreen(new TitleScreen());
423 }
424 progressRenderer = new ProgressRenderer(this);
425
426 RenderManager.CBuffLockStaticCreations();
427}
428
429void Minecraft::renderLoadingScreen()
430{
431 // 4J Unused
432 // testing stuff on vita just now
433#ifdef __PSVITA__
434 ScreenSizeCalculator ssc(options, width, height);
435
436 // xxx
437 RenderManager.StartFrame();
438 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
439 glMatrixMode(GL_PROJECTION);
440 glLoadIdentity();
441 glOrtho(0, (float)ssc.rawWidth, (float)ssc.rawHeight, 0, 1000, 3000);
442 glMatrixMode(GL_MODELVIEW);
443 glLoadIdentity();
444 glTranslatef(0, 0, -2000);
445 glViewport(0, 0, width, height);
446 glClearColor(0, 0, 0, 0);
447
448 Tesselator *t = Tesselator::getInstance();
449
450 glDisable(GL_LIGHTING);
451 glEnable(GL_TEXTURE_2D);
452 glDisable(GL_FOG);
453 // xxx
454 glBindTexture(GL_TEXTURE_2D, textures->loadTexture(TN_MOB_PIG));
455 t->begin();
456 t->color(0xffffff);
457 t->vertexUV((float)(0), (float)( height), (float)( 0), (float)( 0), (float)( 0));
458 t->vertexUV((float)(width), (float)( height), (float)( 0), (float)( 0), (float)( 0));
459 t->vertexUV((float)(width), (float)( 0), (float)( 0), (float)( 0), (float)( 0));
460 t->vertexUV((float)(0), (float)( 0), (float)( 0), (float)( 0), (float)( 0));
461 t->end();
462
463 int lw = 256;
464 int lh = 256;
465 glColor4f(1, 1, 1, 1);
466 t->color(0xffffff);
467 blit((ssc.getWidth() - lw) / 2, (ssc.getHeight() - lh) / 2, 0, 0, lw, lh);
468 glDisable(GL_LIGHTING);
469 glDisable(GL_FOG);
470
471 glEnable(GL_ALPHA_TEST);
472 glAlphaFunc(GL_GREATER, 0.1f);
473
474 Display::swapBuffers();
475 // xxx
476 RenderManager.Present();
477#endif
478}
479
480void Minecraft::blit(int x, int y, int sx, int sy, int w, int h)
481{
482 float us = 1 / 256.0f;
483 float vs = 1 / 256.0f;
484 Tesselator *t = Tesselator::getInstance();
485 t->begin();
486 t->vertexUV((float)(x + 0), (float)( y + h), (float)( 0), (float)( (sx + 0) * us), (float)( (sy + h) * vs));
487 t->vertexUV((float)(x + w), (float)( y + h), (float)( 0), (float)( (sx + w) * us), (float)( (sy + h) * vs));
488 t->vertexUV((float)(x + w), (float)( y + 0), (float)( 0), (float)( (sx + w) * us), (float)( (sy + 0) * vs));
489 t->vertexUV((float)(x + 0), (float)( y + 0), (float)( 0), (float)( (sx + 0) * us), (float)( (sy + 0) * vs));
490 t->end();
491}
492
493LevelStorageSource *Minecraft::getLevelSource()
494{
495 return levelSource;
496}
497
498void Minecraft::setScreen(Screen *screen)
499{
500 if (this->screen != NULL)
501 {
502 this->screen->removed();
503 }
504
505 //4J Gordon: Do not force a stats save here
506 /*if (dynamic_cast<TitleScreen *>(screen)!=NULL)
507 {
508 stats->forceSend();
509 }
510 stats->forceSave();*/
511
512 if (screen == NULL && level == NULL)
513 {
514 screen = new TitleScreen();
515 }
516 else if (player != NULL && !ui.GetMenuDisplayed(player->GetXboxPad()) && player->getHealth() <= 0)
517 {
518 //screen = new DeathScreen();
519
520 // 4J Stu - If we exit from the death screen then we are saved as being dead. In the Java
521 // game when you load the game you are still dead, but this is silly so only show the dead
522 // screen if we have died during gameplay
523 if(ticks==0)
524 {
525 player->respawn();
526 }
527 else
528 {
529 ui.NavigateToScene(player->GetXboxPad(),eUIScene_DeathMenu,NULL);
530 }
531 }
532
533 if (dynamic_cast<TitleScreen *>(screen)!=NULL)
534 {
535 options->renderDebug = false;
536 gui->clearMessages();
537 }
538
539 this->screen = screen;
540 if (screen != NULL)
541 {
542 // releaseMouse(); // 4J - removed
543 ScreenSizeCalculator ssc(options, width, height);
544 int screenWidth = ssc.getWidth();
545 int screenHeight = ssc.getHeight();
546 screen->init(this, screenWidth, screenHeight);
547 noRender = false;
548 }
549 else
550 {
551 // grabMouse(); // 4J - removed
552 }
553
554 // 4J-PB - if a screen has been set, go into menu mode
555 // it's possible that player doesn't exist here yet
556 /*if(screen!=NULL)
557 {
558 if(player && player->GetXboxPad()!=-1)
559 {
560 InputManager.SetMenuDisplayed(player->GetXboxPad(),true);
561 }
562 else
563 {
564 // set all
565 //InputManager.SetMenuDisplayed(XUSER_INDEX_ANY,true);
566 }
567 }
568 else
569 {
570 if(player && player->GetXboxPad()!=-1)
571 {
572 InputManager.SetMenuDisplayed(player->GetXboxPad(),false);
573 }
574 else
575 {
576 //InputManager.SetMenuDisplayed(XUSER_INDEX_ANY,false);
577 }
578 }*/
579}
580
581void Minecraft::checkGlError(const wstring& string)
582{
583 // 4J - TODO
584}
585
586void Minecraft::destroy()
587{
588 //4J Gordon: Do not force a stats save here
589 /*stats->forceSend();
590 stats->forceSave();*/
591
592 // try {
593 setLevel(NULL);
594 // } catch (Throwable e) {
595 // }
596
597 // try {
598 MemoryTracker::release();
599 // } catch (Throwable e) {
600 // }
601
602 soundEngine->destroy();
603 //} finally {
604 Display::destroy();
605 // if (!hasCrashed) System.exit(0); //4J - removed
606 //}
607 //System.gc(); // 4J - removed
608}
609
610// 4J-PB - splitting this function into 3 parts, so we can call the middle part from our xbox game loop
611
612#if 0
613void Minecraft::run()
614{
615 running = true;
616 // try { // 4J - removed try/catch
617 init();
618 // } catch (Exception e) {
619 // e.printStackTrace();
620 // crash(new CrashReport("Failed to start game", e));
621 // return;
622 // }
623 // try { // 4J - removed try/catch
624 if (Minecraft::FLYBY_MODE)
625 {
626 generateFlyby();
627 return;
628 }
629
630 __int64 lastTime = System::currentTimeMillis();
631 int frames = 0;
632
633 while (running)
634 {
635 // try { // 4J - removed try/catch
636 // if (minecraftApplet != null && !minecraftApplet.isActive()) break; // 4J - removed
637 AABB::resetPool();
638 Vec3::resetPool();
639
640 // if (parent == NULL && Display.isCloseRequested()) { // 4J - removed
641 // stop();
642 // }
643
644 if (pause && level != NULL)
645 {
646 float lastA = timer->a;
647 timer->advanceTime();
648 timer->a = lastA;
649 }
650 else
651 {
652 timer->advanceTime();
653 }
654
655 __int64 beforeTickTime = System::nanoTime();
656 for (int i = 0; i < timer->ticks; i++)
657 {
658 ticks++;
659 // try { // 4J - try/catch removed
660 tick();
661 // } catch (LevelConflictException e) {
662 // this.level = null;
663 // setLevel(null);
664 // setScreen(new LevelConflictScreen());
665 // }
666 }
667 __int64 tickDuraction = System::nanoTime() - beforeTickTime;
668 checkGlError(L"Pre render");
669
670 TileRenderer::fancy = options->fancyGraphics;
671
672 // if (pause) timer.a = 1;
673
674 soundEngine->update(player, timer->a);
675
676 glEnable(GL_TEXTURE_2D);
677 if (level != NULL) level->updateLights();
678
679 // if (!Keyboard::isKeyDown(Keyboard.KEY_F7)) Display.update(); // 4J - removed
680
681 if (player != NULL && player->isInWall()) options->thirdPersonView = false;
682 if (!noRender)
683 {
684 if (gameMode != NULL) gameMode->render(timer->a);
685 gameRenderer->render(timer->a);
686 }
687
688 /* 4J - removed
689 if (!Display::isActive())
690 {
691 if (fullscreen)
692 {
693 this->toggleFullScreen();
694 }
695 Sleep(10);
696 }
697 */
698
699 if (options->renderDebug)
700 {
701 renderFpsMeter(tickDuraction);
702 }
703 else
704 {
705 lastTimer = System::nanoTime();
706 }
707
708 achievementPopup->render();
709
710 Sleep(0); // 4J - was Thread.yield()
711
712 // if (Keyboard::isKeyDown(Keyboard::KEY_F7)) Display.update(); // 4J - removed condition
713 Display::update();
714
715 // checkScreenshot(); // 4J - removed
716
717 /* 4J - removed
718 if (parent != NULL && !fullscreen)
719 {
720 if (parent.getWidth() != width || parent.getHeight() != height)
721 {
722 width = parent.getWidth();
723 height = parent.getHeight();
724 if (width <= 0) width = 1;
725 if (height <= 0) height = 1;
726
727 resize(width, height);
728 }
729 }
730 */
731 checkGlError(L"Post render");
732 frames++;
733 pause = !isClientSide() && screen != NULL && screen->isPauseScreen();
734
735 while (System::currentTimeMillis() >= lastTime + 1000)
736 {
737 fpsString = _toString<int>(frames) + L" fps, " + _toString<int>(Chunk::updates) + L" chunk updates";
738 Chunk::updates = 0;
739 lastTime += 1000;
740 frames = 0;
741 }
742 /*
743 } catch (LevelConflictException e) {
744 this.level = null;
745 setLevel(null);
746 setScreen(new LevelConflictScreen());
747 } catch (OutOfMemoryError e) {
748 emergencySave();
749 setScreen(new OutOfMemoryScreen());
750 System.gc();
751 }
752 */
753 }
754 /*
755 } catch (StopGameException e) {
756 } catch (Throwable e) {
757 emergencySave();
758 e.printStackTrace();
759 crash(new CrashReport("Unexpected error", e));
760 } finally {
761 destroy();
762 }
763 */
764 destroy();
765}
766#endif
767
768void Minecraft::run()
769{
770 running = true;
771 // try { // 4J - removed try/catch
772 init();
773 // } catch (Exception e) {
774 // e.printStackTrace();
775 // crash(new CrashReport("Failed to start game", e));
776 // return;
777 // }
778 // try { // 4J - removed try/catch
779 }
780
781// 4J added - Selects which local player is currently active for processing by the existing minecraft code
782bool Minecraft::setLocalPlayerIdx(int idx)
783{
784 localPlayerIdx = idx;
785 // If the player is not null, but the game mode is then this is just a temp player
786 // whose only real purpose is to hold the viewport position
787 if( localplayers[idx] == NULL || localgameModes[idx] == NULL ) return false;
788
789 gameMode = localgameModes[idx];
790 player = localplayers[idx];
791 cameraTargetPlayer = localplayers[idx];
792 gameRenderer->itemInHandRenderer = localitemInHandRenderers[idx];
793 level = getLevel( localplayers[idx]->dimension );
794 particleEngine->setLevel( level );
795
796 return true;
797}
798
799int Minecraft::getLocalPlayerIdx()
800{
801 return localPlayerIdx;
802}
803
804void Minecraft::updatePlayerViewportAssignments()
805{
806 unoccupiedQuadrant = -1;
807 // Find out how many viewports we'll be needing
808 int viewportsRequired = 0;
809 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
810 {
811 if( localplayers[i] != NULL ) viewportsRequired++;
812 }
813 if( viewportsRequired == 3 ) viewportsRequired = 4;
814
815 // Allocate away...
816 if( viewportsRequired == 1 )
817 {
818 // Single viewport
819 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
820 {
821 if( localplayers[i] != NULL ) localplayers[i]->m_iScreenSection = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
822 }
823 }
824 else if( viewportsRequired == 2 )
825 {
826 // Split screen - TODO - option for vertical/horizontal split
827 int found = 0;
828 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
829 {
830 if( localplayers[i] != NULL )
831 {
832 // Primary player settings decide what the mode is
833 if(app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_SplitScreenVertical))
834 {
835 localplayers[i]->m_iScreenSection = C4JRender::VIEWPORT_TYPE_SPLIT_LEFT + found;
836 }
837 else
838 {
839 localplayers[i]->m_iScreenSection = C4JRender::VIEWPORT_TYPE_SPLIT_TOP + found;
840 }
841 found++;
842 }
843 }
844 }
845 else if( viewportsRequired >= 3 )
846 {
847 // Quadrants - this is slightly more complicated. We don't want to move viewports around if we are going from 3 to 4, or 4 to 3 players,
848 // so persist any allocations for quadrants that already exist.
849 bool quadrantsAllocated[4] = {false,false,false,false};
850
851 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
852 {
853 if( localplayers[i] != NULL )
854 {
855
856 // 4J Stu - If the game hasn't started, ignore current allocations (as the players won't have seen them)
857 // This fixes an issue with the primary player being the 4th controller quadrant, but ending up in the 3rd viewport.
858 if(app.GetGameStarted())
859 {
860 if( ( localplayers[i]->m_iScreenSection >= C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT ) &&
861 ( localplayers[i]->m_iScreenSection <= C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT ) )
862 {
863 quadrantsAllocated[localplayers[i]->m_iScreenSection - C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT] = true;
864 }
865 }
866 else
867 {
868 // Reset the viewport so that it can be assigned in the next loop
869 localplayers[i]->m_iScreenSection = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
870 }
871 }
872 }
873
874 // Found which quadrants are currently in use, now allocate out any spares that are required
875 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
876 {
877 if( localplayers[i] != NULL )
878 {
879 if( ( localplayers[i]->m_iScreenSection < C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT ) ||
880 ( localplayers[i]->m_iScreenSection > C4JRender::VIEWPORT_TYPE_QUADRANT_BOTTOM_RIGHT ) )
881 {
882 for( int j = 0; j < 4; j++ )
883 {
884 if( !quadrantsAllocated[j] )
885 {
886 localplayers[i]->m_iScreenSection = C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT + j;
887 quadrantsAllocated[j] = true;
888 break;
889 }
890 }
891 }
892 }
893 }
894 // If there's an unoccupied quadrant, record which one so we can clear it to black when rendering
895 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
896 {
897 if( quadrantsAllocated[i] == false )
898 {
899 unoccupiedQuadrant = i;
900 }
901 }
902 }
903
904 // 4J Stu - If the game is not running we do not want to do this yet, and should wait until the task
905 // that caused the app to not be running is finished
906 if(app.GetGameStarted())ui.UpdatePlayerBasePositions();
907}
908
909// Add a temporary player so that the viewports get re-arranged, and add the player to the game session
910bool Minecraft::addLocalPlayer(int idx)
911{
912 //int iLocalPlayerC=app.GetLocalPlayerCount();
913 if( m_pendingLocalConnections[idx] != NULL )
914 {
915 // 4J Stu - Should we ever be in a state where this happens?
916 assert(false);
917 m_pendingLocalConnections[idx]->close();
918 }
919 m_connectionFailed[idx] = false;
920 m_pendingLocalConnections[idx] = NULL;
921
922 bool success=g_NetworkManager.AddLocalPlayerByUserIndex(idx);
923
924 if(success)
925 {
926 app.DebugPrintf("Adding temp local player on pad %d\n", idx);
927 localplayers[idx] = shared_ptr<MultiplayerLocalPlayer>( new MultiplayerLocalPlayer(this, level, user, NULL ) );
928 localgameModes[idx] = NULL;
929
930 updatePlayerViewportAssignments();
931
932#ifdef _XBOX
933 // tell the xui scenes a splitscreen player joined
934 XUIMessage xuiMsg;
935 CustomMessage_Splitscreenplayer_Struct myMsgData;
936 CustomMessage_Splitscreenplayer( &xuiMsg, &myMsgData, true);
937
938 // send the message
939 for(int i=0;i<XUSER_MAX_COUNT;i++)
940 {
941 //if((i!=idx) && (localplayers[i]!=NULL))
942 {
943 XuiBroadcastMessage( CXuiSceneBase::GetPlayerBaseScene(i), &xuiMsg );
944 }
945 }
946#endif
947
948 ConnectionProgressParams *param = new ConnectionProgressParams();
949 param->iPad = idx;
950 param->stringId = IDS_PROGRESS_CONNECTING;
951 param->showTooltips = true;
952 param->setFailTimer = true;
953 param->timerTime = CONNECTING_PROGRESS_CHECK_TIME;
954
955 // Joining as second player so always the small progress
956 ui.NavigateToScene(idx, eUIScene_ConnectingProgress, param);
957
958 }
959 else
960 {
961 app.DebugPrintf("g_NetworkManager.AddLocalPlayerByUserIndex failed\n");
962#ifdef _DURANGO
963 ProfileManager.RemoveGamepadFromGame(idx);
964#endif
965 }
966
967 return success;
968}
969
970void Minecraft::addPendingLocalConnection(int idx, ClientConnection *connection)
971{
972 m_pendingLocalConnections[idx] = connection;
973}
974
975shared_ptr<MultiplayerLocalPlayer> Minecraft::createExtraLocalPlayer(int idx, const wstring& name, int iPad, int iDimension, ClientConnection *clientConnection /*= NULL*/,MultiPlayerLevel *levelpassedin)
976{
977 if( clientConnection == NULL) return nullptr;
978
979 if( clientConnection == m_pendingLocalConnections[idx] )
980 {
981 int tempScreenSection = C4JRender::VIEWPORT_TYPE_FULLSCREEN;
982 if( localplayers[idx] != NULL && localgameModes[idx] == NULL )
983 {
984 // A temp player displaying a connecting screen
985 tempScreenSection = localplayers[idx]->m_iScreenSection;
986 }
987 wstring prevname = user->name;
988 user->name = name;
989
990 // Don't need this any more
991 m_pendingLocalConnections[idx] = NULL;
992
993 // Add the connection to the level which will now take responsibility for ticking it
994 // 4J-PB - can't use the dimension from localplayers[idx], since there may be no localplayers at this point
995 //MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)getLevel( localplayers[idx]->dimension );
996
997 MultiPlayerLevel *mpLevel;
998
999 if(levelpassedin)
1000 {
1001 level=levelpassedin;
1002 mpLevel=levelpassedin;
1003 }
1004 else
1005 {
1006 level=getLevel( iDimension );
1007 mpLevel = getLevel( iDimension );
1008 mpLevel->addClientConnection( clientConnection );
1009 }
1010
1011 if( app.GetTutorialMode() )
1012 {
1013 localgameModes[idx] = new FullTutorialMode(idx, this, clientConnection);
1014 }
1015 // check if we're in the trial version
1016 else if(ProfileManager.IsFullVersion()==false)
1017 {
1018 localgameModes[idx] = new TrialMode(idx, this, clientConnection);
1019 }
1020 else
1021 {
1022 localgameModes[idx] = new ConsoleGameMode(idx, this, clientConnection);
1023 }
1024
1025 // 4J-PB - can't do this here because they use a render context, but this is running from a thread.
1026 // Moved the creation of these into the main thread, before level launch
1027 //localitemInHandRenderers[idx] = new ItemInHandRenderer(this);
1028 localplayers[idx] = localgameModes[idx]->createPlayer(level);
1029
1030 PlayerUID playerXUIDOffline = INVALID_XUID;
1031 PlayerUID playerXUIDOnline = INVALID_XUID;
1032 ProfileManager.GetXUID(idx,&playerXUIDOffline,false);
1033 ProfileManager.GetXUID(idx,&playerXUIDOnline,true);
1034 localplayers[idx]->setXuid(playerXUIDOffline);
1035 localplayers[idx]->setOnlineXuid(playerXUIDOnline);
1036 localplayers[idx]->setIsGuest(ProfileManager.IsGuest(idx));
1037
1038 localplayers[idx]->m_displayName = ProfileManager.GetDisplayName(idx);
1039
1040 localplayers[idx]->m_iScreenSection = tempScreenSection;
1041
1042 if( levelpassedin == NULL) level->addEntity(localplayers[idx]); // Don't add if we're passing the level in, we only do this from the client connection & we'll be handling adding it ourselves
1043
1044 localplayers[idx]->SetXboxPad(iPad);
1045
1046 if( localplayers[idx]->input != NULL ) delete localplayers[idx]->input;
1047 localplayers[idx]->input = new Input();
1048
1049 localplayers[idx]->resetPos();
1050
1051 levelRenderer->setLevel(idx, level);
1052 localplayers[idx]->level = level;
1053
1054 user->name = prevname;
1055
1056 updatePlayerViewportAssignments();
1057
1058 // Fix for #105852 - TU12: Content: Gameplay: Local splitscreen Players are spawned at incorrect places after re-joining previously saved and loaded "Mass Effect World".
1059 // Move this check to ClientConnection::handleMovePlayer
1060// // 4J-PB - can't call this when this function is called from the qnet thread (GetGameStarted will be false)
1061// if(app.GetGameStarted())
1062// {
1063// ui.CloseUIScenes(idx);
1064// }
1065 }
1066
1067 return localplayers[idx];
1068}
1069
1070// on a respawn of the local player, just store them
1071void Minecraft::storeExtraLocalPlayer(int idx)
1072{
1073 localplayers[idx] = player;
1074
1075 if( localplayers[idx]->input != NULL ) delete localplayers[idx]->input;
1076 localplayers[idx]->input = new Input();
1077
1078 if(ProfileManager.IsSignedIn(idx))
1079 {
1080 localplayers[idx]->name = convStringToWstring( ProfileManager.GetGamertag(idx) );
1081 }
1082}
1083
1084void Minecraft::removeLocalPlayerIdx(int idx)
1085{
1086 bool updateXui = true;
1087 if(localgameModes[idx] != NULL)
1088 {
1089 if( getLevel( localplayers[idx]->dimension )->isClientSide )
1090 {
1091 shared_ptr<MultiplayerLocalPlayer> mplp = localplayers[idx];
1092 ( (MultiPlayerLevel *)getLevel( localplayers[idx]->dimension ) )->removeClientConnection(mplp->connection, true);
1093 delete mplp->connection;
1094 mplp->connection = NULL;
1095 g_NetworkManager.RemoveLocalPlayerByUserIndex(idx);
1096 }
1097 getLevel( localplayers[idx]->dimension )->removeEntity(localplayers[idx]);
1098
1099#ifdef _XBOX
1100 // 4J Stu - Fix for #12368 - Crash: Game crashes when saving then exiting and selecting to save
1101 app.TutorialSceneNavigateBack(idx);
1102#endif
1103
1104 // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title crashed after exiting the tutorial
1105 // It doesn't matter if they were in the tutorial already
1106 playerLeftTutorial( idx );
1107
1108 delete localgameModes[idx];
1109 localgameModes[idx] = NULL;
1110 }
1111 else if( m_pendingLocalConnections[idx] != NULL )
1112 {
1113 m_pendingLocalConnections[idx]->sendAndDisconnect( shared_ptr<DisconnectPacket>( new DisconnectPacket(DisconnectPacket::eDisconnect_Quitting) ) );;
1114 delete m_pendingLocalConnections[idx];
1115 m_pendingLocalConnections[idx] = NULL;
1116 g_NetworkManager.RemoveLocalPlayerByUserIndex(idx);
1117 }
1118 else
1119 {
1120 // Not sure how this works on qnet, but for other platforms, calling RemoveLocalPlayerByUserIndex won't do anything if there isn't a local user to remove
1121 // Now just updating the UI directly in this case
1122#ifdef _XBOX
1123 // 4J Stu - A signout early in the game creation before this player has connected to the game server
1124 updateXui = false;
1125#endif
1126 // 4J Stu - Adding this back in for exactly the reason my comment above suggests it was added in the first place
1127#if defined(_XBOX_ONE) || defined(__ORBIS__)
1128 g_NetworkManager.RemoveLocalPlayerByUserIndex(idx);
1129#endif
1130 }
1131 localplayers[idx] = nullptr;
1132
1133 if( idx == ProfileManager.GetPrimaryPad() )
1134 {
1135 // We should never try to remove the Primary player in this way
1136 assert(false);
1137 /*
1138 // If we are removing the primary player then there can't be a valid gamemode left anymore, this
1139 // pointer will be referring to the one we've just deleted
1140 gameMode = NULL;
1141 // Remove references to player
1142 player = NULL;
1143 cameraTargetPlayer = NULL;
1144 EntityRenderDispatcher::instance->cameraEntity = NULL;
1145 TileEntityRenderDispatcher::instance->cameraEntity = NULL;
1146 */
1147 }
1148 else if( updateXui )
1149 {
1150 gameRenderer->DisableUpdateThread();
1151 levelRenderer->setLevel(idx, NULL);
1152 gameRenderer->EnableUpdateThread();
1153 ui.CloseUIScenes(idx,true);
1154 updatePlayerViewportAssignments();
1155 }
1156
1157 // We only create these once ever so don't delete it here
1158 //delete localitemInHandRenderers[idx];
1159}
1160
1161void Minecraft::createPrimaryLocalPlayer(int iPad)
1162{
1163 localgameModes[iPad] = gameMode;
1164 localplayers[iPad] = player;
1165 //gameRenderer->itemInHandRenderer = localitemInHandRenderers[iPad];
1166 // Give them the gamertag if they're signed in
1167 if(ProfileManager.IsSignedIn(ProfileManager.GetPrimaryPad()))
1168 {
1169 user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad()) );
1170 }
1171}
1172
1173#ifdef _WINDOWS64
1174void Minecraft::applyFrameMouseLook()
1175{
1176 // Per-frame mouse look: consume mouse deltas every frame instead of waiting
1177 // for the 20Hz game tick. Apply the same delta to both xRot/yRot AND xRotO/yRotO
1178 // so the render interpolation instantly reflects the change without waiting for a tick.
1179 if (level == NULL) return;
1180
1181 for (int i = 0; i < XUSER_MAX_COUNT; i++)
1182 {
1183 if (localplayers[i] == NULL) continue;
1184 int iPad = localplayers[i]->GetXboxPad();
1185 if (iPad != 0) continue; // Mouse only applies to pad 0
1186
1187 if (!KMInput.IsCaptured()) continue;
1188 if (localgameModes[iPad] == NULL) continue;
1189
1190 float rawDx, rawDy;
1191 KMInput.ConsumeMouseDelta(rawDx, rawDy);
1192 if (rawDx == 0.0f && rawDy == 0.0f) continue;
1193
1194 float mouseSensitivity = 0.5f;
1195 float mdx = rawDx * mouseSensitivity;
1196 float mdy = -rawDy * mouseSensitivity;
1197 if (app.GetGameSettings(iPad, eGameSetting_ControlInvertLook))
1198 mdy = -mdy;
1199
1200 // Apply 0.15f scaling (same as Entity::interpolateTurn / Entity::turn)
1201 float dyaw = mdx * 0.15f;
1202 float dpitch = -mdy * 0.15f;
1203
1204 // Apply to both current and old rotation so render interpolation
1205 // reflects the change immediately (no 50ms tick delay)
1206 localplayers[i]->yRot += dyaw;
1207 localplayers[i]->yRotO += dyaw;
1208 localplayers[i]->xRot += dpitch;
1209 localplayers[i]->xRotO += dpitch;
1210
1211 // Clamp pitch
1212 if (localplayers[i]->xRot < -90.0f) localplayers[i]->xRot = -90.0f;
1213 if (localplayers[i]->xRot > 90.0f) localplayers[i]->xRot = 90.0f;
1214 if (localplayers[i]->xRotO < -90.0f) localplayers[i]->xRotO = -90.0f;
1215 if (localplayers[i]->xRotO > 90.0f) localplayers[i]->xRotO = 90.0f;
1216 }
1217}
1218#endif
1219
1220void Minecraft::run_middle()
1221{
1222 static __int64 lastTime = 0;
1223 static bool bFirstTimeIntoGame = true;
1224 static bool bAutosaveTimerSet=false;
1225 static unsigned int uiAutosaveTimer=0;
1226 static int iFirstTimeCountdown=60;
1227 if( lastTime == 0 ) lastTime = System::nanoTime();
1228 static int frames = 0;
1229
1230 EnterCriticalSection(&m_setLevelCS);
1231
1232 if(running)
1233 {
1234 if (reloadTextures)
1235 {
1236 reloadTextures = false;
1237 textures->reloadAll();
1238 }
1239
1240 //while (running)
1241 {
1242 // try { // 4J - removed try/catch
1243 // if (minecraftApplet != null && !minecraftApplet.isActive()) break; // 4J - removed
1244 AABB::resetPool();
1245 Vec3::resetPool();
1246
1247 // if (parent == NULL && Display.isCloseRequested()) { // 4J - removed
1248 // stop();
1249 // }
1250
1251 // 4J-PB - AUTOSAVE TIMER - only in the full game and if the player is the host
1252 if(level!=NULL && ProfileManager.IsFullVersion() && g_NetworkManager.IsHost())
1253 {
1254 /*if(!bAutosaveTimerSet)
1255 {
1256 // set the timer
1257 bAutosaveTimerSet=true;
1258
1259 app.SetAutosaveTimerTime();
1260 }
1261 else*/
1262 {
1263 // if the pause menu is up for the primary player, don't autosave
1264 // If saving isn't disabled, and the main player has a app action running , or has any crafting or containers open, don't autosave
1265 if(!StorageManager.GetSaveDisabled() && (app.GetXuiAction(ProfileManager.GetPrimaryPad())==eAppAction_Idle) )
1266 {
1267 if(!ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad()) && !ui.IsIgnoreAutosaveMenuDisplayed(ProfileManager.GetPrimaryPad()))
1268 {
1269 // check if the autotimer countdown has reached zero
1270 unsigned char ucAutosaveVal=app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_Autosave);
1271 bool bTrialTexturepack=false;
1272 if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin())
1273 {
1274 TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected();
1275 DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack;
1276
1277 DLCPack *pDLCPack=pDLCTexPack->getDLCInfoParentPack();
1278
1279 if( pDLCPack )
1280 {
1281 if(!pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" ))
1282 {
1283 bTrialTexturepack=true;
1284 }
1285 }
1286 }
1287
1288 // If the autosave value is not zero, and the player isn't using a trial texture pack, then check whether we need to save this tick
1289 if((ucAutosaveVal!=0) && !bTrialTexturepack)
1290 {
1291 if(app.AutosaveDue())
1292 {
1293 // disable the autosave countdown
1294 ui.ShowAutosaveCountdownTimer(false);
1295
1296 // Need to save now
1297 app.DebugPrintf("+++++++++++\n");
1298 app.DebugPrintf("+++Autosave\n");
1299 app.DebugPrintf("+++++++++++\n");
1300 app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_AutosaveSaveGame);
1301 //app.SetAutosaveTimerTime();
1302#ifndef _CONTENT_PACKAGE
1303 {
1304 // print the time
1305 SYSTEMTIME UTCSysTime;
1306 GetSystemTime( &UTCSysTime );
1307 //char szTime[15];
1308
1309 app.DebugPrintf("%02d:%02d:%02d\n",UTCSysTime.wHour,UTCSysTime.wMinute,UTCSysTime.wSecond);
1310 }
1311#endif
1312 }
1313 else
1314 {
1315 unsigned int uiTimeToAutosave=app.SecondsToAutosave();
1316
1317 if(uiTimeToAutosave<6)
1318 {
1319 ui.ShowAutosaveCountdownTimer(true);
1320 ui.UpdateAutosaveCountdownTimer(uiTimeToAutosave);
1321 }
1322 }
1323 }
1324 }
1325 else
1326 {
1327 // disable the autosave countdown
1328 ui.ShowAutosaveCountdownTimer(false);
1329 }
1330 }
1331 }
1332 }
1333
1334 // 4J-PB - Once we're in the level, check if the players have the level in their banned list and ask if they want to play it
1335 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
1336 {
1337 if( localplayers[i] && (app.GetBanListCheck(i)==false) && !Minecraft::GetInstance()->isTutorial() && ProfileManager.IsSignedInLive(i) && !ProfileManager.IsGuest(i) )
1338 {
1339 // If there is a sys ui displayed, we can't display the message box here, so ignore until we can
1340 if(!ProfileManager.IsSystemUIDisplayed())
1341 {
1342 app.SetBanListCheck(i,true);
1343 // 4J-PB - check if the level is in the banned level list
1344 // get the unique save name and xuid from whoever is the host
1345#if defined _XBOX || defined _XBOX_ONE
1346 INetworkPlayer *pHostPlayer = g_NetworkManager.GetHostPlayer();
1347
1348#ifdef _XBOX
1349 PlayerUID xuid=((NetworkPlayerXbox *)pHostPlayer)->GetUID();
1350#else
1351 PlayerUID xuid=pHostPlayer->GetUID();
1352#endif
1353
1354 if(app.IsInBannedLevelList(i,xuid,app.GetUniqueMapName()))
1355 {
1356 // put up a message box asking if the player would like to unban this level
1357 app.DebugPrintf("This level is banned\n");
1358 // set the app action to bring up the message box to give them the option to remove from the ban list or exit the level
1359 app.SetAction(i,eAppAction_LevelInBanLevelList,(void *)TRUE);
1360 }
1361#endif
1362 }
1363 }
1364 }
1365
1366 if(!ProfileManager.IsSystemUIDisplayed() && app.DLCInstallProcessCompleted() && !app.DLCInstallPending() && app.m_dlcManager.NeedsCorruptCheck() )
1367 {
1368 app.m_dlcManager.checkForCorruptDLCAndAlert();
1369 }
1370
1371 // When we go into the first loaded level, check if the console has active joypads that are not in the game, and bring up the quadrant display to remind them to press start (if the session has space)
1372 if(level!=NULL && bFirstTimeIntoGame && g_NetworkManager.SessionHasSpace())
1373 {
1374 // have a short delay before the display
1375 if(iFirstTimeCountdown==0)
1376 {
1377 bFirstTimeIntoGame=false;
1378
1379 if(app.IsLocalMultiplayerAvailable())
1380 {
1381 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
1382 {
1383 if((localplayers[i] == NULL) && InputManager.IsPadConnected(i))
1384 {
1385 if(!ui.PressStartPlaying(i))
1386 {
1387 ui.ShowPressStart(i);
1388 }
1389 }
1390 }
1391 }
1392 }
1393 else iFirstTimeCountdown--;
1394 }
1395 // 4J-PB - store any button toggles for the players, since the minecraft::tick may not be called if we're running fast, and a button press and release will be missed
1396
1397 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
1398 {
1399#ifdef __ORBIS__
1400 if ( m_pPsPlusUpsell != NULL && m_pPsPlusUpsell->hasResponse() && m_pPsPlusUpsell->m_userIndex == i )
1401 {
1402 delete m_pPsPlusUpsell;
1403 m_pPsPlusUpsell = NULL;
1404
1405 if ( ProfileManager.HasPlayStationPlus(i) )
1406 {
1407 app.DebugPrintf("<Minecraft.cpp> Player_%i is now authorised for PsPlus.\n", i);
1408 if (!ui.PressStartPlaying(i)) ui.ShowPressStart(i);
1409 }
1410 else
1411 {
1412 UINT uiIDA[1] = { IDS_OK };
1413 ui.RequestErrorMessage( IDS_CANTJOIN_TITLE, IDS_NO_PLAYSTATIONPLUS, uiIDA, 1, i);
1414 }
1415 }
1416 else
1417#endif
1418 if(localplayers[i])
1419 {
1420 // 4J-PB - add these to check for coming out of idle
1421 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_JUMP)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_JUMP;
1422 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_USE)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_USE;
1423
1424 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_INVENTORY)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_INVENTORY;
1425 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_ACTION)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_ACTION;
1426 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_CRAFTING)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_CRAFTING;
1427 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_PAUSEMENU))
1428 {
1429 localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
1430 app.DebugPrintf("PAUSE PRESSED - ipad = %d, Storing press\n",i);
1431 }
1432#ifdef _DURANGO
1433 if(InputManager.ButtonPressed(i, ACTION_MENU_GTC_PAUSE)) localplayers[i]->ullButtonsPressed|=1LL<<ACTION_MENU_GTC_PAUSE;
1434#endif
1435 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DROP)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_DROP;
1436
1437 // 4J-PB - If we're flying, the sneak needs to be held on to go down
1438 if(localplayers[i]->abilities.flying)
1439 {
1440 if(InputManager.ButtonDown(i, MINECRAFT_ACTION_SNEAK_TOGGLE)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE;
1441 }
1442 else
1443 {
1444 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_SNEAK_TOGGLE)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE;
1445 }
1446 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_RENDER_THIRD_PERSON)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
1447 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_GAME_INFO)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_GAME_INFO;
1448
1449#ifdef _WINDOWS64
1450 // Keyboard/mouse button presses for player 0
1451 if (i == 0)
1452 {
1453 if (KMInput.ConsumeKeyPress(VK_ESCAPE)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_PAUSEMENU;
1454 if (KMInput.ConsumeKeyPress('E')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_INVENTORY;
1455 if (KMInput.ConsumeKeyPress('Q')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_DROP;
1456 if (KMInput.ConsumeKeyPress('C')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_CRAFTING;
1457 if (KMInput.ConsumeKeyPress(VK_F5)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
1458 // In flying mode, Shift held = sneak/descend
1459 if (localplayers[i]->abilities.flying && KMInput.IsKeyDown(VK_SHIFT))
1460 localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE;
1461 }
1462#endif
1463
1464#ifndef _FINAL_BUILD
1465 if( app.DebugSettingsOn() && app.GetUseDPadForDebug() )
1466 {
1467 localplayers[i]->ullDpad_last = 0;
1468 localplayers[i]->ullDpad_this = 0;
1469 localplayers[i]->ullDpad_filtered = 0;
1470 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_RIGHT)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_CHANGE_SKIN;
1471 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_UP)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_FLY_TOGGLE;
1472 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_DOWN)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_DEBUG;
1473 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_DPAD_LEFT)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_SPAWN_CREEPER;
1474 }
1475 else
1476#endif
1477 {
1478 // Movement on DPAD is stored ulimately into ullDpad_filtered - this ignores any diagonals pressed, instead reporting the last single direction - otherwise
1479 // we get loads of accidental diagonal movements
1480
1481 localplayers[i]->ullDpad_this = 0;
1482 int dirCount = 0;
1483
1484#ifndef __PSVITA__
1485 if(InputManager.ButtonDown(i, MINECRAFT_ACTION_DPAD_LEFT)) { localplayers[i]->ullDpad_this|=1LL<<MINECRAFT_ACTION_DPAD_LEFT; dirCount++; }
1486 if(InputManager.ButtonDown(i, MINECRAFT_ACTION_DPAD_RIGHT)) { localplayers[i]->ullDpad_this|=1LL<<MINECRAFT_ACTION_DPAD_RIGHT; dirCount++; }
1487 if(InputManager.ButtonDown(i, MINECRAFT_ACTION_DPAD_UP)) { localplayers[i]->ullDpad_this|=1LL<<MINECRAFT_ACTION_DPAD_UP; dirCount++; }
1488 if(InputManager.ButtonDown(i, MINECRAFT_ACTION_DPAD_DOWN)) { localplayers[i]->ullDpad_this|=1LL<<MINECRAFT_ACTION_DPAD_DOWN; dirCount++; }
1489#endif
1490
1491 if( dirCount <= 1 )
1492 {
1493 localplayers[i]->ullDpad_last = localplayers[i]->ullDpad_this;
1494 localplayers[i]->ullDpad_filtered = localplayers[i]->ullDpad_this;
1495 }
1496 else
1497 {
1498 localplayers[i]->ullDpad_filtered = localplayers[i]->ullDpad_last;
1499 }
1500 }
1501
1502 // for the opacity timer
1503 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_LEFT_SCROLL) || InputManager.ButtonPressed(i, MINECRAFT_ACTION_RIGHT_SCROLL))
1504 //InputManager.ButtonPressed(i, MINECRAFT_ACTION_USE) || InputManager.ButtonPressed(i, MINECRAFT_ACTION_ACTION))
1505 {
1506 app.SetOpacityTimer(i);
1507 }
1508 }
1509 else
1510 {
1511 // 4J Stu - This doesn't make any sense with the way we handle XboxOne users
1512#ifndef _DURANGO
1513 // did we just get input from a player who doesn't exist? They'll be wanting to join the game then
1514#ifdef _WINDOWS64
1515 // The 4J toggle system is unreliable here: UIController::handleInput() calls
1516 // ButtonPressed for every ACTION_MENU_* mapped button (which covers all physical
1517 // buttons) before run_middle() runs. Bypass it with raw XInput and own edge detection.
1518 // A latch counter keeps startJustPressed active for ~120 frames after the rising edge
1519 // so the detection window is large enough to be caught reliably.
1520 static WORD s_prevXButtons[XUSER_MAX_COUNT] = {};
1521 static int s_startPressLatch[XUSER_MAX_COUNT] = {};
1522 XINPUT_STATE xstate_join;
1523 memset(&xstate_join, 0, sizeof(xstate_join));
1524 WORD xCurButtons = 0;
1525 if (XInputGetState(i, &xstate_join) == ERROR_SUCCESS)
1526 {
1527 xCurButtons = xstate_join.Gamepad.wButtons;
1528 if ((xCurButtons & XINPUT_GAMEPAD_START) != 0 && (s_prevXButtons[i] & XINPUT_GAMEPAD_START) == 0)
1529 s_startPressLatch[i] = 120; // rising edge: latch for ~120 frames (~2s at 60fps)
1530 else if (s_startPressLatch[i] > 0)
1531 s_startPressLatch[i]--;
1532 s_prevXButtons[i] = xCurButtons;
1533 }
1534 bool startJustPressed = s_startPressLatch[i] > 0;
1535 bool tryJoin = !pause && !ui.IsIgnorePlayerJoinMenuDisplayed(ProfileManager.GetPrimaryPad()) && g_NetworkManager.SessionHasSpace() && xCurButtons != 0;
1536#else
1537 bool tryJoin = !pause && !ui.IsIgnorePlayerJoinMenuDisplayed(ProfileManager.GetPrimaryPad()) && g_NetworkManager.SessionHasSpace() && RenderManager.IsHiDef() && InputManager.ButtonPressed(i);
1538#endif
1539#ifdef __ORBIS__
1540 // Check for remote play
1541 tryJoin = tryJoin && InputManager.IsLocalMultiplayerAvailable();
1542
1543 // 4J Stu - Check that content restriction information has been received
1544 if( !g_NetworkManager.IsLocalGame() )
1545 {
1546 tryJoin = tryJoin && ProfileManager.GetChatAndContentRestrictions(i,true,NULL,NULL,NULL);
1547 }
1548#endif
1549 if(tryJoin)
1550 {
1551 if(!ui.PressStartPlaying(i))
1552 {
1553#ifdef __ORBIS__
1554 // Don't let player start joining until their PS Plus check has finished
1555 if (g_NetworkManager.IsLocalGame() || !ProfileManager.RequestingPlaystationPlus(i))
1556#endif
1557 {
1558 ui.ShowPressStart(i);
1559 }
1560 }
1561 else
1562 {
1563 // did we just get input from a player who doesn't exist? They'll be wanting to join the game then
1564#ifdef __ORBIS__
1565 if(InputManager.ButtonPressed(i, ACTION_MENU_A))
1566#elif defined _WINDOWS64
1567 if(startJustPressed)
1568#else
1569 if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_PAUSEMENU))
1570#endif
1571 {
1572 // Let them join
1573
1574 // are they signed in?
1575#ifdef _WINDOWS64
1576 if(ProfileManager.IsSignedIn(i) || (g_NetworkManager.IsLocalGame() && InputManager.IsPadConnected(i)))
1577#else
1578 if(ProfileManager.IsSignedIn(i))
1579#endif
1580 {
1581 // if this is a local game, then the player just needs to be signed in
1582 if( g_NetworkManager.IsLocalGame() || (ProfileManager.IsSignedInLive(i) && ProfileManager.AllowedToPlayMultiplayer(i) ) )
1583 {
1584#ifdef __ORBIS__
1585 bool contentRestricted = false;
1586 ProfileManager.GetChatAndContentRestrictions(i,false,NULL,&contentRestricted,NULL); // TODO!
1587
1588 if (!g_NetworkManager.IsLocalGame() && contentRestricted)
1589 {
1590 ui.RequestContentRestrictedMessageBox(IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_CONTENT_RESTRICTION, i);
1591 }
1592 else if(!g_NetworkManager.IsLocalGame() && !ProfileManager.HasPlayStationPlus(i))
1593 {
1594 m_pPsPlusUpsell = new PsPlusUpsellWrapper(i);
1595 m_pPsPlusUpsell->displayUpsell();
1596 }
1597 else
1598#endif
1599 if( level->isClientSide )
1600 {
1601 bool success=addLocalPlayer(i);
1602
1603 if(!success)
1604 {
1605 app.DebugPrintf("Bringing up the sign in ui\n");
1606 ProfileManager.RequestSignInUI(false, g_NetworkManager.IsLocalGame(), true, false,true,&Minecraft::InGame_SignInReturned, this,i);
1607 }
1608 else
1609 {
1610#ifdef __ORBIS__
1611 if(g_NetworkManager.IsLocalGame() == false)
1612 {
1613 bool chatRestricted = false;
1614 ProfileManager.GetChatAndContentRestrictions(i,false,&chatRestricted,NULL,NULL);
1615 if(chatRestricted)
1616 {
1617 ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, i );
1618 }
1619 }
1620#endif
1621 }
1622 }
1623 else
1624 {
1625 // create the localplayer
1626 shared_ptr<Player> player = localplayers[i];
1627 if( player == NULL)
1628 {
1629 player = createExtraLocalPlayer(i, (convStringToWstring( ProfileManager.GetGamertag(i) )).c_str(), i, level->dimension->id);
1630 }
1631 }
1632 }
1633 else
1634 {
1635 if( ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && !ProfileManager.AllowedToPlayMultiplayer(i) )
1636 {
1637 ProfileManager.RequestConvertOfflineToGuestUI( &Minecraft::InGame_SignInReturned, this,i);
1638 // 4J Stu - Don't allow converting to guests as we don't allow any guest sign-in while in the game
1639 // Fix for #66516 - TCR #124: MPS Guest Support ; #001: BAS Game Stability: TU8: The game crashes when second Guest signs-in on console which takes part in Xbox LIVE multiplayer session.
1640 //ProfileManager.RequestConvertOfflineToGuestUI( &Minecraft::InGame_SignInReturned, this,i);
1641
1642#ifndef _XBOX
1643 ui.HidePressStart();
1644#endif
1645
1646#ifdef __ORBIS__
1647 int npAvailability = ProfileManager.getNPAvailability(i);
1648
1649 // Check if PSN is unavailable because of age restriction
1650 if (npAvailability == SCE_NP_ERROR_AGE_RESTRICTION)
1651 {
1652 UINT uiIDA[1];
1653 uiIDA[0] = IDS_OK;
1654 ui.RequestErrorMessage(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, i);
1655 }
1656 else if (ProfileManager.IsSignedIn(i) && !ProfileManager.IsSignedInLive(i))
1657 {
1658 // You're not signed in to PSN!
1659 UINT uiIDA[2];
1660 uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT;
1661 uiIDA[1] = IDS_CANCEL;
1662 ui.RequestAlertMessage(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, i,&Minecraft::MustSignInReturnedPSN, this);
1663 }
1664 else
1665#endif
1666 {
1667 UINT uiIDA[1];
1668 uiIDA[0]=IDS_CONFIRM_OK;
1669 ui.RequestErrorMessage(IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA, 1, i);
1670 }
1671 }
1672 //else
1673 {
1674 // player not signed in to live
1675 // bring up the sign in dialog
1676 app.DebugPrintf("Bringing up the sign in ui\n");
1677 ProfileManager.RequestSignInUI(false, g_NetworkManager.IsLocalGame(), true, false,true,&Minecraft::InGame_SignInReturned, this,i);
1678 }
1679 }
1680 }
1681 else
1682 {
1683 // bring up the sign in dialog
1684 app.DebugPrintf("Bringing up the sign in ui\n");
1685 ProfileManager.RequestSignInUI(false, g_NetworkManager.IsLocalGame(), true, false,true,&Minecraft::InGame_SignInReturned, this,i);
1686 }
1687 }
1688 }
1689 }
1690#endif // _DURANGO
1691 }
1692 }
1693
1694#ifdef _DURANGO
1695 // did we just get input from a player who doesn't exist? They'll be wanting to join the game then
1696 if(!pause && !ui.IsIgnorePlayerJoinMenuDisplayed(ProfileManager.GetPrimaryPad()) && g_NetworkManager.SessionHasSpace() && RenderManager.IsHiDef() )
1697 {
1698 int firstEmptyUser = 0;
1699 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
1700 {
1701 if(localplayers[i] == NULL)
1702 {
1703 firstEmptyUser = i;
1704 break;
1705 }
1706 }
1707
1708 // For durango, check for unmapped controllers
1709 for(unsigned int iPad = XUSER_MAX_COUNT; iPad < (XUSER_MAX_COUNT + InputManager.MAX_GAMEPADS); ++iPad)
1710 {
1711 bool isPadLocked = InputManager.IsPadLocked(iPad), isPadConnected = InputManager.IsPadConnected(iPad), buttonPressed = InputManager.ButtonPressed(iPad);
1712 if (isPadLocked || !isPadConnected || !buttonPressed) continue;
1713
1714 if(!ui.PressStartPlaying(firstEmptyUser))
1715 {
1716 ui.ShowPressStart(firstEmptyUser);
1717 }
1718 else
1719 {
1720 // did we just get input from a player who doesn't exist? They'll be wanting to join the game then
1721 if(InputManager.ButtonPressed(iPad, MINECRAFT_ACTION_PAUSEMENU))
1722 {
1723 // bring up the sign in dialog
1724 app.DebugPrintf("Bringing up the sign in ui\n");
1725 ProfileManager.RequestSignInUI(false, g_NetworkManager.IsLocalGame(), true, false,true,&Minecraft::InGame_SignInReturned, this,iPad);
1726
1727 // 4J Stu - If we are joining a pad here, then we don't want to try and join any others
1728 break;
1729 }
1730 }
1731 }
1732 }
1733#endif
1734
1735 if (pause && level != NULL)
1736 {
1737 float lastA = timer->a;
1738 timer->advanceTime();
1739 timer->a = lastA;
1740 }
1741 else
1742 {
1743 timer->advanceTime();
1744 }
1745
1746 //__int64 beforeTickTime = System::nanoTime();
1747 for (int i = 0; i < timer->ticks; i++)
1748 {
1749 bool bLastTimerTick = ( i == ( timer->ticks - 1 ) );
1750 // 4J-PB - the tick here can run more than once, and this is a problem for our input, which would see the a key press twice with the same time - let's tick the inputmanager again
1751 if(i!=0)
1752 {
1753 InputManager.Tick();
1754 app.HandleButtonPresses();
1755 }
1756
1757 ticks++;
1758 // try { // 4J - try/catch removed
1759 bool bFirst = true;
1760 for( int idx = 0; idx < XUSER_MAX_COUNT; idx++ )
1761 {
1762 // 4J - If we are waiting for this connection to do something, then tick it here.
1763 // This replaces many of the original Java scenes which would tick the connection while showing that scene
1764 if( m_pendingLocalConnections[idx] != NULL )
1765 {
1766 m_pendingLocalConnections[idx]->tick();
1767 }
1768
1769 // reset the player inactive tick
1770 if(localplayers[idx]!=NULL)
1771 {
1772 // any input received?
1773 if((localplayers[idx]->ullButtonsPressed!=0) || InputManager.GetJoypadStick_LX(idx,false)!=0.0f ||
1774 InputManager.GetJoypadStick_LY(idx,false)!=0.0f || InputManager.GetJoypadStick_RX(idx,false)!=0.0f ||
1775 InputManager.GetJoypadStick_RY(idx,false)!=0.0f )
1776 {
1777 localplayers[idx]->ResetInactiveTicks();
1778 }
1779 else
1780 {
1781 localplayers[idx]->IncrementInactiveTicks();
1782 }
1783
1784 if(localplayers[idx]->GetInactiveTicks()>200)
1785 {
1786 if(!localplayers[idx]->isIdle() && localplayers[idx]->onGround)
1787 {
1788 localplayers[idx]->setIsIdle(true);
1789 }
1790 }
1791 else
1792 {
1793 if(localplayers[idx]->isIdle())
1794 {
1795 localplayers[idx]->setIsIdle(false);
1796 }
1797 }
1798 }
1799
1800 if( setLocalPlayerIdx(idx) )
1801 {
1802 tick(bFirst, bLastTimerTick);
1803 bFirst = false;
1804 // clear the stored button downs since the tick for this player will now have actioned them
1805 player->ullButtonsPressed=0LL;
1806 }
1807 }
1808
1809 ui.HandleGameTick();
1810
1811 setLocalPlayerIdx(ProfileManager.GetPrimaryPad());
1812
1813 // 4J - added - now do the equivalent of level::animateTick, but taking into account the positions of all our players
1814
1815 for( int l = 0; l < levels.length; l++ )
1816 {
1817 if( levels[l] )
1818 {
1819 levels[l]->animateTickDoWork();
1820 }
1821 }
1822
1823 // } catch (LevelConflictException e) {
1824 // this.level = null;
1825 // setLevel(null);
1826 // setScreen(new LevelConflictScreen());
1827 // }
1828// SparseLightStorage::tick(); // 4J added
1829// CompressedTileStorage::tick(); // 4J added
1830// SparseDataStorage::tick(); // 4J added
1831 }
1832 //__int64 tickDuraction = System::nanoTime() - beforeTickTime;
1833 MemSect(31);
1834 checkGlError(L"Pre render");
1835 MemSect(0);
1836
1837 TileRenderer::fancy = options->fancyGraphics;
1838
1839 // if (pause) timer.a = 1;
1840
1841 PIXBeginNamedEvent(0,"Sound engine update");
1842 soundEngine->tick((shared_ptr<Mob> *)localplayers, timer->a);
1843 PIXEndNamedEvent();
1844
1845 PIXBeginNamedEvent(0,"Light update");
1846
1847 glEnable(GL_TEXTURE_2D);
1848
1849 PIXEndNamedEvent();
1850
1851 // if (!Keyboard::isKeyDown(Keyboard.KEY_F7)) Display.update(); // 4J - removed
1852
1853 // 4J-PB - changing this to be per player
1854 //if (player != NULL && player->isInWall()) options->thirdPersonView = false;
1855 if (player != NULL && player->isInWall()) player->SetThirdPersonView(0);
1856
1857 if (!noRender)
1858 {
1859 bool bFirst = true;
1860 int iPrimaryPad=ProfileManager.GetPrimaryPad();
1861 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
1862 {
1863 if( setLocalPlayerIdx(i) )
1864 {
1865 PIXBeginNamedEvent(0,"Game render player idx %d",i);
1866 RenderManager.StateSetViewport((C4JRender::eViewportType)player->m_iScreenSection);
1867 gameRenderer->render(timer->a, bFirst);
1868 bFirst = false;
1869 PIXEndNamedEvent();
1870
1871 if(i==iPrimaryPad)
1872 {
1873#ifdef __ORBIS__
1874 // PS4 does much of the screen-capturing for every frame, to simplify the synchronisation when we actually want a capture. This call tells it the point in the frame to do it.
1875 RenderManager.InternalScreenCapture();
1876#endif
1877 // check to see if we need to capture a screenshot for the save game thumbnail
1878 switch(app.GetXuiAction(i))
1879 {
1880 case eAppAction_ExitWorldCapturedThumbnail:
1881 case eAppAction_SaveGameCapturedThumbnail:
1882 case eAppAction_AutosaveSaveGameCapturedThumbnail:
1883 // capture the save thumbnail
1884 app.CaptureSaveThumbnail();
1885 break;
1886 }
1887 }
1888 }
1889 }
1890 // If there's an unoccupied quadrant, then clear that to black
1891 if( unoccupiedQuadrant > -1 )
1892 {
1893 // render a logo
1894 RenderManager.StateSetViewport((C4JRender::eViewportType)(C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT + unoccupiedQuadrant));
1895 glClearColor(0, 0, 0, 0);
1896 glClear(GL_COLOR_BUFFER_BIT);
1897
1898 ui.SetEmptyQuadrantLogo(C4JRender::VIEWPORT_TYPE_QUADRANT_TOP_LEFT + unoccupiedQuadrant);
1899 }
1900 setLocalPlayerIdx(iPrimaryPad);
1901 RenderManager.StateSetViewport(C4JRender::VIEWPORT_TYPE_FULLSCREEN);
1902
1903#ifdef _XBOX
1904 // Do we need to capture a screenshot for a social post?
1905 for( int i = 0; i < XUSER_MAX_COUNT; i++ )
1906 {
1907 if(app.GetXuiAction(i)==eAppAction_SocialPostScreenshot)
1908 {
1909 app.CaptureScreenshot(i);
1910 }
1911 }
1912#endif
1913 }
1914 glFlush();
1915
1916 /* 4J - removed
1917 if (!Display::isActive())
1918 {
1919 if (fullscreen)
1920 {
1921 this->toggleFullScreen();
1922 }
1923 Sleep(10);
1924 }
1925 */
1926
1927#if PACKET_ENABLE_STAT_TRACKING
1928 Packet::updatePacketStatsPIX();
1929#endif
1930
1931 if (options->renderDebug)
1932 {
1933 //renderFpsMeter(tickDuraction);
1934
1935#if DEBUG_RENDER_SHOWS_PACKETS
1936 // To show data for only one packet type
1937 //Packet::renderPacketStats(31);
1938
1939 // To show data for all packet types selected as being renderable in the Packet:static_ctor call to Packet::map
1940 Packet::renderAllPacketStats();
1941#else
1942 // To show the size of the QNet queue in bytes and messages
1943 g_NetworkManager.renderQueueMeter();
1944#endif
1945 }
1946 else
1947 {
1948 lastTimer = System::nanoTime();
1949 }
1950
1951 achievementPopup->render();
1952
1953 PIXBeginNamedEvent(0,"Sleeping");
1954 Sleep(0); // 4J - was Thread.yield()
1955 PIXEndNamedEvent();
1956
1957 // if (Keyboard::isKeyDown(Keyboard::KEY_F7)) Display.update(); // 4J - removed condition
1958 PIXBeginNamedEvent(0,"Display update");
1959 Display::update();
1960 PIXEndNamedEvent();
1961
1962 // checkScreenshot(); // 4J - removed
1963
1964 /* 4J - removed
1965 if (parent != NULL && !fullscreen)
1966 {
1967 if (parent.getWidth() != width || parent.getHeight() != height)
1968 {
1969 width = parent.getWidth();
1970 height = parent.getHeight();
1971 if (width <= 0) width = 1;
1972 if (height <= 0) height = 1;
1973
1974 resize(width, height);
1975 }
1976 }
1977 */
1978 MemSect(31);
1979 checkGlError(L"Post render");
1980 MemSect(0);
1981 frames++;
1982 //pause = !isClientSide() && screen != NULL && screen->isPauseScreen();
1983 //pause = g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 && app.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad());
1984 pause = app.IsAppPaused();
1985
1986#ifndef _CONTENT_PACKAGE
1987 while (System::nanoTime() >= lastTime + 1000000000)
1988 {
1989 MemSect(31);
1990 fpsString = _toString<int>(frames) + L" fps, " + _toString<int>(Chunk::updates) + L" chunk updates";
1991 MemSect(0);
1992 Chunk::updates = 0;
1993 lastTime += 1000000000;
1994 frames = 0;
1995 }
1996#endif
1997 /*
1998 } catch (LevelConflictException e) {
1999 this.level = null;
2000 setLevel(null);
2001 setScreen(new LevelConflictScreen());
2002 } catch (OutOfMemoryError e) {
2003 emergencySave();
2004 setScreen(new OutOfMemoryScreen());
2005 System.gc();
2006 }
2007 */
2008 }
2009 /*
2010 } catch (StopGameException e) {
2011 } catch (Throwable e) {
2012 emergencySave();
2013 e.printStackTrace();
2014 crash(new CrashReport("Unexpected error", e));
2015 } finally {
2016 destroy();
2017 }
2018 */
2019 }
2020 LeaveCriticalSection(&m_setLevelCS);
2021}
2022
2023void Minecraft::run_end()
2024{
2025 destroy();
2026}
2027
2028void Minecraft::emergencySave()
2029{
2030 // 4J - lots of try/catches removed here, and garbage collector things
2031 levelRenderer->clear();
2032 AABB::clearPool();
2033 Vec3::clearPool();
2034 setLevel(NULL);
2035}
2036
2037void Minecraft::renderFpsMeter(__int64 tickTime)
2038{
2039 int nsPer60Fps = 1000000000l / 60;
2040 if (lastTimer == -1)
2041 {
2042 lastTimer = System::nanoTime();
2043 }
2044 __int64 now = System::nanoTime();
2045 Minecraft::tickTimes[(Minecraft::frameTimePos) & (Minecraft::frameTimes_length - 1)] = tickTime;
2046 Minecraft::frameTimes[(Minecraft::frameTimePos++) & (Minecraft::frameTimes_length - 1)] = now - lastTimer;
2047 lastTimer = now;
2048
2049 glClear(GL_DEPTH_BUFFER_BIT);
2050 glMatrixMode(GL_PROJECTION);
2051 glEnable(GL_COLOR_MATERIAL);
2052 glLoadIdentity();
2053 glOrtho(0, (float)width, (float)height, 0, 1000, 3000);
2054 glMatrixMode(GL_MODELVIEW);
2055 glLoadIdentity();
2056 glTranslatef(0, 0, -2000);
2057
2058 glLineWidth(1);
2059 glDisable(GL_TEXTURE_2D);
2060 Tesselator *t = Tesselator::getInstance();
2061 t->begin(GL_QUADS);
2062 int hh1 = (int) (nsPer60Fps / 200000);
2063 t->color(0x20000000);
2064 t->vertex((float)(0), (float)( height - hh1), (float)( 0));
2065 t->vertex((float)(0), (float)( height), (float)( 0));
2066 t->vertex((float)(Minecraft::frameTimes_length), (float)( height), (float)( 0));
2067 t->vertex((float)(Minecraft::frameTimes_length), (float)( height - hh1), (float)( 0));
2068
2069 t->color(0x20200000);
2070 t->vertex((float)(0), (float)( height - hh1 * 2), (float)( 0));
2071 t->vertex((float)(0), (float)( height - hh1), (float)( 0));
2072 t->vertex((float)(Minecraft::frameTimes_length), (float)( height - hh1), (float)( 0));
2073 t->vertex((float)(Minecraft::frameTimes_length), (float)( height - hh1 * 2), (float)( 0));
2074
2075 t->end();
2076 __int64 totalTime = 0;
2077 for (int i = 0; i < Minecraft::frameTimes_length; i++)
2078 {
2079 totalTime += Minecraft::frameTimes[i];
2080 }
2081 int hh = (int) (totalTime / 200000 / Minecraft::frameTimes_length);
2082 t->begin(GL_QUADS);
2083 t->color(0x20400000);
2084 t->vertex((float)(0), (float)( height - hh), (float)( 0));
2085 t->vertex((float)(0), (float)( height), (float)( 0));
2086 t->vertex((float)(Minecraft::frameTimes_length), (float)( height), (float)( 0));
2087 t->vertex((float)(Minecraft::frameTimes_length), (float)( height - hh), (float)( 0));
2088 t->end();
2089 t->begin(GL_LINES);
2090 for (int i = 0; i < Minecraft::frameTimes_length; i++)
2091 {
2092 int col = ((i - Minecraft::frameTimePos) & (Minecraft::frameTimes_length - 1)) * 255 / Minecraft::frameTimes_length;
2093 int cc = col * col / 255;
2094 cc = cc * cc / 255;
2095 int cc2 = cc * cc / 255;
2096 cc2 = cc2 * cc2 / 255;
2097 if (Minecraft::frameTimes[i] > nsPer60Fps)
2098 {
2099 t->color(0xff000000 + cc * 65536);
2100 }
2101 else
2102 {
2103 t->color(0xff000000 + cc * 256);
2104 }
2105
2106 __int64 time = Minecraft::frameTimes[i] / 200000;
2107 __int64 time2 = Minecraft::tickTimes[i] / 200000;
2108
2109 t->vertex((float)(i + 0.5f), (float)( height - time + 0.5f), (float)( 0));
2110 t->vertex((float)(i + 0.5f), (float)( height + 0.5f), (float)( 0));
2111
2112 // if (Minecraft.frameTimes[i]>nsPer60Fps) {
2113 t->color(0xff000000 + cc * 65536 + cc * 256 + cc * 1);
2114 // } else {
2115 // t.color(0xff808080 + cc/2 * 256);
2116 // }
2117 t->vertex((float)(i + 0.5f), (float)( height - time + 0.5f), (float)( 0));
2118 t->vertex((float)(i + 0.5f), (float)( height - (time - time2) + 0.5f), (float)( 0));
2119 }
2120 t->end();
2121
2122 glEnable(GL_TEXTURE_2D);
2123}
2124
2125void Minecraft::stop()
2126{
2127 running = false;
2128 // keepPolling = false;
2129}
2130
2131void Minecraft::pauseGame()
2132{
2133 if (screen != NULL) return;
2134
2135 // setScreen(new PauseScreen()); // 4J - TODO put back in
2136}
2137
2138void Minecraft::resize(int width, int height)
2139{
2140 if (width <= 0) width = 1;
2141 if (height <= 0) height = 1;
2142 this->width = width;
2143 this->height = height;
2144
2145 if (screen != NULL)
2146 {
2147 ScreenSizeCalculator ssc(options, width, height);
2148 int screenWidth = ssc.getWidth();
2149 int screenHeight = ssc.getHeight();
2150 // screen->init(this, screenWidth, screenHeight); // 4J - TODO - put back in
2151 }
2152}
2153
2154void Minecraft::verify()
2155{
2156 /* 4J - TODO
2157 new Thread() {
2158 public void run() {
2159 try {
2160 HttpURLConnection huc = (HttpURLConnection) new URL("https://login.minecraft.net/session?name=" + user.name + "&session=" + user.sessionId).openConnection();
2161 huc.connect();
2162 if (huc.getResponseCode() == 400) {
2163 warezTime = System.currentTimeMillis();
2164 }
2165 huc.disconnect();
2166 } catch (Exception e) {
2167 e.printStackTrace();
2168 }
2169 }
2170 }.start();
2171 */
2172}
2173
2174
2175
2176
2177void Minecraft::levelTickUpdateFunc(void* pParam)
2178{
2179 Level* pLevel = (Level*)pParam;
2180 pLevel->tick();
2181}
2182
2183void Minecraft::levelTickThreadInitFunc()
2184{
2185 AABB::CreateNewThreadStorage();
2186 Vec3::CreateNewThreadStorage();
2187 IntCache::CreateNewThreadStorage();
2188 Compression::UseDefaultThreadStorage();
2189}
2190
2191
2192// 4J - added bFirst parameter, which is true for the first active viewport in splitscreen
2193// 4J - added bUpdateTextures, which is true if the actual renderer textures are to be updated - this will be true for the last time this tick runs with bFirst true
2194void Minecraft::tick(bool bFirst, bool bUpdateTextures)
2195{
2196 int iPad=player->GetXboxPad();
2197 //OutputDebugString("Minecraft::tick\n");
2198
2199 //4J-PB - only tick this player's stats
2200 stats[iPad]->tick(iPad);
2201
2202 // Tick the opacity timer (to display the interface at default opacity for a certain time if the user has been navigating it)
2203 app.TickOpacityTimer(iPad);
2204
2205 // 4J added
2206 if( bFirst ) levelRenderer->destroyedTileManager->tick();
2207
2208 gui->tick();
2209 gameRenderer->pick(1);
2210#if 0
2211 // 4J - removed - we don't use ChunkCache anymore
2212 if (player != NULL)
2213 {
2214 ChunkSource *cs = level->getChunkSource();
2215 if (dynamic_cast<ChunkCache *>(cs) != NULL)
2216 {
2217 ChunkCache *spcc = (ChunkCache *)cs;
2218
2219 // 4J - there was also Mth::floors on these ints but that seems superfluous
2220 int xt = ((int) player->x) >> 4;
2221 int zt = ((int) player->z) >> 4;
2222 spcc->centerOn(xt, zt);
2223 }
2224 }
2225#endif
2226
2227 // soundEngine.playMusicTick();
2228
2229 if (!pause && level != NULL) gameMode->tick();
2230 MemSect(31);
2231 glBindTexture(GL_TEXTURE_2D, textures->loadTexture(TN_TERRAIN)); //L"/terrain.png"));
2232 MemSect(0);
2233 if( bFirst )
2234 {
2235 PIXBeginNamedEvent(0,"Texture tick");
2236 if (!pause) textures->tick(bUpdateTextures);
2237 PIXEndNamedEvent();
2238 }
2239
2240 /*
2241 * if (serverConnection != null && !(screen instanceof ErrorScreen)) {
2242 * if (!serverConnection.isConnected()) {
2243 * progressRenderer.progressStart("Connecting..");
2244 * progressRenderer.progressStagePercentage(0); } else {
2245 * serverConnection.tick(); serverConnection.sendPosition(player); } }
2246 */
2247 if (screen == NULL && player != NULL )
2248 {
2249 if (player->getHealth() <= 0 && !ui.GetMenuDisplayed(iPad) )
2250 {
2251 setScreen(NULL);
2252 }
2253 else if (player->isSleeping() && level != NULL && level->isClientSide)
2254 {
2255 // setScreen(new InBedChatScreen()); // 4J - TODO put back in
2256 }
2257 }
2258 else if (screen != NULL && (dynamic_cast<InBedChatScreen *>(screen)!=NULL) && !player->isSleeping())
2259 {
2260 setScreen(NULL);
2261 }
2262
2263 if (screen != NULL)
2264 {
2265 player->missTime = 10000;
2266 player->lastClickTick[0] = ticks + 10000;
2267 player->lastClickTick[1] = ticks + 10000;
2268 }
2269
2270 if (screen != NULL)
2271 {
2272 screen->updateEvents();
2273 if (screen != NULL)
2274 {
2275 screen->particles->tick();
2276 screen->tick();
2277 }
2278 }
2279
2280 if (screen == NULL && !ui.GetMenuDisplayed(iPad) )
2281 {
2282 // 4J-PB - add some tooltips if required
2283 int iA=-1, iB=-1, iX, iY=IDS_CONTROLS_INVENTORY, iLT=-1, iRT=-1, iLB=-1, iRB=-1, iLS=-1, iRS=-1;
2284
2285 if(player->abilities.instabuild)
2286 {
2287 iX=IDS_TOOLTIPS_CREATIVE;
2288 }
2289 else
2290 {
2291 iX=IDS_CONTROLS_CRAFTING;
2292 }
2293 // control scheme remapping can move the Action button, so we need to check this
2294 int *piAction;
2295 int *piJump;
2296 int *piUse;
2297 int *piAlt;
2298
2299 unsigned int uiAction = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_ACTION );
2300 unsigned int uiJump = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_JUMP );
2301 unsigned int uiUse = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_USE );
2302 unsigned int uiAlt = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal( iPad ) ,MINECRAFT_ACTION_SNEAK_TOGGLE );
2303
2304 // Also need to handle PS3 having swapped triggers/bumpers
2305 switch(uiAction)
2306 {
2307 case _360_JOY_BUTTON_RT:
2308 piAction=&iRT;
2309 break;
2310 case _360_JOY_BUTTON_LT:
2311 piAction=&iLT;
2312 break;
2313 case _360_JOY_BUTTON_LB:
2314 piAction=&iLB;
2315 break;
2316 case _360_JOY_BUTTON_RB:
2317 piAction=&iRB;
2318 break;
2319 case _360_JOY_BUTTON_A:
2320 default:
2321 piAction=&iA;
2322 break;
2323 }
2324
2325 switch(uiJump)
2326 {
2327 case _360_JOY_BUTTON_LT:
2328 piJump=&iLT;
2329 break;
2330 case _360_JOY_BUTTON_RT:
2331 piJump=&iRT;
2332 break;
2333 case _360_JOY_BUTTON_LB:
2334 piJump=&iLB;
2335 break;
2336 case _360_JOY_BUTTON_RB:
2337 piJump=&iRB;
2338 break;
2339 case _360_JOY_BUTTON_A:
2340 default:
2341 piJump=&iA;
2342 break;
2343 }
2344
2345 switch(uiUse)
2346 {
2347 case _360_JOY_BUTTON_LB:
2348 piUse=&iLB;
2349 break;
2350 case _360_JOY_BUTTON_RB:
2351 piUse=&iRB;
2352 break;
2353 case _360_JOY_BUTTON_LT:
2354 piUse=&iLT;
2355 break;
2356 case _360_JOY_BUTTON_RT:
2357 default:
2358 piUse=&iRT;
2359 break;
2360 }
2361
2362 switch(uiAlt)
2363 {
2364 default:
2365 case _360_JOY_BUTTON_LSTICK_RIGHT:
2366 piAlt=&iRS;
2367 break;
2368
2369 //TODO
2370 }
2371
2372 if (player->isUnderLiquid(Material::water))
2373 {
2374 *piJump=IDS_TOOLTIPS_SWIMUP;
2375 }
2376 else
2377 {
2378 *piJump=-1;
2379 }
2380
2381 *piUse=-1;
2382 *piAction=-1;
2383 *piAlt=-1;
2384
2385 // 4J-PB another special case for when the player is sleeping in a bed
2386 if (player->isSleeping() && (level != NULL) && level->isClientSide)
2387 {
2388 *piUse=IDS_TOOLTIPS_WAKEUP;
2389 }
2390 else
2391 {
2392 if (player->isRiding())
2393 {
2394 shared_ptr<Entity> mount = player->riding;
2395
2396 if ( mount->instanceof(eTYPE_MINECART) || mount->instanceof(eTYPE_BOAT) )
2397 {
2398 *piAlt = IDS_TOOLTIPS_EXIT;
2399 }
2400 else
2401 {
2402 *piAlt = IDS_TOOLTIPS_DISMOUNT;
2403 }
2404 }
2405
2406 // no hit result, but we may have something in our hand that we can do something with
2407 shared_ptr<ItemInstance> itemInstance = player->inventory->getSelected();
2408
2409 // 4J-JEV: Moved all this here to avoid having it in 3 different places.
2410 if (itemInstance)
2411 {
2412 // 4J-PB - very special case for boat and empty bucket and glass bottle and more
2413 bool bUseItem = gameMode->useItem(player, level, itemInstance, true);
2414
2415 switch (itemInstance->getItem()->id)
2416 {
2417 // food
2418 case Item::potatoBaked_Id:
2419 case Item::potato_Id:
2420 case Item::pumpkinPie_Id:
2421 case Item::potatoPoisonous_Id:
2422 case Item::carrotGolden_Id:
2423 case Item::carrots_Id:
2424 case Item::mushroomStew_Id:
2425 case Item::apple_Id:
2426 case Item::bread_Id:
2427 case Item::porkChop_raw_Id:
2428 case Item::porkChop_cooked_Id:
2429 case Item::apple_gold_Id:
2430 case Item::fish_raw_Id:
2431 case Item::fish_cooked_Id:
2432 case Item::cookie_Id:
2433 case Item::beef_cooked_Id:
2434 case Item::beef_raw_Id:
2435 case Item::chicken_cooked_Id:
2436 case Item::chicken_raw_Id:
2437 case Item::melon_Id:
2438 case Item::rotten_flesh_Id:
2439 case Item::spiderEye_Id:
2440 // Check that we are actually hungry so will eat this item
2441 {
2442 FoodItem *food = (FoodItem *)itemInstance->getItem();
2443 if (food != NULL && food->canEat(player))
2444 {
2445 *piUse=IDS_TOOLTIPS_EAT;
2446 }
2447 }
2448 break;
2449
2450 case Item::bucket_milk_Id:
2451 *piUse=IDS_TOOLTIPS_DRINK;
2452 break;
2453
2454 case Item::fishingRod_Id: // use
2455 case Item::emptyMap_Id:
2456 *piUse=IDS_TOOLTIPS_USE;
2457 break;
2458
2459 case Item::egg_Id: // throw
2460 case Item::snowBall_Id:
2461 *piUse=IDS_TOOLTIPS_THROW;
2462 break;
2463
2464 case Item::bow_Id: // draw or release
2465 if ( player->abilities.instabuild || player->inventory->hasResource(Item::arrow_Id) )
2466 {
2467 if (player->isUsingItem()) *piUse=IDS_TOOLTIPS_RELEASE_BOW;
2468 else *piUse=IDS_TOOLTIPS_DRAW_BOW;
2469 }
2470 break;
2471
2472 case Item::sword_wood_Id:
2473 case Item::sword_stone_Id:
2474 case Item::sword_iron_Id:
2475 case Item::sword_diamond_Id:
2476 case Item::sword_gold_Id:
2477 *piUse=IDS_TOOLTIPS_BLOCK;
2478 break;
2479
2480 case Item::bucket_empty_Id:
2481 case Item::glassBottle_Id:
2482 if (bUseItem) *piUse=IDS_TOOLTIPS_COLLECT;
2483 break;
2484
2485 case Item::bucket_lava_Id:
2486 case Item::bucket_water_Id:
2487 *piUse=IDS_TOOLTIPS_EMPTY;
2488 break;
2489
2490 case Item::boat_Id:
2491 case Tile::waterLily_Id:
2492 if (bUseItem) *piUse=IDS_TOOLTIPS_PLACE;
2493 break;
2494
2495 case Item::potion_Id:
2496 if (bUseItem)
2497 {
2498 if (MACRO_POTION_IS_SPLASH(itemInstance->getAuxValue())) *piUse=IDS_TOOLTIPS_THROW;
2499 else *piUse=IDS_TOOLTIPS_DRINK;
2500 }
2501 break;
2502
2503 case Item::enderPearl_Id:
2504 if (bUseItem) *piUse=IDS_TOOLTIPS_THROW;
2505 break;
2506
2507 case Item::eyeOfEnder_Id:
2508 // This will only work if there is a stronghold in this dimension
2509 if ( bUseItem && (level->dimension->id==0) && level->getLevelData()->getHasStronghold() )
2510 {
2511 *piUse=IDS_TOOLTIPS_THROW;
2512 }
2513 break;
2514
2515 case Item::expBottle_Id:
2516 if (bUseItem) *piUse=IDS_TOOLTIPS_THROW;
2517 break;
2518 }
2519 }
2520
2521 if (hitResult!=NULL)
2522 {
2523 switch(hitResult->type)
2524 {
2525 case HitResult::TILE:
2526 {
2527 int x,y,z;
2528 x=hitResult->x;
2529 y=hitResult->y;
2530 z=hitResult->z;
2531 int face = hitResult->f;
2532
2533 int iTileID=level->getTile(x,y ,z );
2534 int iData = level->getData(x, y, z);
2535
2536 if( gameMode != NULL && gameMode->getTutorial() != NULL )
2537 {
2538 // 4J Stu - For the tutorial we want to be able to record what items we look at so that we can give hints
2539 gameMode->getTutorial()->onLookAt(iTileID,iData);
2540 }
2541
2542 // 4J-PB - Call the useItemOn with the TestOnly flag set
2543 bool bUseItemOn=gameMode->useItemOn(player, level, itemInstance, x, y, z, face, hitResult->pos, true);
2544
2545 /* 4J-Jev:
2546 * Moved this here so we have item tooltips to fallback on
2547 * for noteblocks, enderportals and flowerpots in case of non-standard items.
2548 * (ie. ignite behaviour)
2549 */
2550 if (bUseItemOn && itemInstance!=NULL)
2551 {
2552 switch (itemInstance->getItem()->id)
2553 {
2554 case Tile::mushroom_brown_Id:
2555 case Tile::mushroom_red_Id:
2556 case Tile::tallgrass_Id:
2557 case Tile::cactus_Id:
2558 case Tile::sapling_Id:
2559 case Tile::reeds_Id:
2560 case Tile::flower_Id:
2561 case Tile::rose_Id:
2562 *piUse=IDS_TOOLTIPS_PLANT;
2563 break;
2564
2565 // Things to USE
2566 case Item::hoe_wood_Id:
2567 case Item::hoe_stone_Id:
2568 case Item::hoe_iron_Id:
2569 case Item::hoe_diamond_Id:
2570 case Item::hoe_gold_Id:
2571 *piUse=IDS_TOOLTIPS_TILL;
2572 break;
2573
2574 case Item::seeds_wheat_Id:
2575 case Item::netherwart_seeds_Id:
2576 *piUse=IDS_TOOLTIPS_PLANT;
2577 break;
2578
2579 case Item::dye_powder_Id:
2580 // bonemeal grows various plants
2581 if (itemInstance->getAuxValue() == DyePowderItem::WHITE)
2582 {
2583 switch(iTileID)
2584 {
2585 case Tile::sapling_Id:
2586 case Tile::wheat_Id:
2587 case Tile::grass_Id:
2588 case Tile::mushroom_brown_Id:
2589 case Tile::mushroom_red_Id:
2590 case Tile::melonStem_Id:
2591 case Tile::pumpkinStem_Id:
2592 case Tile::carrots_Id:
2593 case Tile::potatoes_Id:
2594 *piUse=IDS_TOOLTIPS_GROW;
2595 break;
2596 }
2597 }
2598 break;
2599
2600 case Item::painting_Id:
2601 *piUse=IDS_TOOLTIPS_HANG;
2602 break;
2603
2604 case Item::flintAndSteel_Id:
2605 case Item::fireball_Id:
2606 *piUse=IDS_TOOLTIPS_IGNITE;
2607 break;
2608
2609 case Item::fireworks_Id:
2610 *piUse=IDS_TOOLTIPS_FIREWORK_LAUNCH;
2611 break;
2612
2613 case Item::lead_Id:
2614 *piUse=IDS_TOOLTIPS_ATTACH;
2615 break;
2616
2617 default:
2618 *piUse=IDS_TOOLTIPS_PLACE;
2619 break;
2620 }
2621 }
2622
2623 switch(iTileID)
2624 {
2625 case Tile::anvil_Id:
2626 case Tile::enchantTable_Id:
2627 case Tile::brewingStand_Id:
2628 case Tile::workBench_Id:
2629 case Tile::furnace_Id:
2630 case Tile::furnace_lit_Id:
2631 case Tile::door_wood_Id:
2632 case Tile::dispenser_Id:
2633 case Tile::lever_Id:
2634 case Tile::button_stone_Id:
2635 case Tile::button_wood_Id:
2636 case Tile::trapdoor_Id:
2637 case Tile::fenceGate_Id:
2638 case Tile::beacon_Id:
2639 *piAction=IDS_TOOLTIPS_MINE;
2640 *piUse=IDS_TOOLTIPS_USE;
2641 break;
2642
2643 case Tile::chest_Id:
2644 *piAction = IDS_TOOLTIPS_MINE;
2645 *piUse = (Tile::chest->getContainer(level,x,y,z) != NULL) ? IDS_TOOLTIPS_OPEN : -1;
2646 break;
2647
2648 case Tile::enderChest_Id:
2649 case Tile::chest_trap_Id:
2650 case Tile::dropper_Id:
2651 case Tile::hopper_Id:
2652 *piUse=IDS_TOOLTIPS_OPEN;
2653 *piAction=IDS_TOOLTIPS_MINE;
2654 break;
2655
2656 case Tile::activatorRail_Id:
2657 case Tile::goldenRail_Id:
2658 case Tile::detectorRail_Id:
2659 case Tile::rail_Id:
2660 if (bUseItemOn) *piUse=IDS_TOOLTIPS_PLACE;
2661 *piAction=IDS_TOOLTIPS_MINE;
2662 break;
2663
2664 case Tile::bed_Id:
2665 if (bUseItemOn) *piUse=IDS_TOOLTIPS_SLEEP;
2666 *piAction=IDS_TOOLTIPS_MINE;
2667 break;
2668
2669 case Tile::noteblock_Id:
2670 // if in creative mode, we will mine
2671 if (player->abilities.instabuild) *piAction=IDS_TOOLTIPS_MINE;
2672 else *piAction=IDS_TOOLTIPS_PLAY;
2673 *piUse=IDS_TOOLTIPS_CHANGEPITCH;
2674 break;
2675
2676 case Tile::sign_Id:
2677 *piAction=IDS_TOOLTIPS_MINE;
2678 break;
2679
2680 case Tile::cauldron_Id:
2681 // special case for a cauldron of water and an empty bottle
2682 if (itemInstance)
2683 {
2684 int iID=itemInstance->getItem()->id;
2685 int currentData = level->getData(x, y, z);
2686 if ((iID==Item::glassBottle_Id) && (currentData > 0))
2687 {
2688 *piUse=IDS_TOOLTIPS_COLLECT;
2689 }
2690 }
2691 *piAction=IDS_TOOLTIPS_MINE;
2692 break;
2693
2694 case Tile::cake_Id:
2695 if (player->abilities.instabuild) // if in creative mode, we will mine
2696 {
2697 *piAction=IDS_TOOLTIPS_MINE;
2698 }
2699 else
2700 {
2701 if (player->getFoodData()->needsFood() ) // 4J-JEV: Changed from healthto hunger.
2702 {
2703 *piAction=IDS_TOOLTIPS_EAT;
2704 *piUse=IDS_TOOLTIPS_EAT;
2705 }
2706 else
2707 {
2708 *piAction=IDS_TOOLTIPS_MINE;
2709 }
2710 }
2711 break;
2712
2713 case Tile::jukebox_Id:
2714 if (!bUseItemOn && itemInstance!=NULL)
2715 {
2716 int iID=itemInstance->getItem()->id;
2717 if ( (iID>=Item::record_01_Id) && (iID<=Item::record_12_Id) )
2718 {
2719 *piUse=IDS_TOOLTIPS_PLAY;
2720 }
2721 *piAction=IDS_TOOLTIPS_MINE;
2722 }
2723 else
2724 {
2725 if (Tile::jukebox->TestUse(level, x, y, z, player)) // means we can eject
2726 {
2727 *piUse=IDS_TOOLTIPS_EJECT;
2728 }
2729 *piAction=IDS_TOOLTIPS_MINE;
2730 }
2731 break;
2732
2733 case Tile::flowerPot_Id:
2734 if ( !bUseItemOn && (itemInstance != NULL) && (iData == 0) )
2735 {
2736 int iID = itemInstance->getItem()->id;
2737 if (iID<256) // is it a tile?
2738 {
2739 switch(iID)
2740 {
2741 case Tile::flower_Id:
2742 case Tile::rose_Id:
2743 case Tile::sapling_Id:
2744 case Tile::mushroom_brown_Id:
2745 case Tile::mushroom_red_Id:
2746 case Tile::cactus_Id:
2747 case Tile::deadBush_Id:
2748 *piUse=IDS_TOOLTIPS_PLANT;
2749 break;
2750
2751 case Tile::tallgrass_Id:
2752 if (itemInstance->getAuxValue() != TallGrass::TALL_GRASS) *piUse=IDS_TOOLTIPS_PLANT;
2753 break;
2754 }
2755 }
2756 }
2757 *piAction=IDS_TOOLTIPS_MINE;
2758 break;
2759
2760 case Tile::comparator_off_Id:
2761 case Tile::comparator_on_Id:
2762 *piUse=IDS_TOOLTIPS_USE;
2763 *piAction=IDS_TOOLTIPS_MINE;
2764 break;
2765
2766 case Tile::diode_off_Id:
2767 case Tile::diode_on_Id:
2768 *piUse=IDS_TOOLTIPS_USE;
2769 *piAction=IDS_TOOLTIPS_MINE;
2770 break;
2771
2772 case Tile::redStoneOre_Id:
2773 if (bUseItemOn) *piUse=IDS_TOOLTIPS_USE;
2774 *piAction=IDS_TOOLTIPS_MINE;
2775 break;
2776
2777 case Tile::door_iron_Id:
2778 if(*piUse==IDS_TOOLTIPS_PLACE)
2779 {
2780 *piUse = -1;
2781 }
2782 *piAction=IDS_TOOLTIPS_MINE;
2783 break;
2784
2785 default:
2786 *piAction=IDS_TOOLTIPS_MINE;
2787 break;
2788 }
2789 }
2790 break;
2791
2792 case HitResult::ENTITY:
2793 eINSTANCEOF entityType = hitResult->entity->GetType();
2794
2795 if ( (gameMode != NULL) && (gameMode->getTutorial() != NULL) )
2796 {
2797 // 4J Stu - For the tutorial we want to be able to record what items we look at so that we can give hints
2798 gameMode->getTutorial()->onLookAtEntity(hitResult->entity);
2799 }
2800
2801 shared_ptr<ItemInstance> heldItem = nullptr;
2802 if (player->inventory->IsHeldItem())
2803 {
2804 heldItem = player->inventory->getSelected();
2805 }
2806 int heldItemId = heldItem != NULL ? heldItem->getItem()->id : -1;
2807
2808 switch(entityType)
2809 {
2810 case eTYPE_CHICKEN:
2811 {
2812 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
2813
2814 shared_ptr<Animal> animal = dynamic_pointer_cast<Animal>(hitResult->entity);
2815
2816 if (animal->isLeashed() && animal->getLeashHolder() == player)
2817 {
2818 *piUse=IDS_TOOLTIPS_UNLEASH;
2819 break;
2820 }
2821
2822 switch(heldItemId)
2823 {
2824 case Item::nameTag_Id:
2825 *piUse=IDS_TOOLTIPS_NAME;
2826 break;
2827
2828 case Item::lead_Id:
2829 if (!animal->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
2830 break;
2831
2832 default:
2833 {
2834 if(!animal->isBaby() && !animal->isInLove() && (animal->getAge() == 0) && animal->isFood(heldItem))
2835 {
2836 *piUse=IDS_TOOLTIPS_LOVEMODE;
2837 }
2838 }
2839 break;
2840
2841 case -1: break; // 4J-JEV: Empty hand.
2842 }
2843 }
2844 break;
2845
2846 case eTYPE_COW:
2847 {
2848 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
2849
2850 shared_ptr<Animal> animal = dynamic_pointer_cast<Animal>(hitResult->entity);
2851
2852 if (animal->isLeashed() && animal->getLeashHolder() == player)
2853 {
2854 *piUse=IDS_TOOLTIPS_UNLEASH;
2855 break;
2856 }
2857
2858 switch (heldItemId)
2859 {
2860 // Things to USE
2861 case Item::nameTag_Id:
2862 *piUse=IDS_TOOLTIPS_NAME;
2863 break;
2864 case Item::lead_Id:
2865 if (!animal->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
2866 break;
2867 case Item::bucket_empty_Id:
2868 *piUse=IDS_TOOLTIPS_MILK;
2869 break;
2870 default:
2871 {
2872 if(!animal->isBaby() && !animal->isInLove() && (animal->getAge() == 0) && animal->isFood(heldItem))
2873 {
2874 *piUse=IDS_TOOLTIPS_LOVEMODE;
2875 }
2876 }
2877 break;
2878
2879 case -1: break; // 4J-JEV: Empty hand.
2880 }
2881 }
2882 break;
2883 case eTYPE_MUSHROOMCOW:
2884 {
2885 // 4J-PB - Fix for #13081 - No tooltip is displayed for hitting a cow when you have nothing in your hand
2886 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
2887
2888 shared_ptr<Animal> animal = dynamic_pointer_cast<Animal>(hitResult->entity);
2889
2890 if (animal->isLeashed() && animal->getLeashHolder() == player)
2891 {
2892 *piUse=IDS_TOOLTIPS_UNLEASH;
2893 break;
2894 }
2895
2896 // It's an item
2897 switch(heldItemId)
2898 {
2899 // Things to USE
2900 case Item::nameTag_Id:
2901 *piUse=IDS_TOOLTIPS_NAME;
2902 break;
2903
2904 case Item::lead_Id:
2905 if (!animal->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
2906 break;
2907
2908 case Item::bowl_Id:
2909 case Item::bucket_empty_Id: // You can milk a mooshroom with either a bowl (mushroom soup) or a bucket (milk)!
2910 *piUse=IDS_TOOLTIPS_MILK;
2911 break;
2912 case Item::shears_Id:
2913 {
2914 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
2915 if(!animal->isBaby()) *piUse=IDS_TOOLTIPS_SHEAR;
2916 }
2917 break;
2918 default:
2919 {
2920 if(!animal->isBaby() && !animal->isInLove() && (animal->getAge() == 0) && animal->isFood(heldItem))
2921 {
2922 *piUse=IDS_TOOLTIPS_LOVEMODE;
2923 }
2924 }
2925 break;
2926
2927 case -1: break; // 4J-JEV: Empty hand.
2928 }
2929 }
2930 break;
2931
2932 case eTYPE_BOAT:
2933 *piAction=IDS_TOOLTIPS_MINE;
2934 *piUse=IDS_TOOLTIPS_SAIL;
2935 break;
2936
2937 case eTYPE_MINECART_RIDEABLE:
2938 *piAction = IDS_TOOLTIPS_MINE;
2939 *piUse = IDS_TOOLTIPS_RIDE; // are we in the minecart already? - 4J-JEV: Doesn't matter anymore.
2940 break;
2941
2942 case eTYPE_MINECART_FURNACE:
2943 *piAction = IDS_TOOLTIPS_MINE;
2944
2945 // if you have coal, it'll go. Is there an object in hand?
2946 if (heldItemId == Item::coal_Id) *piUse=IDS_TOOLTIPS_USE;
2947 break;
2948
2949 case eTYPE_MINECART_CHEST:
2950 case eTYPE_MINECART_HOPPER:
2951 *piAction = IDS_TOOLTIPS_MINE;
2952 *piUse = IDS_TOOLTIPS_OPEN;
2953 break;
2954
2955 case eTYPE_MINECART_SPAWNER:
2956 case eTYPE_MINECART_TNT:
2957 *piUse = IDS_TOOLTIPS_MINE;
2958 break;
2959
2960 case eTYPE_SHEEP:
2961 {
2962 // can dye a sheep
2963 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
2964
2965 shared_ptr<Sheep> sheep = dynamic_pointer_cast<Sheep>(hitResult->entity);
2966
2967 if (sheep->isLeashed() && sheep->getLeashHolder() == player)
2968 {
2969 *piUse=IDS_TOOLTIPS_UNLEASH;
2970 break;
2971 }
2972
2973 switch(heldItemId)
2974 {
2975 case Item::nameTag_Id:
2976 *piUse=IDS_TOOLTIPS_NAME;
2977 break;
2978
2979 case Item::lead_Id:
2980 if (!sheep->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
2981 break;
2982
2983 case Item::dye_powder_Id:
2984 {
2985 // convert to tile-based color value (0 is white instead of black)
2986 int newColor = ColoredTile::getTileDataForItemAuxValue(heldItem->getAuxValue());
2987
2988 // can only use a dye on sheep that haven't been sheared
2989 if(!(sheep->isSheared() && sheep->getColor() != newColor))
2990 {
2991 *piUse=IDS_TOOLTIPS_DYE;
2992 }
2993 }
2994 break;
2995 case Item::shears_Id:
2996 {
2997 // can only shear a sheep that hasn't been sheared
2998 if ( !sheep->isBaby() && !sheep->isSheared() )
2999 {
3000 *piUse=IDS_TOOLTIPS_SHEAR;
3001 }
3002 }
3003
3004 break;
3005 default:
3006 {
3007 if(!sheep->isBaby() && !sheep->isInLove() && (sheep->getAge() == 0) && sheep->isFood(heldItem))
3008 {
3009 *piUse=IDS_TOOLTIPS_LOVEMODE;
3010 }
3011 }
3012 break;
3013
3014 case -1: break; // 4J-JEV: Empty hand.
3015 }
3016 }
3017 break;
3018
3019 case eTYPE_PIG:
3020 {
3021 // can ride a pig
3022 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
3023
3024 shared_ptr<Pig> pig = dynamic_pointer_cast<Pig>(hitResult->entity);
3025
3026 if (pig->isLeashed() && pig->getLeashHolder() == player)
3027 {
3028 *piUse=IDS_TOOLTIPS_UNLEASH;
3029 }
3030 else if (heldItemId == Item::lead_Id)
3031 {
3032 if (!pig->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
3033 }
3034 else if (heldItemId == Item::nameTag_Id)
3035 {
3036 *piUse = IDS_TOOLTIPS_NAME;
3037 }
3038 else if (pig->hasSaddle()) // does the pig have a saddle?
3039 {
3040 *piUse=IDS_TOOLTIPS_MOUNT;
3041 }
3042 else if (!pig->isBaby())
3043 {
3044 if(player->inventory->IsHeldItem())
3045 {
3046 switch(heldItemId)
3047 {
3048 case Item::saddle_Id:
3049 *piUse=IDS_TOOLTIPS_SADDLE;
3050 break;
3051
3052 default:
3053 {
3054 if (!pig->isInLove() && (pig->getAge() == 0) && pig->isFood(heldItem))
3055 {
3056 *piUse=IDS_TOOLTIPS_LOVEMODE;
3057 }
3058 }
3059 break;
3060 }
3061 }
3062 }
3063 }
3064 break;
3065
3066 case eTYPE_WOLF:
3067 // can be tamed, fed, and made to sit/stand, or enter love mode
3068 {
3069 shared_ptr<Wolf> wolf = dynamic_pointer_cast<Wolf>(hitResult->entity);
3070
3071 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
3072
3073 if (wolf->isLeashed() && wolf->getLeashHolder() == player)
3074 {
3075 *piUse=IDS_TOOLTIPS_UNLEASH;
3076 break;
3077 }
3078
3079 switch(heldItemId)
3080 {
3081 case Item::nameTag_Id:
3082 *piUse=IDS_TOOLTIPS_NAME;
3083 break;
3084
3085 case Item::lead_Id:
3086 if (!wolf->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
3087 break;
3088
3089 case Item::bone_Id:
3090 if (!wolf->isAngry() && !wolf->isTame())
3091 {
3092 *piUse=IDS_TOOLTIPS_TAME;
3093 }
3094 else if (equalsIgnoreCase(player->getUUID(), wolf->getOwnerUUID()))
3095 {
3096 if(wolf->isSitting())
3097 {
3098 *piUse=IDS_TOOLTIPS_FOLLOWME;
3099 }
3100 else
3101 {
3102 *piUse=IDS_TOOLTIPS_SIT;
3103 }
3104 }
3105
3106 break;
3107 case Item::enderPearl_Id:
3108 // Use is throw, so don't change the tips for the wolf
3109 break;
3110 case Item::dye_powder_Id:
3111 if (wolf->isTame())
3112 {
3113 if (ColoredTile::getTileDataForItemAuxValue(heldItem->getAuxValue()) != wolf->getCollarColor())
3114 {
3115 *piUse=IDS_TOOLTIPS_DYECOLLAR;
3116 }
3117 else if (wolf->isSitting())
3118 {
3119 *piUse=IDS_TOOLTIPS_FOLLOWME;
3120 }
3121 else
3122 {
3123 *piUse=IDS_TOOLTIPS_SIT;
3124 }
3125 }
3126 break;
3127 default:
3128 if(wolf->isTame())
3129 {
3130 if(wolf->isFood(heldItem))
3131 {
3132 if(wolf->GetSynchedHealth() < wolf->getMaxHealth())
3133 {
3134 *piUse=IDS_TOOLTIPS_HEAL;
3135 }
3136 else
3137 {
3138 if(!wolf->isBaby() && !wolf->isInLove() && (wolf->getAge() == 0))
3139 {
3140 *piUse=IDS_TOOLTIPS_LOVEMODE;
3141 }
3142 }
3143 // break out here
3144 break;
3145 }
3146
3147 if (equalsIgnoreCase(player->getUUID(), wolf->getOwnerUUID()))
3148 {
3149 if(wolf->isSitting())
3150 {
3151 *piUse=IDS_TOOLTIPS_FOLLOWME;
3152 }
3153 else
3154 {
3155 *piUse=IDS_TOOLTIPS_SIT;
3156 }
3157 }
3158 }
3159 break;
3160 }
3161 }
3162 break;
3163 case eTYPE_OCELOT:
3164 {
3165 shared_ptr<Ocelot> ocelot = dynamic_pointer_cast<Ocelot>(hitResult->entity);
3166
3167 if(player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
3168
3169 if (ocelot->isLeashed() && ocelot->getLeashHolder() == player)
3170 {
3171 *piUse = IDS_TOOLTIPS_UNLEASH;
3172 }
3173 else if (heldItemId == Item::lead_Id)
3174 {
3175 if (!ocelot->isLeashed()) *piUse = IDS_TOOLTIPS_LEASH;
3176 }
3177 else if (heldItemId == Item::nameTag_Id)
3178 {
3179 *piUse = IDS_TOOLTIPS_NAME;
3180 }
3181 else if(ocelot->isTame())
3182 {
3183 // 4J-PB - if you have a raw fish in your hand, you will feed the ocelot rather than have it sit/follow
3184 if(ocelot->isFood(heldItem))
3185 {
3186 if(!ocelot->isBaby())
3187 {
3188 if(!ocelot->isInLove())
3189 {
3190 if(ocelot->getAge() == 0)
3191 {
3192 *piUse=IDS_TOOLTIPS_LOVEMODE;
3193 }
3194 }
3195 else
3196 {
3197 *piUse=IDS_TOOLTIPS_FEED;
3198 }
3199 }
3200
3201 }
3202 else if (equalsIgnoreCase(player->getUUID(), ocelot->getOwnerUUID()) && !ocelot->isSittingOnTile() )
3203 {
3204 if(ocelot->isSitting())
3205 {
3206 *piUse=IDS_TOOLTIPS_FOLLOWME;
3207 }
3208 else
3209 {
3210 *piUse=IDS_TOOLTIPS_SIT;
3211 }
3212 }
3213 }
3214 else if(heldItemId >= 0)
3215 {
3216 if (ocelot->isFood(heldItem)) *piUse=IDS_TOOLTIPS_TAME;
3217 }
3218 }
3219 break;
3220
3221 case eTYPE_PLAYER:
3222 {
3223 // Fix for #58576 - TU6: Content: Gameplay: Hit button prompt is available when attacking a host who has "Invisible" option turned on
3224 shared_ptr<Player> TargetPlayer = dynamic_pointer_cast<Player>(hitResult->entity);
3225
3226 if(!TargetPlayer->hasInvisiblePrivilege()) // This means they are invisible, not just that they have the privilege
3227 {
3228 if( app.GetGameHostOption(eGameHostOption_PvP) && player->isAllowedToAttackPlayers())
3229 {
3230 *piAction=IDS_TOOLTIPS_HIT;
3231 }
3232 }
3233 }
3234 break;
3235
3236 case eTYPE_ITEM_FRAME:
3237 {
3238 shared_ptr<ItemFrame> itemFrame = dynamic_pointer_cast<ItemFrame>(hitResult->entity);
3239
3240 // is the frame occupied?
3241 if(itemFrame->getItem()!=NULL)
3242 {
3243 // rotate the item
3244 *piUse=IDS_TOOLTIPS_ROTATE;
3245 }
3246 else
3247 {
3248 // is there an object in hand?
3249 if(heldItemId >= 0) *piUse=IDS_TOOLTIPS_PLACE;
3250 }
3251
3252 *piAction=IDS_TOOLTIPS_HIT;
3253 }
3254 break;
3255
3256 case eTYPE_VILLAGER:
3257 {
3258 // 4J-JEV: Cannot leash villagers.
3259
3260 shared_ptr<Villager> villager = dynamic_pointer_cast<Villager>(hitResult->entity);
3261 if (!villager->isBaby())
3262 {
3263 *piUse=IDS_TOOLTIPS_TRADE;
3264 }
3265 *piAction=IDS_TOOLTIPS_HIT;
3266 }
3267 break;
3268
3269 case eTYPE_ZOMBIE:
3270 {
3271 shared_ptr<Zombie> zomb = dynamic_pointer_cast<Zombie>(hitResult->entity);
3272 static GoldenAppleItem *goldapple = (GoldenAppleItem *) Item::apple_gold;
3273
3274 //zomb->hasEffect(MobEffect::weakness) - not present on client.
3275 if ( zomb->isVillager() && zomb->isWeakened() && (heldItemId == Item::apple_gold_Id) && !goldapple->isFoil(heldItem) )
3276 {
3277 *piUse=IDS_TOOLTIPS_CURE;
3278 }
3279 *piAction=IDS_TOOLTIPS_HIT;
3280 }
3281 break;
3282
3283 case eTYPE_HORSE:
3284 {
3285 shared_ptr<EntityHorse> horse = dynamic_pointer_cast<EntityHorse>(hitResult->entity);
3286
3287 bool heldItemIsFood = false, heldItemIsLove = false, heldItemIsArmour = false;
3288
3289 switch( heldItemId )
3290 {
3291 case Item::wheat_Id:
3292 case Item::sugar_Id:
3293 case Item::bread_Id:
3294 case Tile::hayBlock_Id:
3295 case Item::apple_Id:
3296 heldItemIsFood = true;
3297 break;
3298 case Item::carrotGolden_Id:
3299 case Item::apple_gold_Id:
3300 heldItemIsLove = true;
3301 heldItemIsFood = true;
3302 break;
3303 case Item::horseArmorDiamond_Id:
3304 case Item::horseArmorGold_Id:
3305 case Item::horseArmorMetal_Id:
3306 heldItemIsArmour = true;
3307 break;
3308 }
3309
3310 if (horse->isLeashed() && horse->getLeashHolder() == player)
3311 {
3312 *piUse=IDS_TOOLTIPS_UNLEASH;
3313 }
3314 else if ( heldItemId == Item::lead_Id)
3315 {
3316 if (!horse->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
3317 }
3318 else if (heldItemId == Item::nameTag_Id)
3319 {
3320 *piUse = IDS_TOOLTIPS_NAME;
3321 }
3322 else if (horse->isBaby()) // 4J-JEV: Can't ride baby horses due to morals.
3323 {
3324 if (heldItemIsFood)
3325 {
3326 // 4j - Can feed foles to speed growth.
3327 *piUse = IDS_TOOLTIPS_FEED;
3328 }
3329 }
3330 else if ( !horse->isTamed() )
3331 {
3332 if (heldItemId == -1)
3333 {
3334 // 4j - Player not holding anything, ride and attempt to break untamed horse.
3335 *piUse = IDS_TOOLTIPS_TAME;
3336 }
3337 else if (heldItemIsFood)
3338 {
3339 // 4j - Attempt to make it like you more by feeding it.
3340 *piUse = IDS_TOOLTIPS_FEED;
3341 }
3342 }
3343 else if ( player->isSneaking()
3344 || (heldItemId == Item::saddle_Id)
3345 || (horse->canWearArmor() && heldItemIsArmour)
3346 )
3347 {
3348 // 4j - Access horses inventory
3349 if (*piUse == -1) *piUse = IDS_TOOLTIPS_OPEN;
3350 }
3351 else if ( horse->canWearBags()
3352 && !horse->isChestedHorse()
3353 && (heldItemId == Tile::chest_Id) )
3354 {
3355 // 4j - Attach saddle-bags (chest) to donkey or mule.
3356 *piUse = IDS_TOOLTIPS_ATTACH;
3357 }
3358 else if ( horse->isReadyForParenting()
3359 && heldItemIsLove )
3360 {
3361 // 4j - Different food to mate horses.
3362 *piUse = IDS_TOOLTIPS_LOVEMODE;
3363 }
3364 else if ( heldItemIsFood && (horse->getHealth() < horse->getMaxHealth()) )
3365 {
3366 // 4j - Horse is damaged and can eat held item to heal
3367 *piUse = IDS_TOOLTIPS_HEAL;
3368 }
3369 else
3370 {
3371 // 4j - Ride tamed horse.
3372 *piUse = IDS_TOOLTIPS_MOUNT;
3373 }
3374
3375 if (player->isAllowedToAttackAnimals()) *piAction=IDS_TOOLTIPS_HIT;
3376 }
3377 break;
3378
3379 case eTYPE_ENDERDRAGON:
3380 // 4J-JEV: Enderdragon cannot be named.
3381 *piAction = IDS_TOOLTIPS_HIT;
3382 break;
3383
3384 case eTYPE_LEASHFENCEKNOT:
3385 *piAction = IDS_TOOLTIPS_UNLEASH;
3386 if (heldItemId == Item::lead_Id && LeashItem::bindPlayerMobsTest(player, level, player->x, player->y, player->z))
3387 {
3388 *piUse = IDS_TOOLTIPS_ATTACH;
3389 }
3390 else
3391 {
3392 *piUse = IDS_TOOLTIPS_UNLEASH;
3393 }
3394 break;
3395
3396 default:
3397 if ( hitResult->entity->instanceof(eTYPE_MOB) )
3398 {
3399 shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(hitResult->entity);
3400 if (mob->isLeashed() && mob->getLeashHolder() == player)
3401 {
3402 *piUse=IDS_TOOLTIPS_UNLEASH;
3403 }
3404 else if (heldItemId == Item::lead_Id)
3405 {
3406 if (!mob->isLeashed()) *piUse=IDS_TOOLTIPS_LEASH;
3407 }
3408 else if (heldItemId == Item::nameTag_Id)
3409 {
3410 *piUse=IDS_TOOLTIPS_NAME;
3411 }
3412 }
3413 *piAction=IDS_TOOLTIPS_HIT;
3414 break;
3415 }
3416 break;
3417 }
3418 }
3419 }
3420
3421 // 4J-JEV: Don't set tooltips when we're reloading the skin, it'll crash.
3422 if (!ui.IsReloadingSkin()) ui.SetTooltips( iPad, iA, iB, iX, iY, iLT, iRT, iLB, iRB, iLS, iRS);
3423
3424 int wheel = 0;
3425 if (InputManager.GetValue(iPad, MINECRAFT_ACTION_LEFT_SCROLL, true) > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL) )
3426 {
3427 wheel = 1;
3428 }
3429 else if (InputManager.GetValue(iPad, MINECRAFT_ACTION_RIGHT_SCROLL,true) > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_RIGHT_SCROLL) )
3430 {
3431 wheel = -1;
3432 }
3433
3434#ifdef _WINDOWS64
3435 // Mouse scroll wheel for hotbar
3436 if (iPad == 0)
3437 {
3438 int kbWheel = KMInput.ConsumeScrollDelta();
3439 if (kbWheel > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL)) wheel += 1;
3440 else if (kbWheel < 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_RIGHT_SCROLL)) wheel -= 1;
3441
3442 // 1-9 keys for direct hotbar selection
3443 if (gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL))
3444 {
3445 for (int k = '1'; k <= '9'; k++)
3446 {
3447 if (KMInput.ConsumeKeyPress(k))
3448 {
3449 player->inventory->selected = k - '1';
3450 app.SetOpacityTimer(iPad);
3451 break;
3452 }
3453 }
3454 }
3455 }
3456#endif
3457 if (wheel != 0)
3458 {
3459 player->inventory->swapPaint(wheel);
3460
3461 if( gameMode != NULL && gameMode->getTutorial() != NULL )
3462 {
3463 // 4J Stu - For the tutorial we want to be able to record what items we are using so that we can give hints
3464 gameMode->getTutorial()->onSelectedItemChanged(player->inventory->getSelected());
3465 }
3466
3467 // Update presence
3468 player->updateRichPresence();
3469
3470 if (options->isFlying)
3471 {
3472 if (wheel > 0) wheel = 1;
3473 if (wheel < 0) wheel = -1;
3474
3475 options->flySpeed += wheel * .25f;
3476 }
3477 }
3478
3479 if( gameMode->isInputAllowed(MINECRAFT_ACTION_ACTION) )
3480 {
3481 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_ACTION)))
3482 //if(InputManager.ButtonPressed(iPad, MINECRAFT_ACTION_ACTION) )
3483 {
3484 //printf("MINECRAFT_ACTION_ACTION ButtonPressed");
3485 player->handleMouseClick(0);
3486 player->lastClickTick[0] = ticks;
3487 }
3488#ifdef _WINDOWS64
3489 else if (iPad == 0 && KMInput.IsCaptured() && KMInput.ConsumeMousePress(0))
3490 {
3491 player->handleMouseClick(0);
3492 player->lastClickTick[0] = ticks;
3493 }
3494#endif
3495
3496 if (InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION) && ticks - player->lastClickTick[0] >= timer->ticksPerSecond / 4)
3497 {
3498 //printf("MINECRAFT_ACTION_ACTION ButtonDown");
3499 player->handleMouseClick(0);
3500 player->lastClickTick[0] = ticks;
3501 }
3502#ifdef _WINDOWS64
3503 else if (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(0) && ticks - player->lastClickTick[0] >= timer->ticksPerSecond / 4)
3504 {
3505 player->handleMouseClick(0);
3506 player->lastClickTick[0] = ticks;
3507 }
3508#endif
3509
3510 if(InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION)
3511#ifdef _WINDOWS64
3512 || (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(0))
3513#endif
3514 )
3515 {
3516 player->handleMouseDown(0, true );
3517 }
3518 else
3519 {
3520 player->handleMouseDown(0, false );
3521 }
3522 }
3523
3524 // 4J Stu - This is how we used to handle the USE action. It has now been replaced with the block below which is more like the way the Java game does it,
3525 // however we may find that the way we had it previously is more fun to play.
3526 /*
3527 if ((InputManager.GetValue(iPad, MINECRAFT_ACTION_USE,true)>0) && gameMode->isInputAllowed(MINECRAFT_ACTION_USE) )
3528 {
3529 handleMouseClick(1);
3530 lastClickTick = ticks;
3531 }
3532 */
3533 if( player->isUsingItem() )
3534 {
3535 if(!InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE)
3536#ifdef _WINDOWS64
3537 && !(iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(1))
3538#endif
3539 ) gameMode->releaseUsingItem(player);
3540 }
3541 else if( gameMode->isInputAllowed(MINECRAFT_ACTION_USE) )
3542 {
3543#ifdef _WINDOWS64
3544 bool useButtonDown = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE) || (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(1));
3545#else
3546 bool useButtonDown = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE);
3547#endif
3548 if( player->abilities.instabuild )
3549 {
3550 // 4J - attempt to handle click in special creative mode fashion if possible (used for placing blocks at regular intervals)
3551 bool didClick = player->creativeModeHandleMouseClick(1, useButtonDown );
3552 // If this handler has put us in lastClick_oldRepeat mode then it is because we aren't placing blocks - behave largely as the code used to
3553 if( player->lastClickState == LocalPlayer::lastClick_oldRepeat )
3554 {
3555 // If we've already handled the click in creativeModeHandleMouseClick then just record the time of this click
3556 if( didClick )
3557 {
3558 player->lastClickTick[1] = ticks;
3559 }
3560 else
3561 {
3562 // Otherwise just the original game code for handling autorepeat
3563 if (useButtonDown && ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4)
3564 {
3565 player->handleMouseClick(1);
3566 player->lastClickTick[1] = ticks;
3567 }
3568 }
3569 }
3570 }
3571 else
3572 {
3573 // Consider as a click if we've had a period of not pressing the button, or we've reached auto-repeat time since the last time
3574 // Auto-repeat is only considered if we aren't riding or sprinting, to avoid photo sensitivity issues when placing fire whilst doing fast things
3575 // Also disable repeat when the player is sleeping to stop the waking up right after using the bed
3576 bool firstClick = ( player->lastClickTick[1] == 0 );
3577 bool autoRepeat = ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4;
3578 if ( player->isRiding() || player->isSprinting() || player->isSleeping() ) autoRepeat = false;
3579 if (useButtonDown )
3580 {
3581 // If the player has just exited a bed, then delay the time before a repeat key is allowed without releasing
3582 if(player->isSleeping() ) player->lastClickTick[1] = ticks + (timer->ticksPerSecond * 2);
3583 if( firstClick || autoRepeat )
3584 {
3585 bool wasSleeping = player->isSleeping();
3586
3587 player->handleMouseClick(1);
3588
3589 // If the player has just exited a bed, then delay the time before a repeat key is allowed without releasing
3590 if(wasSleeping) player->lastClickTick[1] = ticks + (timer->ticksPerSecond * 2);
3591 else player->lastClickTick[1] = ticks;
3592 }
3593 }
3594 else
3595 {
3596 player->lastClickTick[1] = 0;
3597 }
3598 }
3599 }
3600
3601 if(app.DebugSettingsOn())
3602 {
3603 if (player->ullButtonsPressed & ( 1LL << MINECRAFT_ACTION_CHANGE_SKIN) )
3604 {
3605 player->ChangePlayerSkin();
3606 }
3607 }
3608
3609 if (player->missTime > 0) player->missTime--;
3610
3611#ifdef _DEBUG_MENUS_ENABLED
3612 if(app.DebugSettingsOn())
3613 {
3614#ifndef __PSVITA__
3615 // 4J-PB - debugoverlay for primary player only
3616 if(iPad==ProfileManager.GetPrimaryPad())
3617 {
3618 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_RENDER_DEBUG)) )
3619 {
3620#ifndef _CONTENT_PACKAGE
3621
3622 options->renderDebug = !options->renderDebug;
3623#ifdef _XBOX
3624 app.EnableDebugOverlay(options->renderDebug,iPad);
3625#else
3626 // 4J Stu - The xbox uses a completely different way of navigating to this scene
3627 ui.NavigateToScene(0, eUIScene_DebugOverlay, NULL, eUILayer_Debug);
3628#endif
3629#endif
3630 }
3631
3632 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_SPAWN_CREEPER)) && app.GetMobsDontAttackEnabled())
3633 {
3634 //shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(Creeper::_class->newInstance( level ));
3635 //shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(Wolf::_class->newInstance( level ));
3636 shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(shared_ptr<Spider>(new Spider( level )));
3637 mob->moveTo(player->x+1, player->y, player->z+1, level->random->nextFloat() * 360, 0);
3638 level->addEntity(mob);
3639 }
3640 }
3641
3642 if( (player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_FLY_TOGGLE)) )
3643 {
3644 player->abilities.debugflying = !player->abilities.debugflying;
3645 player->abilities.flying = !player->abilities.flying;
3646 }
3647#endif // PSVITA
3648 }
3649#endif
3650
3651 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON)) && gameMode->isInputAllowed(MINECRAFT_ACTION_RENDER_THIRD_PERSON))
3652 {
3653 // 4J-PB - changing this to be per player
3654 player->SetThirdPersonView((player->ThirdPersonView()+1)%3);
3655 //options->thirdPersonView = !options->thirdPersonView;
3656 }
3657
3658 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_GAME_INFO)) && gameMode->isInputAllowed(MINECRAFT_ACTION_GAME_INFO))
3659 {
3660 ui.NavigateToScene(iPad,eUIScene_InGameInfoMenu);
3661 ui.PlayUISFX(eSFX_Press);
3662 }
3663
3664 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_INVENTORY)) && gameMode->isInputAllowed(MINECRAFT_ACTION_INVENTORY))
3665 {
3666 shared_ptr<MultiplayerLocalPlayer> player = Minecraft::GetInstance()->player;
3667 ui.PlayUISFX(eSFX_Press);
3668
3669 if(gameMode->isServerControlledInventory())
3670 {
3671 player->sendOpenInventory();
3672 }
3673 else
3674 {
3675 app.LoadInventoryMenu(iPad,player);
3676 }
3677 }
3678
3679 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_CRAFTING)) && gameMode->isInputAllowed(MINECRAFT_ACTION_CRAFTING))
3680 {
3681 shared_ptr<MultiplayerLocalPlayer> player = Minecraft::GetInstance()->player;
3682
3683 // 4J-PB - reordered the if statement so creative mode doesn't bring up the crafting table
3684 // Fix for #39014 - TU5: Creative Mode: Pressing X to access the creative menu while looking at a crafting table causes the crafting menu to display
3685 if(gameMode->hasInfiniteItems())
3686 {
3687 // Creative mode
3688
3689 ui.PlayUISFX(eSFX_Press);
3690 app.LoadCreativeMenu(iPad,player);
3691 }
3692 // 4J-PB - Microsoft request that we use the 3x3 crafting if someone presses X while at the workbench
3693 else if ((hitResult!=NULL) && (hitResult->type == HitResult::TILE) && (level->getTile(hitResult->x, hitResult->y, hitResult->z) == Tile::workBench_Id))
3694 {
3695 //ui.PlayUISFX(eSFX_Press);
3696 //app.LoadXuiCrafting3x3Menu(iPad,player,hitResult->x, hitResult->y, hitResult->z);
3697 bool usedItem = false;
3698 gameMode->useItemOn(player, level, nullptr, hitResult->x, hitResult->y, hitResult->z, 0, hitResult->pos, false, &usedItem);
3699 }
3700 else
3701 {
3702 ui.PlayUISFX(eSFX_Press);
3703 app.LoadCrafting2x2Menu(iPad,player);
3704 }
3705 }
3706
3707 if ( (player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_PAUSEMENU))
3708#ifdef _DURANGO
3709 || (player->ullButtonsPressed&(1LL<<ACTION_MENU_GTC_PAUSE))
3710#endif
3711 )
3712 {
3713 app.DebugPrintf("PAUSE PRESS PROCESSING - ipad = %d, NavigateToScene\n",player->GetXboxPad());
3714 ui.PlayUISFX(eSFX_Press);
3715 ui.NavigateToScene(iPad, eUIScene_PauseMenu, NULL, eUILayer_Scene);
3716 }
3717
3718 if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_DROP)) && gameMode->isInputAllowed(MINECRAFT_ACTION_DROP))
3719 {
3720 player->drop();
3721 }
3722
3723 __uint64 ullButtonsPressed=player->ullButtonsPressed;
3724
3725 bool selected = false;
3726#ifdef __PSVITA__
3727 // 4J-PB - use the touchscreen for quickselect
3728 SceTouchData* pTouchData = InputManager.GetTouchPadData(iPad,false);
3729
3730 if(pTouchData->reportNum==1)
3731 {
3732 int iHudSize=app.GetGameSettings(iPad,eGameSetting_UISize);
3733 int iYOffset = (app.GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_Tooltips) == 0) ? iToolTipOffset : 0;
3734 if((pTouchData->report[0].x>QuickSelectRect[iHudSize].left)&&(pTouchData->report[0].x<QuickSelectRect[iHudSize].right) &&
3735 (pTouchData->report[0].y>QuickSelectRect[iHudSize].top+iYOffset)&&(pTouchData->report[0].y<QuickSelectRect[iHudSize].bottom+iYOffset))
3736 {
3737 player->inventory->selected=(pTouchData->report[0].x-QuickSelectRect[iHudSize].left)/QuickSelectBoxWidth[iHudSize];
3738 selected = true;
3739 app.DebugPrintf("Touch %d\n",player->inventory->selected);
3740 }
3741 }
3742#endif
3743 if( selected || wheel != 0 || (player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_DROP)) )
3744 {
3745 wstring itemName = L"";
3746 shared_ptr<ItemInstance> selectedItem = player->getSelectedItem();
3747 // Dropping items happens over network, so if we only have one then assume that we dropped it and should hide the item
3748 int iCount=0;
3749
3750 if(selectedItem != NULL) iCount=selectedItem->GetCount();
3751 if(selectedItem != NULL && !( (player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_DROP)) && selectedItem->GetCount() == 1))
3752 {
3753 itemName = selectedItem->getHoverName();
3754 }
3755 if( !(player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_DROP)) || (selectedItem != NULL && selectedItem->GetCount() <= 1) ) ui.SetSelectedItem( iPad, itemName );
3756 }
3757 }
3758 else
3759 {
3760 // 4J-PB
3761 if (InputManager.GetValue(iPad, ACTION_MENU_CANCEL) > 0 && gameMode->isInputAllowed(ACTION_MENU_CANCEL))
3762 {
3763 setScreen(NULL);
3764 }
3765 }
3766
3767 // monitor for keyboard input
3768 // #ifndef _CONTENT_PACKAGE
3769 // if(!(ui.GetMenuDisplayed(iPad)))
3770 // {
3771 // WCHAR wchInput;
3772 // if(InputManager.InputDetected(iPad,&wchInput))
3773 // {
3774 // printf("Input Detected!\n");
3775 //
3776 // // see if we can react to this
3777 // if(app.GetXuiAction(iPad)==eAppAction_Idle)
3778 // {
3779 // app.SetAction(iPad,eAppAction_DebugText,(LPVOID)wchInput);
3780 // }
3781 // }
3782 // }
3783 // #endif
3784
3785#if 0
3786 // 4J - TODO - some replacement for input handling...
3787 if (screen == NULL || screen.passEvents)
3788 {
3789 while (Mouse.next())
3790 {
3791 long passedTime = System.currentTimeMillis() - lastTickTime;
3792 if (passedTime > 200) continue;
3793
3794 int wheel = Mouse.getEventDWheel();
3795 if (wheel != 0) {
3796 player->inventory.swapPaint(wheel);
3797
3798 if (options.isFlying) {
3799 if (wheel > 0) wheel = 1;
3800 if (wheel < 0) wheel = -1;
3801
3802 options.flySpeed += wheel * .25f;
3803 }
3804 }
3805
3806 if (screen == null) {
3807 if (!mouseGrabbed && Mouse.getEventButtonState()) {
3808 grabMouse();
3809 } else {
3810 if (Mouse.getEventButton() == 0 && Mouse.getEventButtonState()) {
3811 handleMouseClick(0);
3812 lastClickTick = ticks;
3813 }
3814 if (Mouse.getEventButton() == 1 && Mouse.getEventButtonState()) {
3815 handleMouseClick(1);
3816 lastClickTick = ticks;
3817 }
3818 if (Mouse.getEventButton() == 2 && Mouse.getEventButtonState()) {
3819 handleGrabTexture();
3820 }
3821 }
3822 } else if (screen != null) {
3823 screen.mouseEvent();
3824 }
3825 }
3826
3827 if (missTime > 0) missTime--;
3828
3829 while (Keyboard.next()) {
3830 player->setKey(Keyboard.getEventKey(), Keyboard.getEventKeyState());
3831 if (Keyboard.getEventKeyState()) {
3832 if (Keyboard.getEventKey() == Keyboard.KEY_F11) {
3833 toggleFullScreen();
3834 continue;
3835 }
3836 /*
3837 * if (Keyboard.getEventKey() == Keyboard.KEY_F4) { new
3838 * PortalForcer().createPortal(level, player); continue; }
3839 */
3840
3841 /*
3842 * if (Keyboard.getEventKey() == Keyboard.KEY_RETURN) {
3843 * level.pathFind(); continue; }
3844 */
3845
3846 if (screen != null) {
3847 screen.keyboardEvent();
3848 } else {
3849 if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) {
3850 pauseGame();
3851 }
3852
3853 if (Keyboard.getEventKey() == Keyboard.KEY_S && Keyboard.isKeyDown(Keyboard.KEY_F3)) {
3854 reloadSound();
3855 }
3856
3857 // if (Keyboard.getEventKey() == Keyboard.KEY_P) {
3858 // gameMode = new DemoMode(this);
3859 // selectLevel(CreateWorldScreen.findAvailableFolderName(getLevelSource(), "Demo"), "Demo World", 0L);
3860 // setScreen(null);
3861 //
3862 // }
3863
3864 if (Keyboard.getEventKey() == Keyboard.KEY_F1) {
3865 options.hideGui = !options.hideGui;
3866 }
3867 if (Keyboard.getEventKey() == Keyboard.KEY_F3) {
3868 options.renderDebug = !options.renderDebug;
3869 }
3870 if (Keyboard.getEventKey() == Keyboard.KEY_F5) {
3871 options.thirdPersonView = !options.thirdPersonView;
3872 }
3873 if (Keyboard.getEventKey() == Keyboard.KEY_F8) {
3874 options.smoothCamera = !options.smoothCamera;
3875 }
3876 if (DEADMAU5_CAMERA_CHEATS) {
3877 if (Keyboard.getEventKey() == Keyboard.KEY_F6) {
3878 options.isFlying = !options.isFlying;
3879 }
3880 if (Keyboard.getEventKey() == Keyboard.KEY_F9) {
3881 options.fixedCamera = !options.fixedCamera;
3882 }
3883 if (Keyboard.getEventKey() == Keyboard.KEY_ADD) {
3884 options.cameraSpeed += .1f;
3885 }
3886 if (Keyboard.getEventKey() == Keyboard.KEY_SUBTRACT) {
3887 options.cameraSpeed -= .1f;
3888 if (options.cameraSpeed < 0) {
3889 options.cameraSpeed = 0;
3890 }
3891 }
3892 }
3893
3894 if (Keyboard.getEventKey() == options.keyBuild.key) {
3895 setScreen(new InventoryScreen(player));
3896 }
3897
3898 if (Keyboard.getEventKey() == options.keyDrop.key) {
3899 player->drop();
3900 }
3901 if (isClientSide() && Keyboard.getEventKey() == options.keyChat.key) {
3902 setScreen(new ChatScreen());
3903 }
3904 }
3905
3906 for (int i = 0; i < 9; i++) {
3907 if (Keyboard.getEventKey() == Keyboard.KEY_1 + i) player->inventory.selected = i;
3908 }
3909 if (Keyboard.getEventKey() == options.keyFog.key) {
3910 options.toggle(Options.Option.RENDER_DISTANCE, Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT) ? -1 : 1);
3911 }
3912 }
3913 }
3914
3915 if (screen == null) {
3916 if (Mouse.isButtonDown(0) && ticks - lastClickTick >= timer.ticksPerSecond / 4 && mouseGrabbed) {
3917 handleMouseClick(0);
3918 lastClickTick = ticks;
3919 }
3920 if (Mouse.isButtonDown(1) && ticks - lastClickTick >= timer.ticksPerSecond / 4 && mouseGrabbed) {
3921 handleMouseClick(1);
3922 lastClickTick = ticks;
3923 }
3924 }
3925
3926 handleMouseDown(0, screen == null && Mouse.isButtonDown(0) && mouseGrabbed);
3927 }
3928#endif
3929
3930 if (level != NULL)
3931 {
3932 if (player != NULL)
3933 {
3934 recheckPlayerIn++;
3935 if (recheckPlayerIn == 30)
3936 {
3937 recheckPlayerIn = 0;
3938 level->ensureAdded(player);
3939 }
3940 }
3941 // 4J Changed - We are setting the difficulty the same as the server so that leaderboard updates work correctly
3942 //level->difficulty = options->difficulty;
3943 //if (level->isClientSide) level->difficulty = Difficulty::HARD;
3944 if( !level->isClientSide )
3945 {
3946 //app.DebugPrintf("Minecraft::tick - Difficulty = %d",options->difficulty);
3947 level->difficulty = options->difficulty;
3948 }
3949
3950 PIXBeginNamedEvent(0,"Game renderer tick");
3951 if (!pause) gameRenderer->tick( bFirst);
3952 PIXEndNamedEvent();
3953
3954 // 4J - we want to tick each level once only per frame, and do it when a player that is actually in that level happens to be active.
3955 // This is important as things that get called in the level tick (eg the levellistener) eventually end up working out what the current
3956 // level is by determing it from the current player. Use flags here to make sure each level is only ticked the once.
3957 static unsigned int levelsTickedFlags;
3958 if( bFirst )
3959 {
3960 levelsTickedFlags = 0;
3961
3962#ifndef DISABLE_LEVELTICK_THREAD
3963 PIXBeginNamedEvent(0,"levelTickEventQueue waitForFinish");
3964 levelTickEventQueue->waitForFinish();
3965 PIXEndNamedEvent();
3966#endif // DISABLE_LEVELTICK_THREAD
3967 SparseLightStorage::tick(); // 4J added
3968 CompressedTileStorage::tick(); // 4J added
3969 SparseDataStorage::tick(); // 4J added
3970 }
3971
3972 for(unsigned int i = 0; i < levels.length; ++i)
3973 {
3974 if( player->level != levels[i] ) continue; // Don't tick if the current player isn't in this level
3975
3976 // 4J - this doesn't fully tick the animateTick here, but does register this player's position. The actual
3977 // work is now done in Level::animateTickDoWork() so we can take into account multiple players in the one level.
3978 if (!pause && levels[i] != NULL) levels[i]->animateTick(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z));
3979
3980 if( levelsTickedFlags & ( 1 << i ) ) continue; // Don't tick further if we've already ticked this level this frame
3981 levelsTickedFlags |= (1 << i);
3982
3983 PIXBeginNamedEvent(0,"Level renderer tick");
3984 if (!pause) levelRenderer->tick();
3985 PIXEndNamedEvent();
3986 // if (!pause && player!=null) {
3987 // if (player != null && !level.entities.contains(player)) {
3988 // level.addEntity(player);
3989 // }
3990 // }
3991 if( levels[i] != NULL )
3992 {
3993 if (!pause)
3994 {
3995 if (levels[i]->skyFlashTime > 0) levels[i]->skyFlashTime--;
3996 PIXBeginNamedEvent(0,"Level entity tick");
3997 levels[i]->tickEntities();
3998 PIXEndNamedEvent();
3999 }
4000
4001 // optimisation to set the culling off early, in parallel with other stuff
4002#if defined __PS3__ && !defined DISABLE_SPU_CODE
4003 // kick off the culling for all valid players in this level
4004 int currPlayerIdx = getLocalPlayerIdx();
4005 for( int idx = 0; idx < XUSER_MAX_COUNT; idx++ )
4006 {
4007 if(localplayers[idx]!=NULL)
4008 {
4009 if( localplayers[idx]->level == levels[i] )
4010 {
4011 setLocalPlayerIdx(idx);
4012 gameRenderer->setupCamera(timer->a, i);
4013 Camera::prepare(localplayers[idx], localplayers[idx]->ThirdPersonView() == 2);
4014 shared_ptr<LivingEntity> cameraEntity = cameraTargetPlayer;
4015 double xOff = cameraEntity->xOld + (cameraEntity->x - cameraEntity->xOld) * timer->a;
4016 double yOff = cameraEntity->yOld + (cameraEntity->y - cameraEntity->yOld) * timer->a;
4017 double zOff = cameraEntity->zOld + (cameraEntity->z - cameraEntity->zOld) * timer->a;
4018 FrustumCuller frustObj;
4019 Culler *frustum = &frustObj;
4020 MemSect(0);
4021 frustum->prepare(xOff, yOff, zOff);
4022 levelRenderer->cull_SPU(idx, frustum, 0);
4023 }
4024 }
4025 }
4026 setLocalPlayerIdx(currPlayerIdx);
4027#endif // __PS3__
4028
4029 // 4J Stu - We are always online, but still could be paused
4030 if (!pause) // || isClientSide())
4031 {
4032 //app.DebugPrintf("Minecraft::tick spawn settings - Difficulty = %d",options->difficulty);
4033 levels[i]->setSpawnSettings(level->difficulty > 0, true);
4034 PIXBeginNamedEvent(0,"Level tick");
4035#ifdef DISABLE_LEVELTICK_THREAD
4036 levels[i]->tick();
4037#else
4038 levelTickEventQueue->sendEvent(levels[i]);
4039#endif // DISABLE_LEVELTICK_THREAD
4040 PIXEndNamedEvent();
4041 }
4042 }
4043 }
4044
4045 if( bFirst )
4046 {
4047 PIXBeginNamedEvent(0,"Particle tick");
4048 if (!pause) particleEngine->tick();
4049 PIXEndNamedEvent();
4050 }
4051
4052 // 4J Stu - Keep ticking the connections if paused so that they don't time out
4053 if( pause ) tickAllConnections();
4054 // player->tick();
4055 }
4056#ifdef __PS3__
4057
4058// while(!g_tickLevelQueue.empty())
4059// {
4060// Level* pLevel = g_tickLevelQueue.front();
4061// g_tickLevelQueue.pop();
4062// pLevel->tick();
4063// };
4064
4065#endif
4066
4067 // if (Keyboard.isKeyDown(Keyboard.KEY_NUMPAD7) ||
4068 // Keyboard.isKeyDown(Keyboard.KEY_Q)) rota++;
4069 // if (Keyboard.isKeyDown(Keyboard.KEY_NUMPAD9) ||
4070 // Keyboard.isKeyDown(Keyboard.KEY_E)) rota--;
4071 // 4J removed
4072 //lastTickTime = System::currentTimeMillis();
4073}
4074
4075void Minecraft::reloadSound()
4076{
4077 // System.out.println("FORCING RELOAD!"); // 4J - removed
4078 soundEngine = new SoundEngine();
4079 soundEngine->init(options);
4080 bgLoader->forceReload();
4081}
4082
4083bool Minecraft::isClientSide()
4084{
4085 return level != NULL && level->isClientSide;
4086}
4087
4088void Minecraft::selectLevel(ConsoleSaveFile *saveFile, const wstring& levelId, const wstring& levelName, LevelSettings *levelSettings)
4089{
4090 }
4091
4092bool Minecraft::saveSlot(int slot, const wstring& name)
4093{
4094 return false;
4095}
4096
4097bool Minecraft::loadSlot(const wstring& userName, int slot)
4098{
4099 return false;
4100}
4101
4102void Minecraft::releaseLevel(int message)
4103{
4104 //this->level = NULL;
4105 setLevel(NULL, message);
4106}
4107
4108// 4J Stu - This code was within setLevel, but I moved it out so that I can call it at a better
4109// time when exiting from an online game
4110void Minecraft::forceStatsSave(int idx)
4111{
4112 //4J Gordon: Force a stats save
4113 stats[idx]->save(idx, true);
4114
4115 //4J Gordon: If the player is signed in, save the leaderboards
4116 if( ProfileManager.IsSignedInLive(idx) )
4117 {
4118 int tempLockedProfile = ProfileManager.GetLockedProfile();
4119 ProfileManager.SetLockedProfile(idx);
4120 stats[idx]->saveLeaderboards();
4121 ProfileManager.SetLockedProfile(tempLockedProfile);
4122 }
4123}
4124
4125// 4J Added
4126MultiPlayerLevel *Minecraft::getLevel(int dimension)
4127{
4128 if (dimension == -1) return levels[1];
4129 else if(dimension == 1) return levels[2];
4130 else return levels[0];
4131}
4132
4133// 4J Stu - Removed as redundant with default values in params.
4134//void Minecraft::setLevel(Level *level, bool doForceStatsSave /*= true*/)
4135//{
4136// setLevel(level, -1, NULL, doForceStatsSave);
4137//}
4138
4139// Also causing ambiguous call for some reason
4140// as it is matching shared_ptr<Player> from the func below with bool from this one
4141//void Minecraft::setLevel(Level *level, const wstring& message, bool doForceStatsSave /*= true*/)
4142//{
4143// setLevel(level, message, NULL, doForceStatsSave);
4144//}
4145
4146void Minecraft::forceaddLevel(MultiPlayerLevel *level)
4147{
4148 int dimId = level->dimension->id;
4149 if (dimId == -1) levels[1] = level;
4150 else if(dimId == 1) levels[2] = level;
4151 else levels[0] = level;
4152}
4153
4154void Minecraft::setLevel(MultiPlayerLevel *level, int message /*=-1*/, shared_ptr<Player> forceInsertPlayer /*=NULL*/, bool doForceStatsSave /*=true*/, bool bPrimaryPlayerSignedOut /*=false*/)
4155{
4156 EnterCriticalSection(&m_setLevelCS);
4157 bool playerAdded = false;
4158 this->cameraTargetPlayer = nullptr;
4159
4160 if(progressRenderer != NULL)
4161 {
4162 this->progressRenderer->progressStart(message);
4163 this->progressRenderer->progressStage(-1);
4164 }
4165
4166 // 4J-PB - since we now play music in the menu, just let it keep playing
4167 //soundEngine->playStreaming(L"", 0, 0, 0, 0, 0);
4168
4169 // 4J - stop update thread from processing this level, which blocks until it is safe to move on - will be re-enabled if we set the level to be non-NULL
4170 gameRenderer->DisableUpdateThread();
4171
4172 for(unsigned int i = 0; i < levels.length; ++i)
4173 {
4174 // 4J We only need to save out in multiplayer is we are setting the level to NULL
4175 // If we ever go back to making single player only then this will not work properly!
4176 if (levels[i] != NULL && level == NULL)
4177 {
4178 // 4J Stu - This is really only relevant for single player (ie not what we do at the moment)
4179 if((doForceStatsSave==true) && player!=NULL)
4180 forceStatsSave(player->GetXboxPad() );
4181
4182 // 4J Stu - Added these for the case when we exit a level so we are setting the level to NULL
4183 // The level renderer needs to have it's stored level set to NULL so that it doesn't break next time we set one
4184 if (levelRenderer != NULL)
4185 {
4186 for(DWORD p = 0; p < XUSER_MAX_COUNT; ++p)
4187 {
4188 levelRenderer->setLevel(p, NULL);
4189 }
4190 }
4191 if (particleEngine != NULL) particleEngine->setLevel(NULL);
4192 }
4193 }
4194 // 4J If we are setting the level to NULL then we are exiting, so delete the levels
4195 if( level == NULL )
4196 {
4197 if(levels[0]!=NULL)
4198 {
4199 delete levels[0];
4200 levels[0] = NULL;
4201
4202 // Both level share the same savedDataStorage
4203 if(levels[1]!=NULL) levels[1]->savedDataStorage = NULL;
4204 }
4205 if(levels[1]!=NULL)
4206 {
4207 delete levels[1];
4208 levels[1] = NULL;
4209 }
4210 if(levels[2]!=NULL)
4211 {
4212 delete levels[2];
4213 levels[2] = NULL;
4214 }
4215
4216 // Delete all the player objects
4217 for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
4218 {
4219 shared_ptr<MultiplayerLocalPlayer> mplp = localplayers[idx];
4220 if(mplp != NULL && mplp->connection != NULL )
4221 {
4222 delete mplp->connection;
4223 mplp->connection = NULL;
4224 }
4225
4226 if( localgameModes[idx] != NULL )
4227 {
4228 delete localgameModes[idx];
4229 localgameModes[idx] = NULL;
4230 }
4231
4232 if( m_pendingLocalConnections[idx] != NULL )
4233 {
4234 delete m_pendingLocalConnections[idx];
4235 m_pendingLocalConnections[idx] = NULL;
4236 }
4237
4238 localplayers[idx] = nullptr;
4239 }
4240 // If we are removing the primary player then there can't be a valid gamemode left anymore, this
4241 // pointer will be referring to the one we've just deleted
4242 gameMode = NULL;
4243 // Remove references to player
4244 player = nullptr;
4245 cameraTargetPlayer = nullptr;
4246 EntityRenderDispatcher::instance->cameraEntity = nullptr;
4247 TileEntityRenderDispatcher::instance->cameraEntity = nullptr;
4248 }
4249 this->level = level;
4250
4251 if (level != NULL)
4252 {
4253 int dimId = level->dimension->id;
4254 if (dimId == -1) levels[1] = level;
4255 else if(dimId == 1) levels[2] = level;
4256 else levels[0] = level;
4257
4258 // If no player has been set, then this is the first level to be set this game, so set up
4259 // a primary player & initialise some other things
4260 if (player == NULL)
4261 {
4262 int iPrimaryPlayer = ProfileManager.GetPrimaryPad();
4263
4264 player = gameMode->createPlayer(level);
4265
4266 PlayerUID playerXUIDOffline = INVALID_XUID;
4267 PlayerUID playerXUIDOnline = INVALID_XUID;
4268 ProfileManager.GetXUID(iPrimaryPlayer,&playerXUIDOffline,false);
4269 ProfileManager.GetXUID(iPrimaryPlayer,&playerXUIDOnline,true);
4270#ifdef __PSVITA__
4271 if(CGameNetworkManager::usingAdhocMode() && playerXUIDOnline.getOnlineID()[0] == 0)
4272 {
4273 // player doesn't have an online UID, set it from the player name
4274 playerXUIDOnline.setForAdhoc();
4275 }
4276#endif
4277 player->setXuid(playerXUIDOffline);
4278 player->setOnlineXuid(playerXUIDOnline);
4279
4280 player->m_displayName = ProfileManager.GetDisplayName(iPrimaryPlayer);
4281
4282
4283
4284 player->resetPos();
4285 gameMode->initPlayer(player);
4286
4287 player->SetXboxPad(iPrimaryPlayer);
4288
4289 for(int i=0;i<XUSER_MAX_COUNT;i++)
4290 {
4291 m_pendingLocalConnections[i] = NULL;
4292 if( i != iPrimaryPlayer ) localgameModes[i] = NULL;
4293 }
4294 }
4295
4296 if (player != NULL)
4297 {
4298 player->resetPos();
4299 // gameMode.initPlayer(player);
4300 if (level != NULL)
4301 {
4302 level->addEntity(player);
4303 playerAdded = true;
4304 }
4305 }
4306
4307 if(player->input != NULL) delete player->input;
4308 player->input = new Input();
4309
4310 if (levelRenderer != NULL) levelRenderer->setLevel(player->GetXboxPad(), level);
4311 if (particleEngine != NULL) particleEngine->setLevel(level);
4312
4313#if 0
4314 // 4J - removed - we don't use ChunkCache anymore
4315 ChunkSource *cs = level->getChunkSource();
4316 if (dynamic_cast<ChunkCache *>(cs) != NULL)
4317 {
4318 ChunkCache *spcc = (ChunkCache *)cs;
4319
4320 // 4J - these had a Mth::floor which seems unrequired
4321 int xt = ((int) player->x) >> 4;
4322 int zt = ((int) player->z) >> 4;
4323
4324 spcc->centerOn(xt, zt);
4325 }
4326#endif
4327 gameMode->adjustPlayer(player);
4328
4329 for(int i=0;i<XUSER_MAX_COUNT;i++)
4330 {
4331 m_pendingLocalConnections[i] = NULL;
4332 }
4333 updatePlayerViewportAssignments();
4334
4335 this->cameraTargetPlayer = player;
4336
4337 // 4J - allow update thread to start processing the level now both it & the player should be ok
4338 gameRenderer->EnableUpdateThread();
4339 }
4340 else
4341 {
4342 levelSource->clearAll();
4343 player = nullptr;
4344
4345 // Clear all players if the new level is NULL
4346 for(int i=0;i<XUSER_MAX_COUNT;i++)
4347 {
4348 if( m_pendingLocalConnections[i] != NULL ) m_pendingLocalConnections[i]->close();
4349 m_pendingLocalConnections[i] = NULL;
4350 localplayers[i] = nullptr;
4351 localgameModes[i] = NULL;
4352 }
4353 }
4354
4355 // System.gc(); // 4J - removed
4356 // 4J removed
4357 //this->lastTickTime = 0;
4358 LeaveCriticalSection(&m_setLevelCS);
4359}
4360
4361void Minecraft::prepareLevel(int title)
4362{
4363 if(progressRenderer != NULL)
4364 {
4365 this->progressRenderer->progressStart(title);
4366 this->progressRenderer->progressStage(IDS_PROGRESS_BUILDING_TERRAIN);
4367 }
4368 int r = 128;
4369 if (gameMode->isCutScene()) r = 64;
4370 int pp = 0;
4371 int max = r * 2 / 16 + 1;
4372 max = max * max;
4373 ChunkSource *cs = level->getChunkSource();
4374
4375 Pos *spawnPos = level->getSharedSpawnPos();
4376 if (player != NULL)
4377 {
4378 spawnPos->x = (int) player->x;
4379 spawnPos->z = (int) player->z;
4380 }
4381
4382#if 0
4383 // 4J - removed - we don't use ChunkCache anymore
4384 if (dynamic_cast<ChunkCache *>(cs)!=NULL)
4385 {
4386 ChunkCache *spcc = (ChunkCache *) cs;
4387
4388 spcc->centerOn(spawnPos->x >> 4, spawnPos->z >> 4);
4389 }
4390#endif
4391
4392 for (int x = -r; x <= r; x += 16)
4393 {
4394 for (int z = -r; z <= r; z += 16)
4395 {
4396 if(progressRenderer != NULL) this->progressRenderer->progressStagePercentage((pp++) * 100 / max);
4397 level->getTile(spawnPos->x + x, 64, spawnPos->z + z);
4398 if (!gameMode->isCutScene()) {
4399 }
4400 }
4401 }
4402 delete spawnPos;
4403 if (!gameMode->isCutScene())
4404 {
4405 if(progressRenderer != NULL) this->progressRenderer->progressStage(IDS_PROGRESS_SIMULATING_WORLD);
4406 max = 2000;
4407}
4408}
4409
4410wstring Minecraft::gatherStats1()
4411{
4412 //return levelRenderer->gatherStats1();
4413 return L"Time to autosave: " + _toString<unsigned int>( app.SecondsToAutosave() ) + L"s";
4414}
4415
4416wstring Minecraft::gatherStats2()
4417{
4418 return g_NetworkManager.GatherStats();
4419 //return levelRenderer->gatherStats2();
4420}
4421
4422wstring Minecraft::gatherStats3()
4423{
4424 return g_NetworkManager.GatherRTTStats();
4425 //return L"P: " + particleEngine->countParticles() + L". T: " + level->gatherStats();
4426}
4427
4428wstring Minecraft::gatherStats4()
4429{
4430 return level->gatherChunkSourceStats();
4431}
4432
4433void Minecraft::respawnPlayer(int iPad, int dimension, int newEntityId)
4434{
4435 gameRenderer->DisableUpdateThread(); // 4J - don't do updating whilst we are adjusting the player & localplayer array
4436 shared_ptr<MultiplayerLocalPlayer> localPlayer = localplayers[iPad];
4437
4438 level->validateSpawn();
4439 level->removeAllPendingEntityRemovals();
4440
4441 if (localPlayer != NULL)
4442 {
4443 level->removeEntity(localPlayer);
4444 }
4445
4446 shared_ptr<Player> oldPlayer = localPlayer;
4447 cameraTargetPlayer = nullptr;
4448
4449 // 4J-PB - copy and set the players xbox pad
4450 int iTempPad=localPlayer->GetXboxPad();
4451 int iTempScreenSection = localPlayer->m_iScreenSection;
4452 EDefaultSkins skin = localPlayer->getPlayerDefaultSkin();
4453 player = localgameModes[iPad]->createPlayer(level);
4454
4455 PlayerUID playerXUIDOffline = INVALID_XUID;
4456 PlayerUID playerXUIDOnline = INVALID_XUID;
4457 ProfileManager.GetXUID(iTempPad,&playerXUIDOffline,false);
4458 ProfileManager.GetXUID(iTempPad,&playerXUIDOnline,true);
4459 player->setXuid(playerXUIDOffline);
4460 player->setOnlineXuid(playerXUIDOnline);
4461 player->setIsGuest( ProfileManager.IsGuest(iTempPad) );
4462
4463 player->m_displayName = ProfileManager.GetDisplayName(iPad);
4464
4465 player->SetXboxPad(iTempPad);
4466
4467 player->m_iScreenSection = iTempScreenSection;
4468 player->setPlayerIndex( localPlayer->getPlayerIndex() );
4469 player->setCustomSkin(localPlayer->getCustomSkin());
4470 player->setPlayerDefaultSkin( skin );
4471 player->setCustomCape(localPlayer->getCustomCape());
4472 player->m_sessionTimeStart = localPlayer->m_sessionTimeStart;
4473 player->m_dimensionTimeStart = localPlayer->m_dimensionTimeStart;
4474 player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, localPlayer->getAllPlayerGamePrivileges());
4475
4476 player->SetThirdPersonView(oldPlayer->ThirdPersonView());
4477
4478 // Fix for #63021 - TU7: Content: UI: Travelling from/to the Nether results in switching currently held item to another.
4479 // Fix for #81759 - TU9: Content: Gameplay: Entering The End Exit Portal replaces the Player's currently held item with the first one from the Quickbar
4480 if( localPlayer->getHealth() > 0 && localPlayer->y > -64)
4481 {
4482 player->inventory->selected = localPlayer->inventory->selected;
4483 }
4484
4485 // Set the animation override if the skin has one
4486 DWORD dwSkinID=app.getSkinIdFromPath(player->customTextureUrl);
4487 if(GET_IS_DLC_SKIN_FROM_BITMASK(dwSkinID))
4488 {
4489 player->setAnimOverrideBitmask(player->getSkinAnimOverrideBitmask(dwSkinID));
4490 }
4491
4492 player->dimension = dimension;
4493 cameraTargetPlayer = player;
4494
4495 // 4J-PB - are we the primary player or a local player?
4496 if(iPad==ProfileManager.GetPrimaryPad())
4497 {
4498 createPrimaryLocalPlayer(iPad);
4499
4500 // update the debugoptions
4501 app.SetGameSettingsDebugMask(ProfileManager.GetPrimaryPad(),app.GetGameSettingsDebugMask(-1,true));
4502 }
4503 else
4504 {
4505 storeExtraLocalPlayer(iPad);
4506 }
4507
4508 player->setShowOnMaps(app.GetGameHostOption(eGameHostOption_Gamertags)!=0?true:false);
4509
4510 player->resetPos();
4511 level->addEntity(player);
4512 gameMode->initPlayer(player);
4513
4514 if(player->input != NULL) delete player->input;
4515 player->input = new Input();
4516 player->entityId = newEntityId;
4517 player->animateRespawn();
4518 gameMode->adjustPlayer(player);
4519
4520 // 4J - added isClientSide check here
4521 if (!level->isClientSide)
4522 {
4523 prepareLevel(IDS_PROGRESS_RESPAWNING);
4524 }
4525
4526 // 4J Added for multiplayer. At this point we know everything is ready to run again
4527 //SetEvent(m_hPlayerRespawned);
4528 player->SetPlayerRespawned(true);
4529
4530 if (dynamic_cast<DeathScreen *>(screen) != NULL) setScreen(NULL);
4531
4532 gameRenderer->EnableUpdateThread();
4533}
4534
4535void Minecraft::start(const wstring& name, const wstring& sid)
4536{
4537 startAndConnectTo(name, sid, L"");
4538}
4539
4540void Minecraft::startAndConnectTo(const wstring& name, const wstring& sid, const wstring& url)
4541{
4542 bool fullScreen = false;
4543 wstring userName = name;
4544
4545 /* 4J - removed window handling things here
4546 final Frame frame = new Frame("Minecraft");
4547 Canvas canvas = new Canvas();
4548 frame.setLayout(new BorderLayout());
4549
4550 frame.add(canvas, BorderLayout.CENTER);
4551
4552 // OverlayLayout oll = new OverlayLayout(frame);
4553 // oll.addLayoutComponent(canvas, BorderLayout.CENTER);
4554 // oll.addLayoutComponent(new JLabel("TEST"), BorderLayout.EAST);
4555
4556 canvas.setPreferredSize(new Dimension(854, 480));
4557 frame.pack();
4558 frame.setLocationRelativeTo(null);
4559 */
4560
4561 Minecraft *minecraft;
4562 // 4J - was new Minecraft(frame, canvas, NULL, 854, 480, fullScreen);
4563
4564 minecraft = new Minecraft(NULL, NULL, NULL, 1280, 720, fullScreen);
4565
4566 /* - 4J - removed
4567 {
4568 @Override
4569 public void onCrash(CrashReport crashReport) {
4570 frame.removeAll();
4571 frame.add(new CrashInfoPanel(crashReport), BorderLayout.CENTER);
4572 frame.validate();
4573 }
4574 }; */
4575
4576 /* 4J - removed
4577 final Thread thread = new Thread(minecraft, "Minecraft main thread");
4578 thread.setPriority(Thread.MAX_PRIORITY);
4579 */
4580 minecraft->serverDomain = L"www.minecraft.net";
4581
4582 // 4J Stu - We never want the player to be DemoUser, we always want them to have their gamertag displayed
4583 //if (ProfileManager.IsFullVersion())
4584 {
4585 if (userName != L"" && sid != L"") // 4J - username & side were compared with NULL rather than empty strings
4586 {
4587 minecraft->user = new User(userName, sid);
4588 }
4589 else
4590 {
4591 minecraft->user = new User(L"Player" + _toString<int>(System::currentTimeMillis() % 1000), L"");
4592 }
4593 }
4594 //else
4595 //{
4596 // minecraft->user = new DemoUser();
4597 //}
4598
4599 /* 4J - TODO
4600 if (url != NULL)
4601 {
4602 String[] tokens = url.split(":");
4603 minecraft.connectTo(tokens[0], Integer.parseInt(tokens[1]));
4604 }
4605 */
4606
4607 /* 4J - removed
4608 frame.setVisible(true);
4609 frame.addWindowListener(new WindowAdapter() {
4610 public void windowClosing(WindowEvent arg0) {
4611 minecraft.stop();
4612 try {
4613 thread.join();
4614 } catch (InterruptedException e) {
4615 e.printStackTrace();
4616 }
4617 System.exit(0);
4618 }
4619 });
4620 */
4621 // 4J - TODO - consider whether we need to actually create a thread here
4622 minecraft->run();
4623}
4624
4625ClientConnection *Minecraft::getConnection(int iPad)
4626{
4627 return localplayers[iPad]->connection;
4628}
4629
4630// 4J-PB - so we can access this from within our xbox game loop
4631Minecraft *Minecraft::GetInstance()
4632{
4633 return m_instance;
4634}
4635
4636bool useLomp = false;
4637
4638int g_iMainThreadId;
4639
4640void Minecraft::main()
4641{
4642 wstring name;
4643 wstring sessionId;
4644
4645 //g_iMainThreadId = GetCurrentThreadId();
4646
4647 useLomp = true;
4648
4649 MinecraftWorld_RunStaticCtors();
4650 EntityRenderDispatcher::staticCtor();
4651 TileEntityRenderDispatcher::staticCtor();
4652 User::staticCtor();
4653 Tutorial::staticCtor();
4654 ColourTable::staticCtor();
4655 app.loadDefaultGameRules();
4656
4657#ifdef _LARGE_WORLDS
4658 LevelRenderer::staticCtor();
4659#endif
4660
4661 // 4J Stu - This block generates XML for the game rules schema
4662#if 0
4663 for(unsigned int i = 0; i < Item::items.length; ++i)
4664 {
4665 if(Item::items[i] != NULL)
4666 {
4667 app.DebugPrintf("<xs:enumeration value=\"%d\"><xs:annotation><xs:documentation>%ls</xs:documentation></xs:annotation></xs:enumeration>\n", i, app.GetString( Item::items[i]->getDescriptionId() ));
4668 }
4669 }
4670
4671 app.DebugPrintf("\n\n\n\n\n");
4672
4673 for(unsigned int i = 0; i < 256; ++i)
4674 {
4675 if(Tile::tiles[i] != NULL)
4676 {
4677 app.DebugPrintf("<xs:enumeration value=\"%d\"><xs:annotation><xs:documentation>%ls</xs:documentation></xs:annotation></xs:enumeration>\n", i, app.GetString( Tile::tiles[i]->getDescriptionId() ));
4678 }
4679 }
4680 __debugbreak();
4681#endif
4682
4683 // 4J-PB - Can't call this for the first 5 seconds of a game - MS rule
4684 //if (ProfileManager.IsFullVersion())
4685 {
4686 name = L"Player" + _toString<__int64>(System::currentTimeMillis() % 1000);
4687 sessionId = L"-";
4688 /* 4J - TODO - get a session ID from somewhere?
4689 if (args.length > 0) name = args[0];
4690 sessionId = "-";
4691 if (args.length > 1) sessionId = args[1];
4692 */
4693 }
4694
4695 // Common for all platforms
4696 IUIScene_CreativeMenu::staticCtor();
4697
4698 // On PS4, we call Minecraft::Start from another thread, as this has been timed taking ~2.5 seconds and we need to do some basic
4699 // rendering stuff so that we don't break the TRCs on SubmitDone calls
4700#ifndef __ORBIS__
4701 Minecraft::start(name, sessionId);
4702#endif
4703}
4704
4705bool Minecraft::renderNames()
4706{
4707 if (m_instance == NULL || !m_instance->options->hideGui)
4708 {
4709 return true;
4710 }
4711 return false;
4712}
4713
4714bool Minecraft::useFancyGraphics()
4715{
4716 return (m_instance != NULL && m_instance->options->fancyGraphics);
4717}
4718
4719bool Minecraft::useAmbientOcclusion()
4720{
4721 return (m_instance != NULL && m_instance->options->ambientOcclusion != Options::AO_OFF);
4722}
4723
4724bool Minecraft::renderDebug()
4725{
4726 return (m_instance != NULL && m_instance->options->renderDebug);
4727}
4728
4729bool Minecraft::handleClientSideCommand(const wstring& chatMessage)
4730{
4731 return false;
4732}
4733
4734int Minecraft::maxSupportedTextureSize()
4735{
4736 // 4J Force value
4737 return 1024;
4738
4739 //for (int texSize = 16384; texSize > 0; texSize >>= 1) {
4740 // GL11.glTexImage2D(GL11.GL_PROXY_TEXTURE_2D, 0, GL11.GL_RGBA, texSize, texSize, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null);
4741 // final int width = GL11.glGetTexLevelParameteri(GL11.GL_PROXY_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH);
4742 // if (width != 0) {
4743 // return texSize;
4744 // }
4745 //}
4746 //return -1;
4747}
4748
4749void Minecraft::delayTextureReload()
4750{
4751 reloadTextures = true;
4752}
4753
4754__int64 Minecraft::currentTimeMillis()
4755{
4756 return System::currentTimeMillis();//(Sys.getTime() * 1000) / Sys.getTimerResolution();
4757}
4758
4759/*void Minecraft::handleMouseDown(int button, bool down)
4760{
4761if (gameMode->instaBuild) return;
4762if (!down) missTime = 0;
4763if (button == 0 && missTime > 0) return;
4764
4765if (down && hitResult != NULL && hitResult->type == HitResult::TILE && button == 0)
4766{
4767int x = hitResult->x;
4768int y = hitResult->y;
4769int z = hitResult->z;
4770gameMode->continueDestroyBlock(x, y, z, hitResult->f);
4771particleEngine->crack(x, y, z, hitResult->f);
4772}
4773else
4774{
4775gameMode->stopDestroyBlock();
4776}
4777}
4778
4779void Minecraft::handleMouseClick(int button)
4780{
4781if (button == 0 && missTime > 0) return;
4782if (button == 0)
4783{
4784app.DebugPrintf("handleMouseClick - Player %d is swinging\n",player->GetXboxPad());
4785player->swing();
4786}
4787
4788bool mayUse = true;
4789
4790// * if (button == 1) { ItemInstance item =
4791// * player.inventory.getSelected(); if (item != null) { if
4792// * (gameMode.useItem(player, item)) {
4793// * gameRenderer.itemInHandRenderer.itemUsed(); return; } } }
4794
4795// 4J-PB - Adding a special case in here for sleeping in a bed in a multiplayer game - we need to wake up, and we don't have the inbedchatscreen with a button
4796
4797if(button==1 && (player->isSleeping() && level != NULL && level->isClientSide))
4798{
4799shared_ptr<MultiplayerLocalPlayer> mplp = dynamic_pointer_cast<MultiplayerLocalPlayer>( player );
4800
4801if(mplp) mplp->StopSleeping();
4802
4803// 4J - TODO
4804//if (minecraft.player instanceof MultiplayerLocalPlayer)
4805//{
4806// ClientConnection connection = ((MultiplayerLocalPlayer) minecraft.player).connection;
4807// connection.send(new PlayerCommandPacket(minecraft.player, PlayerCommandPacket.STOP_SLEEPING));
4808//}
4809}
4810
4811if (hitResult == NULL)
4812{
4813if (button == 0 && !(dynamic_cast<CreativeMode *>(gameMode) != NULL)) missTime = 10;
4814}
4815else if (hitResult->type == HitResult::ENTITY)
4816{
4817if (button == 0)
4818{
4819gameMode->attack(player, hitResult->entity);
4820}
4821if (button == 1)
4822{
4823gameMode->interact(player, hitResult->entity);
4824}
4825}
4826else if (hitResult->type == HitResult::TILE)
4827{
4828int x = hitResult->x;
4829int y = hitResult->y;
4830int z = hitResult->z;
4831int face = hitResult->f;
4832
4833// * if (button != 0) { if (hitResult.f == 0) y--; if (hitResult.f ==
4834// * 1) y++; if (hitResult.f == 2) z--; if (hitResult.f == 3) z++; if
4835// * (hitResult.f == 4) x--; if (hitResult.f == 5) x++; }
4836
4837// if (isClientSide())
4838// {
4839// return;
4840// }
4841
4842if (button == 0)
4843{
4844gameMode->startDestroyBlock(x, y, z, hitResult->f);
4845}
4846else
4847{
4848shared_ptr<ItemInstance> item = player->inventory->getSelected();
4849int oldCount = item != NULL ? item->count : 0;
4850if (gameMode->useItemOn(player, level, item, x, y, z, face))
4851{
4852mayUse = false;
4853app.DebugPrintf("Player %d is swinging\n",player->GetXboxPad());
4854player->swing();
4855}
4856if (item == NULL)
4857{
4858return;
4859}
4860
4861if (item->count == 0)
4862{
4863player->inventory->items[player->inventory->selected] = NULL;
4864}
4865else if (item->count != oldCount)
4866{
4867gameRenderer->itemInHandRenderer->itemPlaced();
4868}
4869}
4870}
4871
4872if (mayUse && button == 1)
4873{
4874shared_ptr<ItemInstance> item = player->inventory->getSelected();
4875if (item != NULL)
4876{
4877if (gameMode->useItem(player, level, item))
4878{
4879gameRenderer->itemInHandRenderer->itemUsed();
4880}
4881}
4882}
4883}
4884*/
4885
4886// 4J-PB
4887Screen * Minecraft::getScreen()
4888{
4889 return screen;
4890}
4891
4892bool Minecraft::isTutorial()
4893{
4894 return m_inFullTutorialBits > 0;
4895
4896 /*if( gameMode != NULL && gameMode->isTutorial() )
4897 {
4898 return true;
4899 }
4900 else
4901 {
4902 return false;
4903 }*/
4904}
4905
4906void Minecraft::playerStartedTutorial(int iPad)
4907{
4908 // If the app doesn't think we are in a tutorial mode then just ignore this add
4909 if( app.GetTutorialMode() ) m_inFullTutorialBits = m_inFullTutorialBits | ( 1 << iPad );
4910}
4911
4912void Minecraft::playerLeftTutorial(int iPad)
4913{
4914 // 4J Stu - Fix for bug that was flooding Sentient with LevelStart events
4915 // If the tutorial bits are already 0 then don't need to update anything
4916 if(m_inFullTutorialBits == 0)
4917 {
4918 app.SetTutorialMode( false );
4919 return;
4920 }
4921
4922 m_inFullTutorialBits = m_inFullTutorialBits & ~( 1 << iPad );
4923 if(m_inFullTutorialBits == 0)
4924 {
4925 app.SetTutorialMode( false );
4926
4927 // 4J Stu -This telemetry event means something different on XboxOne, so we don't call it for simple state changes like this
4928#ifndef _XBOX_ONE
4929 for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx)
4930 {
4931 if(localplayers[idx] != NULL)
4932 {
4933 TelemetryManager->RecordLevelStart(idx, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, level->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount());
4934 }
4935 }
4936#endif
4937 }
4938}
4939
4940#ifdef _DURANGO
4941void Minecraft::inGameSignInCheckAllPrivilegesCallback(LPVOID lpParam, bool hasPrivileges, int iPad)
4942{
4943 Minecraft* pClass = (Minecraft*)lpParam;
4944
4945 if(!hasPrivileges)
4946 {
4947 ProfileManager.RemoveGamepadFromGame(iPad);
4948 }
4949 else
4950 {
4951 if( !g_NetworkManager.SessionHasSpace() )
4952 {
4953 UINT uiIDA[1];
4954 uiIDA[0]=IDS_OK;
4955 ui.RequestErrorMessage(IDS_MULTIPLAYER_FULL_TITLE, IDS_MULTIPLAYER_FULL_TEXT, uiIDA, 1);
4956 ProfileManager.RemoveGamepadFromGame(iPad);
4957 }
4958 else if( ProfileManager.IsSignedInLive(iPad) && ProfileManager.AllowedToPlayMultiplayer(iPad) )
4959 {
4960 // create the local player for the iPad
4961 shared_ptr<Player> player = pClass->localplayers[iPad];
4962 if( player == NULL)
4963 {
4964 if( pClass->level->isClientSide )
4965 {
4966 pClass->addLocalPlayer(iPad);
4967 }
4968 else
4969 {
4970 // create the local player for the iPad
4971 shared_ptr<Player> player = pClass->localplayers[iPad];
4972 if( player == NULL)
4973 {
4974 player = pClass->createExtraLocalPlayer(iPad, (convStringToWstring( ProfileManager.GetGamertag(iPad) )).c_str(), iPad, pClass->level->dimension->id);
4975 }
4976 }
4977 }
4978 }
4979 }
4980}
4981#endif
4982
4983#ifdef _XBOX_ONE
4984int Minecraft::InGame_SignInReturned(void *pParam,bool bContinue, int iPad, int iController)
4985#else
4986int Minecraft::InGame_SignInReturned(void *pParam,bool bContinue, int iPad)
4987#endif
4988{
4989 Minecraft* pMinecraftClass = (Minecraft*)pParam;
4990
4991 if(g_NetworkManager.IsInSession())
4992 {
4993 // 4J Stu - There seems to be a bug in the signin ui call that enables guest sign in. We never allow this within game, so make sure that it's disabled
4994 // Fix for #66516 - TCR #124: MPS Guest Support ; #001: BAS Game Stability: TU8: The game crashes when second Guest signs-in on console which takes part in Xbox LIVE multiplayer session.
4995 app.DebugPrintf("Disabling Guest Signin\n");
4996 XEnableGuestSignin(FALSE);
4997 }
4998
4999 // If sign in succeded, we're in game and this player isn't already playing, continue
5000 if(bContinue==true && g_NetworkManager.IsInSession() && pMinecraftClass->localplayers[iPad] == NULL)
5001 {
5002 // It's possible that the player has not signed in - they can back out or choose no for the converttoguest
5003 if(ProfileManager.IsSignedIn(iPad))
5004 {
5005#ifdef _DURANGO
5006 if(!g_NetworkManager.IsLocalGame() && ProfileManager.IsSignedInLive(iPad) && ProfileManager.AllowedToPlayMultiplayer(iPad))
5007 {
5008 ProfileManager.CheckMultiplayerPrivileges(iPad, true, &inGameSignInCheckAllPrivilegesCallback, pMinecraftClass);
5009 }
5010 else
5011#endif
5012 if( !g_NetworkManager.SessionHasSpace() )
5013 {
5014 UINT uiIDA[1];
5015 uiIDA[0]=IDS_OK;
5016 ui.RequestErrorMessage(IDS_MULTIPLAYER_FULL_TITLE, IDS_MULTIPLAYER_FULL_TEXT, uiIDA, 1);
5017#ifdef _DURANGO
5018 ProfileManager.RemoveGamepadFromGame(iPad);
5019#endif
5020 }
5021 // if this is a local game then profiles just need to be signed in
5022 else if( g_NetworkManager.IsLocalGame() || (ProfileManager.IsSignedInLive(iPad) && ProfileManager.AllowedToPlayMultiplayer(iPad)) )
5023 {
5024#ifdef __ORBIS__
5025 bool contentRestricted = false;
5026 ProfileManager.GetChatAndContentRestrictions(iPad,false,NULL,&contentRestricted,NULL); // TODO!
5027
5028 if (!g_NetworkManager.IsLocalGame() && contentRestricted)
5029 {
5030 ui.RequestContentRestrictedMessageBox(IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_CONTENT_RESTRICTION, iPad);
5031 }
5032 else if(!g_NetworkManager.IsLocalGame() && !ProfileManager.HasPlayStationPlus(iPad))
5033 {
5034 pMinecraftClass->m_pPsPlusUpsell = new PsPlusUpsellWrapper(iPad);
5035 pMinecraftClass->m_pPsPlusUpsell->displayUpsell();
5036 }
5037 else
5038#endif
5039 if( pMinecraftClass->level->isClientSide )
5040 {
5041 pMinecraftClass->addLocalPlayer(iPad);
5042 }
5043 else
5044 {
5045 // create the local player for the iPad
5046 shared_ptr<Player> player = pMinecraftClass->localplayers[iPad];
5047 if( player == NULL)
5048 {
5049 player = pMinecraftClass->createExtraLocalPlayer(iPad, (convStringToWstring( ProfileManager.GetGamertag(iPad) )).c_str(), iPad, pMinecraftClass->level->dimension->id);
5050 }
5051 }
5052 }
5053 else if( ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) && !ProfileManager.AllowedToPlayMultiplayer(iPad) )
5054 {
5055 // 4J Stu - Don't allow converting to guests as we don't allow any guest sign-in while in the game
5056 // Fix for #66516 - TCR #124: MPS Guest Support ; #001: BAS Game Stability: TU8: The game crashes when second Guest signs-in on console which takes part in Xbox LIVE multiplayer session.
5057 //ProfileManager.RequestConvertOfflineToGuestUI( &Minecraft::InGame_SignInReturned, pMinecraftClass,iPad);
5058 UINT uiIDA[1];
5059 uiIDA[0]=IDS_CONFIRM_OK;
5060 ui.RequestErrorMessage( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,iPad);
5061#ifdef _DURANGO
5062 ProfileManager.RemoveGamepadFromGame(iPad);
5063#endif
5064 }
5065 }
5066 }
5067 return 0;
5068}
5069
5070void Minecraft::tickAllConnections()
5071{
5072 int oldIdx = getLocalPlayerIdx();
5073 for(unsigned int i = 0; i < XUSER_MAX_COUNT; i++ )
5074 {
5075 shared_ptr<MultiplayerLocalPlayer> mplp = localplayers[i];
5076 if( mplp && mplp->connection)
5077 {
5078 setLocalPlayerIdx(i);
5079 mplp->connection->tick();
5080 }
5081 }
5082 setLocalPlayerIdx(oldIdx);
5083}
5084
5085bool Minecraft::addPendingClientTextureRequest(const wstring &textureName)
5086{
5087 AUTO_VAR(it, find( m_pendingTextureRequests.begin(), m_pendingTextureRequests.end(), textureName));
5088 if( it == m_pendingTextureRequests.end() )
5089 {
5090 m_pendingTextureRequests.push_back(textureName);
5091 return true;
5092 }
5093 return false;
5094}
5095
5096void Minecraft::handleClientTextureReceived(const wstring &textureName)
5097{
5098 AUTO_VAR(it, find( m_pendingTextureRequests.begin(), m_pendingTextureRequests.end(), textureName));
5099 if( it != m_pendingTextureRequests.end() )
5100 {
5101 m_pendingTextureRequests.erase(it);
5102 }
5103}
5104
5105unsigned int Minecraft::getCurrentTexturePackId()
5106{
5107 return skins->getSelected()->getId();
5108}
5109
5110ColourTable *Minecraft::getColourTable()
5111{
5112 TexturePack *selected = skins->getSelected();
5113
5114 ColourTable *colours = selected->getColourTable();
5115
5116 if(colours == NULL)
5117 {
5118 colours = skins->getDefault()->getColourTable();
5119 }
5120
5121 return colours;
5122}
5123
5124#if defined __ORBIS__
5125int Minecraft::MustSignInReturnedPSN(void *pParam, int iPad, C4JStorage::EMessageResult result)
5126{
5127 Minecraft* pMinecraft = (Minecraft *)pParam;
5128
5129 if(result == C4JStorage::EMessage_ResultAccept)
5130 {
5131 SQRNetworkManager_Orbis::AttemptPSNSignIn(&Minecraft::InGame_SignInReturned, pMinecraft, false, iPad);
5132 }
5133
5134 return 0;
5135}
5136#endif
5137